mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-27 15:01:03 +08:00
STM32F OTA support
This commit is contained in:
parent
d3ffe8c647
commit
3e55478b3b
231
mongoose.c
231
mongoose.c
@ -6042,6 +6042,237 @@ bool mg_ota_end(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MG_ENABLE_LINES
|
||||||
|
#line 1 "src/ota_stm32f.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_OTA == MG_OTA_STM32F
|
||||||
|
|
||||||
|
static bool mg_stm32f_write(void *, const void *, size_t);
|
||||||
|
static bool mg_stm32f_swap(void);
|
||||||
|
|
||||||
|
static struct mg_flash s_mg_flash_stm32f = {
|
||||||
|
(void *) 0x08000000, // Start
|
||||||
|
0, // Size, FLASH_SIZE_REG
|
||||||
|
0, // Irregular sector size
|
||||||
|
32, // Align, 256 bit
|
||||||
|
mg_stm32f_write,
|
||||||
|
mg_stm32f_swap,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MG_FLASH_BASE 0x40023c00
|
||||||
|
#define MG_FLASH_KEYR 0x04
|
||||||
|
#define MG_FLASH_SR 0x0c
|
||||||
|
#define MG_FLASH_CR 0x10
|
||||||
|
#define MG_FLASH_OPTCR 0x14
|
||||||
|
#define MG_FLASH_SIZE_REG_F7 0x1FF0F442
|
||||||
|
#define MG_FLASH_SIZE_REG_F4 0x1FFF7A22
|
||||||
|
|
||||||
|
#define STM_DBGMCU_IDCODE 0xE0042000
|
||||||
|
#define STM_DEV_ID (MG_REG(STM_DBGMCU_IDCODE) & (MG_BIT(12) - 1))
|
||||||
|
#define SYSCFG_MEMRMP 0x40013800
|
||||||
|
|
||||||
|
#define MG_FLASH_SIZE_REG_LOCATION \
|
||||||
|
((STM_DEV_ID >= 0x449) ? MG_FLASH_SIZE_REG_F7 : MG_FLASH_SIZE_REG_F4)
|
||||||
|
|
||||||
|
static size_t flash_size(void) {
|
||||||
|
return (MG_REG(MG_FLASH_SIZE_REG_LOCATION) & 0xFFFF) * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static int is_dualbank(void) {
|
||||||
|
// only F42x/F43x series (0x419) support dual bank
|
||||||
|
return STM_DEV_ID == 0x419;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static void flash_unlock(void) {
|
||||||
|
static bool unlocked = false;
|
||||||
|
if (unlocked == false) {
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_KEYR) = 0x45670123;
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_KEYR) = 0xcdef89ab;
|
||||||
|
unlocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MG_FLASH_CONFIG_16_64_128 1 // used by STM32F7
|
||||||
|
#define MG_FLASH_CONFIG_32_128_256 2 // used by STM32F4 and F2
|
||||||
|
|
||||||
|
MG_IRAM static bool flash_page_start(volatile uint32_t *dst) {
|
||||||
|
char *base = (char *) s_mg_flash_stm32f.start;
|
||||||
|
char *end = base + s_mg_flash_stm32f.size;
|
||||||
|
|
||||||
|
if (is_dualbank() && dst >= (uint32_t *) (base + (end - base) / 2)) {
|
||||||
|
dst = (uint32_t *) ((uint32_t) dst - (end - base) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flash_config = MG_FLASH_CONFIG_16_64_128;
|
||||||
|
if (STM_DEV_ID >= 0x449) {
|
||||||
|
flash_config = MG_FLASH_CONFIG_32_128_256;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile char *p = (char *) dst;
|
||||||
|
if (p >= base && p < end) {
|
||||||
|
if (p < base + 16 * 1024 * 4 * flash_config) {
|
||||||
|
if ((p - base) % (16 * 1024 * flash_config) == 0) return true;
|
||||||
|
} else if (p == base + 16 * 1024 * 4 * flash_config) {
|
||||||
|
return true;
|
||||||
|
} else if ((p - base) % (128 * 1024 * flash_config) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static int flash_sector(volatile uint32_t *addr) {
|
||||||
|
char *base = (char *) s_mg_flash_stm32f.start;
|
||||||
|
char *end = base + s_mg_flash_stm32f.size;
|
||||||
|
bool addr_in_bank_2 = false;
|
||||||
|
if (is_dualbank() && addr >= (uint32_t *) (base + (end - base) / 2)) {
|
||||||
|
addr = (uint32_t *) ((uint32_t) addr - (end - base) / 2);
|
||||||
|
addr_in_bank_2 = true;
|
||||||
|
}
|
||||||
|
volatile char *p = (char *) addr;
|
||||||
|
uint32_t flash_config = MG_FLASH_CONFIG_16_64_128;
|
||||||
|
if (STM_DEV_ID >= 0x449) {
|
||||||
|
flash_config = MG_FLASH_CONFIG_32_128_256;
|
||||||
|
}
|
||||||
|
int sector = -1;
|
||||||
|
if (p >= base && p < end) {
|
||||||
|
if (p < base + 16 * 1024 * 4 * flash_config) {
|
||||||
|
sector = (p - base) / (16 * 1024 * flash_config);
|
||||||
|
} else if (p >= base + 64 * 1024 * flash_config &&
|
||||||
|
p < base + 128 * 1024 * flash_config) {
|
||||||
|
sector = 4;
|
||||||
|
} else {
|
||||||
|
sector = (p - base) / (128 * 1024 * flash_config) + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sector == -1) return -1;
|
||||||
|
if (addr_in_bank_2) sector += 12; // a bank has 12 sectors
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static bool flash_is_err(void) {
|
||||||
|
return MG_REG(MG_FLASH_BASE + MG_FLASH_SR) & ((MG_BIT(7) - 1) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static void flash_wait(void) {
|
||||||
|
while (MG_REG(MG_FLASH_BASE + MG_FLASH_SR) & (MG_BIT(16))) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static void flash_clear_err(void) {
|
||||||
|
flash_wait(); // Wait until ready
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_SR) = 0xf2; // Clear all errors
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline)) MG_IRAM static bool mg_stm32f_erase(void *addr) {
|
||||||
|
bool ok = false;
|
||||||
|
if (flash_page_start(addr) == false) {
|
||||||
|
MG_ERROR(("%p is not on a sector boundary", addr));
|
||||||
|
} else {
|
||||||
|
int sector = flash_sector(addr);
|
||||||
|
if (sector < 0) return false;
|
||||||
|
uint32_t sector_reg = sector;
|
||||||
|
if (is_dualbank() && sector >= 12) {
|
||||||
|
// 3.9.8 Flash control register (FLASH_CR) for F42xxx and F43xxx
|
||||||
|
// BITS[7:3]
|
||||||
|
sector_reg -= 12;
|
||||||
|
sector_reg |= MG_BIT(4);
|
||||||
|
}
|
||||||
|
flash_unlock();
|
||||||
|
flash_wait();
|
||||||
|
uint32_t cr = MG_BIT(1); // SER
|
||||||
|
cr |= MG_BIT(16); // STRT
|
||||||
|
cr |= (sector_reg & 31) << 3; // sector
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = cr;
|
||||||
|
ok = !flash_is_err();
|
||||||
|
MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr,
|
||||||
|
ok ? "ok" : "fail", MG_REG(MG_FLASH_BASE + MG_FLASH_CR),
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_SR)));
|
||||||
|
// After we have erased the sector, set CR flags for programming
|
||||||
|
// 2 << 8 is word write parallelism, bit(0) is PG. RM0385, section 3.7.5
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = MG_BIT(0) | (2 << 8);
|
||||||
|
flash_clear_err();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static bool mg_stm32f_swap(void) {
|
||||||
|
// STM32 F42x/F43x support dual bank, however, the memory mapping
|
||||||
|
// change will not be carried through a hard reset. Therefore, we will use
|
||||||
|
// the single bank approach for this family as well.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool s_flash_irq_disabled;
|
||||||
|
|
||||||
|
__attribute__((noinline)) MG_IRAM static bool mg_stm32f_write(void *addr,
|
||||||
|
const void *buf,
|
||||||
|
size_t len) {
|
||||||
|
if ((len % s_mg_flash_stm32f.align) != 0) {
|
||||||
|
MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_stm32f.align));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t *dst = (uint32_t *) addr;
|
||||||
|
uint32_t *src = (uint32_t *) buf;
|
||||||
|
uint32_t *end = (uint32_t *) ((char *) buf + len);
|
||||||
|
bool ok = true;
|
||||||
|
MG_ARM_DISABLE_IRQ();
|
||||||
|
flash_unlock();
|
||||||
|
flash_clear_err();
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = MG_BIT(0) | MG_BIT(9); // PG, 32-bit
|
||||||
|
flash_wait();
|
||||||
|
MG_DEBUG(("Writing flash @ %p, %lu bytes", addr, len));
|
||||||
|
while (ok && src < end) {
|
||||||
|
if (flash_page_start(dst) && mg_stm32f_erase(dst) == false) break;
|
||||||
|
*(volatile uint32_t *) dst++ = *src++;
|
||||||
|
MG_DSB(); // ensure flash is written with no errors
|
||||||
|
flash_wait();
|
||||||
|
if (flash_is_err()) ok = false;
|
||||||
|
}
|
||||||
|
if (!s_flash_irq_disabled) MG_ARM_ENABLE_IRQ();
|
||||||
|
MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst,
|
||||||
|
ok ? "ok" : "fail", MG_REG(MG_FLASH_BASE + MG_FLASH_CR),
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_SR)));
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) &= ~MG_BIT(0); // Clear programming flag
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just overwrite instead of swap
|
||||||
|
__attribute__((noinline)) MG_IRAM void single_bank_swap(char *p1, char *p2,
|
||||||
|
size_t size) {
|
||||||
|
// no stdlib calls here
|
||||||
|
mg_stm32f_write(p1, p2, size);
|
||||||
|
*(volatile unsigned long *) 0xe000ed0c = 0x5fa0004;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_ota_begin(size_t new_firmware_size) {
|
||||||
|
s_mg_flash_stm32f.size = flash_size();
|
||||||
|
return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_ota_write(const void *buf, size_t len) {
|
||||||
|
return mg_ota_flash_write(buf, len, &s_mg_flash_stm32f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_ota_end(void) {
|
||||||
|
if (mg_ota_flash_end(&s_mg_flash_stm32f)) {
|
||||||
|
// Swap partitions. Pray power does not go away
|
||||||
|
MG_INFO(("Swapping partitions, size %u (%u sectors)",
|
||||||
|
s_mg_flash_stm32f.size, STM_DEV_ID == 0x449 ? 8 : 12));
|
||||||
|
MG_INFO(("Do NOT power off..."));
|
||||||
|
mg_log_level = MG_LL_NONE;
|
||||||
|
s_flash_irq_disabled = true;
|
||||||
|
char *p1 = (char *) s_mg_flash_stm32f.start;
|
||||||
|
char *p2 = p1 + s_mg_flash_stm32f.size / 2;
|
||||||
|
size_t size = s_mg_flash_stm32f.size / 2;
|
||||||
|
// Runs in RAM, will reset when finished
|
||||||
|
single_bank_swap(p1, p2, size);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef MG_ENABLE_LINES
|
#ifdef MG_ENABLE_LINES
|
||||||
#line 1 "src/ota_stm32h5.c"
|
#line 1 "src/ota_stm32h5.c"
|
||||||
#endif
|
#endif
|
||||||
|
@ -2643,6 +2643,7 @@ void mg_rpc_list(struct mg_rpc_req *r);
|
|||||||
#define MG_OTA_NONE 0 // No OTA support
|
#define MG_OTA_NONE 0 // No OTA support
|
||||||
#define MG_OTA_STM32H5 1 // STM32 H5
|
#define MG_OTA_STM32H5 1 // STM32 H5
|
||||||
#define MG_OTA_STM32H7 2 // STM32 H7
|
#define MG_OTA_STM32H7 2 // STM32 H7
|
||||||
|
#define MG_OTA_STM32F 3 // STM32 F7/F4/F2
|
||||||
#define MG_OTA_CH32V307 100 // WCH CH32V307
|
#define MG_OTA_CH32V307 100 // WCH CH32V307
|
||||||
#define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
|
#define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
|
||||||
#define MG_OTA_RT1020 300 // IMXRT1020
|
#define MG_OTA_RT1020 300 // IMXRT1020
|
||||||
@ -2670,6 +2671,7 @@ bool mg_ota_write(const void *buf, size_t len); // Write chunk, aligned to 1k
|
|||||||
bool mg_ota_end(void); // Stop writing
|
bool mg_ota_end(void); // Stop writing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if MG_OTA != MG_OTA_NONE && MG_OTA != MG_OTA_CUSTOM
|
#if MG_OTA != MG_OTA_NONE && MG_OTA != MG_OTA_CUSTOM
|
||||||
|
|
||||||
struct mg_flash {
|
struct mg_flash {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define MG_OTA_NONE 0 // No OTA support
|
#define MG_OTA_NONE 0 // No OTA support
|
||||||
#define MG_OTA_STM32H5 1 // STM32 H5
|
#define MG_OTA_STM32H5 1 // STM32 H5
|
||||||
#define MG_OTA_STM32H7 2 // STM32 H7
|
#define MG_OTA_STM32H7 2 // STM32 H7
|
||||||
|
#define MG_OTA_STM32F 3 // STM32 F7/F4/F2
|
||||||
#define MG_OTA_CH32V307 100 // WCH CH32V307
|
#define MG_OTA_CH32V307 100 // WCH CH32V307
|
||||||
#define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
|
#define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
|
||||||
#define MG_OTA_RT1020 300 // IMXRT1020
|
#define MG_OTA_RT1020 300 // IMXRT1020
|
||||||
|
229
src/ota_stm32f.c
Normal file
229
src/ota_stm32f.c
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
#include "flash.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "ota.h"
|
||||||
|
|
||||||
|
#if MG_OTA == MG_OTA_STM32F
|
||||||
|
|
||||||
|
static bool mg_stm32f_write(void *, const void *, size_t);
|
||||||
|
static bool mg_stm32f_swap(void);
|
||||||
|
|
||||||
|
static struct mg_flash s_mg_flash_stm32f = {
|
||||||
|
(void *) 0x08000000, // Start
|
||||||
|
0, // Size, FLASH_SIZE_REG
|
||||||
|
0, // Irregular sector size
|
||||||
|
32, // Align, 256 bit
|
||||||
|
mg_stm32f_write,
|
||||||
|
mg_stm32f_swap,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MG_FLASH_BASE 0x40023c00
|
||||||
|
#define MG_FLASH_KEYR 0x04
|
||||||
|
#define MG_FLASH_SR 0x0c
|
||||||
|
#define MG_FLASH_CR 0x10
|
||||||
|
#define MG_FLASH_OPTCR 0x14
|
||||||
|
#define MG_FLASH_SIZE_REG_F7 0x1FF0F442
|
||||||
|
#define MG_FLASH_SIZE_REG_F4 0x1FFF7A22
|
||||||
|
|
||||||
|
#define STM_DBGMCU_IDCODE 0xE0042000
|
||||||
|
#define STM_DEV_ID (MG_REG(STM_DBGMCU_IDCODE) & (MG_BIT(12) - 1))
|
||||||
|
#define SYSCFG_MEMRMP 0x40013800
|
||||||
|
|
||||||
|
#define MG_FLASH_SIZE_REG_LOCATION \
|
||||||
|
((STM_DEV_ID >= 0x449) ? MG_FLASH_SIZE_REG_F7 : MG_FLASH_SIZE_REG_F4)
|
||||||
|
|
||||||
|
static size_t flash_size(void) {
|
||||||
|
return (MG_REG(MG_FLASH_SIZE_REG_LOCATION) & 0xFFFF) * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static int is_dualbank(void) {
|
||||||
|
// only F42x/F43x series (0x419) support dual bank
|
||||||
|
return STM_DEV_ID == 0x419;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static void flash_unlock(void) {
|
||||||
|
static bool unlocked = false;
|
||||||
|
if (unlocked == false) {
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_KEYR) = 0x45670123;
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_KEYR) = 0xcdef89ab;
|
||||||
|
unlocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MG_FLASH_CONFIG_16_64_128 1 // used by STM32F7
|
||||||
|
#define MG_FLASH_CONFIG_32_128_256 2 // used by STM32F4 and F2
|
||||||
|
|
||||||
|
MG_IRAM static bool flash_page_start(volatile uint32_t *dst) {
|
||||||
|
char *base = (char *) s_mg_flash_stm32f.start;
|
||||||
|
char *end = base + s_mg_flash_stm32f.size;
|
||||||
|
|
||||||
|
if (is_dualbank() && dst >= (uint32_t *) (base + (end - base) / 2)) {
|
||||||
|
dst = (uint32_t *) ((uint32_t) dst - (end - base) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flash_config = MG_FLASH_CONFIG_16_64_128;
|
||||||
|
if (STM_DEV_ID >= 0x449) {
|
||||||
|
flash_config = MG_FLASH_CONFIG_32_128_256;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile char *p = (char *) dst;
|
||||||
|
if (p >= base && p < end) {
|
||||||
|
if (p < base + 16 * 1024 * 4 * flash_config) {
|
||||||
|
if ((p - base) % (16 * 1024 * flash_config) == 0) return true;
|
||||||
|
} else if (p == base + 16 * 1024 * 4 * flash_config) {
|
||||||
|
return true;
|
||||||
|
} else if ((p - base) % (128 * 1024 * flash_config) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static int flash_sector(volatile uint32_t *addr) {
|
||||||
|
char *base = (char *) s_mg_flash_stm32f.start;
|
||||||
|
char *end = base + s_mg_flash_stm32f.size;
|
||||||
|
bool addr_in_bank_2 = false;
|
||||||
|
if (is_dualbank() && addr >= (uint32_t *) (base + (end - base) / 2)) {
|
||||||
|
addr = (uint32_t *) ((uint32_t) addr - (end - base) / 2);
|
||||||
|
addr_in_bank_2 = true;
|
||||||
|
}
|
||||||
|
volatile char *p = (char *) addr;
|
||||||
|
uint32_t flash_config = MG_FLASH_CONFIG_16_64_128;
|
||||||
|
if (STM_DEV_ID >= 0x449) {
|
||||||
|
flash_config = MG_FLASH_CONFIG_32_128_256;
|
||||||
|
}
|
||||||
|
int sector = -1;
|
||||||
|
if (p >= base && p < end) {
|
||||||
|
if (p < base + 16 * 1024 * 4 * flash_config) {
|
||||||
|
sector = (p - base) / (16 * 1024 * flash_config);
|
||||||
|
} else if (p >= base + 64 * 1024 * flash_config &&
|
||||||
|
p < base + 128 * 1024 * flash_config) {
|
||||||
|
sector = 4;
|
||||||
|
} else {
|
||||||
|
sector = (p - base) / (128 * 1024 * flash_config) + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sector == -1) return -1;
|
||||||
|
if (addr_in_bank_2) sector += 12; // a bank has 12 sectors
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static bool flash_is_err(void) {
|
||||||
|
return MG_REG(MG_FLASH_BASE + MG_FLASH_SR) & ((MG_BIT(7) - 1) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static void flash_wait(void) {
|
||||||
|
while (MG_REG(MG_FLASH_BASE + MG_FLASH_SR) & (MG_BIT(16))) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static void flash_clear_err(void) {
|
||||||
|
flash_wait(); // Wait until ready
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_SR) = 0xf2; // Clear all errors
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline)) MG_IRAM static bool mg_stm32f_erase(void *addr) {
|
||||||
|
bool ok = false;
|
||||||
|
if (flash_page_start(addr) == false) {
|
||||||
|
MG_ERROR(("%p is not on a sector boundary", addr));
|
||||||
|
} else {
|
||||||
|
int sector = flash_sector(addr);
|
||||||
|
if (sector < 0) return false;
|
||||||
|
uint32_t sector_reg = sector;
|
||||||
|
if (is_dualbank() && sector >= 12) {
|
||||||
|
// 3.9.8 Flash control register (FLASH_CR) for F42xxx and F43xxx
|
||||||
|
// BITS[7:3]
|
||||||
|
sector_reg -= 12;
|
||||||
|
sector_reg |= MG_BIT(4);
|
||||||
|
}
|
||||||
|
flash_unlock();
|
||||||
|
flash_wait();
|
||||||
|
uint32_t cr = MG_BIT(1); // SER
|
||||||
|
cr |= MG_BIT(16); // STRT
|
||||||
|
cr |= (sector_reg & 31) << 3; // sector
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = cr;
|
||||||
|
ok = !flash_is_err();
|
||||||
|
MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr,
|
||||||
|
ok ? "ok" : "fail", MG_REG(MG_FLASH_BASE + MG_FLASH_CR),
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_SR)));
|
||||||
|
// After we have erased the sector, set CR flags for programming
|
||||||
|
// 2 << 8 is word write parallelism, bit(0) is PG. RM0385, section 3.7.5
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = MG_BIT(0) | (2 << 8);
|
||||||
|
flash_clear_err();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_IRAM static bool mg_stm32f_swap(void) {
|
||||||
|
// STM32 F42x/F43x support dual bank, however, the memory mapping
|
||||||
|
// change will not be carried through a hard reset. Therefore, we will use
|
||||||
|
// the single bank approach for this family as well.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool s_flash_irq_disabled;
|
||||||
|
|
||||||
|
__attribute__((noinline)) MG_IRAM static bool mg_stm32f_write(void *addr,
|
||||||
|
const void *buf,
|
||||||
|
size_t len) {
|
||||||
|
if ((len % s_mg_flash_stm32f.align) != 0) {
|
||||||
|
MG_ERROR(("%lu is not aligned to %lu", len, s_mg_flash_stm32f.align));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t *dst = (uint32_t *) addr;
|
||||||
|
uint32_t *src = (uint32_t *) buf;
|
||||||
|
uint32_t *end = (uint32_t *) ((char *) buf + len);
|
||||||
|
bool ok = true;
|
||||||
|
MG_ARM_DISABLE_IRQ();
|
||||||
|
flash_unlock();
|
||||||
|
flash_clear_err();
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) = MG_BIT(0) | MG_BIT(9); // PG, 32-bit
|
||||||
|
flash_wait();
|
||||||
|
MG_DEBUG(("Writing flash @ %p, %lu bytes", addr, len));
|
||||||
|
while (ok && src < end) {
|
||||||
|
if (flash_page_start(dst) && mg_stm32f_erase(dst) == false) break;
|
||||||
|
*(volatile uint32_t *) dst++ = *src++;
|
||||||
|
MG_DSB(); // ensure flash is written with no errors
|
||||||
|
flash_wait();
|
||||||
|
if (flash_is_err()) ok = false;
|
||||||
|
}
|
||||||
|
if (!s_flash_irq_disabled) MG_ARM_ENABLE_IRQ();
|
||||||
|
MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst,
|
||||||
|
ok ? "ok" : "fail", MG_REG(MG_FLASH_BASE + MG_FLASH_CR),
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_SR)));
|
||||||
|
MG_REG(MG_FLASH_BASE + MG_FLASH_CR) &= ~MG_BIT(0); // Clear programming flag
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just overwrite instead of swap
|
||||||
|
__attribute__((noinline)) MG_IRAM void single_bank_swap(char *p1, char *p2,
|
||||||
|
size_t size) {
|
||||||
|
// no stdlib calls here
|
||||||
|
mg_stm32f_write(p1, p2, size);
|
||||||
|
*(volatile unsigned long *) 0xe000ed0c = 0x5fa0004;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_ota_begin(size_t new_firmware_size) {
|
||||||
|
s_mg_flash_stm32f.size = flash_size();
|
||||||
|
return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_stm32f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_ota_write(const void *buf, size_t len) {
|
||||||
|
return mg_ota_flash_write(buf, len, &s_mg_flash_stm32f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_ota_end(void) {
|
||||||
|
if (mg_ota_flash_end(&s_mg_flash_stm32f)) {
|
||||||
|
// Swap partitions. Pray power does not go away
|
||||||
|
MG_INFO(("Swapping partitions, size %u (%u sectors)",
|
||||||
|
s_mg_flash_stm32f.size, STM_DEV_ID == 0x449 ? 8 : 12));
|
||||||
|
MG_INFO(("Do NOT power off..."));
|
||||||
|
mg_log_level = MG_LL_NONE;
|
||||||
|
s_flash_irq_disabled = true;
|
||||||
|
char *p1 = (char *) s_mg_flash_stm32f.start;
|
||||||
|
char *p2 = p1 + s_mg_flash_stm32f.size / 2;
|
||||||
|
size_t size = s_mg_flash_stm32f.size / 2;
|
||||||
|
// Runs in RAM, will reset when finished
|
||||||
|
single_bank_swap(p1, p2, size);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user