Although the NHS31xx IC has full debugging capabilities, there are a number of peculiarities to be reckoned with. These items have been grouped here.
SWD
- Default setup
- After boot, by default - i.e. if no code read protection is enabled - the SWD pins (PIO 10 and 11) are configured for ARM Single-wire debug (
FUNC2
): see chapter 7 Pinning information, table 3 Pin allocation of the HVQFN24 package in the Objective Data Sheet and chapter 26 Input/Output configuration, sections 26.3.11 PIO0_10 and 26.3.12 PIO0_11 in the HW User Manual.
- GPIO
- These pins can be reconfigured using Chip_IOCON_SetPinConfig but this will break any existing debugging session, and prevent establishing a new one. When it is necessary to re-assign the purpose of these pins, it is therefore recommended to ensure there is a way to force a new debug session: e.g. by ensuring that after a reset these pins are not touched for a couple of seconds, or by using msg: Message Handler for communication and enabling the message MSG_ID_PREPAREDEBUG via MSG_ENABLE_PREPAREDEBUG.
Low Power Modes
- Power-off & Deep power down
- Another way to 'brick' a device is to go to the Power-off mode or the Deep power down mode. When using these modes, a SW error may be enough to prematurely decide to go into one of these modes. In both mentioned modes the SWD lines are not accessible. Existing debug sessions will yield errors; new debug sessions can not be created. One precaution to take is to wait for a number of seconds before going to such a mode using Chip_Clock_System_BusyWait_ms. New firmware can then always be flashed by toggling the
RESETN
pin just before the IC is targeted for a debug session. In case a debug build is used, it is possible to introduce a 500ms delay by approaching an NFC field before entering Deep Power Down. This functionality is embedded in the Chip_PMU_PowerMode_EnterDeepPowerDown function and allows starting a debug session in ICs that would otherwise never accept a debug connection anymore.
Another possibility is to ensure the ARM remains Active or in Sleep mode while an NFC field is present.
A third way is to configure one unused GPIO as input with a pull-up and to wait indefinitely just before entering these modes as long as the pin is low. You can then be sure to be able to create a debug session and to flash a new program by putting the NHS31xx IC below an NFC-enabled phone.
- Note
- A mistake easily made when attempting to establish a debug session is to forget to ensure the IC is not in power-off mode: inserting a battery will not wake up the IC.
-
Connecting the LPC-Link2 board with the demo PCB starts the IC when it was in power-off mode, and wakes up the IC when it was in deep power down mode.
-
Be careful when placing a jumper over JP2 on the LPC-Link2 board as disconnecting the battery via SW - i.e. entering power-off mode using Chip_PMU_Switch_OpenVDDBat - will put the IC in an undetermined state: the ALON domain will remain powered and full power-off is only achieved after disconnecting the SWD cable or removing the jumper over JP2. Do not attempt to continue debugging, as nothing is guaranteed anymore and any behavior may be provoked. As a precaution, add an infinite wait loop
for
(;;); or similar after a call to Chip_PMU_Switch_OpenVDDBat.
Development
- Development strategy
- Because of the difficulties with debugging while using the Power-off mode or the Deep power down mode it may be worthwhile to avoid these states as long as possible during the development traject: try to split the application's responsibilities in separate chunks where these power states are required; implement those separately and only after that merge and tie them all together. This may also be very helpful for your testing strategy.
- Examples
- You can check these different provisions in the implementation of the Temperature logger demo - app_demo_dp_tlogger and the Therapy adherence demo - app_demo_dp_tadherence.
- CRP
- The NHS31xx ICs support Code Read Protection (CRP). This is a mechanism to add a level of protection: at startup, when the bootloader runs, a specific location in FLASH memory is read. Depending on the value read, the bootloader can decide to keep SWD access disabled, or to erase the entire FLASH.
The CRP modes supported by the NHS31xx IC are CRP_NO_CRP
, CRP_CRP2
and CRP_CRP3_CONSUME_PART
. The CRP magic word has to be stored in Flash address 0x000002FC
.
CRP_NO_CRP
(value: 0xFFFFFFFF
)
CRP is disabled in this mode and hence SWD will be enabled when the bootloader has finished.
CRP_CRP2
(value: 0x87654321
)
This will disable SWD access. The application firmware can decide to re-enable SWD access. In addition, the WAKE-UP pin is checked and if it is pulled low, the entire FLASH memory is erased.
CRP_CRP3_CONSUME_PART
(value: 0x43218765
)
This will disable SWD access. The application firmware can decide to re-enable SWD access.
- Building applications with CRP
- The CRP_NO_CRP, CRP_CRP2 and CRP_CRP3_CONSUME_PART macros are defined in the crp.h header file which is part of the LPCXpresso tool directory. All applications have to mandatorily define the macro CRP_WORD to one of the above values in the crp.c file. This file gets automatically generated on creating a new project using the LPCXpresso wizard. All applications delivered by the SDK have the CRP feature turned off. When your application starts to use the code read protection feature - using value
CRP_CRP2
or CRP_CRP3_CONSUME_PART
- the SWD pins are configured as input and for GPIO usage when your application gets control. You can then still allow debugging by explicitly configuring the pins using the below code included in your application firmware:
- Note
- Using CRP mode
CRP_CRP3_CONSUME_PART
while still developing - and debugging - your code only makes a developer's life even harder. Only use this mode for your final firmware, and in that final firmware, also ensure the SWD pins are never reconfigured as in the code above, or the extra security gained from this will be lost.
-
When the SWD pins are multiplexed and to be used both to allow a debugging session and for sensing, it is easy to 'brick' your IC. In that case, enabling CRP mode
CRP_CRP2
makes sense, as it provides another way to 'unbrick' your IC and development board: pull and keep PIO0_1
low, then reset the IC: the bootloader will then ensure all writeable FLASH sectors (FLASH_NR_OF_RW_SECTORS) are erased.
All code and data in FLASH is lost, but your IC can be reprogrammed and used again.
When considering this latter approach, be aware that after a reset (hard reset or when leaving Deep Power Down) the pulls are removed from all pins. They are re-configured by calling Board_Init, i.e. em after the bootloader has run. To prevent unwanted full flash erasures, you must add an external weak pull-up on PIO0_1
.
Debug connection
- Breakpoints
- While debugging with breakpoints set these breakpoints remain when the debug session is forcefully broken (i.e. when the SWD cable is disconnected before the debug session is properly terminated in the LPCXpresso IDE. The ARM application will then be halted perpetually when it is hit. You can then try to establish a new debug session without reflashing the program and resetting the program counter PC and stack pointer SP (see the Attach only option in your Debug configuration) and continue execution. If that is not possible, a hard reset is the only option left.
- Error messages
- When trying to establish a debug session with an IC still in power-off mode, the LPCXpresso IDE will pop up an error dialog with the message
Target reported errors
Reason: 02: Failed on connect Could not connect to core. 31: No connection to emulator device.
This error indicates everything seems to be fine with the LPC-Link2 board but the NHS31xx IC could not be reached. Close the dialog, and restart using one of these options:
- timely toggle the
RESETN
pin to wake up the IC - press and release the Reset button on a demo PCB,
- hold a phone close with the NFC field enabled to power the NFC controller which will wake up the IC.
- When while debugging using the LPCXpresso IDE the debug session is broken - be it by unplugging the SWD cable or by reconfiguring the SWD pins - an error dialog will pop up with the message
Target reported errors
Reason: 16: Target error from status-poll: Ee(FF). Undocumented error.
Close the dialog, terminate the ongoing session, and restart.
- Even after an error occurred the LPCXpresso IDE will never automatically terminate a now defunct debug session. Trying to start a new session before terminating the old one will yield the error message
No debug targets available.
Reason: All SWD target are currently connected to other debug sessions.
Close the dialog, terminate the ongoing session, and restart.
Stack size
The NHS31xx IC has 8 KB of SRAM memory, of which 8716 bytes are available for the firmware. When this is not enough, the stack memory used will end up overwriting static data. Worst case the program will not crash but behave odd and produce incorrect results.
- Note
- For more background, visit e.g. this blog post on the ARM community.
It is not possible to track the stack usage live while debugging. You can instrument the project to retrieve stack size information.
- During compilation
- Add the gcc compiler option
-fstack-usage
to have a
.su file generated for each compilation unit (C file) within the folder of the used build configuration. These files can then be aggregated and checked for high numbers or unexpected changes between two points in time.
- During execution
- You can surround all or part of your program with non-production code.
- First write a pattern into unused SRAM.
- Next execute the block you want to learn the stack usage from.
- Finally check how much of the pattern is altered.
For the NHS31xx ICs, you can use these blocks of code.
- Before the block of code to check:
extern const int _pvHeapStart;
char top;
memset((void *)&_pvHeapStart, 0xA5, (unsigned int)&top - (unsigned int)&_pvHeapStart - 32);
- After the block of code to check:
char * b = &top - 32;
do {
b--;
}
while ((b >= (char *)&_pvHeapStart) && (b != 0xA5));
extern const int __top_RAM;
int used = (int)&__top_RAM - (int)b;