Running UC3A FreeRTOS Demo from SDRAM

dksquires wrote on Wednesday, November 19, 2008:

I am working with a client that plans on using an AT32UC3A0512-based controller board with 64MB of SDRAM @0xD0000000 and oodles of battery-backed SRAM for critical data. This controller board has two SPI DataFlash chips to provide storage for binary program files.

We would like to use FreeRTOS for the controller but need to configure it to run from the SDRAM instead of from internal CPU FLASH memory. I’ve written a loader program that initializes (and tests) SDRAM, then loads a binary file into SDRAM and executes it. I’ve modified one of the Atmel 1.3.0 software framework programs (USART demo) to run from SDRAM and it works fine.

I’ve not been successful, however, at rebuilding the FREERTOS Demo program in the 1.3.0 Software Framework to run out of SDRAM at 0xD0000000. For now I am using the EVK1100 board for proof of concept testing. I am using the gnu Makefile version of the project, and can use the original config.mk file to build it to run succcessfully from internal FLASH memory. But I suspect that my modified config.mk file for SDRAM execution is not  right.

When running from SDRAM on the EVK1100, the USART demo spits out 24 characters on the USART, then dies. No LEDs flash at all. My loader program disables global interrupts before jumping to 0xD0000000. Of course, the JTAGICE Mk II cannot help me here because the SDRAM isn’t running after a reset.

The config.mk is shown below - it’s one that was posted on the AVRFreaks support forum (AVR General) by J Cesnik on Mar 21, 2008.

/* Default linker script, for normal executables */
OUTPUT_FORMAT(“elf32-avr32”, “elf32-avr32”,
         “elf32-avr32”)
OUTPUT_ARCH(avr32:uc)
ENTRY(_start)
SEARCH_DIR("/home/mingwbuild/mingwavr32/avr32/lib");
/* Do we need any of these for elf?
   __DYNAMIC = 0;    */
MEMORY
  {
    SDRAM (rxai!w) : ORIGIN = 0xD0000000, LENGTH = 0x02000000
    INTRAM (wxa!ri) : ORIGIN = 0x00000000, LENGTH = 64K
  }
SECTIONS
{
  /* Read-only sections, merged into text segment: */
  PROVIDE (__executable_start = 0xD0000000); . = 0xD0000000;
  .interp         : { *(.interp) } >SDRAM AT>SDRAM
  .reset : {  *(.reset) } >SDRAM AT>SDRAM
  .hash           : { *(.hash) } >SDRAM AT>SDRAM
  .dynsym         : { *(.dynsym) } >SDRAM AT>SDRAM
  .dynstr         : { *(.dynstr) } >SDRAM AT>SDRAM
  .gnu.version    : { *(.gnu.version) } >SDRAM AT>SDRAM
  .gnu.version_d  : { *(.gnu.version_d) } >SDRAM AT>SDRAM
  .gnu.version_r  : { *(.gnu.version_r) } >SDRAM AT>SDRAM
  .rel.init       : { *(.rel.init) } >SDRAM AT>SDRAM
  .rela.init      : { *(.rela.init) } >SDRAM AT>SDRAM
  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } >SDRAM AT>SDRAM
  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } >SDRAM AT>SDRAM
  .rel.fini       : { *(.rel.fini) } >SDRAM AT>SDRAM
  .rela.fini      : { *(.rela.fini) } >SDRAM AT>SDRAM
  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } >SDRAM AT>SDRAM
  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } >SDRAM AT>SDRAM
  .rel.data.rel.ro   : { *(.rel.data.rel.ro*) } >SDRAM AT>SDRAM
  .rela.data.rel.ro   : { *(.rel.data.rel.ro*) } >SDRAM AT>SDRAM
  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } >SDRAM AT>SDRAM
  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } >SDRAM AT>SDRAM
  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } >SDRAM AT>SDRAM
  .rela.tdata     : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } >SDRAM AT>SDRAM
  .rel.tbss     : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } >SDRAM AT>SDRAM
  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } >SDRAM AT>SDRAM
  .rel.ctors      : { *(.rel.ctors) } >SDRAM AT>SDRAM
  .rela.ctors     : { *(.rela.ctors) } >SDRAM AT>SDRAM
  .rel.dtors      : { *(.rel.dtors) } >SDRAM AT>SDRAM
  .rela.dtors     : { *(.rela.dtors) } >SDRAM AT>SDRAM
  .rel.got        : { *(.rel.got) } >SDRAM AT>SDRAM
  .rela.got       : { *(.rela.got) } >SDRAM AT>SDRAM
  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } >SDRAM AT>SDRAM
  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } >SDRAM AT>SDRAM
  .rel.plt        : { *(.rel.plt) } >SDRAM AT>SDRAM
  .rela.plt       : { *(.rela.plt) } >SDRAM AT>SDRAM
  .init           :
  {
    KEEP (*(.init))
  } >SDRAM AT>SDRAM =0xd703d703
  .plt            : { *(.plt) } >SDRAM AT>SDRAM
  .text           :
  {
    *(.text .stub .text.* .gnu.linkonce.t.*)
    KEEP (*(.text.*personality*))
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  } >SDRAM AT>SDRAM =0xd703d703
  .fini           :
  {
    KEEP (*(.fini))
  } >SDRAM AT>SDRAM =0xd703d703
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) } >SDRAM AT>SDRAM
  .rodata1        : { *(.rodata1) } >SDRAM AT>SDRAM
  .eh_frame_hdr : { *(.eh_frame_hdr) } >SDRAM AT>SDRAM
  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) } >SDRAM AT>SDRAM
  .gcc_except_table   : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } >SDRAM AT>SDRAM
  .dalign   : { . = ALIGN(8); PROVIDE(_data_lma = .); } >SDRAM AT>SDRAM
  PROVIDE (_data = ORIGIN(INTRAM));
  . = ORIGIN(INTRAM);
  /* Exception handling  */
  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) } >INTRAM AT>SDRAM
  .gcc_except_table   : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } >INTRAM AT>SDRAM
  /* Thread Local Storage sections  */
  .tdata     : { *(.tdata .tdata.* .gnu.linkonce.td.*) } >INTRAM AT>SDRAM
  .tbss        : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } >INTRAM AT>SDRAM
  /* Ensure the __preinit_array_start label is properly aligned.  We
     could instead move the label definition inside the section, but
     the linker would then create the section even if it turns out to
     be empty, which isn’t pretty.  */
  PROVIDE (__preinit_array_start = ALIGN(32 / 8));
  .preinit_array     : { KEEP (*(.preinit_array)) } >INTRAM AT>SDRAM
  PROVIDE (__preinit_array_end = .);
  PROVIDE (__init_array_start = .);
  .init_array     : { KEEP (*(.init_array)) } >INTRAM AT>SDRAM
  PROVIDE (__init_array_end = .);
  PROVIDE (__fini_array_start = .);
  .fini_array     : { KEEP (*(.fini_array)) } >INTRAM AT>SDRAM
  PROVIDE (__fini_array_end = .);
  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn’t matter if the user does not
       actually link against crtbegin.o; the
       linker won’t look for a file to match a
       wildcard.  The wildcard also means that it
       doesn’t matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin*.o(.ctors))
    /* We don’t want to include the .ctor section from
       from the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  } >INTRAM AT>SDRAM
  .dtors          :
  {
    KEEP (*crtbegin*.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  } >INTRAM AT>SDRAM
  .jcr            : { KEEP (*(.jcr)) } >INTRAM AT>SDRAM
  .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } >INTRAM AT>SDRAM
  .dynamic        : { *(.dynamic) } >INTRAM AT>SDRAM
  .got            : { *(.got.plt) *(.got) } >INTRAM AT>SDRAM
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    KEEP (*(.gnu.linkonce.d.*personality*))
    SORT(CONSTRUCTORS)
  } >INTRAM AT>SDRAM
  .data1          : { *(.data1) } >INTRAM AT>SDRAM
  .balign   : { . = ALIGN(8); _edata = .; } >INTRAM AT>SDRAM
  _edata = .;
  PROVIDE (edata = .);
  __bss_start = .;
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.  */
   . = ALIGN(8);
  } >INTRAM AT>SDRAM
  . = ALIGN(8);
  _end = .;
  PROVIDE (end = .);
  __heap_start__ = ALIGN(8);
  . = ORIGIN(INTRAM) + LENGTH(INTRAM) - 0x1000;
  __heap_end__ = .;
  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  .stack         ORIGIN(INTRAM) + LENGTH(INTRAM) - 0x1000 :
  {
    _stack = .;
    *(.stack)
    . = 0x1000;
    _estack = .;
  } >INTRAM AT>SDRAM
  /DISCARD/ : { *(.note.GNU-stack) }
}

--------------------------------------
Here’s the linker output displayed:
uc3a0512-rtosdemo.elf  :
section              size         addr
.reset             0x2008   0xd0000000
.got                  0xc         0x18
.init                0x1c   0xd0002008
.text              0xbf78   0xd0002024
.exception          0x200   0xd000e000
.fini                0x18   0xd000e200
.rodata             0x294   0xd000e218
.dalign               0x4   0xd000e4ac
.ctors                0x8          0x4
.dtors                0x8          0xc
.jcr                  0x4         0x14
.data               0x844         0x24
.bss                0x320        0x868
.comment            0x9fc          0x0
.debug_aranges      0x9e0          0x0
.debug_pubnames    0x1156          0x0
.debug_info       0x100c1          0x0
.debug_abbrev      0x1fe3          0x0
.debug_line        0x29aa          0x0
.debug_frame       0x2bcc          0x0
.debug_str          0xd02          0x0
.debug_loc         0x3129          0x0
.stack             0x1000       0xf000
.debug_ranges       0x1e8          0x0
Total             0x2db2f

   text       data        bss        dec        hex    filename
0xe448      0x864     0x1324      65488       ffd0    uc3a0512-rtosdemo.elf

I can’t help but notice that there’s no .heap shown.

Any hints would be most appreciated. I do not profess to be a linker expert and hopefully won’t need to be to get past

this issue.

Thanks,

Dave Squires

SQUIRES ENGINEERING, INC.

edwards3 wrote on Thursday, November 20, 2008:

FreeRTOS runs out of RAM fine on ARM7 and Coldfire so I think you are right to suspect the linker script. You could try the AVRFreaks WEB site to see if anybody can give you a linker script that is all set as you need it.

dksquires wrote on Friday, November 21, 2008:

I’ve got a pertinent update. Apparently in Atmel’s updated datasheet (08/2008) for the AVR32 UC3A processor, they now say that code execution from SDRAM does NOT work in any revision of silicon, contrary to the errata of the previous (04/2008) datasheet for the UC3A chips.

So now according to the best information I have, running FreeRTOS (or anything else) from SDRAM on a silicon Rev E, H, I J chip is not expected to work.

So my linker script may or may not be an issue. Trival (non-FreeRTOS) programs seem to work. I may have just gotten lucky. :slight_smile:

Dave