Claudio Lanconelli's WEB pages - Updated 26 Aug 98

Home page ] Projects ] Useful links ] Who am I? ]


;***************************************************************************
;* RS232.ASM
;*
;* rs232 Tx only example based on
;* AVR MINI THREADS v.1.02
;* ---> nanoKernel for the AVR AT90S1200
;*
;* To try this code you need AvrTools from ATMEL, PonyProg and a simple
;* hardware (See schematics in PDF).
;*
;* Copyright (c) 1998 by Claudio Lanconelli
;* e-mail: lanconel@cs.unibo.it
;* WWW: http://www.cs.unibo.it/~lanconel
;*
;/ This program is free software; you can redistribute it and/or //
;/ modify it under the terms of the GNU General Public License //
;/ as published by the Free Software Foundation; either version2 of //
;/ the License, or (at your option) any later version. //
;/ //
;/ This program is distributed in the hope that it will be useful, //
;/ but WITHOUT ANY WARRANTY; without even the implied warranty of //
;/ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
;/ General Public License for more details. //
;/ //
;/ You should have received a copy of the GNU General Public License //
;/ along with this program (see COPYING); if not, write to the //
;/ Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //
;***************************************************************************
.DEVICE AT90S1200

.include "macro.inc"
.include "1200def.inc"

; Follows an example of the use of mini-threads (three threads).
;-the first thread (main) send data to the Serial driver thread
;-the second thread do nothing
;-the third thread (the serial driver) wait for the timer or thread1 request
; and send the data to the SerTx pin in a 1200 8N1 data format (with a 3.6864MHz xtal)
;

.CSEG

;***************************************************************************
;* VARIABLE ASSIGNEMENTS
;***************************************************************************

    .def    SaveThr1Status    =     r0 ;status copy for thread 1
    .def    SaveThr2Status    =     r1    ;status copy for thread 2
    .def    SaveThr3Status    =     r2    ;status copy for thread 3
    .def    SaveStatus    =     r3    ;status copy for interrupts

    .def    SerNbit         =    r16     ;serial bit to transmit
    .def    SerData         =    r17     ;serial data byte to transmit

    .def Main1        =     r21    ;Temp variable used by main program
    .def    MiscFlags    =     r31    ;threads status flags + signal flags

    ;flags bit definition
    .equ    Thread1Status    =     0    ; 1 --> ready, 0 --> waiting
    .equ    Thread2Status    =     1
    .equ    Thread3Status    =     2
    .equ    Thread1Signal    =     3
    .equ    Thread2Signal    =     4
    .equ    Thread3Signal    =     5
    .equ    SerRequest    =     6

    .equ    THRSTATUSMASK =         7
    .equ    SIGNALMASK =         112


;***************************************************************************
;* Port Pin Assignements
;***************************************************************************

    ;port D bit definitions
    .equ    Led1    =    0     ;out
    .equ    Led2    =    1     ;out

    ;port B bit definitions
    .equ    Key1    =    0     ;in (pullup)
    .equ    SerTx    =    4     ;out
    

;***************************************************************************
;* VECTORS
;***************************************************************************

        rjmp RESET             ;Reset Handle
        rjmp INT0DRV             ;Ext. interrupt request 0
        rjmp TIMERDRV         ;Timer


;***************************************************************************
;*
;* MAIN PROGRAM
;*
;***************************************************************************
;* INITIALIZATION
;***************************************************************************

RESET: 
        ldi    Main1, 0b01111011     ;set port D bits to outputs (INT0 as an input)
        out    DDRD, Main1
        ldi    Main1, 0b00000111     ;preset output state (activate INT0 pull-up)
        out    PortD, Main1
        ldi    Main1, 0b00010000     ;set port B to inputs
        out    DDRB, Main1
        ldi    Main1, 0b11101111     ;turn on pullups on inputs
        out    PortB, Main1

        ldi    Main1, 5
        out    TCCR0, Main1         ;set prescaler to CK/1024
        ldi    Main1, 32+2
        out    MCUCR, Main1         ;enable sleep idle mode (ext int on falling edge)
        ldi    Main1, 2
        out    TIMSK, Main1         ;enable timer interrupt 
        ldi    Main1, 64
        out    GIMSK, Main1         ;enable external interrupt

        ldi    Main1, 256-3
        out    TCNT0, Main1

        ldi    MiscFlags,THRSTATUSMASK 

        sei                 ;enable interrupts

        in    SaveThr1Status,SREG         ;initialize status (interrupts enabled in all thread)
        mov     SaveThr2Status,SaveThr1Status
        mov     SaveThr3Status,SaveThr1Status
        
;=====================================
;THREAD 1
; main loop
THR1LOOP:
        sbic    PinB,Key1
        rjmp    L001
        cbi    PortD,Led1

        sbr    MiscFlags, EXP2(SerRequest)
        ldi    SerData,66         ;Carattere 'B'
        sbr    MiscFlags, EXP2(Thread3Signal)        ;send the request to serial thread
        rcall    WAIT1

        sbr    MiscFlags, EXP2(SerRequest)
        ldi    SerData,65         ;Carattere 'A'
        sbr    MiscFlags, EXP2(Thread3Signal)        ;send the request to serial thread
        rcall    WAIT1

        sbr    MiscFlags, EXP2(SerRequest)
        ldi    SerData,66         ;Carattere 'B'
        sbr    MiscFlags, EXP2(Thread3Signal)        ;send the request to serial thread
        rcall    WAIT1

        sbr    MiscFlags, EXP2(SerRequest)
        ldi    SerData,69         ;Carattere 'E'
        sbr    MiscFlags, EXP2(Thread3Signal)        ;send the request to serial thread
        rcall    WAIT1

        rjmp    THR1LOOP
L001:
        sbi    PortD,Led1
        rjmp    THR1LOOP

;-----------------
WAIT1:
        ;save status before switch to another thread
        in    SaveThr1Status,SREG
        sbrs    MiscFlags, Thread1Signal         ;check for reeceived signal
        cbr    MiscFlags, EXP2(Thread1Status)        ;thread1 in wait state
        cbr    MiscFlags, EXP2(Thread1Signal)        ;reset signal
        rjmp    SCHEDULER2
THR1WAKEUP:
        ret


;=================================
;THREAD 2    (do nothing in this example)
; main loop
THR2LOOP:
        ;thread 2 WAIT
        ;we can't do a separate Wait subroutine for every thread. Note that
        ;the stack is hardware, and not accessible.
        ;save status before switch to another thread
        in    SaveThr2Status,SREG
        sbrs    MiscFlags, Thread2Signal         ;check for received signal, if we have already
                                ;received the signal don't go sleep
        cbr    MiscFlags, EXP2(Thread2Status)        ;thread2 in wait state
        cbr    MiscFlags, EXP2(Thread2Signal)
        rjmp    SCHEDULER3
THR2WAKEUP:
        rjmp    THR2LOOP


;===================================
;SERIAL DRIVER THREAD
; main loop
THR3LOOP:
        ;thread 3 WAIT
        ;save status before switch to another thread
        in    SaveThr3Status,SREG
        sbrs    MiscFlags, Thread3Signal         ;check for received signal
        cbr    MiscFlags, EXP2(Thread3Status)        ;thread3 in wait state
        cbr    MiscFlags, EXP2(Thread3Signal)
        rjmp    SCHEDULER1
THR3WAKEUP:
        ;test SerRequest to know who have sent the the signal (Thr1 or Timer)
        sbrc    MiscFlags, SerRequest
        rjmp    THR3_L1

        ;waked up from Timer, are some data bits to transmit?
        tst    SerNBit                     ;if zero do nothing
        breq    THR3LOOP

        dec    SerNBit
        breq    THR3_TXEND                 ;if zero tx stop and finish

        cpi    SerNBit,9                 ;tx start
        breq    THR3_TX0
THR3_TXDATA:
        lsr    SerData                     ;tx next bit (in the carry)
        brcc    THR3_TX0
THR3_TX1:
        cbi    PortB,SerTx
        rjmp    THR3LOOP
THR3_TX0:
        sbi    PortB,SerTx
        rjmp    THR3LOOP
THR3_L1:
        ;new request from Thr1
        cbr    MiscFlags, EXP2(SerRequest)
        ldi    SerNBit,10                 ;tx 10 bits: 1start + 8data + 1stop
        rjmp    THR3LOOP
THR3_TXEND:
        sbr    MiscFlags, EXP2(Thread1Signal)        ;wakeup thread 1
        rjmp    THR3_TX1


;---------------
;Interrupts routine just send a signal to a thread. If you need a VERY short interrupt
;response you can put some instructions here, then send the signal to the thread
;---------------
TIMERDRV:
        in    SaveStatus,SREG

        ldi    Main1, 256-3
        out    TCNT0, Main1
        sbr    MiscFlags, EXP2(Thread3Signal)        ;wakeup thread 3 (serial driver)

        out    SREG,SaveStatus
        reti


;---------------
INT0DRV:
        in    SaveStatus,SREG
        sbr    MiscFlags, EXP2(Thread2Signal)        ;wakeup thread 2
        out    SREG,SaveStatus
        reti


;-----------------
;This is the scheduler, the core of the nanoKernel. You can decide to go sleep
; when there's nothing to do. You can also put there the watchdog reset instruction.
;-----------------
SCHEDULER:
        sei                         ;be sure interrupts on here

        ;if you don't want to go sleep remove next 3 instr
        tst    MiscFlags
        brne    SCHEDULER1
        sleep
SCHEDULER1:
        sbrc    MiscFlags, Thread1Status         ;test if thread1 is ready
        rjmp    SCHEDRDY1
        ;check for wakeup
        sbrs    MiscFlags, Thread1Signal         ;test if thread1 received a signal
        rjmp    SCHEDULER2
        cbr    MiscFlags, EXP2(Thread1Signal)        ;clear signal
SCHEDRDY1:
        ;switch to thread 1
        sbr    MiscFlags, EXP2(Thread1Status)
        out    SREG,SaveThr1Status
        rjmp    THR1WAKEUP

SCHEDULER2:
        sbrc    MiscFlags, Thread2Status         ;test if thread2 is ready
        rjmp    SCHEDRDY2
        ;check for wakeup
        sbrs    MiscFlags, Thread2Signal         ;test if thread1 received a signal
        rjmp    SCHEDULER3
        cbr    MiscFlags, EXP2(Thread2Signal)        ;clear signal
SCHEDRDY2:
        ;switch to thread 2
        sbr    MiscFlags, EXP2(Thread2Status)
        out    SREG,SaveThr2Status
        rjmp    THR2WAKEUP
SCHEDULER3:
        sbrc    MiscFlags, Thread3Status         ;test if thread3 is ready
        rjmp    SCHEDRDY3
        ;check for wakeup
        sbrs    MiscFlags, Thread3Signal         ;test if thread1 received a signal
        rjmp    SCHEDULER
        cbr    MiscFlags, EXP2(Thread3Signal)        ;clear signal
SCHEDRDY3:
        ;switch to thread 3
        sbr    MiscFlags, EXP2(Thread3Status)
        out    SREG,SaveThr3Status
        rjmp    THR3WAKEUP