pynrfjprog: FICR and UICR register offsets

As far as I can tell, it is not currently possible to implement the following functionality in a simple way with pynrfjprog across the various device families.

* What is the connected device hardware ID?
* What is the memory address of the UICR CUSTOMER/OTP region?

With the upcoming deprecation of the HighLevel API (https://github.com/NordicSemiconductor/pynrfjprog/blob/master/pynrfjprog/HighLevel.py#L4), the functionality goes backwards in some respects, mostly due to the removal of `get_device_info`, which contained the base offsets of the FICR and UICR regions.

To answer these two simple questions I now need to iterate through the `read_memory_descriptors()` array to find the base addresses, and then create my own device_family->register_offset mapping, populated by reading through a number of datasheets.

Have I missed some simple method to answer these questions?

Parents Reply Children
  • From what I can tell, the only part of my problem that nrfutil helps with is determining the base UICR address, which is the one piece of information it is relatively easy to get from pynrfjprog.

    Neither "device list" or "device core-info" report the hardware ID, nor do they provide the UICR CUSTOMER/OTP memory address.

    I don't believe reading the hardware ID to identify the board and flashing some provisioning information to the memory region specifically intended for it is some crazy use case, it would be nice to get some exact commands that demonstrate how to do this.

  • Hi!

    By " hardware ID " what specific register are you referring to?

  • For the nRF52840 DEVICEID in the above, and the equivalent register that exists on all other Nordic parts I have seen.

  • For pynrfjprog, I think you just need to do something like this as of now:

    pseudo code snippet:

    FICR_ADDR_DEVICEID = {"NRF91": 0xFF0204, "NRF53": 0xFF0204, "NRF52": 0x10000060}
    
    def read_ficr(self, snr):
        with LowLevel.API() as api:
            api.connect_to_emu_with_snr(snr)
            device_family = api.read_device_family()
            device_id_addr = FICR_ADDR_DEVICEID[device_family]
            device_id = api.read(device_id_addr, 4)

    For nrfutil we can look into adding a built-in function for this.

  • I'm not claiming that its particularly difficult to do what you have done, just that it seems odd that

    > a DLL that exports functions for programming and controlling nRF51, nRF52, nRF53 and nRF91 Series devices and lets developers create their own development tools using the DLLs API

    Does not expose basic constants for those very devices.

    It is also not quite as simple as you propose, even in that snippet there is an error and ommissions:

    * Device ID is a 64bit number, but you're only reading 4 bytes
    * api.read() returns bytes, not an integer, whats the encoding? It's certainly not clear if you've ever looked at the Zephyr function that gets the hardware ID: https://github.com/zephyrproject-rtos/zephyr/blob/dcf42917c550714d2457947538b9e29d083e872e/drivers/hwinfo/hwinfo_nrf.c#L37-L38

    I say this not because I can't answer these questions myself, but to hopefully make the point that it would be nice if the tools could provide these values directly.

    And of course users have 0 idea of whether a given register has the same memory address across all parts of a family. If they come across a sample like yours, not integrated into the tool itself, they are still going to need to double check against a datasheet to see if its valid for their particular part.

Related