如何通过LM3S811的UART发送数据

How to send data through UART of LM3S811

我正在学习裸机编程,我尝试通过Qemu中的LM3S811的UART发送数据。但它没有在终端中打印任何字符。我提供了 .c 文件和链接描述文件。如果有任何链接可以帮助您从头开始学习裸机编程。谢谢

.c 文件

char stack[1024];

extern char etext;
extern char sdata;
extern char edata;
extern char sbss;
extern char ebss;

static char *bssp = (char *)0xDEADBEEF;
unsigned int *uart = (unsigned int *)0x4000C000;

void start()
{
    char *from, *to;

    from = &etext;
    to = &sdata;

    while (to != &edata) {
        *to++ = *from++;
    }
    
    bssp = &sbss;
    while (bssp != &ebss) {
        *bssp++ = 0;
    }

    main();

    while(1);
}


__attribute__((section(".vectors")))
void *vectors[] = {
    stack + sizeof(stack),
    start,
};


int main()
{
    char *ptr = "Have a great day";
    while (*ptr != '[=10=]') {
        *uart = *ptr;
        ptr++;
    }
    return 0;
}

链接描述文件:

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


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

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

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

所以从这个开始,然后去改变它

flash.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
.word 0x20001000
.word reset

.thumb_func
reset:
    bl notmain
    b hang
.thumb_func
hang:   b .

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

notmain.c

void PUT32 ( unsigned int, unsigned int );
#define UART_DR 0x4000C000
int notmain ( void )
{
    char *ptr = "Have a great day";
    while (*ptr != '[=11=]') {
        PUT32(UART_DR,*ptr);
        ptr++;
    }
    return(0);
}

flash.ld

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
    .rodata : { *(.rodata*) } > rom
}

建造

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m0 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o notmain.o -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy -O binary notmain.elf notmain.bin

检查

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000009    andeq   r0, r0, r9

00000008 <reset>:
   8:   f000 f804   bl  14 <notmain>
   c:   e7ff        b.n e <hang>

所以矢量 table 看起来不错

  18:   4c04        ldr r4, [pc, #16]   ; (2c <notmain+0x18>)
  1a:   4805        ldr r0, [pc, #20]   ; (30 <notmain+0x1c>)
  1c:   3401        adds    r4, #1
  1e:   f7ff fff7   bl  10 <PUT32>
  22:   7821        ldrb    r1, [r4, #0]
  24:   2900        cmp r1, #0
...
  2c:   00000034    andeq   r0, r0, r4, lsr r0
...
Disassembly of section .rodata:

00000034 <.rodata>:
  34:   65766148    ldrbvs  r6, [r6, #-328]!    ; 0xfffffeb8
  38:   67206120    strvs   r6, [r0, -r0, lsr #2]!
  3c:   74616572    strbtvc r6, [r1], #-1394    ; 0xfffffa8e
  40:   79616420    stmdbvc r1!, {r5, r10, sp, lr}^
    ...

字符串似乎在 rodata 中,因此看起来也不错。

qemu-system-arm -M lm3s811evb -m 1M -nographic -kernel notmain.bin
Have a great day

ctrl-a 然后 x 退出 qemu

flash.s

.thumb
.global _start
_start:
.word 0x20001000
.word notmain

notmain.c

#define UART_DR (*((volatile unsigned int *)0x4000C000))
void notmain ( void )
{
    char *ptr = "Have a great day";
    while (*ptr != '[=18=]') {
        UART_DR=*ptr;
        ptr++;
    }
    while(1) continue;
}

flash.ld

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
    .rodata : { *(.rodata*) } > rom
}

建造

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m3 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m3 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o notmain.o -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy -O binary notmain.elf notmain.bin

检查

Disassembly of section .text:

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000009    andeq   r0, r0, r9

00000008 <notmain>:

向量table很好

00000008 <notmain>:
   8:   2348        movs    r3, #72 ; 0x48
   a:   4a04        ldr r2, [pc, #16]   ; (1c <notmain+0x14>)
   c:   4904        ldr r1, [pc, #16]   ; (20 <notmain+0x18>)
   e:   600b        str r3, [r1, #0]
  10:   f812 3f01   ldrb.w  r3, [r2, #1]!
  14:   2b00        cmp r3, #0
  16:   d1fa        bne.n   e <notmain+0x6>
  18:   e7fe        b.n 18 <notmain+0x10>
  1a:   bf00        nop
  1c:   00000024    andeq   r0, r0, r4, lsr #32
  20:   4000c000    andmi   r12, r0, r0


Disassembly of section .rodata:

00000024 <.rodata>:
  24:   65766148    ldrbvs  r6, [r6, #-328]!    ; 0xfffffeb8
  28:   67206120    strvs   r6, [r0, -r0, lsr #2]!
  2c:   74616572    strbtvc r6, [r1], #-1394    ; 0xfffffa8e
  30:   79616420    stmdbvc r1!, {r5, r10, sp, lr}^
    ...

这是一个有趣的解决方案,但看起来不错,字符串在 flash 中,等等。

qemu-system-arm -M lm3s811evb -m 1M -nographic -kernel notmain.bin
Have a great day

您需要检查构建的输出。

如果我建造它

00000000 <vectors>:
   0:   20000408    andcs   r0, r0, r8, lsl #8
   4:   00000009    andeq   r0, r0, r9

00000008 <start>:

非常奇怪的 sp 初始值,但无论如何,它应该可以工作是吗?

Disassembly of section .text:

00000000 <vectors>:
   0:   20000408    andcs   r0, r0, r8, lsl #8
   4:   00000009    andeq   r0, r0, r9

00000008 <start>:
   8:   b508        push    {r3, lr}
   a:   480d        ldr r0, [pc, #52]   ; (40 <start+0x38>)  20000008
   c:   4b0d        ldr r3, [pc, #52]   ; (44 <start+0x3c>)  20000000
   e:   4283        cmp r3, r0
  10:   d006        beq.n   20 <start+0x18>
  12:   4a0d        ldr r2, [pc, #52]   ; (48 <start+0x40>)  00000058
  14:   f812 1b01   ldrb.w  r1, [r2], #1
  18:   f803 1b01   strb.w  r1, [r3], #1
  1c:   4298        cmp r0, r3
  1e:   d1f9        bne.n   14 <start+0xc>

从 0x0x0058 复制 8 个字节到 0x20000000

  20:   4b0a        ldr r3, [pc, #40]   ; (4c <start+0x44>)  20000008
  22:   4a0b        ldr r2, [pc, #44]   ; (50 <start+0x48>)  20000408
  24:   480b        ldr r0, [pc, #44]   ; (54 <start+0x4c>)  20000000
  26:   4293        cmp r3, r2
  28:   bf18        it  ne
  2a:   2100        movne   r1, #0
  2c:   6043        str r3, [r0, #4]
  2e:   d004        beq.n   3a <start+0x32>
  30:   f803 1b01   strb.w  r1, [r3], #1
  34:   4293        cmp r3, r2
  36:   d1fb        bne.n   30 <start+0x28>
  38:   6043        str r3, [r0, #4]

0 从 0x20000008 到 0x20000408 清除堆栈,幸好局部变量不在堆栈上,而且你没有从这个函数中 returning。

  3a:   f000 f80d   bl  58 <etext>
  3e:   e7fe        b.n 3e <start+0x36>
  40:   20000008    andcs   r0, r0, r8
  44:   20000000    andcs   r0, r0, r0
  48:   00000058    andeq   r0, r0, r8, asr r0
  4c:   20000008    andcs   r0, r0, r8
  50:   20000408    andcs   r0, r0, r8, lsl #8
  54:   20000000    andcs   r0, r0, r0



Disassembly of section .data:

20000000 <uart>:
20000000:   4000c000    andmi   r12, r0, r0

20000004 <bssp>:
20000004:   deadbeef    cdple   14, 10, cr11, cr13, cr15, {7}

Disassembly of section .bss:

20000008 <stack>:
    ...


hexdump -C notmain.bin 
00000000  08 04 00 20 09 00 00 00  08 b5 0d 48 0d 4b 83 42  |... .......H.K.B|
00000010  06 d0 0d 4a 12 f8 01 1b  03 f8 01 1b 98 42 f9 d1  |...J.........B..|
00000020  0a 4b 0b 4a 0b 48 93 42  18 bf 00 21 43 60 04 d0  |.K.J.H.B...!C`..|
00000030  03 f8 01 1b 93 42 fb d1  43 60 00 f0 0d f8 fe e7  |.....B..C`......|
00000040  08 00 00 20 00 00 00 20  58 00 00 00 08 00 00 20  |... ... X...... |
00000050  08 04 00 20 00 00 00 20  61 20 05 4a 05 4b 11 68  |... ... a .J.K.h|
00000060  02 46 13 f8 01 0f 00 28  fa d1 0a 60 70 47 00 bf  |.F.....(...`pG..|
00000070  00 00 00 20 81 00 00 00  00 c0 00 40 ef be ad de  |... .......@....|
00000080  48 61 76 65 20 61 20 67  72 65 61 74 20 64 61 79  |Have a great day|
00000090  00                                                |.|
00000091

.data 肯定不在闪存中的 0x58 处,幸好你没有使用 .data

根据设计,您可能希望 .data 紧跟在 .text 之后,但最好只询问链接器确切的位置。此外,事情的排列方式也可能使 etext 不是下一节的开始。

如果我们试试这个

MEMORY
{
    FLASH : ORIGIN = 0x00000000, LENGTH = 0x1000
    SRAM : ORIGIN  = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
   .text : { *(.text*) } > FLASH
   .rodata : { *(.rodata*) } > FLASH
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > SRAM AT > FLASH
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > SRAM
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;
}

.thumb
.global _start
_start:
.word 0x20001000
.word main


.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__
.word __bss_start__
.word __bss_end__
.word __bss_size__

移除启动功能

Disassembly of section .text:

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000025    andeq   r0, r0, r5, lsr #32
   8:   00000055    andeq   r0, r0, r5, asr r0
   c:   20000000    andcs   r0, r0, r0
  10:   20000004    andcs   r0, r0, r4
  14:   00000004    andeq   r0, r0, r4
  18:   20000004    andcs   r0, r0, r4
  1c:   20000404    andcs   r0, r0, r4, lsl #8
  20:   00000400    andeq   r0, r0, r0, lsl #8

Disassembly of section .text:

00000000 <_start>:
   0:   20001000 
   4:   00000025 
   8:   00000055 __data_rom_start__ 
   c:   20000000 __data_start__  
  10:   20000004 __data_end__  
  14:   00000004 __data_size__  
  18:   20000004 __bss_start__  
  1c:   20000404 __bss_end__  
  20:   00000400 __bss_size__  


    
      Disassembly of section .data:

20000000 <uart>:
20000000:   4000c000    andmi   r12, r0, r0

hexdump -C notmain.bin 
00000000  00 10 00 20 25 00 00 00  55 00 00 00 00 00 00 20  |... %...U...... |
00000010  04 00 00 20 04 00 00 00  04 00 00 20 04 04 00 20  |... ....... ... |
00000020  00 04 00 00 61 20 05 4a  05 4b 11 68 02 46 13 f8  |....a .J.K.h.F..|
00000030  01 0f 00 28 fa d1 0a 60  70 47 00 bf 00 00 00 20  |...(...`pG..... |
00000040  45 00 00 00 48 61 76 65  20 61 20 67 72 65 61 74  |E...Have a great|
00000050  20 64 61 79 00 00 c0 00  40                       | day....@|
00000059

所以 .data 位于 0x55

现在:

MEMORY
{
    FLASH : ORIGIN = 0x00000000, LENGTH = 0x1000
    SRAM : ORIGIN  = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
   .text : { *(.text*) } > FLASH
   .rodata : { *(.rodata*) } > FLASH
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > SRAM AT > FLASH
   __data_end__ = .;
}


.thumb
.global _start
_start:
.word 0x20001000
.word reset

.thumb_func
reset:
    ldr r0,=__data_rom_start__
    ldr r1,=__data_start__
    ldr r2,=__data_end__
data_loop:
    ldrb r3,[r0]
    strb r3,[r1]
    add r0,r0,#1
    add r1,r1,#1
    cmp r1,r2
    bne data_loop
    bl main
    b .


unsigned int *uart = (unsigned int *)0x4000C000;

int main()
{
    char *ptr = "Have a great day";
    while (*ptr != '[=30=]') {
        *uart = *ptr;
        ptr++;
    }
    return 0;
}



Disassembly of section .text:

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000009    andeq   r0, r0, r9

00000008 <reset>:
   8:   4805        ldr r0, [pc, #20]   ; (20 <data_loop+0x12>)
   a:   4906        ldr r1, [pc, #24]   ; (24 <data_loop+0x16>)
   c:   4a06        ldr r2, [pc, #24]   ; (28 <data_loop+0x1a>)

0000000e <data_loop>:
   e:   7803        ldrb    r3, [r0, #0]
  10:   700b        strb    r3, [r1, #0]
  12:   3001        adds    r0, #1
  14:   3101        adds    r1, #1
  16:   4291        cmp r1, r2
  18:   d1f9        bne.n   e <data_loop>
  1a:   f000 f807   bl  2c <main>
  1e:   e7fe        b.n 1e <data_loop+0x10>
  20:   0000005d    andeq   r0, r0, sp, asr r0
  24:   20000000    andcs   r0, r0, r0
  28:   20000004    andcs   r0, r0, r4

0000002c <main>:
  2c:   2061        movs    r0, #97 ; 0x61
  2e:   4a05        ldr r2, [pc, #20]   ; (44 <main+0x18>)
  30:   4b05        ldr r3, [pc, #20]   ; (48 <main+0x1c>)
  32:   6811        ldr r1, [r2, #0]
  34:   4602        mov r2, r0
  36:   f813 0f01   ldrb.w  r0, [r3, #1]!
  3a:   2800        cmp r0, #0
  3c:   d1fa        bne.n   34 <main+0x8>
  3e:   600a        str r2, [r1, #0]
  40:   4770        bx  lr
  42:   bf00        nop
  44:   20000000    andcs   r0, r0, r0
  48:   0000004d    andeq   r0, r0, sp, asr #32

Disassembly of section .rodata:

0000004c <__data_rom_start__-0x11>:
  4c:   65766148    ldrbvs  r6, [r6, #-328]!    ; 0xfffffeb8
  50:   67206120    strvs   r6, [r0, -r0, lsr #2]!
  54:   74616572    strbtvc r6, [r1], #-1394    ; 0xfffffa8e
  58:   79616420    stmdbvc r1!, {r5, r10, sp, lr}^
    ...

Disassembly of section .data:

20000000 <uart>:
20000000:   4000c000    andmi   r12, r0, r0

hexdump -C notmain.bin 
00000000  00 10 00 20 09 00 00 00  05 48 06 49 06 4a 03 78  |... .....H.I.J.x|
00000010  0b 70 01 30 01 31 91 42  f9 d1 00 f0 07 f8 fe e7  |.p.0.1.B........|
00000020  5d 00 00 00 00 00 00 20  04 00 00 20 61 20 05 4a  |]...... ... a .J|
00000030  05 4b 11 68 02 46 13 f8  01 0f 00 28 fa d1 0a 60  |.K.h.F.....(...`|
00000040  70 47 00 bf 00 00 00 20  4d 00 00 00 48 61 76 65  |pG..... M...Have|
00000050  20 61 20 67 72 65 61 74  20 64 61 79 00 00 c0 00  | a great day....|
00000060  40                                                |@|
00000061

qemu-system-arm -M lm3s811evb -m 1M -nographic -kernel notmain.bin
y

因为 uart 不是易失性的,所以如果您查看编译后的输出,它只会将最后一项 y 写入寄存器,循环的其余部分正在寻找字符串的结尾。但至少现在 .data 全局变量已经用正确的值初始化,所以它可以工作。

改成这个

volatile unsigned int *uart = (unsigned int *)0x4000C000;
int main()
{
    char *ptr = "Have a great day";
    while (*ptr != '[=31=]') {
        *uart = *ptr;
        ptr++;
    }
    return 0;
}

qemu-system-arm -M lm3s811evb -m 1M -nographic -kernel notmain.bin
Have a great day

我故意不 use/support .data 或 .bss 部分原因是非 portable 链接器脚本和 bootstraps 等。所以多烧一点有时会闪烁以避免它。使 bootstrap 和链接描述文件变得简单。但我会花更多时间在链接描述文件上,这样 bootstrap 看起来更像这样

    ldr r0,=__data_rom_start__
    ldr r1,=__data_start__
    ldr r2,=__data_end__
data_loop:
    ldm r0!,{r4,r5}
    stm r1!,{r4,r5}
    cmp r1,r2
    bne data_loop

通过将两端的 .data 段对齐到 64 位对齐。也会根据需要为 .bss 执行此操作,但如果我假设 .bss 为零,那么我更有可能将所有 sram 归零而不仅仅是 bss,这将是我在复制 .data 之前做的第一件事.

    ldr r0,=0x20000000
    ldr r1,=0x20001000 <-- adjust for sram available/used in this part/app
    mov r4,#0
    mov r5,#0
    mov r6,#0
    mov r7,#0
sram_init:
    stm r0!,{r4,r5,r6,r7}
    cmp r1,r2
    bne sram_init

我没有用于初始化堆栈或 bss,所以如图所示,我的 bootstrap 看起来像这样

reset:
    bl notmain
    b .

因为我确实想从 C 入口点 return(各种原因)。有时这样:

reset:
    bl notmain
wfi_loop:
    wfi
    b wfi_loop

wfi、wfe 等等。其中一些内核将等待实现为 nop,因为它们不支持它们。

所以...

  1. 您的 .data init 似乎已损坏。 2) 它没有被定义为 volatile 3) 你不需要有一个 read/write (.data) 全局变量来指向一个寄存器,你可以通过不让它成为 .data 全局变量来节省 ram 和代码变量,而只是 #define 它。

我没有校对这么多,所以希望我所有的剪​​切和粘贴都能奏效。无论我是否正确粘贴它,它都在我的机器上正确地 运行,并且二进制文件看起来可以正常工作。