AVR Assembly code for UART, sending two characters over Serial?

213 Views Asked by At

I am just trying to send a character from my ATMEGA32A to Serial. Here is the code but its not working. I am unsure why because I think I am doing everything right. Can anybody help me fix?

(BAUD Rate: 9600)

.cseg
.org 0x00 

main:
ldi r16,0x80
ldi r17,0x25
call USART_Init

loop:
ldi r20, 0x86
call USART_Transmit
ldi r20, 0xFF
call USART_Transmit
rjmp loop


USART_Init:
; Set baud rate
out UBRRH, r17
out UBRRL, r16
; Enable receiver and transmitter
ldi r16, (1<<RXEN)|(1<<TXEN)
out UCSRB,r16
; Set frame format: 8data, 2stop bit
ldi r16, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)
out UCSRC,r16
ret

USART_Transmit:
; Wait for empty transmit buffer
sbis UCSRA,UDRE
rjmp USART_Transmit
; Put data (r16) into buffer, sends the data
out UDR,r20
ret

I don't see anything in the Serial Terminal. I am confident wiring is okay. Also set the 8bit data and 2-stop bit properly in the serial terminal settings.

1

There are 1 best solutions below

0
emacs drives me nuts On
ldi r16,0x80
ldi r17,0x25
call USART_Init

It's 0x2580 = 9600, but that's not how you initialitze a USART. Instead, it's similar to initializing a timer: The higher the baud rate, the smaller UBRR.

For example, when the AVR runs at 1 MHz and you want 9600, then you need U2X = 1 and UBRR = 0xc = 12.

U2X = 0 won't work with 1 MHz, because the resulting clock would have an error of 7%, which is too much for reliable UART operation.

If you use a reasonable assembler (like GNU as), then you can let the assembler compute the UBRR values provided it is known at assembly time. In C, you would write something like:

void uart_init (void)
{
    unsigned short ubrr = -.6 + F_CPU / ((16L - 8*U2X_BIT) * BAUDRATE);

    UBRRH = ubrr >> 8;
    UBRRL = ubrr;

    UCSRA = (U2X_BIT << U2X) | ...

where U2X_BIT is 0 or 1, BAUDRATE is the desired baud rate and F_CPU is the clock frequency (in Hz) of the controller.

So better read the ATmega32 manual again.