mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-05 07:33:45 +07:00
79 lines
2.0 KiB
C
79 lines
2.0 KiB
C
#include "device.h"
|
|
#include "log.h"
|
|
|
|
#if MG_DEVICE == MG_DEVICE_CH32V307
|
|
// RM: https://www.wch-ic.com/downloads/CH32FV2x_V3xRM_PDF.html
|
|
|
|
#define FLASH_BASE 0x40022000
|
|
#define FLASH_ACTLR (FLASH_BASE + 0)
|
|
#define FLASH_KEYR (FLASH_BASE + 4)
|
|
#define FLASH_OBKEYR (FLASH_BASE + 8)
|
|
#define FLASH_STATR (FLASH_BASE + 12)
|
|
#define FLASH_CTLR (FLASH_BASE + 16)
|
|
#define FLASH_ADDR (FLASH_BASE + 20)
|
|
#define FLASH_OBR (FLASH_BASE + 28)
|
|
#define FLASH_WPR (FLASH_BASE + 32)
|
|
|
|
void *mg_flash_start(void) {
|
|
return (void *) 0x08000000;
|
|
}
|
|
size_t mg_flash_size(void) {
|
|
return 480 * 1024; // First 320k is 0-wait
|
|
}
|
|
size_t mg_flash_sector_size(void) {
|
|
return 4096;
|
|
}
|
|
size_t mg_flash_write_align(void) {
|
|
return 4;
|
|
}
|
|
int mg_flash_bank(void) {
|
|
return 0;
|
|
}
|
|
void mg_device_reset(void) {
|
|
*((volatile uint32_t *) 0xbeef0000) |= 1U << 7; // NVIC_SystemReset()
|
|
}
|
|
static void flash_unlock(void) {
|
|
static bool unlocked;
|
|
if (unlocked == false) {
|
|
MG_REG(FLASH_KEYR) = 0x45670123;
|
|
MG_REG(FLASH_KEYR) = 0xcdef89ab;
|
|
unlocked = true;
|
|
}
|
|
}
|
|
static void flash_wait(void) {
|
|
while (MG_REG(FLASH_STATR) & MG_BIT(0)) (void) 0;
|
|
}
|
|
|
|
bool mg_flash_erase(void *addr) {
|
|
//MG_INFO(("%p", addr));
|
|
flash_unlock();
|
|
flash_wait();
|
|
MG_REG(FLASH_ADDR) = (uint32_t) addr;
|
|
MG_REG(FLASH_CTLR) |= MG_BIT(1) | MG_BIT(6); // PER | STRT;
|
|
flash_wait();
|
|
return true;
|
|
}
|
|
|
|
static bool is_page_boundary(const void *addr) {
|
|
uint32_t val = (uint32_t) addr;
|
|
return (val & (mg_flash_sector_size() - 1)) == 0;
|
|
}
|
|
|
|
bool mg_flash_write(void *addr, const void *buf, size_t len) {
|
|
//MG_INFO(("%p %p %lu", addr, buf, len));
|
|
//mg_hexdump(buf, len);
|
|
flash_unlock();
|
|
const uint16_t *src = (uint16_t *) buf, *end = &src[len / 2];
|
|
uint16_t *dst = (uint16_t *) addr;
|
|
MG_REG(FLASH_CTLR) |= MG_BIT(0); // Set PG
|
|
//MG_INFO(("CTLR: %#lx", MG_REG(FLASH_CTLR)));
|
|
while (src < end) {
|
|
if (is_page_boundary(dst)) mg_flash_erase(dst);
|
|
*dst++ = *src++;
|
|
flash_wait();
|
|
}
|
|
MG_REG(FLASH_CTLR) &= ~MG_BIT(0); // Clear PG
|
|
return true;
|
|
}
|
|
#endif
|