Writing this post just want to remind the customer of RAM allocation when use the on-chip CAN drivers in LPC11C24. Otherwise, when meet the abnormal issues, it is difficult to locate the root reason and it also causes a waste of time.
Now, take a real customer question as an example, to highlight the RAM allocation importance when using the on-chip CAN API in LPC11C24.
- Problem description
Customer used the LPC11C24 on-chip CAN API to realize the CAN frames sending and receiving, the CAN code was from the official lpcopen, and it worked OK when he just used the CAN code. But when customer added the UART code, they found the code always enter hardfault after a short time running. They test the UART code which without the CAN code directly, the UART code worked perfectly. It means, independent UART code and independent CAN code are all working normally, but when combine the UART and on-chip CAN code together, the code will enter hardfault.
- Problem analysis
From the Cortex M0 devices generic user guide, we can get the information about the hard fault:
Faults are a subset of exceptions, see Exception model. All faults result in the HardFault exception being taken or cause lockup if they occur in the NMI or HardFault handler. The faults are:
- execution of an SVC instruction at a priority equal or higher than SVCall
- execution of a BKPT instruction without a debugger attached
- a system-generated bus error on a load or store
- execution of an instruction from an XN memory address
- execution of an instruction from a location for which the system generates a bus fault
- a system-generated bus error on a vector fetch
- execution of an Undefined instruction
- execution of an instruction when not in Thumb-State as a result of the T-bit being previously cleared to 0
- an attempted load or store to an unaligned address
Now we debug the problem project to check, which detail code line caused this hardfault problem. When the code enters the hardfault handler, check the MSP address in the flash, then find the LR register, which will link to the code before entering in the hardfault handler, the following are the according debug result:
The LR register is 0X1FFF2C1F, it means before enter in hardfault handler, the code runs to this address code. Now, check the 0X1FFF2C1F in the memory map.
We can find the address is in the ROM area, because we just use the ROM CAN driver, UART is just the pure register control code, then we can get the problem still relate to the on-chip CAN driver, not the UART code. But we can’t see or debug the detail ROM CAN driver directly, we still can’t find the root problem.
Even we know the problem is not caused by the UART, but another important clue which relates to the UART function also influence the test result after I do a lot of testing. In the customer code, he defines the UART user transmit and receive buffer like this:
#define UART_SRB_SIZE 128 // Send
/* Transmit and receive buffers */
On one occasion, I tried changing
#define UART_SRB_SIZE 128
#define UART_SRB_SIZE 32
Just minimize the txbuff size, I found the code won’t enter in the hardfault handler any more. It seems very strange and contradiction with the hardfault handler enter point which is test before.
I also check the generated code size, the used RAM and flash size is:
text data bss dec hex filename
7672 0 244 7916 1eec pscan.axf
LPC11C24 RAM is 8K, here just 244 Bytes, the stack also use the whole RAM, so the 8K RAM size should be enough to use.
In this situation, I check the project’s .map file about the txbuff with 128 and 32 respectively.
- 1)txbuff with 128Bytes
Rxbuff and txbuff occupy the RAM address from 0X10000048 to 0X100000E8.
- 2)txbuff with 32Bytes
Rxbuff and txbuff occupy the RAM address from 0X10000048 to 0X10000088.
We can find the txbuff start address is the same, just the end address has difference.
With these information, we checked the LPC11C24 user manual chapter C_CAN on-chip drivers again, we found a significant description:
0X10000050 to 0X100000B8 is used by the on-chip CAN API RAM, and from the issue project, memory map file, we can find rxbuff and txbuff RAM address is 0X10000048 to 0X100000E8, it already occupies the whole CAN API RAM, this is the key point.
Minimize the txbuff, then rxbuff and txbuff occupy the RAM address from 0X10000048 to 0X10000088, this address doesn’t occupy the whole on chip CAN API RAM, in this situation, the problem doesn’t happen, I think the used CAN API may in the RAM address 0X10000089-0X100000B8.
Anyway, just minimize the buffer size can’t solve the problem from the root side. We must follow the user manual to keep the RAM address from 0x10000050 to 0x100000b8 won’t be used by any other application code.
- Problem solutions
From the above chapter, we can find the root problem is the application code occupies the on-chip CAN RAM, to solve the problem, we need to modify the linker file, to prevent the usage of on-chip CAN RAM range.
Because the customer is using the LPCXPresso IDE, then we take this IDE as an example, to protect the RAM address 0x10000050 to 0x100000b8.
From the above, we can get that the LPCX11C24 have 8Kbytes RAM, normally, customer will define it just in one, now we divide the RAM to two pieces.
- 1) RAM2: Location 0X10000000, size 0X100
- 2) RAM: Location 0X10000100, size 0X1F00
In the LPCXpresso, Project Properties -> C/C++ Build -> MCU settings, then modify it like this:
Then generate the code, and check the map file again.
RAM address from 0x10000000 to 0X10000FF is not used by any other application code. All the application code RAM is using from address 0x10000100. After long time testing, we find the hardfault problem never happens, on customer side, it also works OK.
In conclusion, when customer want to use the on-chip CAN API, they need to protect the RAM address from 0x10000050 to 0x100000b8 in the linker file.