The necessary linker command is:
EXTMEMOPTS +=-Wl,--defsym=__stack=0x801100,--section-start,.data=0x801200,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF
The details:
Normally, the .data section is located at address 0x100 (0x800100
with the SRAM offset). Compile firmware and check this by searching
for the first 008... in the .sym file (symbol table).
00800100 D __data_start
I created a static variable, varInDATA, in the main .c file and in
the makefile I relocated the .data section to 0x300:
--section-start,.data=0x800300
The varInDATA variable wound up at 0x3cd = 973 and when I ran the
test script the output was:
varInDATA=33 at 973
If you look in the .sym file you will notice there are many variables
that need to be initialized (they have the 0x800000 offset). These
need to be copied from FLASH to SRAM before your firmware will run.
Quite a few of them are related to LUFA and USB operation in general.
I relocated the .data section to 0x802100 (start of external SRAM)
and the firmware did not run. This means that the SRAM data variables
are not being initialized which implies the XMEM interface is not
functional during initialization. This is the strange part as I have
placed all the XMEM initialization code into .init0. If you look at
the .lst file (assembly listing) you will see that the first two
instructions (lines 25 and 26) enable XMEM:
XMCRA = ((1 << SRE)); // first line of EnableExternalSRAM
// (1 << SRE) = (1 << 7) = 128 = 0b10000000
// from iousbxx6_7.h:
#define XMCRA _SFR_MEM8(0x74) // 0x74 = 116
#define SRE 7
1 .file "USBVirtualSerial-ExtSRAMTest.c"
2 __SREG__ = 0x3f
3 __SP_H__ = 0x3e
4 __SP_L__ = 0x3d
5 __CCP__ = 0x34
6 __tmp_reg__ = 0
7 __zero_reg__ = 1
15 .Ltext0:
16 .section .init0,"ax",@progbits
17 .global EnableExternalSRAM
19 EnableExternalSRAM:
20 .LFB93:
21 .LSM0:
22 /* prologue: naked */
23 /* frame size = 0 */
24 .LSM1:
25 0000 80E8 ldi r24,lo8(-128)
26 0002 8093 7400 sts 116,r24
For some reason SRAM variables do not want to be initialized in
external memory. I took another look at the .sym file and the final
SRAM variable is at 0x224d (0x0080224d N _end). (0x224d - 0x2100) =
0x14d = 333. Only 333 bytes are required for proper LUFA operation.
You can also get this value by typing make without any programming
target, "Data: 333 bytes (4.1% Full)".
I relocated the .data section to 0x1F00 (0x2100 - 0x1F00 = 0x200 =
512) and allowed 16kbytes for the heap (0xFFFF-0xBFFF=0x4000=16384)
EXTMEMOPTS +=-Wl,--section-start,.data=0x801F00,--defsym=__heap_start=0x80BFFF,--defsym=__heap_end=0x80FFFF
It works but the stack will now eventually collide with .data!
varInDATA=33 at 8139
stackVal=38 at 8436
someVal=38 at 8431
Variable varInDATA is in .data, stackVal is a local variable (on the
stack) in main() and someVal is a local variable in the function
returnStackAddress(). As you can see, the stack is growing up towards
zero and will eventually collide with .data.
Therefore, the solution is to move the stack below .data or figure
out how to get .data to initialize in external SRAM. Internal SRAM is
faster so better to move the stack and leave room in internal SRAM for
.data. Put it on a 4-byte boundary just in case.
EXTMEMOPTS +=-Wl,--defsym=__stack=0x801100,--section-start,.data=0x801200,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF
Success! There is now a (0x1100-0x100)=1000= 4096 byte stack, a
((0xDFFF-1)-0x1200)=CDFE= 52734 byte .data+.bss section with the first
3584 bytes in internal SRAM and the rest in external SRAM, and a heap
for malloc() of (0xDFFF-0xFFFF)= 8192 bytes. Note the first 0x100=256
bytes of internal SRAM are used as addresses for the data and
peripheral registers. Test script output is:
PORTE=135
__malloc_heap_start=57343
__malloc_heap_end=65535
ExtMemArray[0]=4294967295 at 57345
varInDATA=33 at 4832
stackVal=38 at 4343
someVal=38 at 4338
ExtMemArray[ExtMemLastIndex]=1234567890 at 65529
ExtMemLastIndex=2046
As you can see from the above, the stack is growing upward
(someVal-stackVal= -5) to 0 and varInDATA in .data is after the stack
(4832>4343).
Good luck with your project!
On Mon, Apr 18, 2011 at 7:12 AM, Opendous Support
<opendous...@gmail.com> wrote:
> The attached USBVirtualSerial-ExtSRAMTest firmware is a complete
> LUFA-based example of how to use malloc() and its associated linker
> commands to allocate and access a 32-bit integer array in external
> SRAM on the Micropendous boards and communicate with the user over
> USBVirtualSerial using stdlib printf functions.
>
> Either compile it from scratch or load
> USBVirtualSerial-ExtSRAMTest_Micropendous-AT90USB1287.hex directly
> onto your board. A 16MHz crystal is assumed.
>
> The Host side testing script, TestExtSRAMAccess.py, requires Python
> 2.5.x and PySerial
> http://python.org/download/releases/2.5.5
> http://sourceforge.net/projects/pyserial/files/pyserial/2.5/
>
> If you do not want to install Python the communication protocol is
> very simple. Send some data to the Serial Port of the device loaded
> with USBVirtualSerial-ExtSRAMTest firmware and read back seven lines
> of \r\n-terminated text.
>
> The output should be something like:
> PORTE=135
>
>
> __malloc_heap_start=8448
>
> __malloc_heap_end=65535
>
>
> ExtMemArray[0]=4294967295 at 8450
>
> ExtMemArray[1]=1010101010 at 8454
>
> ExtMemArray[ExtMemLastIndex]=1234567890 at 65506
>
>
> ExtMemLastIndex=14264
>
>
>
> Changes made to USBVirtualSerial.c from Micropendous-2011-03-01.zip
> to create USBVirtualSerial-ExtSRAMTest.c include:
>
> The required linker command in the makefile is:
> EXTMEMOPTS +=-Wl,--defsym=__heap_start=0x802100,--defsym=__heap_end=0x80ffff
> This places the heap in external SRAM while leaving internal SRAM
> for variables and the stack. Other options given at
> http://www.nongnu.org/avr-libc/user-manual/malloc.html are not
> workable.
>
> Set up external SRAM in an .init section:
> // set up external SRAM prior to anything else to make sure malloc()
> has access to it
>
> void EnableExternalSRAM (void) __attribute__ ((naked)) __attribute__
> ((section (".init3")));
>
> void EnableExternalSRAM(void)
>
> {
> PORTE_EXT_SRAM_SETUP;
>
> XMCRA = ((1 << SRE)); // zero wait-states
>
> XMCRB = 0;
> }
>
> Create a global pointer to the data array:
> static uint32_t* ExtMemArray;
>
> Use malloc to allocate the memory for 32-bit integers near the top of main()
> uint16_t ExtMemArraySize = 57056; // 57056/4 = 14264
>
> ExtMemArray = (uint32_t *) malloc(ExtMemArraySize);
>
>
> if (ExtMemArray == NULL) {
> abort(); }
>
> Before the call to USB_Init() in SetupHardware, make sure once more
> that the external SRAM interface is active:
> PORTE_EXT_SRAM_SETUP;
>
> ENABLE_EXT_SRAM;
>
> SELECT_EXT_SRAM_BANK0;
>
> Inside MainTask() change the values of array elements and send
> associated data to the Host if it requests it:
> ExtMemArray[0] = (uint32_t)4294967295;
> // maximum unsigned 32-bit integer value
> ExtMemArray[14264] = (uint32_t)1234567890; // final array element
> if ((count = fread(&buffer, 1, CDC_TXRX_EPSIZE, &USBSerialStream)) > 0) {
> fprintf(&USBSerialStream, "__malloc_heap_start=%5u\r\n",
> ((uint16_t)__malloc_heap_start));
> fprintf(&USBSerialStream, "ExtMemArray[0]=%10lu at %5u\r\n",
> ((uint32_t)ExtMemArray[0]), ((uint16_t)&ExtMemArray[0]));
> fprintf(&USBSerialStream, "ExtMemArray[14264]=%10lu at %5u\r\n",
> ((uint32_t)ExtMemArray[14264]), ((uint16_t)&ExtMemArray[14264]));
> }
>
> USBVirtualSerial-ExtSRAMTest firmware can be found at:
> http://code.google.com/p/micropendous/downloads/detail?name=USBVirtualSerial-ExtSRAMTest.zip
>
>
> On Sun, Apr 17, 2011 at 1:45 PM, hcaltenco <hcal...@gmail.com> wrote:
>> Yes, hehe... and many other makefiles I have seen also have the wrong
>> linker command, including all the LUFA library examples. I will write
>> Dean about it so he corrects it in future LUFA distributions.
>>
>> A demo that uses the linker and malloc to allocate the data and
>> possibly also the bss and heap sections will be very helpful. Thank
>> you very much.
>>
>> On Apr 17, 8:45 am, Opendous Support <opendous.supp...@gmail.com>
>> wrote:
>>> I seem to have copied the wrong linker command into/from the
>>> makefile. -T will never work and --section-start must be used:http://www.nongnu.org/avr-libc/user-manual/malloc.html
>>>
>>> I will finish up a demo based on malloc() and update the Micropendous
>>> distribution accordingly.
>>>
>>> On Apr 16, 11:43 am, hcaltenco <hcalte...@gmail.com> wrote:
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> > Hello all,
>>>
>>> > I am having a problem storing the ".data" section in the external ram
>>> > of the micropendous board. I hope someone here can help me, since I
>>> > have been looking in forums and no one seems to have had the same
>>> > problem.
>>>
>>> > I have an application that uses 50 kb of static data, therefore needs
>>> > external ram. Which is not a problem since the micropendous boards
>>> > come very well equiped ;). However, I was quite surprised that the
>>> > default makefiles in the micropendous distribution and other examples
>>> > (i.e. latest LUFA distribution) give the linker external memory
>>> > options that do not work.
>>>
>>> > The "-Tdata" is not recognized by the linker. Give it a try, try to
>>> > compile one of the examples (e.g. MicropendousKeyboardTest) using the
>>> > default " -Wl,-Tdata=0x802100,--defsym=__heap_end=0x80ffff " for the
>>> > at90usb1287. Then open the .lss or .map files and you will see that
>>> > the data section starts at the internal address 0x800100. The correct
>>> > extmemoptions for the linker should be: "-Wl,--section-
>>> > start,.data=0x802100,--defsym=__heap_end=0x8090ff ", as stated in the
>>> > avr-libc documentation (http://www.nongnu.org/avr-libc/user-manual/
>>> > malloc.html). Compiling with these flags will produce lss and map
>>> > files with the correct external address starting at 0x802100. It took
>>> > me some time to find out that, and will probably save many people that
>>> > use external sram some time if this was corrected in all the
>>> > distribution examples.
>>>
>>> > Anyway, then you are just supposed to initialize external memory in
>>> > the hardware initialization or at the beginning of your main() as:
>>> > /* Enable External SRAM */
>>> > DISABLE_VOLTAGE_TXRX;
>>> > PORTE_EXT_SRAM_SETUP;
>>> > ENABLE_EXT_SRAM;
>>> > XMCRA = ((1 << SRE)); // enable external SRAM with 0 wait
>>> > states
>>> > XMCRB = 0;
>>> > //__malloc_heap_start = (void*) 0x5100; // make sure that
>>> > your heap starts after your data and bss
>>> > //__malloc_heap_end = (void*) 0x90ff;
>>>
>>> > /*Allocating external memory using __malloc_heap_start and
>>> > __malloc_heap_end do not seem to have any effect on any of the four
>>> > options described below (thats why I commented them).*/
>>>
>>> > However this does not solve the problem completely. Try it out for
>>> > example in the "MicropendousKeyboardTest" example. Setting all the
>>> > data, bss, and heap to the external does not type anything when you
>>> > ground a pin with a cable:
>>> > EXTMEMOPTS += -Wl,--section-start,.data=0x802100,--
>>> > defsym=__heap_end=0x8090ff
>>>
>>> > Setting the data section in the external and the rest on the internal
>>> > does not type anything either:
>>> > EXTMEMOPTS += -Wl,--section-start,.data=0x802100,--section-
>>> > start,.bss=0x800100
>>> > EXTMEMOPTS += --defsym=__heap_start=__bss_end,--
>>> > defsym=__heap_end=0x8010ff
>>>
>>> > But Setting the bss section in external and the rest on the internal
>>> > works (types continuously a2 and a0 because the external memory
>>> > registers need to have that pins in low).
>>> > EXTMEMOPTS += -Wl,--section-start,.data=0x800100,--section-
>>> > start,.bss=0x802100
>>> > EXTMEMOPTS += --defsym=__heap_start=__data_end,--
>>> > defsym=__heap_end=0x8010ff
>>>
>>> > Also Setting only the heap to external ram and the rest in internal
>>> > also works (typing a2 and a0 continuously).
>>> > EXTMEMOPTS += --defsym=__heap_start=0x802100,--
>>> > defsym=__heap_end=0x8090ff
>>>
>>> > Due to this issue, it seems that the .data section cannot be located
>>> > in external ram!!! Which is a bit annoying since is the 50kb section i
>>> > need to put there. The .bss and the heap seem to have no problem being
>>> > in the external memory.
>>>
>>> > I am suspecting it has something to do with the timings, since it
>>> > takes two clock cycles to write and read from external ram while it
>>> > takes only one clock cycle to write and read from internal ram. Has
>>> > anyone been successful using the data section in external memory?
>>>
>>> > I would appreciate very much the help, this problem is driving me
>>> > crazy.
>>>
>>> > All the best,
>