Hello NCS team,
Target: Custom nRF5340 board
NCS Version: 1.5
After observing sub-standard radio performance on my custom nRF5340 board, I realised that the XOSC32MCAPS register was being set incorrectly. As it turned out, the culprit was in the ncs/modules/hal/nordic/nrfx/mdk/system_nrf5340_application.c file.
In the process of applying the trimming values, it was pulling across the default value (0x010c) from the FICR register and applying it to the XOSC32MCAPS register; this was trashing the actual value I applied. After moving my code post the application of trim values, radio performance was as expected.
In summary, as it stands, the are the following inadequacies / issues:
- There is no configuration option to enable / disable the on-chip capacitors on XC1 and XC2.
- There is no configuration option to specify the target on-chip capacitance.
- The calculation in the official Nordic doco (see "Using internal capacitors") gives a formula of CAPVALUE = (((FICR->XOSC32MTRIM.SLOPE+56)*(CAPACITANCE*2-14))+((FICR->XOSC32MTRIM.OFFSET-8)<<4)+32)>>6, which contradicts the calculation specified in the code comments (CAPVALUE = (1+FICR->XOSC32MTRIM.SLOPE/16) * (CAPACITANCE*2-14) + FICR->XOSC32MTRIM.OFFSET) - the latter is (somewhat) correct.
- The calculation specified in the code in point 3 above forces floating point math unnecessarily - the right way to do it is CAPVALUE = ( ( 16 + FICR->XOSC32MTRIM.SLOPE ) * ( CAPACITANCE*2 - 14 ) + 16 * FICR->XOSC32MTRIM.OFFSET ) >> 4
FWIW, the code I have applied AFTER the device trimming is as follows - I can confirm various devices with differing slope and offset values behave performant with the following code:
const int32_t double_cap_pf = 15; /* 7.5 pF caps */
int32_t slope;
int32_t ofst;
__ASM(
"mov %0, %[trim]\n\t" /* copy XOSC32MTRIM to reg 0 */
"mov %1, %[trim]\n\t" /* copy XOSC32MTRIM to reg 1 */
"and %[slope], %0, #0x1f\n\t" /* mask off lower 5 bits of XOSC32MTRIM for slope (signed) */
"lsl.w %[slope], %[slope], #0x03\n\t" /* logical shift left 3 to enable sign extend */
"sxtb %[slope], %[slope]\n\t" /* sign extend slope to 32-bit */
"asr.w %[slope], %[slope], #0x03\n\t" /* arithmetic shift right 3 bits to obtain int32_t value */
"and %[ofst], %1, #0x3e0\n\t" /* mask off bits 5-9 of XOSC32MTRIM for offset (unsigned) */
"lsr.w %[ofst], #0x05\n\t" /* logical shift right 5 bits of obtain int32_t value */
: [slope] "=r" (slope),
[ofst] "=r" (ofst)
: [trim] "r" (NRF_FICR_S->XOSC32MTRIM)
);
/* calculate CAPVALUE register value */
uint32_t CAPVALUE = (uint32_t)( ( ( 16 + slope ) * ( double_cap_pf - 14 ) + 16 * ofst ) >> 4 );
*((volatile uint32_t *)0x500045c4ul) = CAPVALUE | 0x00000100; // <== 0x00000100 to turn on;
I'm happy to make the changes and submit a PR to the NCS repo, however to do it correctly there are various Kconfig mods etc. that need to be done. Given I am particularly busy ATM, I would not be able to do this for approx. another two weeks. I wasted a LOT of time on this one, so would hope that no-one else has to deal with this - accordingly, if there is likely to be another release imminently, it would be good if this issue is addressed in that release.
BR,
Zyrus