This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NCS 1.5 / nRF5340 - inadequate facility for setting XOSC32MCAPS register

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:

  1. There is no configuration option to enable / disable the on-chip capacitors on XC1 and XC2.
  2. There is no configuration option to specify the target on-chip capacitance.
  3. 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.
  4. 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

Related