assemblyarmmicrocontrollercortex-mmicroprocessors

How to echo the data in the UART in ARM CORTEX-M3


I am trying to wait for the characters from UART, and then transmit back to the UART, I have attached the .c file, startup, and the linker code. I emulating the LM3S811 ARM Cortex-M3 board using the Qemu. But my qemu gives the following error. Actually this is my extension of the previous post How to wait for characters from UART and transmit back on the UART in ARM Cortex -M3 emulated by Qemu

ERROR :

(qemu) qemu-system-arm: Trying to execute code outside RAM or ROM at 0xbf00e000
This usually means one of the following happened:

(1) You told QEMU to execute a kernel for the wrong machine type, and it crashed on startup (eg trying to run a raspberry pi kernel on a versatilepb QEMU machine)
(2) You didn't give QEMU a kernel or BIOS filename at all, and QEMU executed a ROM full of no-op instructions until it fell off the end
(3) Your guest kernel has a bug and crashed by jumping off into nowhere

main.c

#define  U0RBR (*((volatile unsigned char *) 0x4000C000))
#define  U0THR (*((volatile unsigned char *) 0x4000C000))
#define  U0LSR (*((volatile unsigned char *) 0x4000C004))

unsigned char UART0_RxChar(void);
void UART0_TxChar(char ch);

unsigned char UART0_RxChar(void) 
{
    while( (U0LSR & 0x01) == 0) {
        continue;
    }
    return U0RBR;
}

void UART0_TxChar(char ch) 
{
    U0THR = ch;
    while( (U0LSR & 0x40) == 0 ) {
        continue;
    }
}

int main(void)
{
    char receive;
    
    while(1) {
        receive = UART0_RxChar();
        UART0_TxChar(receive);
    }
    return 0;
}

startup.s

.global start
start:
.word 0x20001000
.word main

flash.ld

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00002000
}


SECTIONS 
{
    .text : {
        *(.vectors);
        *(.text);
        etext = .;
    } > FLASH

    .rodata : {
        *(.rodata);
    } > FLASH

    .data : {
        sdata = .;
        *(.data);
        edata = .;
    } > SRAM AT > FLASH

    .bss : {
        sbss = .;
        *(.bss);
        ebss = .;
    } > SRAM
}

The updated code

#define  UARTDR (*((volatile unsigned int *) 0x4000C000))
#define  UARTFR (*((volatile unsigned int *) 0x4000C018))

unsigned char UART0_RxChar(void);
void UART0_TxChar(char ch);

unsigned char UART0_RxChar(void) 
{
    while( (UARTFR & 0x01) == 0);
        return UARTDR;
}

void UART0_TxChar(char ch) 
{
    UARTDR = ch;
    while ( (UARTFR & 0x40) == 0);
}

int main(void)
{
    char receive;
    
    while(1) {
        receive = UART0_RxChar();
        UART0_TxChar(receive);
    }
    while(1) continue;  
}

Output : The terminal does not allow me to type anything in the terminal.


Solution

  • unsigned char UART0_RxChar(void) 
    {
        while( (UARTFR & 0x01) == 0);
            return UARTDR;
    }
    

    bit 0 is marked as reserved, so this code won't do anything useful.

    Bit 4 though says

    RXFE

    UART Receive FIFO Empty

    The meaning of this bit depends on the state of the FEN bit in the UARTLCRH register.

    If the FIFO is disabled, this bit is set when the receive holding register is empty.

    If the FIFO is enabled, this bit is set when the receive FIFO is empty.

    so independent of the FEN control bit. Bit 4 is set when the fifo is empty which means when it changes from one to zero at least one character has been received.
    So

    unsigned char UART0_RxChar(void) 
    {
        while( (UARTFR & 0x10) != 0) continue; //while empty wait
        return UARTDR;
    }
    

    Bit 5 is set when the tx buffer is full which means there is no more room. So

    void UART0_TxChar(char ch) 
    {
        while ( (UARTFR & 0x20) != 0) continue; //while full wait
        UARTDR = ch;
    }
    

    you could instead

    void UART0_TxChar(char ch) 
    {
        while ( (UARTFR & (1<<5)) != 0) continue; //while full wait
        UARTDR = ch;
    }
    

    Pros and cons to use 0x20 or (1<<5), obviously both are the same. Both offer better readability and validation depending on the individual and how they use/read a manual, etc.

    The problem I found is if you hold the key down on the keyboard and repeat into the virtual terminal it appears it overflows the simulated rx buffer and an explosion of characters come out. You don't have this problem on real hardware. qemu is open source, so you can easily just go read the code to see what is going on. Possible that it wants an more accurate/correct uart init, since the uart on real hardware would not work with this code as written. a uart init is needed.

    Understand that absolutely none of this has to do with a cortex-m3, the fact there is a cortex-m3 is in this chip is irrelevant with respect to the uart, the uart is either created or purchased ip by Luminary Micro which was then assimilated by TI. the cortex-m3 is just the processor core, the bulk of the code and documentation, etc have nothing to do with the cortex-m3. In that this answer is written in English using an English alphabet yet this answer does not dwell on that fact.

    And this answer could easily be written in another language using the alphabet for that language. The cortex-m3 is just the mechanism in which you poke at control registers and make the peripherals do things. chips like this with a purchased ip core get the core from one vendor and the rest of the chip is either the chip vendors IP or a collection of other third party ip, or a combination.

    Your title question makes no sense since the cortex-m3 doesn't have a uart. Your actual question is related to the LM3S811 CHIP (not board) and the QEMU implementation of that, ideally with a qemu version, but at a minimum: "How to echo data through the LM3S811 QEMU simulation"