Simple way to reallocate USB stack to SRAM_LOWER

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Simple way to reallocate USB stack to SRAM_LOWER

2,818 Views
akimata
Contributor IV

Hi,

I'm wondering if there is a simple way to reallocate all usb buffer/stack to sram_lower because if i add usb stack to my project my SRAM_UPPER is overflowing and i got whole SRAM_LOWER free so i could fit usb stack there easily but i don't see any easy method to do that.

Processor : K22

Any suggestions?

Thanks

0 Kudos
12 Replies

2,184 Views
plinioandrade
Contributor I

Just want  to add my contribution here:

Merging the two memories for the KV22FN128M does cause issues: My code was working fine with the two memories merged until a added a couple items to a table (vector of a struct type) in my code and studently I started having issues causing the micro to reset with a hard fault.

Investigating the problem I found out the hard fault was triggered by this line of code:

UInt8 u8FaultEventLogDataRead[62];

UInt8 u8EventLogArray[20][62];

// Copy event log into array
memcpy(u8EventLogArray[wordEventLogTail], u8FaultEventLogDataRead, sizeof(u8FaultEventLogDataRead));

I discored that the u8EventLogArray was allocating memory in the boundary all the time but I was not getting any hard fault before adding extra entries in the table I cited above because because memcpy seems to typecast bytes to 32-bit values to copy them faster and I was just lucky enough that the alignment of the bytes before allowed memcpy to typecast the data without ever crossing the boundary for any combination of 32-bit casting.

I solved me problem re-dividing the memories again, allocating heap and stack to the lower RAM, allocating that huge 20*62 matrix to the lower RAM too and using the upper RAM for the rest of my code. I still have free space in the lower RAM and if I run out of memory in the upper RAM I will allocate more global variables to lower RAM.

Sincerely,

 

 

0 Kudos

2,556 Views
ErichStyger
Senior Contributor V

Hi Grzegorz Mikitiuk,

It depends on your toolchain (GNU?) and IDE (actually linker file) (MCUXpresso SDK?).

But with gnu tools you can specify the section name using an attribute, e.g.

static unsigned char __attribute__((section (".m_data_20000000"))) myArr[1024];

See FreeRTOS Heap with Segmented Kinetis K SRAM | MCU on Eclipse 

That section name depends on your linker file.

E.g. in recent MCUXpresso SDK it would be

".bss.$SRAM_LOWER"

I hope this helps,

Erich

0 Kudos

2,556 Views
akimata
Contributor IV

Yeah i'm using MCUXpresso SDK,

I can specify variable location but it's pretty hard to reallocate all usb buffers/variables as i would have to dig into all files and manually set them to proper region which is pretty problematic but seems like there is no better solution and there is no simple way to allocate all usb variables/buffers on SRAM_LOWER. I might try to move some of my application to SRAM_LOWER so usb can fit into SRAM_UPPER.

0 Kudos

2,554 Views
ErichStyger
Senior Contributor V

The GNU linker scripts support 'wildcards': see Putting Code of Files into Special Section with the GNU Linker | MCU on Eclipse  as an example: you would need to check the linker map file and linker file to match your case. But that way you should be able to place things based on the file name.

0 Kudos

2,554 Views
myke_predko
Senior Contributor III

Hey akimata‌,

I found the simplest solution to this problem was to increase the size of SRAM_UPPER (and decrease the size of SRAM_LOWER) so that it basically takes over the entire SRAM space.  

In MCUXpresso, go to: "Properties" => "C/C++ Build" => "MCU Settings" and (for a 128k MC22 device) change:

  • "SRAM_UPPER" Location to "0x1fff0100" and Size to "0x1ff00"
  • "SRAM_LOWER" Size to "0x100"

I'm curious as to why there is the SRAM_UPPER and SRAM_LOWER partitions that split the total SRAM in the device specification because there doesn't seem to be a need for the two partitions and things seem to run okay with a single large contiguous SRAM space.  

myke

0 Kudos

2,554 Views
ErichStyger
Senior Contributor V

No, do not change that memory splitting! There is a reason for that: there are two memory controllers with indepenent accesses. If you 'merge' the two areas, then objects might be crossing that boundary and you will get a hard fault.

There is a related question on that in FreeRTOS Heap with Segmented Kinetis K SRAM | MCU on Eclipse 

Bottom line: treat it really like separate memory areas (this is what it actually is).

0 Kudos

2,554 Views
myke_predko
Senior Contributor III

Hi ErichS‌,

Can you give me an example application where sharing data across the two regions causes a hard fault?  Along with that, could you show me where the operation of the two memory controllers are in conflict (which is what I think the case is that you are describing)?  

I understand that they are two separate SRAM areas with separate controllers but despite reading the RM, I can't find any cases where there are more than one device accessing them simultaneously - I would expect that with running the (single) processor core and DMA together with show a problem, but it seems like the processor core is always pre-empted by the DMA controller.  If there were two cores, I would expect that a region would be dedicated to each core and I wouldn't be so cavalier, but as it stands with the devices we're discussing (the MK22) I don't see any cases where there is a conflict.  

I'm running with USB (32k heap) along with UART, SPI & I2C EDMA operations and I have never seen a hard fault (when debugging I always run with the first instruction of semihost_hardfault.c as a breakpoint) nor have I seen any unexpected operations of the device.  Looking at the .map file for one of my applications (the one I'm doing right now), the main memory heap straddles the two regions:

 .bss.ucHeap 0x000000001fffb550 0x7700 ./amazon-freertos/freertos_kernel/portable/MemMang/heap_4.o
.bss.xStart 0x0000000020002c50 0x8 ./amazon-freertos/freertos_kernel/portable/MemMang/heap_4.o

Maybe I'm lucky as I would think this is the worst possible case, IFF the two memory controllers were active simultaneously.  

When I first encountered this issue, I did specifically allocated the locations of the heap as you outlined in FreeRTOS Heap with Segmented Kinetis K SRAM but this made working between versions of the SDK quite a bit more difficult (see rant about different SDKs for different devices in the MK22 family elsewhere) and did some research and testing and I can't find a situation where doing this is a problem on these devices.  Looking at the replies by akimata‌ to your comments he has the same concerns.  

Again, If you have an example where the two controllers are causing a conflict and an execution failure, I'd really like to see it as I would then bite the bullet and do the extra work.  It's just that I don't see an actual case where it can happen and I haven't experienced it.  

myke

0 Kudos

2,554 Views
ErichStyger
Senior Contributor V

I think you are just lucky. Early linker files in KDS had it wrong and caused many crashes for me and others (not sure if these reports are still somewhere in the forum). These crashes disappeared for me starting with having the correct memory layout.

I think a simple test case would be to allocate your USB buffer across this boundary. As stated above: it is about burst accesses (not sure how to enforce them).

0 Kudos

2,554 Views
myke_predko
Senior Contributor III

Hi ErichS‌,

I followed your suggestion and created a very cut down version of my code.  You can run the attached project on a FRDM-K22F (it takes an incoming string from a USB CDC device and converts it to uppercase and then sends it back).  

I went through the USB code and the map file for the app with the result being the largest buffer in the entire cut down application is "usb_device_khci_state_struct_t" (512 bytes in size and located in usb_device_khci.c) and it is set to 512 byte alignment (which means that it can never straddle the SRAM_UPPER/SRAM_LOWER boundary):

USB_BDT USB_RAM_ADDRESS_ALIGNMENT(512) static uint8_t s_UsbDeviceKhciBdtBuffer[USB_DEVICE_CONFIG_KHCI][512U];

In my original post, I think I inaccurately represented the situation when I said I had USB with a 32k buffer.  I have the USB interface AND a separate 32k buffer for the heap - they're not together.  

I went from CW 11 and MQX 10.6 to MCUXpresso 11 and the SDKs (I looked at the KDK six-seven years ago and decided it was too much work at the time to port my code without a strong reason) - the reason why I'm doing it now is that it seemed like too much work to create CW BSPs for the MK22 than to use the pre-existing SDKs.  So it sounds like I've missed the grief that you've gone through there.  

As I'm writing this I was going to say that I don't see any reason where I could get a problem with increasing the size of SRAM_UPPER along with noting that I'm going to (actually I already have) set the SRAM alignment of my DMA buffers (using the "__attribute__((aligned(bufferSize)))" declaration parameter) so that they can't straddle the SRAM_UPPER/SRAM_LOWER boundary and then realized that we're really doing the same thing - ensuring that buffers don't go over the boundary.  I would argue that the approach of creating a large single SRAM partition with hardware buffers put on their size boundaries to eliminate any chance of straddling the RAM block boundary produces more portable and easily maintainable code.  

Comments?

myke

0 Kudos

2,554 Views
mjbcswitzerland
Specialist V

Hi

I have been involved with over 250 product developments with various Kinetis parts over the last 8 years and have always used the total memory as a single contiguous area - I think that the SDK is playing extremely safe to sometimes throw away half or a quarter of its potential RAM to ensure that a potential misalignment case couldn't result in a problem.

If one ensures alignment (there is no reason why not to since the Cortex M0+ will hard fault on any misaligned accesses anyway and the Cortex-M4 parts will work less efficiently) there is little or even no risk..

Misaligned accesses don't in fact hard fault on the K22, even across the boundary of the two RAM controllers. They just give bad data, which can then cause a problem of course if used. This can be seen very easily. If you fill the memory with a pattern as such:

Memory Display
md 1ffffffc l 2 {long word read of two works at the address 0x1ffffffc}
0x1ffffffc     12345678 aabbccdd  .4Vx....

Now watch how K22 (Cortex-M4) misaligned reads are handled:

md 1ffffffc l 1
Memory Display
0x1ffffffc     12345678  .4Vx

md 1ffffffd l 1
Memory Display
0x1ffffffd     fc123456  ..4V

md 1ffffffe l 1
Memory Display
0x1ffffffe     fffc1234  ...4

md 1fffffff l 1
Memory Display
0x1fffffff     02fffc12  ....

md 20000000 l 1
Memory Display
0x20000000     aabbccdd  ....

Which shows that access are possible (without hard fault) but the misaligned access across the boundary returns some bad data.

I was always worried about burst DMA across the boundary but never had an issue since my DMA routines ensure that they always use aligned transfers and if I remember correctly I also tested aligned DMA across the boundary without finding issues.

Since I work with a number of IDEs and compilers I never configure in linker script files since that makes for problems of portability. Instead I always use a malloc() version that allows things like alignment to be handled automatically and I can also ensure that any memory allocated for use by things like USB is not only correctly aligned but also avoids being allocated across such a boundary. I never had to use it though.....

Therefore I agree that there should be no reason to not be able to work with a contiguous memory as long as basic alignment rules are observed (good practice anyway). But I don't know whether the SDK respects all alignment rules (?)

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

2,554 Views
myke_predko
Senior Contributor III

Hey mjbcswitzerland‌,

Very interesting data point - do you have any idea how often the "md" is used in GCC C/C++?  

I don't use uint64_t/int64_t at all and when I scan the dissassembly of my code I don't see it used.  

So, I suspect that with the rules that I've outlined here I shouldn't have to worry.

Thank you, it's nice to get confirmation from another source.

myke

0 Kudos

2,554 Views
akimata
Contributor IV

I dont think that's a good idea as reference manual clearly states that :

"Burst-access cannot occur across the 0x2000_0000 boundary that separates the two SRAM arrays. The two arrays should be treated as separate memory ranges for burst accesses."

0 Kudos