Uint32 Uint32 - 4 days ago 6
C Question

C string doesn't iterate correctly in loop

I am trying to print string through a UART0 from Beaglebone Black .The bootloader initializes UART0 and I just have to write characters. I have made a simple function

void uart_put(unsigned char c)
while((UART0->LSR_r & 32) == 0);
UART0->THR = c;

From the startup code the following function is called I simply print character in this function.

#define SIZE_OF_ARRAY 7
int c_entry(void)
unsigned char s_name[SIZE_OF_ARRAY] = "Hello";
unsigned char a_name[SIZE_OF_ARRAY] = {'H','e','l','l','o','\0'};
unsigned int a_int[SIZE_OF_ARRAY] = {9,8,7,6,5,4};
int i = 0;
for(i = 0; i<6; i++)
uart_put('0'+i); /*print value of i*/
uart_put(9); /*print a tab*/
uart_put(s_name[i]); /*print char from string*/
uart_put(9); /*print a tab*/
uart_put(a_name[i]); /*print char from array*/
uart_put(9); /*print a tab*/
uart_put('0'+a_int[i]); /*print int from array*/
return 0;

The function is working fine as the array of characters and the integers is printed correctly, but the string is not printed as it should be. enter image description here


Within the linker script, change:

. = 0x402F0400;


. = 0x80000000;

Per the memory map for the AM335X ARM processor, 0x402F0400 is the core SRAM while 0x8000000 is the DDR2 memory. Per the screenshot of the TFTP boot output, you are loading your application at 0x80000000, but your linker script is configured to reference the memory at 0x402F04000.

Disassembling the raw binary file download.bin built using the original linker script yields:

% arm-none-eabi-objdump -D -b binary -marm download.bin
download.bin:     file format binary

Disassembly of section .data:

00000000 <.data>:
    0:   e51fd000        ldr     sp, [pc, #-0]   ; 0x8
    4:   eb00000e        bl      0x44
    8:   402f1638        eormi   r1, pc, r8, lsr r6      ; <UNPREDICTABLE>
    c:   e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
    [removed several lines of text]
    4c:   e24dd030        sub     sp, sp, #48     ; 0x30
    50:   e300262c        movw    r2, #1580       ; 0x62c
    54:   e344202f        movt    r2, #16431      ; 0x402f
    [remainder of dump removed]

The string is copied from memory into the local variable. Note that the address for the string copy is 0x402f062c (the movw and movt commands load the address into the register). A quick scan of the omitted code does not show any other attempts to access memory.

I don't have access to a Beaglebone Black so I am unable to test this. It does explain the observed behavior. As the program is copying the string from uninitialized SRAM, there is no guarantee of what will be displayed. As there is no other attempt to access memory within the program, this is the only issue.

Changing the linker script and rebuilding results in a slightly different download.bin. A diff between the disassembled download.bin produced by the original linker script and my suggested change is:

<    8: 402f1638        eormi   r1, pc, r8, lsr r6      ; <UNPREDICTABLE>
>    8: 80001238        andhi   r1, r0, r8, lsr r2
<   50: e300262c        movw    r2, #1580       ; 0x62c
<   54: e344202f        movt    r2, #16431      ; 0x402f
>   50: e300222c        movw    r2, #556        ; 0x22c
>   54: e3482000        movt    r2, #32768      ; 0x8000

You can clearly see the new address reference for copying the string. Unfortunately, I'm unsure what the other change is and if this change will cause any issues.

Just to verify the string is at 0x8000022c, we can use xxd to dump 'download.bin'. The output is:

% xxd download.bin
0000000: 00d0 1fe5 0e00 00eb 3816 2f40 04b0 2de5  ........8./@..-.
0000010: 00b0 8de2 14d0 4de2 0030 a0e1 0d30 4be5  ......M..0...0K.
[... omitted lots of lines ...]
0000220: 0500 53e3 cdff ffda feff ffea 4865 6c6c  ..S.........Hell
0000230: 6f00 0000                                o...

The string Hello is visible at 0x22c. When loaded at 0x80000000, the address where the string is copied appears to be correct.