static int cmd_test(int argc, char **argv) { int page; char fill = 'a'; if (argc < 2) { printf("usage: %s <page>\n", argv[0]); return 1; } page = getpage(argv[1]); if (page < 0) { return 1; } for (unsigned i = 0; i < sizeof(page_mem); i++) { page_mem[i] = (uint8_t)fill++; if (fill > 'z') { fill = 'a'; } } if (flashpage_write_and_verify(page, page_mem) != FLASHPAGE_OK) { printf("error verifying the content of page %i\n", page); return 1; } printf("wrote local page buffer to flash page %i at addr %p\n", page, flashpage_addr(page)); return 0; }
void flashpage_write(int page, void *data) { assert(page < FLASHPAGE_NUMOF); uint32_t *page_addr = (uint32_t *)flashpage_addr(page); /* remove peripheral access lock for the NVMCTRL peripheral */ #ifdef CPU_FAM_SAML21 PAC->WRCTRL.reg = (PAC_WRCTRL_KEY_CLR | ID_NVMCTRL); #else if (PAC1->WPSET.reg & NVMCTRL_PAC_BIT) { PAC1->WPCLR.reg = NVMCTRL_PAC_BIT; } #endif /* erase given page (the ADDR register uses 16-bit addresses) */ NVMCTRL->ADDR.reg = (((uint32_t)page_addr) >> 1); NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER); while (!NVMCTRL->INTFLAG.bit.READY) {} /* write data to page */ if (data != NULL) { uint32_t *data_addr = (uint32_t *)data; NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC); for (unsigned i = 0; i < (FLASHPAGE_SIZE / 4); i++) { *page_addr++ = data_addr[i]; } NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP); } }
int flashpage_verify(int page, void *data) { assert(page < (int)FLASHPAGE_NUMOF); if (memcmp(flashpage_addr(page), data, FLASHPAGE_SIZE) == 0) { return FLASHPAGE_OK; } else { return FLASHPAGE_NOMATCH; } }
/** * @brief Does a short raw write on last page available * * @note Since every hardware can have different flash layouts for * automated testing we always write to the last page available * so we are independent of the size or layout */ static int cmd_test_last_raw(int argc, char **argv) { (void) argc; (void) argv; /* try to align */ memcpy(raw_buf, "test12344321tset", 16); /* erase the page first */ flashpage_write(((int)FLASHPAGE_NUMOF - 1), NULL); flashpage_write_raw(flashpage_addr((int)FLASHPAGE_NUMOF - 1), raw_buf, strlen(raw_buf)); /* verify that previous write_raw effectively wrote the desired data */ if (memcmp(flashpage_addr((int)FLASHPAGE_NUMOF - 1), raw_buf, strlen(raw_buf)) != 0) { puts("error verifying the content of last page"); return 1; } puts("wrote raw short buffer to last flash page"); return 0; }
static int cmd_erase(int argc, char **argv) { int page; if (argc < 2) { printf("usage: %s <page>\n", argv[0]); return 1; } page = getpage(argv[1]); if (page < 0) { return 1; } flashpage_write(page, NULL); printf("successfully erased page %i (addr %p)\n", page, flashpage_addr(page)); return 0; }
void flashpage_write(int page, const void *data) { assert(page < FLASHPAGE_NUMOF); uint32_t *page_addr = (uint32_t *)flashpage_addr(page); /* erase given page (the ADDR register uses 16-bit addresses) */ _unlock(); NVMCTRL->ADDR.reg = (((uint32_t)page_addr) >> 1); NVMCTRL->CTRLA.reg = (NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER); while (!NVMCTRL->INTFLAG.bit.READY) {} _lock(); /* write data to page */ if (data != NULL) { flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE); } }
static int cmd_dump(int argc, char **argv) { int page; void *addr; if (argc < 2) { printf("usage: %s <page>\n", argv[0]); return 1; } page = getpage(argv[1]); if (page < 0) { return 1; } addr = flashpage_addr(page); printf("Flash page %i at address %p\n", page, addr); memdump(addr, FLASHPAGE_SIZE); return 0; }
static int cmd_write(int argc, char **argv) { int page; if (argc < 2) { printf("usage: %s <page>\n", argv[0]); return 1; } page = getpage(argv[1]); if (page < 0) { return 1; } if (flashpage_write_and_verify(page, page_mem) != FLASHPAGE_OK) { printf("error: verification for page %i failed\n", page); return 1; } printf("wrote local page buffer to flash page %i at addr %p\n", page, flashpage_addr(page)); return 0; }
void flashpage_write(int page, void *data) { assert(page < FLASHPAGE_NUMOF); uint32_t *page_addr = (uint32_t *)flashpage_addr(page); uint32_t *data_addr = (uint32_t *)data; /* erase given page */ NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een; NRF_NVMC->ERASEPAGE = (uint32_t)page_addr; while (NRF_NVMC->READY == 0) {} /* write data to page */ if (data != NULL) { NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen; for (unsigned i = 0; i < (FLASHPAGE_SIZE / 4); i++) { *page_addr++ = data_addr[i]; } } /* finish up */ NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren; }
void flashpage_read(int page, void *data) { assert(page < (int)FLASHPAGE_NUMOF); memcpy(data, flashpage_addr(page), FLASHPAGE_SIZE); }
void flashpage_write(int page, void *data) { assert(page < FLASHPAGE_NUMOF); uint16_t *page_addr = flashpage_addr(page); uint16_t *data_addr = (uint16_t *)data; uint32_t hsi_state = (RCC->CR & RCC_CR_HSION); /* the internal RC oscillator (HSI) must be enabled */ RCC->CR |= (RCC_CR_HSION); while (!(RCC->CR & RCC_CR_HSIRDY)) {} /* unlock the flash module */ DEBUG("[flashpage] unlocking the flash module\n"); if (FLASH->CR & FLASH_CR_LOCK) { FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; } /* ERASE sequence */ /* make sure no flash operation is ongoing */ DEBUG("[flashpage] erase: waiting for any operation to finish\n"); while (FLASH->SR & FLASH_SR_BSY) {} /* set page erase bit and program page address */ DEBUG("[flashpage] erase: setting the erase bit and page address\n"); FLASH->CR |= FLASH_CR_PER; FLASH->AR = (uint32_t)flashpage_addr(page); DEBUG("address to erase: %p\n", flashpage_addr(page)); /* trigger the page erase and wait for it to be finished */ DEBUG("[flashpage] erase: trigger the page erase\n"); FLASH->CR |= FLASH_CR_STRT; DEBUG("[flashpage] erase: wait as long as device is busy\n"); while (FLASH->SR & FLASH_SR_BSY) {} /* reset PER bit */ DEBUG("[flashpage] erase: resetting the page erase bit\n"); FLASH->CR &= ~(FLASH_CR_PER); /* WRITE sequence */ if (data != NULL) { DEBUG("[flashpage] write: now writing the data\n"); /* set PG bit and program page to flash */ FLASH->CR |= FLASH_CR_PG; for (unsigned i = 0; i < (FLASHPAGE_SIZE / 2); i++) { *page_addr++ = data_addr[i]; while (FLASH->SR & FLASH_SR_BSY) {} } /* clear program bit again */ FLASH->CR &= ~(FLASH_CR_PG); DEBUG("[flashpage] write: done writing data\n"); } /* finally, lock the flash module again */ DEBUG("flashpage] now locking the flash module again\n"); FLASH->CR |= FLASH_CR_LOCK; /* restore the HSI state */ if (!hsi_state) { RCC->CR &= ~(RCC_CR_HSION); while (RCC->CR & RCC_CR_HSIRDY) {} } }