Search code examples
memoryavravr-gccsections

Storing data in RAM without avr-libc. How can I configure the proper memory sections using a custom linker script and initialization code?


Here's my linker script:

MEMORY {

  text   (rx)   : ORIGIN = 0x000000, LENGTH = 64K

  data   (rw!x) : ORIGIN = 0x800100, LENGTH = 0xFFA0

}

SECTIONS {

    .vectors : AT (0x0000) { entry.o (.vectors); }

    .text    : AT (ADDR (.vectors) + SIZEOF(.vectors)) { * (.text.startup); * (.text); * (.progmem.data); _etext = .; }

    .data    : AT (ADDR (.text) + SIZEOF (.text)) { PROVIDE (__data_start = .); * (.data); * (.rodata); * (.rodata.str1.1); PROVIDE (__data_end = .); } > data

    .bss     : AT (ADDR (.bss)) { PROVIDE (__bss_start = .); * (.bss); PROVIDE (__bss_end = .); } > data

    __data_load_start = LOADADDR(.data);

    __data_load_end = __data_load_start + SIZEOF(.data);

}

And this is my initialization code. init is called at reset.

.section .text,"ax",@progbits

/* Handle low level hardware initialization. */

.global init

init:                       eor r1, r1

                            out 0x3f, r1

                            ldi r28, 0xFF

                            ldi r29, 0x02

                            out 0x3e, r29

                            out 0x3d, r28

                            rjmp __do_copy_data

                            rjmp __do_clear_bss

                            jmp main

/* Handle copying data into RAM. */

.global __do_copy_data

__do_copy_data:             ldi r17, hi8(__data_end)

                            ldi r26, lo8(__data_start)

                            ldi r27, hi8(__data_start)

                            ldi r30, lo8(__data_load_start)

                            ldi r31, hi8(__data_load_start)

                            rjmp .L__do_copy_data_start

.L__do_copy_data_loop:      lpm r0, Z+

                            st X+, r0

.L__do_copy_data_start:     cpi r26, lo8(__data_end)

                            cpc r27, r17

                            brne .L__do_copy_data_loop

                            rjmp main

/* Handle clearing the BSS. */

.global __do_clear_bss

__do_clear_bss:             ldi r17, hi8(__bss_end)

                            ldi r26, lo8(__bss_start)

                            ldi r27, hi8(__bss_start)

                            rjmp .L__do_clear_bss_start

.L__do_clear_bss_loop:      st X+, r1

.L__do_clear_bss_start:     cpi r26, lo8(__bss_end)

                            cpc r27, r17

                            brne .L__do_clear_bss_loop

The problem is that the initialization code hangs sometime during the copying process. Here's an edited dump of my symbol table, if it's helpful to anyone.

00000000 a __tmp_reg__
...
00000000 t reset
...
00000001 a __zero_reg__
...
0000003d a __SP_L__
...
00000074 T main
0000009a T init
000000ae T __do_copy_data
000000c6 T __do_clear_bss
...
00000446 A __data_load_start
00000446 T _etext
0000045b A __data_load_end
00800100 D __data_start
00800100 D myint
00800115 B __bss_start
00800115 D __data_end
00800115 b foobar.1671
00800135 B ticks
00800139 B __bss_end

Solution

  • I actually got it to work. All I had to do was enable reading from and writing to external RAM in the SREG. It was mindblowingly obvious and simple, I know, but it was buried in the data sheet and it was poorly documented.

    This resource was helpful, but didn't have any documentation for my chip. If you're having this problem, look in the data sheet for your AVR and see how it is related. The process is not the same for all variations of AVRs.

    How to use external RAM.