Skip to content

Instantly share code, notes, and snippets.

@owskio
Last active March 11, 2018 01:18
Show Gist options
  • Save owskio/08a87b5530be75887b29cc2eadb547cb to your computer and use it in GitHub Desktop.
Save owskio/08a87b5530be75887b29cc2eadb547cb to your computer and use it in GitHub Desktop.
This gist records uart-user-input in a 32 byte buffer and prints/echoes that value out via uart upon encountering a whitespace.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;MAKEFILE EXCERPT
;
;#Output file in intel hex format with -fI
;
;serial:
; sudo putty /dev/ttyUSB0 -serial -sercfg 8,2,9600,n,N # "-cs ISO-8859-1" not necessary
;
;compile:
; wine avrasm2.exe -fI -l test.lst test.asm
;
;flash: compile
; avrdude -c usbtiny -p atmega1284 -U flash:w:test.hex
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;INCLUDES
.nolist
.include "./m1284def.asm"
.list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;MACROS
;Compare the low byte, (cp rA, rB) -> rA-rB
;This will set Z & C in SREG
;Z=1 if rA=rB, and C=1 if |rA|<|rB|;
;Compare the high byte: cpc rA,rB -> rA-rB-C
#define compare16(bigRegLeft,bigRegRight) \
cp bigRegLeft##L,bigRegRight##L \
cpc bigRegLeft##H,bigRegRight##H
;We need to be able to increment these compound registers (X=r27:r26;Y=r29:r28;Z=r31:r30)
;and to my knowledge 'inc' does not work on them, only on single byte registers
#define inc16(reg16) \
push r0 \
ld r0,Z+ \
pop r0
;Set big compound register to address in data/ram/data-segment/memory(as opposed to 'program')
#define set16(reg16,addr) \
ldi reg16##H,high((addr)) \
ldi reg16##L,low((addr))
;Actually storing anything in flash at a word address should
;first result in a lowbyte being populated, if high bytes are not supplied
;with data, then they are 'padded' as a single null byte (0x00)
;Scale by 2*X+1 because flash is byte addressable
#define setFlash16(reg16,addr) \
ldi reg16##H,high(2*(addr)) \
ldi reg16##L,low(2*(addr) + 0)
#define immediate(operation,destination,value) \
push r19 \
ldi r19, value \
operation destination,r19 \
pop r19
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;DATA
.dseg
.org RAMEND/2
word_buffer:
.byte 32
word_buffer_end:
.byte 1; this line exists just to see address in lst file as 32 bytes later than word_buffer:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;DEFS
.def outChar = r16
.def inChar = r17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CODE
.cseg ;Code (flash) segment
;VECTORS
; Reset Vector, just go to init
.org 0x0000
rjmp Reset
; USART0, Rx Complete
.org URXC0addr
rjmp uart_receive_complete
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;INIT
Reset:
;16MHz crystal ;CKDIV8 not set
.equ FOSC = 16000000
.equ BAUD = 9600
call uart_init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;PRINT TEST_MESSAGE
;Initialize compound register Z (=R31:R30)to point to "TEST_MESSAGE" location
set16(Z,word_buffer)
;Reset buffer 'write' pointer to beginning of buffer now
set16(X,word_buffer)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;MAIN
sei ; SEt_global_Interrupt_flag
Main:
;do nothing, respond to events only
rjmp Main
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;SUBROUTINES
uart_receive_complete:
;Get the char
lds inChar, UDR0
;Write the input character to the current 'write' position in the RAM buffer
;, and then increment the 'write' pointer
st X+,inChar
;If we have typed and typed until the end of the buffer
;without typing a word, then just print the contents
;of the buffer so that we can see a little more about
;what is going on
set16(Z,word_buffer_end)
compare16(X,Z)
brlo skipInputBufferReset ; BRanch_if_LOwer_unsigned
set16(Z,word_buffer)
call printString
set16(X,word_buffer);reset
skipInputBufferReset:
;If I type in any white-space char at all, then 'consume the word'
;which, for now, just means to print the word in the word buffer,
;which is why we add a NULL(0x00) byte to the buffer to signify
;the end of the word, at least to the print-string subroutine,
;which terminates printing upon encountering 0x00
cpi inchar,'\t'
breq callConsumeWord
cpi inchar,' '
breq callConsumeWord
cpi inchar,'\r'
breq callConsumeWord
cpi inchar,'\n'
breq callConsumeWord
;Otherwise, word is still incoming (via keyboard or uart),
;so skip 'consumption'
rjmp skipWordConsumption
callConsumeWord:
call consumeWord
skipWordConsumption:
;Prep the output char
mov outChar, inChar
;Transmit the byte char
call printChar
reti
consumeWord:
;Now that the end of the word has been signalled,
;store a null byte in the next empty position in the
;word buffer to signal the end of the word string
immediate(st,X+,0x00)
;Convenience newline for printing out the word-buffer's contents
ldi outChar,'\r'
call printChar
;'Consume the word' - Print it out from RAM
set16(Z,word_buffer)
call printString
;Reset the 'write' pointer to the beginning of the word buffer
;to start recording the next word being typed in
set16(X,word_buffer)
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
printString:
;Loop through each byte location and print out the character found to the uart connection
;Don't know if I want to keep using Z like this in the future
printStringNextChar:
;load the current char for uart transmission
ld outChar,Z
;Do not necessarily rely on null to quit printing string,
;but if exists because assembler inserts it,
;then treat it as a terminating char
cpi outChar,0x00
breq exitPrintString
;Print the current character
call printChar
;Increment the 16 bit "pointer"
inc16(Z)
;Check if we have reached the end of the "string"
set16(Y,word_buffer_end)
compare16(Y,Z)
;compare passed so stop printing
breq exitPrintString
;If not done printing, print the next char
jmp printStringNextChar
exitPrintString:
ret
printChar:
;Prints a byte to uart, but also appends an <LF> to any outgoing <CR>s.
;(Useful when working/debugging uart at the terminal)
;USAGE:
; mov outChar, rXX
; call printChar
;Print the current character
call uart_transmit_byte_sync
;If was carriage-return, load line-feed follow-up
cpi outChar,0x0D ; <CR>
brne skipLineFeed
ldi outChar, 0x0A ; <LF>
call printChar
skipLineFeed:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;UART STUFF
uart_init:
;USAGE:
;
; .equ FOSC = 16000000
; .equ BAUD = 9600
; call uart_init
;
;Set baud rate
;NOTE: ubrr is a 12 bit register so
; take the 16bit clocks/baud-period value and (<< 2^4) aka (/16)
; but not sure what the -1 is for
; the -1 just comes from Atmel's documentation without explanation
.equ ubrr = (((FOSC/BAUD)/16)-1)
immediate(sts, UBRR0H, ubrr >> 8) ;High byte
immediate(sts, UBRR0L, ubrr )
; Enable receiver and transmitter ;Enable the rx complete interrupt
immediate(sts, UCSR0B, (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0))
; Set frame format: 8data, 2stop bit
immediate(sts, UCSR0C, (1<<USBS0) |(1<<UCSZ01)|(1<<UCSZ00))
ret
uart_transmit_byte_sync:
;USAGE:
; mov outChar, rXX
; call uart_transmit_byte_sync
push r17
uart_transmit_check:
; Wait for empty transmit buffer
lds r17, UCSR0A
sbrs r17, UDRE0 ; SBRS = SkipifBitinRegisterSet
; UDRE0 not set, data not ready, check again
rjmp uart_transmit_check
; Put data (r16) into buffer; this sends the data
sts UDR0,outChar
pop r17
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment