How can I read the UICR register of 9160?

The current project needs to save the ID in the programmable register and use the ID in the application image.

So I save the ID number in the URCI->OTP[0] register. When I read the ID in URCI->OTP[0] in the main function of the application image, a fatal error occurred.

uint32_t get_id_from_uicr(){
        uint32_t id;
        id = (NRF_UICR_S->OTP[0]);
        return id;
}

As far as I know, UICR can only be read in secure code.

So I execute this code in the main function of spm and get the ID normally. How can I pass the ID to the application image(not via flash)?

Or is there any other better way to store this ID?

spm.c:

uint32_t get_id_from_uicr(){
        uint32_t id;
        id = (NRF_UICR_S->OTP[0]);
        return id;
}

void main(void)
{
    uint32_t id;
    id = get_imei_from_uicr();
	spm_config();
	spm_jump();
}

Parents
  • Hi - the problem is that OTP memory must be read in 32 bit words. Simply adding the OTP memory to the `ranges` in spm_request_read_nse isn't enough - I used code like this:

    __TZ_NONSECURE_ENTRY_FUNC
    int spm_request_read_nse(void *destination, uint32_t addr, size_t len)
    {
    	static const struct read_range ranges[] = {
    
    #ifdef PM_MCUBOOT_ADDRESS
    		/* Allow reads of mcuboot metadata */
    		{.start = PM_MCUBOOT_PAD_ADDRESS,
    		 .size = PM_MCUBOOT_PAD_SIZE},
    #endif
    		{.start = FICR_INFO_ADDR,
    		 .size = FICR_INFO_SIZE},
    #if defined(FICR_NFC_TAGHEADER0_MFGID_Msk)
    		{.start = FICR_NFC_ADDR,
    		 .size = FICR_NFC_SIZE},
    #endif
    		{.start = FICR_RESTRICTED_ADDR,
    		 .size = FICR_RESTRICTED_SIZE},
    
            // Allow reading UICR
            {.start = NRF_UICR_S_BASE,
             .size = 4096},
    	};
    
    	if (destination == NULL || len <= 0) {
    		return -EINVAL;
    	}
    
    	if (ptr_in_secure_area((intptr_t)destination)) {
    		return -EINVAL;
    	}
    
    	for (size_t i = 0; i < ARRAY_SIZE(ranges); i++) {
    		uint32_t start = ranges[i].start;
    		uint32_t size = ranges[i].size;
    
    		if (addr >= start && addr + len <= start + size)
            {
                if ((addr & 3) == 0 && (len & 3) == 0)
                {
                    // use 32 bit copy
                    uint32_t *d = destination;
                    uint32_t *s = (uint32_t)addr;
                    while (len)
                    {
                        *d++ = *s++;
                        len -= 4;
                    }
                }
                else
                {
    			    memcpy(destination, (const void *)addr, len);
                }
    			return 0;
    		}
    	}
    
    	return -EPERM;
    }

Reply
  • Hi - the problem is that OTP memory must be read in 32 bit words. Simply adding the OTP memory to the `ranges` in spm_request_read_nse isn't enough - I used code like this:

    __TZ_NONSECURE_ENTRY_FUNC
    int spm_request_read_nse(void *destination, uint32_t addr, size_t len)
    {
    	static const struct read_range ranges[] = {
    
    #ifdef PM_MCUBOOT_ADDRESS
    		/* Allow reads of mcuboot metadata */
    		{.start = PM_MCUBOOT_PAD_ADDRESS,
    		 .size = PM_MCUBOOT_PAD_SIZE},
    #endif
    		{.start = FICR_INFO_ADDR,
    		 .size = FICR_INFO_SIZE},
    #if defined(FICR_NFC_TAGHEADER0_MFGID_Msk)
    		{.start = FICR_NFC_ADDR,
    		 .size = FICR_NFC_SIZE},
    #endif
    		{.start = FICR_RESTRICTED_ADDR,
    		 .size = FICR_RESTRICTED_SIZE},
    
            // Allow reading UICR
            {.start = NRF_UICR_S_BASE,
             .size = 4096},
    	};
    
    	if (destination == NULL || len <= 0) {
    		return -EINVAL;
    	}
    
    	if (ptr_in_secure_area((intptr_t)destination)) {
    		return -EINVAL;
    	}
    
    	for (size_t i = 0; i < ARRAY_SIZE(ranges); i++) {
    		uint32_t start = ranges[i].start;
    		uint32_t size = ranges[i].size;
    
    		if (addr >= start && addr + len <= start + size)
            {
                if ((addr & 3) == 0 && (len & 3) == 0)
                {
                    // use 32 bit copy
                    uint32_t *d = destination;
                    uint32_t *s = (uint32_t)addr;
                    while (len)
                    {
                        *d++ = *s++;
                        len -= 4;
                    }
                }
                else
                {
    			    memcpy(destination, (const void *)addr, len);
                }
    			return 0;
    		}
    	}
    
    	return -EPERM;
    }

Children
No Data
Related