Forum Discussion
running sw in SDRAM
Hello,
I want to use SDRAM for a small set of functions, toghether with big chunks of data. The rest of the software runs from SRAM. I verfied the correct working of the SDRAM, the instruction bus is connected to SDRAM. I tried with a small function placed in SDRAM, but the system restarts when I call the function. The test function contained just a printf to see it is called. Then I tried with a function that just increments a global variable, nothing happens, the variable is not incremeted. When I place that same function in SRAM, the value gets incremented everytime I call the function. Is there something I miss here for running sw in SDRAM?? Thanks, Stefaan.9 Replies
- Altera_Forum
Honored Contributor
I use SDRAM for most of my projects and have never had a problem. Looks like normal memory.
A few things to check: Maybe you have a screw-up with the stack or something. * Compile a program to run only from SDRAM. If that works then you might have screw-up pointers. * How have you compiled the code? Most of time the functions are not relocatable. Have you compiled the code for that specific location in SDRAM or just copied it there? *Where are the local variables stored? *When the function returns where does it return to? VictorS - Altera_Forum
Honored Contributor
--- Quote Start --- originally posted by victors@Jan 3 2006, 01:57 PM i use sdram for most of my projects and have never had a problem. looks like normal memory.a few things to check: maybe you have a screw-up with the stack or something.
* compile a program to run only from sdram. if that works then you might have screw-up pointers. --- Quote End --- I tried also a small program running only from SDRAM, no luck. <div class='quotetop'>QUOTE </div> --- Quote Start --- * How have you compiled the code? Most of time the functions are not relocatable. Have you compiled the code for that specific location in SDRAM or just copied it there?[/b] --- Quote End --- I added a section in the linkerscript and then used the __attribute((.section(".sdram"))) on the function. I verified in on object dump, and it seems to be ok. <div class='quotetop'>QUOTE </div> --- Quote Start --- *Where are the local variables stored?[/b] --- Quote End --- in SRAM, only one global integer to test. <div class='quotetop'>QUOTE </div> --- Quote Start --- *When the function returns where does it return to?[/b] --- Quote End --- I hope to the place where it was called from. Here's the small test function :
This function gets compiled to :volatile int ga = 0; void TestSDRam() __attribute__ ((section (".sdram"))); void TestSDRam() { __asm__("NOP"); __asm__("NOP"); __asm__("NOP"); __asm__("NOP"); ga++; }
This function is called from somewhere else in the sw, and I print out the memory contents before the call, so I can verify the code is still there :Disassembly of section .sdram: 01000000 <_Z9TestSDRamv>: 1000000: 0001883a nop 1000004: 0001883a nop 1000008: 0001883a nop 100000c: 0001883a nop 1000010: 00c00534 movhi r3,20 1000014: 18c6d404 addi r3,r3,6992 1000018: 18800037 ldwio r2,0(r3) 100001c: 10800044 addi r2,r2,1 1000020: 18800035 stwio r2,0(r3) 1000024: f800283a ret
The result :void foo() { volatile int* a = (int*) na_SDRAM; for (int k = 0; k < 40; k++) { printf("%08x : %08x \r", a, *a); a++; } TestSDRam(); printf("ga : %d\r", ga); }
The processor starts again at its reset address. Yesterday, I tried the same, and the processor didn't restart, the only change was that I didn't use the -G0 compiler option to get rid of the global pointer. Still the integer 'ga' was nopt modified. With the use of the global pointer, I have this disassembled code :01000000 : 0001883a 01000004 : 0001883a 01000008 : 0001883a 0100000c : 0001883a 01000010 : 00c00534 01000014 : 18c6d404 01000018 : 18800037 0100001c : 10800044 01000020 : 18800035 01000024 : f800283a 01000028 : 32463032 0100002c : 31303343 01000030 : 32423030 01000034 : 31303443 01000038 : 34303030 0100003c : 46464245 01000040 : 41374544 01000044 : 31333033 01000048 : 36423030 0100004c : 33530a0d 01000050 : 30303531 01000054 : 30343030 01000058 : 34303033 0100005c : 46374646 01000060 : 35314645 01000064 : 30343130 01000068 : 35314644 0100006c : 30303030 01000070 : 35314544 01000074 : 30384630 01000078 : 35363844 0100007c : 33530a0d 01000080 : 30303531 ** START BOOTLOADER **
The only difference here seems to be the use of register r3. I can not understand why this changes the effect on calling the function. Stefaan01000000 <_Z9TestSDRamv>: 1000000: 0001883a nop 1000004: 0001883a nop 1000008: 0001883a nop 100000c: 0001883a nop 1000010: d0a00337 ldwio r2,-32756(gp) 1000014: 10800044 addi r2,r2,1 1000018: d0a00335 stwio r2,-32756(gp) 100001c: f800283a ret - Altera_Forum
Honored Contributor
Does it still crash if you take the ga++ out, i.e. only NOPs?
I had a 'thing' about 2 years ago. NIOS1 design. All went well by checking memory with GERMS. BUT as soon as I ran code from it the software crashed. First of all the PCB was crappy. Had to design the entire thing on double sided PCB which caused my tracks to be too long (budget constraint :-( Then I tried to lower the CPU speed but the same thing occured. Hmmm. Eventually I tracked it down. No matter what the speed was the problem originated from the rise times. It seemed that when I had repeated hits on the datalines the data would get corrupted. I could fix the errors by soldering 1pF caps between data and ground but eventually decided to redo the boards using multilayered PCBs- problem solved. It looks like the code should run. It does not jump (relocation error possibility) and when it hits RET the stack should have the right return address. Options: 1) Check with an empty function, e.g. 1 NOP and RET. This should work, surely! 2) Lower the clock speed 3) I don't know what track lengths you have, going to the SDRAM, but try to increase the delay from the PLL (You are using a PLL ?) 4) Write some SRAM code to hammer the SDRAM with a pseudo random stream of data and verify it back. Don't use the same value. The more chaotic the better. If there are errors then the interface doesn't work. VMS - Altera_Forum
Honored Contributor
TO_BE_DONE
- Altera_Forum
Honored Contributor
Being able of writing-then-reading a bunch of bytes from the SDRAM is not the final probe that timing is OK. Between one access and the next (as pointer handling code should be executed) there could be a "too long" time that could mask the timing problems, as the use of a data cache would also do.
Create a new project targeted to run in your SDRAM. Compile and try to run. If you have an invalid timing issue it will show-up here, the JTAG debug module and the instruction cache put much more stress on the SDRAM avalon slave interface than your code. Try with several delay values (compensation) in your SDRAM clock PLL. - Altera_Forum
Honored Contributor
....or use the memtest example software template, running out of SRAM or onchip memory, to really slam the SDRAM. It will even make use of a DMA (which is latency aware), if you have one in your system.
Cheers, - slacker - Altera_Forum
Honored Contributor
Indeed, indeed, The PLL tuning.
The delay was on -4ns. In a small test project, it turned out that -3ns untill +1ns works for both instruction fetching and data access. Mean time I found the document sdram controller (http://www.altera.com/literature/hb/nios2/n2cpu_nii51005.pdf) and used the calculations to estimate the timing, it turns that the shift should be -2ns average. I decided to use -1.5ns, and the SDRAM works fine also in the real project. Thanks for the hint. Stefaan - Altera_Forum
Honored Contributor
Great Post...
- Altera_Forum
Honored Contributor
Next time I'm in Shangai, we can have a drink togheter, ...