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

How to apply Nordic software workarounds/Errata for a given hardware revision in the field

Greetings!

This is about the errata published by Nordic, i.e., software workarounds from Nordic for a given hardware revision.

Example: nRF52840 Errata

https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev2/ERR/nRF52840/Rev2/latest/err_840_new.html 

ID    Module   Description

[20]  RTC:     Register values are invalid

This anomaly applies to IC Rev. Revision 2, build codes CKAA-Dx0, QIAA-Dx0.

In ID [20], there is a software workaround recommended by Nordic. To apply this workaround for our nRF52840 devices in the field, we need to know the build codes QIAA-Dx0 either in the Bill of Materials (BOM) or in the Non-Volatile Memory (NVM) register such as INFO.VARIANT in the chip.

The problem:

  • BOM only captures the order code: nRF52840-QIAA-R.
  • It is not clear which NVM register captures the QIAA-Dx0 in the nRF52840 Product Specification v1.1.
  • Based on my understanding, QIAA-Dx0, seems only to be available in a factory environment and the hardware/software engineers have no information about this unless we look at what is printed on the chip. So, how to DFU these Nordic Software Errata/Workaround?

Questions:

  1. Typically, the software workarounds are available in the SDK. When it is not in the SDK, are these patches available in an easy to integrate way of importing or compiling these patches? For example, are the workarounds available module-wise in a .c file for a given QIAA-Dx0?
  2. Is there any NVM register that I could look up QIAA-Dx0 to apply the patch? 
  3. Currently, there appears to be no way for a developer to know the hardware revision number (like QIAA-Dx0) being used in the factory. Is there any Nordic recommended way of patching our devices in the field for such hardware revisions? Especially when DFU or Firmware Over the Air is performed. 

Kindly let me know your thoughts on this each of the above bullets. Looking forward to your response.

Cheers,
Tilak

Parents
  • I had the same issue understanding the different variants, so wrote code for the various parts like this:

    // nRF52832
    // ========
    // Link https://infocenter.nordicsemi.com/topic/comp_matrix_nrf52832/COMP/nrf52832/nrf52832_comp_matrix.html
    const NRF52Description_t mNRF52832Description[] = {
    //  Code    Rev     Variant Build   Pkg Flash  RAM   Handler
    //  ======  ======  ======= ===== ===== ===== =====  ======
      {"AAAA",  ENG_A,  "QFAA",  "AA0 QFN48 512kB 64kB", NULL}, //
      {"AAAC",  ENG_A,  "QFAA",  "AC0 QFN48 512kB 64kB", NULL}, //
      {"AABA",  ENG_B,  "QFAA",  "BA0 QFN48 512kB 64kB", NULL}, //
      {"AAAA",  ENG_B,  "CHAA",  "AA0 WLCSP 512kB 64kB", NULL}, //
      {"AABB",  ENG_C,  "QFAA",  "BB0 QFN48 512kB 64kB", NULL}, //
      {"AABA",  ENG_C,  "CHAA",  "BA0 WLCSP 512kB 64kB", NULL}, //
      {"AABA",  ENG_C,  "CIAA",  "BA0 WLCSP 512kB 64kB", NULL}, //
      {"AABx",  REV_1,  "QFAA",  "Bx0 QFN48 512kB 64kB", mNRF52832_Anomalies}, //
      {"ABBx",  REV_1,  "QFAB",  "Bx0 QFN48 256kB 32kB", mNRF52832_Anomalies}, //
      {"AABx",  REV_1,  "CIAA",  "Bx0 WLCSP 512kB 64kB", mNRF52832_Anomalies}, //
      {"AAEx",  REV_2,  "QFAA",  "Ex0 QFN48 512kB 64kB", mNRF52832_Anomalies}, //
      {"ABEx",  REV_2,  "QFAB",  "Ex0 QFN48 256kB 32kB", mNRF52832_Anomalies}, //
      {"AAEx",  REV_2,  "CIAA",  "Ex0 WLCSP 512kB 64kB", mNRF52832_Anomalies}  // Testing
    //  ^^^^               ^^     ^^
    //  ||||               ||     || Note first column "Code" is a combination of "Varient" and "Build"
    //  |||+---------------||-----|+
    //  ||+----------------||-----+
    //  ||                 ||
    //  |+-----------------|+
    //  +------------------+
     };
    #define NUMBER_OF_NRF52832_MODELS ( sizeof(mNRF52832Description)/sizeof(mNRF52832Description[0]) )
    const uint16_t NumberNRF52832_Models = NUMBER_OF_NRF52832_MODELS;

    From this it becomes clear how to construct the specific part number to understand which errata require applying. I only apply errata form modules which are actually used. "x" is don't care. Construct the id with something like this:

       char ch, VarientStr[4+1] = "----";
       if (isprint(ch = (NRF_FICR->INFO.VARIANT>> 0 & 0xFF))) VarientStr[3] = ch;
       if (isprint(ch = (NRF_FICR->INFO.VARIANT>> 8 & 0xFF))) VarientStr[2] = ch;
       if (isprint(ch = (NRF_FICR->INFO.VARIANT>>16 & 0xFF))) VarientStr[1] = ch;
       if (isprint(ch = (NRF_FICR->INFO.VARIANT>>24 & 0xFF))) VarientStr[0] = ch;
       snprintf(Settings, sizeof(Settings), "Part nRF%X", NRF_FICR->INFO.PART);

    Checking for a match something like this:

       // Check code for match unless target char in LS byte is 'x' (which means Don't care)
       for (i=NumberOfModels-1; i>0; i--)
       {
          if (pDescription[i].Code[0] != VarientStr[0]) continue;
          if (pDescription[i].Code[1] != VarientStr[1]) continue;
          if (pDescription[i].Code[2] != VarientStr[2]) continue;
          if (pDescription[i].Code[3] != VarientStr[3] && pDescription[i].Code[3]!='x') continue;
          IdMatchFound = true;
          break;
       }

    nRF522840:

    // nRF52840
    // ========
    // Link https://infocenter.nordicsemi.com/topic/comp_matrix_nrf52840/COMP/nrf52840/nRF52840_ic_revision_overview.html
    const NRF52Description_t mNRF52840Description[] = {
    //  Code    Rev     Variant Build   Pkg Flash  RAM   Handler
    //  ======  ======  ======= ===== ===== ===== =====  ======
      {"AAAA",  ENG_A,  "QIAA",  "AA0 aQFN73 1MB 256kB", NULL}, //
      {"AABB",  ENG_B,  "QIAA",  "BB0 aQFN73 1MB 256kB", NULL}, //
      {"AAAA",  ENG_B,  "CKAA",  "AA0 WLCSP  1MB 256kB", NULL}, //
      {"AACA",  ENG_C,  "QIAA",  "CA0 aQFN73 1MB 256kB", NULL}, //
      {"AACA",  ENG_C,  "CKAA",  "CA0 WLCSP  1MB 256kB", NULL}, //
      {"AACx",  REV_1,  "QIAA",  "Cx0 aQFN73 1MB 256kB", mNRF52840_Anomalies}, //
      {"AACx",  REV_1,  "CKAA",  "Cx0 WLCSP  1MB 256kB", mNRF52840_Anomalies}, //
      {"AADA",  ENG_D,  "QIAA",  "DA0 aQFN73 1MB 256kB", NULL}, //
      {"AADA",  ENG_D,  "CKAA",  "DA0 WLCSP  1MB 256kB", NULL}, //
      {"AADx",  REV_2,  "QIAA",  "Dx0 aQFN73 1MB 256kB", mNRF52840_Anomalies}, //
      {"AADx",  REV_2,  "CKAA",  "Dx0 WLCSP  1MB 256kB", mNRF52840_Anomalies}  //
    //  ^^^^               ^^     ^^
    //  ||||               ||     || Note first column "Code" is a combination of "Varient" and "Build"
    //  |||+---------------||-----|+
    //  ||+----------------||-----+
    //  ||                 ||
    //  |+-----------------|+
    //  +------------------+
     };
    #define NUMBER_OF_NRF52840_MODELS ( sizeof(mNRF52840Description)/sizeof(mNRF52840Description[0]) )
    const uint16_t NumberNRF52840_Models = NUMBER_OF_NRF52840_MODELS;

  • Thank you  for the elegant code :) I will get back to you if I run into trouble. Thanks.

Reply Children
No Data
Related