/*** *** internal Pointer to the DATAFLASH MEMORY region start address ***/ #define NVM_MEMORY ((volatile uint32_t *)FLASH_ADDR) void secure_dataflash_init(void) { /*** Enable security features of Dataflash *** Data Scrambling (key = 0x1234) *** Silent Access *** Tamper detection ***/ NVMCTRL_SEC->DSCC.reg = NVMCTRL_DSCC_DSCKEY(0x1234); NVMCTRL_SEC->SECCTRL.reg = (NVMCTRL_SECCTRL_KEY_KEY|NVMCTRL_SECCTRL_DSCEN|NVMCTRL_SECCTRL_TEROW(0)|NVMCTRL_SECCTRL_SILACC| NVMCTRL_SECCTRL_TAMPEEN); } /*** *** brief Execute a command on the NVM controller ***/ uint8_t _nvmc_exec_cmd(uint32_t cmd, uint32_t dst_addr) { /*** Wait until NVMCTRL is ready ***/ while (!(NVMCTRL_SEC->STATUS.reg & NVMCTRL_STATUS_READY)); /*** Clear NVMCTRL flags ***/ NVMCTRL_SEC->INTFLAG.reg = NVMCTRL_INTFLAG_MASK; /*** Set address if cmd requires it ***/ if ((cmd == NVMCTRL_CTRLA_CMD_ER_Val) || (cmd == NVMCTRL_CTRLA_CMD_WP_Val)) { NVMCTRL_SEC->ADDR.reg = (NVMCTRL_ADDR_ARRAY(0x01)| NVMCTRL_ADDR_AOFFSET(dst_addr)); } /*** Set command ***/ NVMCTRL_SEC->CTRLA.reg = (NVMCTRL_CTRLA_CMD(cmd)|NVMCTRL_CTRLA_CMDEX_KEY); /*** Wait until the command is performed and check errors ***/ while (!(NVMCTRL_SEC->INTFLAG.reg & NVMCTRL_INTFLAG_DONE)) { /*** Check if there is error in NVM erase operation ***/ if (NVMCTRL_SEC->INTFLAG.reg & (NVMCTRL_INTFLAG_LOCKE | NVMCTRL_INTFLAG_NVME | NVMCTRL_INTFLAG_PROGE | NVMCTRL_INTFLAG_KEYE)) { return 1; } } return 0; } /*** *** brief Erase a row in NVM memory ***/ int32_t secure_dataflash_erase_row(const uint32_t dst_addr) { return _nvmc_exec_cmd(NVMCTRL_CTRLA_CMD_ER_Val, dst_addr); } /*** *** brief Write a page buffer in NVM memory ***/ uint32_t secure_dataflash_write_page(const uint32_t dst_addr, const uint32_t *buffer, const uint16_t length) { uint16_t i; /*** Check if the write address is aligned to the start of a page ***/ if (dst_addr & (NVMCTRL_PAGE_SIZE - 1)) { return 1; } /*** Check if the write length is longer than an NVM page ***/ if (length > NVMCTRL_PAGE_SIZE/4) { return 1; } /*** Erase the page buffer before buffering new data ***/ _nvmc_exec_cmd(NVMCTRL_CTRLA_CMD_PBC_Val, dst_addr); uint32_t nvm_addr = dst_addr / 2; /*** NVM must be accessed as a series of 32-bit words, *** perform manual copy *** to ensure alignment ***/ for (i = 0; i < length; i++) { NVM_MEMORY[nvm_addr++] = buffer[i]; } /*** Execute NVM write page command ***/ if ((NVMCTRL_SEC->CTRLC.reg & NVMCTRL_CTRLC_MANW)|| (length < NVMCTRL_PAGE_SIZE)) { return _nvmc_exec_cmd(NVMCTRL_CTRLA_CMD_WP_Val, dst_addr); } return 0; } /*** *** brief Read a number of bytes from a page in the NVM memory ***/ int32_t secure_dataflash_read(uint32_t src_addr, uint32_t *buffer, uint32_t length) { uint32_t i ; uint32_t* pAddr = src_addr; /*** Wait until NVMCTRL is ready ***/ while (!(NVMCTRL_SEC->STATUS.reg & NVMCTRL_STATUS_READY)); while (i < length) { buffer[i++] = *(pAddr) ; pAddr ++ ; } return 0; }