2023-02-13 02:27 AM
Hello,
I got my hands on a H735 Discovery Board which has an external "HyperRAM" (Infineon S70KL1281DABHI023) connected to OCTOSPI2.
I need to use it in memory mapped mode, which is quite easily setup via HAL stuff (just switched to register setup to learn how it works and get better control).
First of all, it's working, clock is 100 MHz. Speed checked with the ARM's cycle counter.
Speed: when reading / writing big buffers (>1kB)
Okay, byte access with a simple for loop takes a few more cycles per byte, but the interesting thing is that with the same clock and a QUAD SPI RAM and byte access I got speeds up to almost 25 MB/s (200 Mbit/s).
Question:
Is that some normal behavior of the peripheral due to different byte / word / ocal / quad handling inside the peripheral?
Or is there some setting I can tune for octal mode?
The one big difference I see in the settings between Hyper / quad is the "refresh rate" which the Hyper RAM needs (a high NCS every now and then to trigger its internal refresh). But even playing around with that didn't change much in byte mode.
2023-02-14 07:30 AM
Any ideas?
2023-02-16 08:06 AM
So, I've been playing with that HyperRam, and there are some amazing results and insights.
Still running "HyperRAM" (Infineon S70KL1281DABHI023) with 100 MHz.
I wrote a super simple test function, writing and reading the complete RAM with 32-bit pointers, writing index in one straight for loop, then another for loop with reading and comparing.
I use the cycle counter to measure the timing, and because I could not believe the (good) results, I checked also with the (1ms) SysTick.
uint32_t *pu32MemAddr = (uint32_t *)OCTOSPI2_BASE;
/* write complete HyperRAM */
u32TickStart = HAL_GetTick();
u32CycStart = DWT->CYCCNT;
for( i = 0; i < u32MaxLen; i++ )
{
pu32MemAddr[i] = i;
}
u32Cycles = DWT->CYCCNT - u32CycStart;
u32Ticks = HAL_GetTick() - u32TickStart;
snip, some UART output...
/* read complete HyperRAM and compare */
pu32MemAddr = (uint32_t *)OCTOSPI2_BASE;
u32TickStart = HAL_GetTick();
u32CycStart = DWT->CYCCNT;
for( i = 0; i < u32MaxLen; i++ )
{
u32Data = pu32MemAddr[i];
if( u32Data != i ) u32Errors++;
}
u32Cycles = DWT->CYCCNT - u32CycStart;
u32Ticks = HAL_GetTick() - u32TickStart;
Here's the result (UART output):
****** OCTOSPI2 HyperRAM test ******
writing 0x00400000 = 4194304 32bit words ...
16777216 bytes written
35176768 CPU cycles -> 87941.9 us
-> 1526.21 Mbit/s
88 ms (ticks)
-> 1525.20 Mbit/s
reading and comparing 0x00400000 = 4194304 32bit words ...
16777216 bytes read
43689082 CPU cycles -> 109222.7 us
-> 1228.84 Mbit/s
110 ms (ticks)
-> 1220.16 Mbit/s
NULL errors
OctoSpi2HyTest() success, no errors
So... it takes only 2.6 CPU cycles per iteration in average for the reading for-loop?
Is that even possible?
And also the about 2 cycles per iteration for the write loop, reaching almost the theoretical maximum of 100 MHz / 8-bit / DDR of 1600 Mbit/s? Holy Moly...
What am I doing wrong?
I checked the HyperRAM contents, and everywhere I looked, I found the correct content.
2023-02-16 08:26 AM
So, next test was my actual application:
SAI -> DMA -> HyperRAM -> DMA -> Ethernet
And here it "failed":
but...
So, thinking about that, this is no big surprise:
the SAI DMA constantly pushes data into the HyperRAM (every 5 µs at 200 kHz), so the ETH DMA doesn't really have the time to get complete packets.
And the constant switching between reading and writing at completely different addresses takes even more time.
Next step:
let SAI DMA write into internal SRAM, then copy complete packet into HyperRAM, either via DMA (MEM2MEM), or as it seems now, with a simple for loop.
2023-02-16 08:34 AM
Right now the results for 1460 bytes (TCP's payload maximum) are:
DMA MEM2MEM (best settings: burst = 16 beats, size = byte)
for loop with 32-bit pointer:
Again, the simple for loop for writing is insanely fast - unless there's something I'm doing wrong...
I had never expected that this simple copying loop would take less time.
2023-02-16 09:11 AM
I'm not super invested in this, but probably want to look at the MPU and caching settings, how it writes back, or folds things.
These types of memory have a lot of latency when used in random-access, rather the page level bursts.
DMA doesn't have write buffering, or caching, just the minimum number of transistors to accomplish the task.
2023-02-16 09:16 AM
Thanks for your input!
Actually, because I didn't want to worry about cache management for a start, all caches are OFF.
What I don't get is that the for loop is that fast, how can the write loop take only about 2 CPU cycles per iteration?
That some "internal ARM core specialty"?
2023-02-16 11:21 PM
And here comes the problem, which I forgot to tell about yesterday because it didn't happen then, but I had seen that before:
The HyperRAM speed is very dependent on compilation, I changed the code a little bit, some place completely unrelated to HyperRAM, and after that compilation I get only:
What going on there?
Okay, checking the list files... if I can get it back to the higher speed.