I have designed system based on STM32L151. It uses usb for powering/charging and communicating to laptop. My system uses Embedded File System (SPI, 8MB) without RTX, USB(CDC Class), given by ST. I have typical problem and did not find any answer on net and from ST. As long I do not any request from PC on USB to system, things are OK, i.e. I can store and send the file from system to laptop on USB. But if I send any request from Laptop like configuration/reading of file etc, sending file to PC does not work. While digging, I found that lower level fopen function generate hard fault exception, hinting wrong memory access (data address invalid). It happens only when there is req from host, else device can send file without any problem to host by system keypad operation. I suspect that when EP_OUT is called, it is damaging the RAM area, which used by fopen function, like file information etc. I am new to USB, much can not do myself. I have 2K Stack and 1K heap, no of files opened at a time are 2. Is anybody, faced problem like this, if yes, how they solved. Is there any simple example to handle similar case, I do not need serial handling in system. Thanks in advance.
Hello,
Thanks for your suggestions and spent time. Finally the problem has been fixed. It was not null pointer problem or usb library, but corruption of Stack and Memory area by a for loop. In USB receive function, I used to stripped all the unwanted bytes in received message including CR and LF(keeping Printable characters). In the file system functions, before using the file name and command, convert the received message to upper case using one general function (taken from KEIL example code, char *get_entry(char *cp, char **pNext)). In this function, for (sp = cp; *sp != ' ' && *sp != CR && *sp != LF; sp++) { *sp = (char)toupper (*sp); /* convert entry to uppercase */ } breaks with space, LF or CR, which were not part of command to read the file (for argument part, i.e. File Name) - READ FILE_NAME. This for loop create problem in RAM by converting to them upper case till that it does not find either of above three characters. After including the LF/CR in message, it terminate as expected and problem solved. Sometimes changes or optimisation leads blunders as I have optimised the receive function but missed the impact in conversion. Still I feel that the conversion should have null also as break condition so that any String can also be send for conversion without impact with fully occupied RAM.
Is there any way to use Circular buffer implementation for CDC/USB to speed the transmission and save RAM. Tx Can be manage, but how to manage Rx Because Library gives counts and take start address of buffer. Does KEIL USB library uses Circular buffer? How to increase the size of Tx/Rx Packet and Place of changes in files.
> Is there any way to use Circular buffer implementation for CDC/USB to speed the transmission and save RAM.
On the ST CDC example, EP1_IN_Callback() splits data on large buffer, USART_Rx_Buffer, into 64 bytes (or less) packet. You may extend this implemntation into a cyclic buffer. A couple of problems you may meet with are,
1-1) word (two-bytes) access of USB RAM The data on the cyclic buffer is copied to the USB RAM using UserToPMABufferCopy() When the data on the buffer spans from the end of cyclic buffer to the top of the buffer (buffer wrap around), you may need a trick to do this job, for example, - copy the data into a temporary buffer once, and apply UserToPMABufferCopy() to this temporary buffer. The access to the USB RAM is restricted to word access. If the first portion of the data has odd number, you need to bind it with the later portion before UserToPMABufferCopy() is applied.
1-2) CDC bulk IN transfer requires short-packet termination. A large size transfer is split into 64 bytes (or less) packets on the USB line. When a transfer ends with a 64 bytes packet, bulk IN endpoint requires a ZLP (Zero-Length Packet), to indicate transfer termination.
// send ZLP SetEPTxCount(ENDP1, 0); SetEPTxValid(ENDP1);
1-3) Start trigger of transfer. EP1_IN_Callback() is called just when a transaction (packet) finishes. To start a sequence of transactions, your firmware has to call EP1_IN_Callback() explicitly.
On EP3_OUT_Callback(), you'll implement another cyclic buffer, like EP1_IN_Callback() Here are another problems on this implementation.
2-1) word access PMAToUserBufferCopy() (in USB_SIL_Read()) expects a target buffer, alligned in word boundary. You'll need some trick to copy the packet into odd address.
2-2) Flow control When the cyclic buffer is full, the copy from the USB RAM to the buffer is deferred until the data on the buffer is consumed. Your firmware has to give chances to poll this condition in SOF interrupt.
> Does KEIL USB library uses Circular buffer? Keil doesn't have USB CDC example for STM32L15x (nor STM32F103x, which has almost same USB peripheral)
> How to increase the size of Tx/Rx Packet and Place of changes in files.
On the device side, firmware exchanges 64 bytes (or less) packets over the USB peripheral. To move large-size transfer, your firmware has to split/gather the packets into full transfer. On the PC side, PC host controller does this job. Your PC application doesn't need to be aware of the packet size, at all. PC application can send/ receive large size transfer in single write/read call.
Tsuneo