Save array or string and send it by uart assembler avr with atmega328p

200 Views Asked by At

Im trying to save an array from uart rx to an variable and send it to tx, i dont know where is the problem in the code and if the array is saved in the variable but im not receiving any data in the terminal, probably im missing something

.DSEG
.ORG    0X0100
STRNG:      .BYTE   128 ;Strings recommended to be even


.CSEG

STRNG2:     .DB     "Printing aithing from probably the buffer",0X00 ;Strings recommended to be even
            RJMP    MAIN
            
MAIN:       SBI     DDRD,PD1
            LDI     R16,0X00
            LDI     R17,0XCF
            STS     UBRR0L,R17 ;UBRRXL - Usart Baud Rate 0 Register Low| Low byte of Baud Rate
            STS     UBRR0H,R16 ;UBRRXH - Usart Baud Rate 0 Register High| High 4bits of Baud Rate
            LDI     R18,0X22
            STS     UCSR0A,R18 ;UCSRXA - Usart Control and Status Register X A| flags, status and config: (flag after receive)(flag after transmit)(flag buffer data register empty[1 defaul])(flag frame error)(flag buffer overrun)(flag parity error)(U2XX state)(multiprocessor communication state) | set flags acording documentation (all in 0 except UDRE0)
            LDI     R19,0X06
            STS     UCSR0C,R19 ;UCSRXC - Usart Control and Status Register X C| flags, status and config: (Usart modes)(parity mode)(stop bits mode)(character size)(clock polarity[for USART])
            LDI     R20,0X18
            STS     UCSR0B,R20 ;UCSRXB - Usart Control and Status Register X B| config: (after receive interrupt)(after transmit interrupt)(buffer data register empty interrupt)(rx enable)(tx enable)(character size)(receive data bit 8[for 9bit])(transmit data bit 8[for 9bit])

LOOP:       RJMP    RX
            RCALL   WAITT
            RJMP    LOOP

RX:         LDS     R21,UCSR0A
            SBRS    R21,UDRE0
            RJMP    RX

            LDI     XL,LOW(STRNG)       ;Z POINTER  
            LDI     XH,HIGH(STRNG)
            LDS     R22,UDR0

            CPI     R22,0X0D
            BREQ    TX

            LDI     XL,LOW(STRNG)       ;Z POINTER  
            LDI     XH,HIGH(STRNG)
            ST      X+,R22
            RJMP    RX

TX:         LDI     XL,LOW(STRNG)       ;Z POINTER  
            LDI     XH,HIGH(STRNG)
            LD      R23,X+
            CPI     R23,0X00
            BREQ    END

SEND:       LDS     R21,UCSR0A
            SBRS    R21,UDRE0
            RJMP    SEND

            STS     UDR0,R23
            RJMP    TX

END:        RET

WAITT:      LDI  R24, 82
            LDI  R25, 43
L1:         DEC  r25
            BRNE L1
            DEC  r24
            BRNE L1
            RET

I cant understand where is the problem

2

There are 2 best solutions below

2
dimich On

First issue in your program is that AVR8 core starts to execute code from reset vector at address 0 but you have string there. CPU tries to execute its content. Usually at address 0 interrupt vectors table is located. If you don't plan to use interrupts, you can place your code there, but it must start from address 0.

Second issue is that your code waits for character from UART by testing UDRE0 flag:

RX:         LDS     R21,UCSR0A
            SBRS    R21,UDRE0

UDREn: USART Data Register Empty: The UDREn flag indicates if the transmit buffer (UDRn) is ready to receive new data

You should test RXC0 flag to detect character reception:

RXCn: USART Receive Complete: This flag bit is set when there are unread data in the receive buffer and cleared when the receive buffer is empty

RX:         LDS     R21,UCSR0A
            SBRS    R21,RXC0

Third issue is that you initialize current charater pointer (X-register) on every iteration, moreover twice: before testing for end of line and before storing to a buffer.

Fourth issue is that in STORE function you look for NUL terminator as the end of a string but never store it.

The whole program could be like following. I don't know purpose of WAIT function so removed it.

.DEVICE "ATmega328P"
.DSEG
.ORG    0X0100
STRNG:      .BYTE   128 ;Strings recommended to be even

.CSEG
MAIN:       SBI     DDRD,PD1
            LDI     R16,0x00
            LDI     R17,0xCF
            STS     UBRR0L,R17
            STS     UBRR0H,R16
            LDI     R18,0x22
            STS     UCSR0A,R18
            LDI     R19,0x06
            STS     UCSR0C,R19
            LDI     R20,0x18
            STS     UCSR0B,R20

LOOP:       LDI     XL,LOW(STRNG)       ; Set string pointer to the beginning of buffer
            LDI     XH,HIGH(STRNG)

RX:         LDS     R21,UCSR0A
            SBRS    R21,RXC0    ; USART Receive Complete
            RJMP    RX

            LDS     R22,UDR0

            CPI     R22,0x0D    ; End of line?
            BRNE    STORE       ; No - store received character into buffer

            LDI     R22,0x00    ; Store NUL terminator
            ST      X+,R22

            LDI     XL,LOW(STRNG)       ; Set string pointer to the beginning of buffer
            LDI     XH,HIGH(STRNG)

            RJMP TX             ; Print buffer content

STORE:      ST      X+,R22
            RJMP    RX

TX:         LD      R23,X+
            CPI     R23,0x00
            BREQ    LOOP        ; Read next line

SEND:       LDS     R21,UCSR0A
            SBRS    R21,UDRE0
            RJMP    SEND

            STS     UDR0,R23
            RJMP    TX

I didn't test it on real hardware but it does work in QEMU.

Hint for optimization: you can use CR character (0x0D) as string terminator. In this case you shouldn't store NUL character but check for CR in SEND:

...
RX:         LDS     R21,UCSR0A
            SBRS    R21,RXC0    ; USART Receive Complete
            RJMP    RX

            LDS     R22,UDR0    ; Store character into buffer
            ST      X+,R22

            CPI     R22,0x0D    ; End of line?
            BRNE    RX          ; No - receive next character

            LDI     XL,LOW(STRNG)       ; Set string pointer to the beginning of buffer
            LDI     XH,HIGH(STRNG)

TX:         LD      R23,X+
            CPI     R23,0x0D    ; End of line?
            BREQ    LOOP        ; Read next line

SEND:       LDS     R21,UCSR0A
            SBRS    R21,UDRE0
            RJMP    SEND

            STS     UDR0,R23
            RJMP    TX
2
Fazuelli Brabo Demais On

The previous answer does not work for me; data does not appear in the terminal when I try it.

Using the following, however, the data appears in terminal of the Arduino IDE when I test it, and I can continue the modifications that I need for my solution from this point and beyond.

This is my code:

;------------------------------------------------------------------------
; print uart data:
;------------------------------------------------------------------------
    monitor_serial:   
                LDI     XL,LOW(strSerialRead)       
                LDI     XH,HIGH(strSerialRead)  
    
    read:       LDS     R21,UCSR0A
                SBRS    R21,RXC0    ; USART Receive Complete
                RJMP    read
                LDS     R22,UDR0    ; Store character r22  
                CPI     R22,0x0D    ; End of line?
                BREQ    SEND        ;yes - go to send
                ST      X+,R22  ; No - receive next character
                STS     UDR0,R22            
                rjmp read           
    
    SEND:   
            LD      R16, X ; save data of X register in R16 register
            STS     UDR0,R16 ;pass data from r16 register to udr0 register that will show it in the terminal(UDR0 register transmit all data that was stored there or store all data that was received and)
            ret ; return to initial stack point