The data isn't terribly important and will fall back to a reasonable behavior if it reads an unexpected value.
I appreciate all the tips on this. I never would have guessed (and obviously haven't yet read the datasheet) that I could program the flash from 1 to 0, but not vice versa. Here's what I currently have (moderately well tested) if anyone else comes across this and is curious for implementation details.
I appreciate all the tips on this. I never would have guessed (and obviously haven't yet read the datasheet) that I could program the flash from 1 to 0, but not vice versa. Here's what I currently have (moderately well tested) if anyone else comes across this and is curious for implementation details.
Code:
#include <hardware/sync.h>#include <hardware/flash.h>// end - 4096. This doesn't include the XIP_BASE, which the flash_*() functions don't need#define FLASH_LAST_SECTOR (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)// XIP_BASE is execute in place (see pg24: ROM, XIP, SRAM, ...)#define XIP_FLASH_START (XIP_BASE + FLASH_LAST_SECTOR)#define XIP_FLASH_END (XIP_BASE + PICO_FLASH_SIZE_BYTES)#define PAGES_PER_SECTOR (FLASH_SECTOR_SIZE/FLASH_PAGE_SIZE)// Erased flash has 0xFF in each byte, so find the last// non-0XFF value uint8_t flash_read_byte() { uint8_t *p; uint8_t last_val = 0; for (uint32_t addr = XIP_FLASH_START; addr < XIP_FLASH_END; addr++) { p = (uint8_t *)addr; if (*p == 0xFF) { // went too far break; } else { last_val = *p; } } return last_val;}// Taking advantage of this: Individual bytes can have any bit changed from 1 to 0 without requiring erasure. // https://forums.raspberrypi.com/viewtopic.php?t=369026&e=1void flash_update_byte(uint8_t new_val) { // since we will ultimately write an entire page anyway, let's read a page at a time too uint8_t buffer[FLASH_PAGE_SIZE]; uint8_t found_end = 0; uint8_t last_val = 0; uint8_t page; uint8_t *p; uint16_t addr_offset; for (page = 0; page < PAGES_PER_SECTOR; page++) { // clear the buffer memset(buffer, 0xFF, FLASH_PAGE_SIZE); for (addr_offset = 0; addr_offset < FLASH_PAGE_SIZE; addr_offset++) { uint32_t addr = XIP_FLASH_START + (page * FLASH_PAGE_SIZE) + addr_offset; p = (uint8_t *)addr; buffer[addr_offset] = *p; if (*p == 0xFF) { found_end = 1; buffer[addr_offset] = new_val; break; } else { last_val = *p; } } if (found_end) break; } // if value hasn't changed, don't write it. if (last_val == new_val) { return; } uint32_t save_interrupts = save_and_disable_interrupts(); // is the sector full? if (!found_end) { // Erase the last sector of the flash flash_range_erase(FLASH_LAST_SECTOR, FLASH_SECTOR_SIZE); page = 0; memset(buffer, 0xFF, FLASH_PAGE_SIZE); buffer[0] = new_val; } flash_range_program( FLASH_LAST_SECTOR + page * FLASH_PAGE_SIZE, (uint8_t *)buffer, FLASH_PAGE_SIZE ); restore_interrupts(save_interrupts);}
Statistics: Posted by mstrat — Sun Apr 14, 2024 6:33 pm