Claudio Lanconelli's WEB pages - Updated 26 Aug 98
;***************************************************************************
;* 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