cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC Fatal Error with 9 Byte Receive

David Kaplan
Associate II
Posted on May 01, 2017 at 20:20

I'm running into a Hard Fault when sending 9 bytes from a PC to a STM32F103C8T6 using USB CDC code generated by Cube 4.20.1, FW F1 V1.4.0.  I can send 8 bytes to the microcontroller without issue, but once I try 9 bytes, the micro runs into a Hard Fault.

The project is generated in CubeMX, using System Workbench IDE, and running on a custom board.  The only changes to the generated code is a section that pulls down D+ and waits 500 ms before calling MX_USB_DEVICE_Init().  This allows the PC to de-numerate and renumerate the device.

I'm running RealTerm on my Windows 10 PC, under the 'Send' tab, using the data '123456789', and then 'Send ASCII'.  At this point, the microcontrolller goes to a Hard Fault.  (See attached image for stack trace)  If I send '12345678' instead, everything runs fine.  

I'm not sure how to debug this, so any advice is appreciated.  

Thank you!

#cdc #usb-cdc #usb #hard-fault
1 ACCEPTED SOLUTION

Accepted Solutions
David Kaplan
Associate II
Posted on May 03, 2017 at 06:00

I found the issue.  There is a define in usbd_cdc_if.c that defines the size of the Rx buffer.

#define APP_RX_DATA_SIZE  4

Since the Rx Buffer was undersized, the USB_ReadPMA function was going out of bounds, overwriting values in PCD_HandleTypeDef.  USBx is the same pointer as 

PCD_HandleTypeDef->Instance which was overwritten in the USB_ReadPMA function. Since USBx became an invalid pointer, evaluating USBx->BTABLE caused the hard fault.

Changing APP_RX_DATA_SIZE to a larger value seems to have fixed the hard fault.

View solution in original post

4 REPLIES 4
Posted on May 01, 2017 at 21:50

Not sure the stack trace is immensely helpful. Suggest you look at the faulting instruction, the registers and what it was doing.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 01, 2017 at 22:18

 ,

 ,

The line of code where the fault happens is :

/*Set RX buffer count*/

 ,

PCD_SET_EP_RX_CNT(USBx, ep->,num, len),

Unfortunately, the rest of the code from there are a series of ♯ defines, so I can't get the exact line past this.  ,As a note, len is set to 64 at this point.

♯ define PCD_SET_EP_RX_CNT(USBx, bEpNum,wCount) {\

 ,

uint32_t *pdwReg = PCD_EP_RX_CNT((USBx), (bEpNum)), \

 ,

PCD_SET_EP_CNT_RX_REG(pdwReg, (wCount)),\

 ,

}

♯ define PCD_EP_RX_CNT(USBx, bEpNum) ((uint32_t *)(((USBx)->,BTABLE+(bEpNum)*8+6)*2+ ((uint32_t)(USBx) + 0x400)))

♯ define PCD_SET_EP_CNT_RX_REG(dwReg,wCount) {\

 ,

uint16_t wNBlocks,\

 ,

if((wCount) >, 62) \

 ,

{ \

 ,

PCD_CALC_BLK32((dwReg),(wCount),wNBlocks), \

 ,

} \

 ,

else \

 ,

{ \

 ,

PCD_CALC_BLK2((dwReg),(wCount),wNBlocks), \

 ,

} \

 ,

}/* PCD_SET_EP_CNT_RX_REG */

 ,

♯ define PCD_CALC_BLK32(dwReg,wCount,wNBlocks) {\

 ,

(wNBlocks) = (wCount) >,>, 5,\

 ,

if(((wCount) &, 0x1f) == 0)\

 ,

{ \

 ,

(wNBlocks)--,\

 ,

} \

 ,

*pdwReg = (uint16_t)((uint16_t)((wNBlocks) <,<, 10) | 0x8000), \

 ,

}/* PCD_CALC_BLK32 */

♯ define PCD_CALC_BLK2(dwReg,wCount,wNBlocks) {\

 ,

(wNBlocks) = (wCount) >,>, 1,\

 ,

if(((wCount) &, 0x1) != 0)\

 ,

{ \

 ,

(wNBlocks)++,\

 ,

} \

 ,

*pdwReg = (uint16_t)((wNBlocks) <,<, 10),\

 ,

}/* PCD_CALC_BLK2 */
Posted on May 01, 2017 at 22:31

You'd want to be looking at a disassembly, from either a listing or code file (ie source/assembler intermixed), you're interested in the instruction the processor is trying to execute and the register content for those used by the instruction.

ep->num is likely some out-of-range value, resulting in pdwReg touching memory it shouldn't

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
David Kaplan
Associate II
Posted on May 03, 2017 at 06:00

I found the issue.  There is a define in usbd_cdc_if.c that defines the size of the Rx buffer.

#define APP_RX_DATA_SIZE  4

Since the Rx Buffer was undersized, the USB_ReadPMA function was going out of bounds, overwriting values in PCD_HandleTypeDef.  USBx is the same pointer as 

PCD_HandleTypeDef->Instance which was overwritten in the USB_ReadPMA function. Since USBx became an invalid pointer, evaluating USBx->BTABLE caused the hard fault.

Changing APP_RX_DATA_SIZE to a larger value seems to have fixed the hard fault.