Full Version : Vanhorn's Serial UART Routines (ASM)
avr >>ASSMBLER ROUTINES >>Vanhorn's Serial UART Routines (ASM)


Admin5- 04-19-2006
David Vanhorn's Serial.asm

The Serial comms using the on-board uart


CODE


;***************************************************************************
;
; File Name     :'SERIAL.asm"
; Title         :Serial I/O
; Date          :98.07.21
; Version       :0.01
; Support telephone :765 287 1987  David B. VanHorn
; Support fax       :765 287 1989
; Support Email     :dvanhorn@cedar.net
; Target MCU        :AT90S8515
;
; DESCRIPTION
;
;***************************************************************************
;   M O D I F I C A T I O N   H I S T O R Y
;
;       rev.      date    who   why
;   ----    --------  ---   ------------------------------------------
;   0.01    98.07.29  dvh   Creation
;   0,02    98.08.29  dvh   Added break and "wait for char"
;   0.03    98.09.01  dvh   Working on making it more interrupt driven
;
;***************************************************************************
;I'm not really satisfied with this yet, I'm not having a lot of luck modeling
;a fully interrupt-driven comm scheme along with things like the "wait for char"
;feature. Also, there's a conflict if the output buffer fills up. There is just
;no good way to handle that as far as I can see. I always end up with a construct
;that loops forever and dosen't return to the main system.
;
;Your input is most welcome here :)
;***************************************************************************************
;
Set_Baud_2400:

   ldi TEMP,207   ;
   rcall   SET_BAUD   ;
   ret

Set_Baud_4800:

   ldi TEMP,103   ;
   rcall   SET_BAUD   ;
   ret

Set_Baud_9600:

   ldi TEMP,51    ;
   rcall   SET_BAUD   ;
   ret

Set_Baud_14400:

   ldi TEMP,34    ;
   rcall   SET_BAUD   ;
   ret

Set_Baud_19200:

   ldi TEMP,25    ;
   rcall   SET_BAUD   ;
   ret

Set_Baud_28800:

   ldi TEMP,16    ;Error is 2.1%
   rcall   SET_BAUD   ;
   ret

Set_Baud_57600:

   ldi TEMP,8     ;Error is 3.7%
   rcall   SET_BAUD   ;
   ret

Set_Baud_115200:

   ldi TEMP,3     ;Error is 7.8%
   rcall   SET_BAUD   ;
   ret

Set_Baud:

   mov LOOP,TEMP  ;Save it for a moment
   rcall   WT4TXMT    ;Wait till all prev sent data is gone
   out UBRR,LOOP  ;Set the baud rate
   ret        ;
;
;************************************************************
;
;This one waits for TX buffer empty
;
WT4TXMT:
   rcall   Timed_Smack    ;Reset the watchdog if needed
   rcall   SEROUT_Check       ;returns # of bytes stored, in TEMP
   brne    WT4TXMT        ;
   ret
;
;This one waits till the current char is done transmitting
;
WT4XCHR:
   rcall   Timed_Smack;Reset watchdog if needed
   in  TEMP,USR   ;
   andi    TEMP,$40   ;Get the TX Complete bit
   breq    WT4XCHR    ;
   ret
;
;************************************************************
;
Check_Serial_IN:

   rcall   SERIN_Check    ;returns bytes stored, in TEMP
   breq    Check_Serial_IN_Done   ;
   ldi ZL,low(SERIAL_IN_BUF)  ;Absolute pointer to head
   ldi ZH,high(SERIAl_IN_BUF) ;
   ld  TEMP,Z+        ;The head byte is junk
   ld  TEMP,Z         ;If non-empty, then take a byte out of
                  ;serial_in_buf, and use it somehow

   and TEMP,TEMP      ;If non zero
   brne    Check_Serial_in_Full   ;then let the serial in buffer fill

  ;If zero returned, then the byte was stored, so kill it from
  ;the serial in buf.

   ldi ZL,low(SERIAL_IN_BUF)
   ldi ZH,high(SERIAL_IN_BUF)
   lds YL,(SERIAL_IN_TAIL)
   lds YH,(SERIAL_IN_TAIL+1)
   rcall   Kill_Head      ;Kill the sent byte
   sts (SERIAL_IN_TAIL),YL;
   sts (SERIAL_IN_TAIL+1),YH  ;
   rcall   HS_XON         ;Since we ate a char, set HS to true if it was false
   ldi TEMP,0         ;
   ret

Check_Serial_In_Full:
   ldi TEMP,$FF   ;Failed exit

Check_Serial_IN_Done:
   ret
;
;************************************************************
;
;Set output handshaking.
;Toggled based on current status
;Jam XON or XOFF into output buffer
;
HS_XOFF:
   lds TEMP,HS_FLAG   ;
   and TEMP,TEMP  ;
   breq    Ser_HS_Done;

   ldi TEMP,XOFF  ;Jam XOFF into serial out buffer
   rcall   Store_Serout   ;Enable transmit (if not already)
   in  TEMP,UCR   ;
   andi    TEMP,$7F   ;
   out UCR,TEMP   ;Make sure no more data
   in  TEMP,UCR   ;
   ori TEMP,$20   ;Turn on UDRIE
   out UCR,TEMP   ;in case it's off, so xoff and xon get sent
   ldi TEMP,$00   ;
   sts HS_FLAG,TEMP   ;
   rjmp    SER_HS_Done;

;
;************************************************************
;
HS_XON:
   lds TEMP,HS_FLAG   ;Get current status
   and     TEMP,TEMP  ;
   brne    Ser_HS_Done;If non-zero, then it's already cleared

   ldi TEMP,XON   ;Jam XON into serial out buffer
   rcall   Store_Serout   ;Enable transmit if not already
   in  TEMP,UCR   ;
   ori TEMP,$80   ;
   out     UCR,TEMP   ;
   in  TEMP,UCR   ;
   ori TEMP,$20   ;Turn on UDRIE
   out UCR,TEMP   ;in case it's off, so xoff and xon get sent
   ldi TEMP,$FF   ;
   sts HS_FLAG,TEMP   ;

Ser_HS_Done:
   ret
;
;************************************************************
;
SEND_BREAK:

  ;Assumption, that you want anything placed in the serial buffer
  ;to be sent before the break.
   rcall   WT4TXMT    ;Wait for serial buffer empty
   rcall   WT4XCHR    ;Wait for the last char to get out

  ;Shift the baud rate slightly lower.
   in  TEMP,UBRR  ;Get the current baud rate (51 @ 9600)
   push    TEMP       ;Save it
   mov LOOP,TEMP  ;Make a copy

   clc        ;
   lsr TEMP       ;divide it by 8
   lsr TEMP       ;
   lsr TEMP       ;
   add LOOP,TEMP  ;Add that to the old value

   out UBRR,LOOP  ;Set the new baudrate, two "bits" slower

   ldi TEMP,NUL   ;Load a null, 8 bits of zero
   out UDR,TEMP   ;Start Breaking now.    

   rcall   WT4XCHR    ;Wait till the char is sent

   pop TEMP       ;Get the old baud rate
   out UBRR,TEMP  ;Restore the original baud rate

   ret
;
;************************************************************
;
;Input: Char to get in temp, Delay in TEMP2
;Output: TEMP2=0 for ok, or FF for timeout or wrong char
;
WT4CHAR:;This starts the Serial_Wait engine to look for an incoming char.
   
   sts Char_Time,TEMP2;System will decrement on 1mS system ticks
   sts Watch_Char,TEMP;save temp for compare
  ;Turn off inbound serial ints
   ret        ;

;Char_Time = 0, Not waiting, or timed out.
;Char_Time <> 0, actively waiting.
;Watch_Char = byte value waiting on.
;


Serial_Wait:
   lds TEMP,Char_Time ;Are we waiting on a char (0=no)
   and TEMP,TEMP  ;Is Char_Time=0?
   brne    WT4CHAR_ACTIVE ;If not, then we're waiting
   ret        ;Else return

  ;If we're waiting, then see if it's happened

WT4CHAR_ACTIVE:
   in  TEMP,USR   ;Did we get a char yet?
   andi    TEMP,$80   ;Check bit 7
   brne    WT4CHAR_GOTIT  ;
   ret        ;Nope, just keep waiting

WT4CHAR_GOTIT:

   in  TEMP2,UDR  ;Get the Char
   andi    TEMP2,$7F  ;Mask off parity(?)
   lds TEMP,Watch_Char;What were we looking for?
   cp  TEMP,TEMP2 ;Is this it?
   breq    WT4CHAR_SUCCESS;

WT4CHAR_SUCCESS:
   ret




Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.