Skip to content

Commit

Permalink
STM32F series OTA support
Browse files Browse the repository at this point in the history
  • Loading branch information
robert committed Oct 25, 2024
1 parent 8eabf43 commit ab5cb00
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 0 deletions.
213 changes: 213 additions & 0 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,219 @@ MG_IRAM void mg_device_reset(void) {

#endif

#ifdef MG_ENABLE_LINES
#line 1 "src/device_stm32f.c"
#endif



#if MG_DEVICE == MG_DEVICE_STM32F
#define FLASH_BASE1 0x40023c00 // Base address for bank1
#define FLASH_KEYR 0x04
#define FLASH_SR 0x0c
#define FLASH_CR 0x10
#define FLASH_OPTCR 0x14
#define FLASH_SIZE_REG_F7 0x1FF0F442
#define 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

MG_IRAM uintptr_t mg_flash_size_reg_location() {
if (STM_DEV_ID >= 0x449) {
return FLASH_SIZE_REG_F7;
} else {
return FLASH_SIZE_REG_F4;
}
}

MG_IRAM void *mg_flash_start(void) {
return (void *) 0x08000000;
}
MG_IRAM size_t mg_flash_size(void) {
uintptr_t flash_size_reg = mg_flash_size_reg_location();
return (MG_REG(flash_size_reg) & 0xFFFF) * 1024;
}
MG_IRAM size_t mg_flash_sector_size(void) {
return 0; // sector size is not constant
}
MG_IRAM size_t mg_flash_write_align(void) {
return 32; // 256 bit
}
MG_IRAM int mg_flash_bank(void) {
if (STM_DEV_ID == 0x419) {
// only STM32 F42x/F43x support dual bank
return MG_REG(SYSCFG_MEMRMP) & MG_BIT(8) ? 2 : 1;
} else {
return 0;
}
}

MG_IRAM static void flash_unlock(void) {
static bool unlocked = false;
if (unlocked == false) {
MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0x45670123;
MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0xcdef89ab;
unlocked = true;
}
}

#define FLASH_CONFIG_16_64_128 1 // used by STM32F7
#define 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 *) mg_flash_start(), *end = base + mg_flash_size();
if (mg_flash_bank() > 0 && dst > mg_flash_start() + mg_flash_size() / 2) {
dst -= mg_flash_size() / 2;
}

uint32_t flash_config = FLASH_CONFIG_16_64_128;
if (STM_DEV_ID >= 0x449) {
flash_config = 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 *) mg_flash_start(), *end = base + mg_flash_size();
volatile char *p = (char *) addr;
bool addr_in_bank_2 = false;
if (mg_flash_bank() > 0 && addr > mg_flash_start() + mg_flash_size() / 2) {
addr -= mg_flash_size() / 2;
addr_in_bank_2 = true;
}
uint32_t flash_config = FLASH_CONFIG_16_64_128;
if (STM_DEV_ID >= 0x449) {
flash_config = FLASH_CONFIG_32_128_256;
}
int sector = -1;
if (p >= base && p < end) {
if (p < base + 32 * 1024 * 4) {
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(uint32_t bank) {
(void) bank;
return MG_REG(FLASH_BASE1 + FLASH_SR) & ((MG_BIT(7) - 1) << 1);
}

MG_IRAM static void flash_wait(uint32_t bank) {
(void) bank;
while (MG_REG(FLASH_BASE1 + FLASH_SR) & (MG_BIT(16))) (void) 0;
}

MG_IRAM static void flash_clear_err(uint32_t bank) {
flash_wait(bank); // Wait until ready
MG_REG(FLASH_BASE1 + FLASH_SR) = (MG_BIT(7) - 1) << 1; // Clear all errors
}

MG_IRAM static bool flash_bank_is_swapped(uint32_t bank) {
return 0;
}

// Figure out flash bank based on the address
MG_IRAM static uint32_t flash_bank(void *addr) {
return 0;
}

MG_IRAM bool mg_flash_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 (mg_flash_bank() > 0 && 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(0);
uint32_t cr = MG_BIT(1); // SER
cr |= MG_BIT(16); // STRT
cr |= (sector_reg & 31) << 3; // sector
MG_REG(FLASH_BASE1 + FLASH_CR) = cr;
ok = !flash_is_err(0);
MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr,
ok ? "ok" : "fail", MG_REG(FLASH_BASE1 + FLASH_CR),
MG_REG(FLASH_BASE1 + 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(FLASH_BASE1 + FLASH_CR) = MG_BIT(0) | (2 << 8);
}
return ok;
}

MG_IRAM bool mg_flash_swap_bank(void) {
// TODO(): overwrite firmware for single bank
// TODO(): actually swap firmwares when needed
if (mg_flash_bank() == 0) return true;
if(MG_REG(SYSCFG_MEMRMP) & MG_BIT(8)) {
MG_REG(SYSCFG_MEMRMP) &= ~MG_BIT(8);
} else {
MG_REG(SYSCFG_MEMRMP) |= MG_BIT(8);
}
return true;
}

MG_IRAM bool mg_flash_write(void *addr, const void *buf, size_t len) {
if ((len % mg_flash_write_align()) != 0) {
MG_ERROR(("%lu is not aligned to %lu", len, mg_flash_write_align()));
return false;
}
uint32_t bank = flash_bank(addr);
uint32_t *dst = (uint32_t *) addr;
uint32_t *src = (uint32_t *) buf;
uint32_t *end = (uint32_t *) ((char *) buf + len);
bool ok = true;
flash_unlock();
flash_clear_err(bank);
MG_REG(FLASH_BASE1 + FLASH_CR) = MG_BIT(0); // Set programming flag
MG_REG(FLASH_BASE1 + FLASH_CR) |= MG_BIT(9); // 32-bit write parallelism
MG_DEBUG(("Writing flash @ %p, %lu bytes", addr, len));
MG_ARM_DISABLE_IRQ();
while (ok && src < end) {
if (flash_page_start(dst) && mg_flash_erase(dst) == false) break;
*(volatile uint32_t *) dst++ = *src++;
flash_wait(bank);
if (flash_is_err(bank)) ok = false;
}
MG_ARM_ENABLE_IRQ();
MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst,
ok ? "ok" : "fail", MG_REG(FLASH_BASE1 + FLASH_CR),
MG_REG(FLASH_BASE1 + FLASH_SR)));
MG_REG(FLASH_BASE1 + FLASH_CR) &= ~MG_BIT(0); // Clear programming flag
return ok;
}

MG_IRAM void mg_device_reset(void) {
// SCB->AIRCR = ((0x5fa << SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk);
*(volatile unsigned long *) 0xe000ed0c = 0x5fa0004;
}
#endif

#ifdef MG_ENABLE_LINES
#line 1 "src/device_stm32h5.c"
#endif
Expand Down
1 change: 1 addition & 0 deletions mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -2687,6 +2687,7 @@ MG_IRAM void mg_ota_boot(void); // Bootloader function

#define MG_DEVICE_STM32H5 1 // STM32 H5
#define MG_DEVICE_STM32H7 2 // STM32 H7
#define MG_DEVICE_STM32F7 3 // STM32 F7
#define MG_DEVICE_CH32V307 100 // WCH CH32V307
#define MG_DEVICE_U2A 200 // Renesas U2A16, U2A8, U2A6
#define MG_DEVICE_RT1020 300 // IMXRT1020
Expand Down
1 change: 1 addition & 0 deletions src/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#define MG_DEVICE_STM32H5 1 // STM32 H5
#define MG_DEVICE_STM32H7 2 // STM32 H7
#define MG_DEVICE_STM32F7 3 // STM32 F7
#define MG_DEVICE_CH32V307 100 // WCH CH32V307
#define MG_DEVICE_U2A 200 // Renesas U2A16, U2A8, U2A6
#define MG_DEVICE_RT1020 300 // IMXRT1020
Expand Down
Loading

0 comments on commit ab5cb00

Please sign in to comment.