Skip to content

Commit

Permalink
STM32 - support for all STM32F series
Browse files Browse the repository at this point in the history
only F103 and F411 tested
  • Loading branch information
JAndrassy committed Jun 18, 2022
1 parent 11031e4 commit 70db498
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 11 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The library is a modification of the Arduino WiFi101OTA library.
* Arduino SAMD boards like Zero, M0 or MKR and the new "Nano 33 IoT"
* nRF5 board supported by [nRF5 core](https://github.com/sandeepmistry/arduino-nRF5).
* RP2040 boards with [Pico core](https://github.com/earlephilhower/arduino-pico)
* STM32F1 boards with [STM32 core](https://github.com/stm32duino/Arduino_Core_STM32)
* STM32F boards with [STM32 core](https://github.com/stm32duino/Arduino_Core_STM32)
* boards supported by ESP8266 and ESP32 Arduino boards package
* any board with MCU with SD bootloader

Expand Down Expand Up @@ -196,8 +196,9 @@ Does the OTA uploaded sketch have ArduinoOTA?
- [Seeed Wio Terminal](https://github.com/jandrassy/ArduinoOTA/pull/104) (with Blynk.Edgent)
* RP2040
- Raspberry Pi Pico
* STM32F1
* STM32
- BluePill F103CB (128kB flash)
- BlackPill F411CE
* nRF5
- Seeed Arch Link (nRF51 board)
- [nrf52832 board](https://github.com/jandrassy/ArduinoOTA/issues/1)
Expand Down
2 changes: 1 addition & 1 deletion src/ArduinoOTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#if FLASHEND >= 0xFFFF
#include "InternalStorageAVR.h"
#endif
#elif defined(STM32F1xx)
#elif defined(ARDUINO_ARCH_STM32)
#include <InternalStorageSTM32.h>
#elif defined(ARDUINO_ARCH_RP2040)
#include <InternalStorageRP2.h>
Expand Down
37 changes: 33 additions & 4 deletions src/InternalStorageSTM32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,37 @@
*/

#if defined(STM32F1xx)
#ifdef ARDUINO_ARCH_STM32

#ifndef OTA_STORAGE_STM32_SECTOR
#define OTA_STORAGE_STM32_SECTOR 5
#endif

#include <Arduino.h>

#include "InternalStorageSTM32.h"
#include "utility/stm32_flash_boot.h"

InternalStorageSTM32Class::InternalStorageSTM32Class() {
#if defined(STM32F7xx)
const uint32_t SECTOR_SIZE = 0x40000; // from sector 5
#elif defined(STM32F2xx) || defined(STM32F4xx)
const uint32_t SECTOR_SIZE = 0x20000; // from sector 5 (for F2, F4)
#endif

InternalStorageSTM32Class::InternalStorageSTM32Class(uint8_t _sector) {
sector = _sector < 5 ? 5 : _sector;
#ifdef FLASH_TYPEERASE_SECTORS
maxSketchSize = SECTOR_SIZE * (sector - 4); // sum of sectors 0 to 4 is 128kB, starting sector 5 the sector size is 128kB
storageStartAddress = FLASH_BASE + maxSketchSize;
maxSketchSize -= SKETCH_START_ADDRESS;
if (MAX_FLASH - maxSketchSize < maxSketchSize) {
maxSketchSize = MAX_FLASH - maxSketchSize;
}
#else
maxSketchSize = (MAX_FLASH - SKETCH_START_ADDRESS) / 2;
maxSketchSize = (maxSketchSize / PAGE_SIZE) * PAGE_SIZE; // align to page
storageStartAddress = FLASH_BASE + SKETCH_START_ADDRESS + maxSketchSize;
#endif
pageAlignedLength = 0;
writeIndex = 0;
flashWriteAddress = storageStartAddress;
Expand All @@ -43,10 +63,19 @@ int InternalStorageSTM32Class::open(int length) {
writeIndex = 0;

FLASH_EraseInitTypeDef EraseInitStruct;
#ifdef FLASH_TYPEERASE_SECTORS
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.Sector = sector;
EraseInitStruct.NbSectors = 1 + (length / SECTOR_SIZE);
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
#else
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Banks = FLASH_BANK_1;
EraseInitStruct.PageAddress = flashWriteAddress;
EraseInitStruct.NbPages = pageAlignedLength / PAGE_SIZE;
#endif
#ifdef FLASH_BANK_1
EraseInitStruct.Banks = FLASH_BANK_1;
#endif

uint32_t pageError = 0;
return (HAL_FLASH_Unlock() == HAL_OK //
Expand Down Expand Up @@ -82,6 +111,6 @@ void InternalStorageSTM32Class::apply() {
copy_flash_pages(FLASH_BASE + SKETCH_START_ADDRESS, (uint8_t*) storageStartAddress, pageAlignedLength, true);
}

InternalStorageSTM32Class InternalStorage;
InternalStorageSTM32Class InternalStorage(OTA_STORAGE_STM32_SECTOR);

#endif
3 changes: 2 additions & 1 deletion src/InternalStorageSTM32.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
class InternalStorageSTM32Class : public OTAStorage {
public:

InternalStorageSTM32Class();
InternalStorageSTM32Class(uint8_t sector);

virtual int open(int length);
virtual size_t write(uint8_t);
Expand All @@ -40,6 +40,7 @@ class InternalStorageSTM32Class : public OTAStorage {
uint8_t u8[4];
} addressData;

uint8_t sector; // for models with flash organized into sectors
uint32_t maxSketchSize;
uint32_t storageStartAddress;
uint32_t pageAlignedLength;
Expand Down
8 changes: 6 additions & 2 deletions src/OTAStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ char * __text_start__(); // 0x2000, 0x0 without bootloader and 0x4000 for M0 ori
extern "C" {
char * __isr_vector();
}
#elif defined(STM32F1xx)
#elif defined(ARDUINO_ARCH_STM32)
#include "stm32yyxx_ll_utils.h"
extern "C" char * g_pfnVectors; // at first address of the binary. 0x0000 without bootloader. 0x2000 with Maple bootloader
#elif defined(ARDUINO_ARCH_RP2040)
Expand All @@ -39,9 +39,13 @@ OTAStorage::OTAStorage() :
SKETCH_START_ADDRESS((uint32_t) __isr_vector),
PAGE_SIZE((size_t) NRF_FICR->CODEPAGESIZE),
MAX_FLASH(PAGE_SIZE * (uint32_t) NRF_FICR->CODESIZE)
#elif defined(STM32F1xx)
#elif defined(ARDUINO_ARCH_STM32)
SKETCH_START_ADDRESS((uint32_t) &g_pfnVectors - FLASH_BASE), // start address depends on bootloader size
#ifdef FLASH_PAGE_SIZE
PAGE_SIZE(FLASH_PAGE_SIZE),
#else
PAGE_SIZE(4), //for FLASH_TYPEPROGRAM_WORD
#endif
MAX_FLASH((min(LL_GetFlashSize(), 512ul) * 1024)) // LL_GetFlashSize returns size in kB. 512 is max for a bank
#elif defined(ARDUINO_ARCH_RP2040)
SKETCH_START_ADDRESS(0),
Expand Down
53 changes: 52 additions & 1 deletion src/utility/stm32_flash_boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,48 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#if defined(STM32F1xx)
#ifdef ARDUINO_ARCH_STM32

#include "stm32_flash_boot.h"
#if defined(STM32F0xx)
#include <stm32f0xx_hal_flash_ex.h> // FLASH_PAGE_SIZE is in hal.h
#elif defined(STM32F1xx)
#include <stm32f1xx_hal_flash_ex.h> // FLASH_PAGE_SIZE is in hal.h
#elif defined(STM32F2xx)
#include <stm32f2xx.h>
#elif defined(STM32F3xx)
#include <stm32f3xx_hal_flash_ex.h> // FLASH_PAGE_SIZE is in hal.h
#elif defined(STM32F4xx)
#include "stm32f4xx.h"
#elif defined(STM32F7xx)
#include <stm32f7xx.h>
#define SMALL_SECTOR_SIZE 0x8000 // sectors 0 to 3
#define LARGE_SECTOR_SIZE 0x40000 // from sector 5
#endif

#if defined(STM32F2xx) || defined(STM32F4xx)
#define SMALL_SECTOR_SIZE 0x4000 // sectors 0 to 3
#define LARGE_SECTOR_SIZE 0x20000 // from sector 5
#endif

/**
* function for bootload flash to flash
* this function runs exclusively in RAM.
* note: interrupts must be disabled.
* note: parameters must be multiple of FLASH_PAGE_SIZE
* note: for models with sectors, flash_offs must be start address of a sector
*/
void copy_flash_pages(uint32_t flash_offs, const uint8_t *data, uint32_t count, uint8_t reset) {

uint32_t page_address = flash_offs;
while (FLASH->SR & FLASH_SR_BSY);

#ifdef FLASH_CR_PSIZE
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
FLASH->CR |= 0x00000200U; // FLASH_PSIZE_WORD;
FLASH->CR |= FLASH_CR_PG;
#endif
#ifdef FLASH_PAGE_SIZE
SET_BIT(FLASH->CR, FLASH_CR_PER);
for (uint16_t i = 0; i < count / FLASH_PAGE_SIZE; i++) {
WRITE_REG(FLASH->AR, page_address);
Expand All @@ -39,11 +66,35 @@ void copy_flash_pages(uint32_t flash_offs, const uint8_t *data, uint32_t count,
while (FLASH->SR & FLASH_SR_BSY);
}
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
#else
uint8_t startSector = (flash_offs == FLASH_BASE) ? 0 : 1; // 1 if bootloader is in sector 0
uint8_t endSector = 1 + startSector + ((count - 1) / SMALL_SECTOR_SIZE); // size of the first 4 sectors is 0x4000 kB
if (endSector > 4) { // if more than 4 sectors are needed (including bootloader)
if (endSector < 8) { // size of sector 4 is (4 * SMALL_SECTOR_SIZE)
endSector = 5;
} else { // let's divide with the count of large sectors and add the first 5 sectors as one large sector
endSector = 5 + (((count - 1) + (startSector * SMALL_SECTOR_SIZE)) / LARGE_SECTOR_SIZE);
}
}
for (uint8_t sector = startSector; sector < endSector; sector++) {
CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);
FLASH->CR |= FLASH_CR_SER | (sector << FLASH_CR_SNB_Pos);
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
}
CLEAR_BIT(FLASH->CR, (FLASH_CR_SER | FLASH_CR_SNB));
#endif

page_address = flash_offs;
uint16_t* ptr = (uint16_t*) data;
while (FLASH->SR & FLASH_SR_BSY);
#ifdef FLASH_CR_PSIZE
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
FLASH->CR |= 0x00000100U; // FLASH_PSIZE_HALF_WORD
FLASH->CR |= FLASH_CR_PG;
#else
SET_BIT(FLASH->CR, FLASH_CR_PG);
#endif
while (count) {
*(volatile uint16_t*)page_address = *ptr;
page_address += 2;
Expand Down

0 comments on commit 70db498

Please sign in to comment.