| // Conversation about how this code works & what the upper limits are | // Conversation about how this code works & what the upper limits are | ||||
| // https://forum.pjrc.com/threads/57377?p=214566&viewfull=1#post214566 | // https://forum.pjrc.com/threads/57377?p=214566&viewfull=1#post214566 | ||||
| static void flash_write(void *addr, const void *data, uint32_t len); | |||||
| static void flash_erase_sector(void *addr); | |||||
| // To be called from LittleFS_Program, any other use at your own risk! | |||||
| void eepromemu_flash_write(void *addr, const void *data, uint32_t len); | |||||
| void eepromemu_flash_erase_sector(void *addr); | |||||
| static uint8_t initialized=0; | static uint8_t initialized=0; | ||||
| static uint16_t sector_index[FLASH_SECTORS]; | static uint16_t sector_index[FLASH_SECTORS]; | ||||
| if (sector_index[sector] < 2048) { | if (sector_index[sector] < 2048) { | ||||
| //printf("ee_wr, writing\n"); | //printf("ee_wr, writing\n"); | ||||
| uint16_t newdata = offset | (data << 8); | uint16_t newdata = offset | (data << 8); | ||||
| flash_write(end, &newdata, 2); | |||||
| eepromemu_flash_write(end, &newdata, 2); | |||||
| sector_index[sector] = sector_index[sector] + 1; | sector_index[sector] = sector_index[sector] + 1; | ||||
| } else { | } else { | ||||
| //printf("ee_wr, erase then write\n"); | //printf("ee_wr, erase then write\n"); | ||||
| } | } | ||||
| buf[offset] = data; | buf[offset] = data; | ||||
| p = (uint16_t *)(FLASH_BASEADDR + sector * 4096); | p = (uint16_t *)(FLASH_BASEADDR + sector * 4096); | ||||
| flash_erase_sector(p); | |||||
| eepromemu_flash_erase_sector(p); | |||||
| index = 0; | index = 0; | ||||
| for (i=0; i < 256; i++) { | for (i=0; i < 256; i++) { | ||||
| if (buf[i] != 0xFF) { | if (buf[i] != 0xFF) { | ||||
| // TODO: combining these to larger write | // TODO: combining these to larger write | ||||
| // would (probably) be more efficient | // would (probably) be more efficient | ||||
| uint16_t newval = i | (buf[i] << 8); | uint16_t newval = i | (buf[i] << 8); | ||||
| flash_write(p + index, &newval, 2); | |||||
| eepromemu_flash_write(p + index, &newval, 2); | |||||
| index = index + 1; | index = index + 1; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| // write bytes into flash memory (which is already erased to 0xFF) | // write bytes into flash memory (which is already erased to 0xFF) | ||||
| static void flash_write(void *addr, const void *data, uint32_t len) | |||||
| void eepromemu_flash_write(void *addr, const void *data, uint32_t len) | |||||
| { | { | ||||
| __disable_irq(); | __disable_irq(); | ||||
| FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE; | FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE; | ||||
| FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x32) | LUT1(ADDR_SDR, PINS1, 24); // 32 = quad write | FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x32) | LUT1(ADDR_SDR, PINS1, 24); // 32 = quad write | ||||
| FLEXSPI_LUT61 = LUT0(WRITE_SDR, PINS4, 1); | FLEXSPI_LUT61 = LUT0(WRITE_SDR, PINS4, 1); | ||||
| FLEXSPI_IPTXFCR = FLEXSPI_IPTXFCR_CLRIPTXF; // clear tx fifo | FLEXSPI_IPTXFCR = FLEXSPI_IPTXFCR_CLRIPTXF; // clear tx fifo | ||||
| FLEXSPI_IPCR0 = (uint32_t)addr & 0x007FFFFF; | |||||
| FLEXSPI_IPCR0 = (uint32_t)addr & 0x00FFFFFF; | |||||
| FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15) | FLEXSPI_IPCR1_IDATSZ(len); | FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15) | FLEXSPI_IPCR1_IDATSZ(len); | ||||
| FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG; | FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG; | ||||
| const uint8_t *src = (const uint8_t *)data; | const uint8_t *src = (const uint8_t *)data; | ||||
| } | } | ||||
| // erase a 4K sector | // erase a 4K sector | ||||
| static void flash_erase_sector(void *addr) | |||||
| void eepromemu_flash_erase_sector(void *addr) | |||||
| { | { | ||||
| __disable_irq(); | __disable_irq(); | ||||
| FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE; | FLEXSPI_LUTKEY = FLEXSPI_LUTKEY_VALUE; | ||||
| while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait | while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait | ||||
| FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE; | FLEXSPI_INTR = FLEXSPI_INTR_IPCMDDONE; | ||||
| FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x20) | LUT1(ADDR_SDR, PINS1, 24); // 20 = sector erase | FLEXSPI_LUT60 = LUT0(CMD_SDR, PINS1, 0x20) | LUT1(ADDR_SDR, PINS1, 24); // 20 = sector erase | ||||
| FLEXSPI_IPCR0 = (uint32_t)addr & 0x007FF000; | |||||
| FLEXSPI_IPCR0 = (uint32_t)addr & 0x00FFF000; | |||||
| FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15); | FLEXSPI_IPCR1 = FLEXSPI_IPCR1_ISEQID(15); | ||||
| FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG; | FLEXSPI_IPCMD = FLEXSPI_IPCMD_TRG; | ||||
| while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait | while (!(FLEXSPI_INTR & FLEXSPI_INTR_IPCMDDONE)) ; // wait |