mirror of https://github.com/wolfSSL/wolfBoot.git
Add wolfBoot support for STM32G4
parent
0cb6bd42ac
commit
c075549ea2
|
|
@ -458,6 +458,12 @@ jobs:
|
|||
arch: arm
|
||||
config-file: ./config/examples/stm32g0.config
|
||||
|
||||
stm32g4_test:
|
||||
uses: ./.github/workflows/test-build.yml
|
||||
with:
|
||||
arch: arm
|
||||
config-file: ./config/examples/stm32g4.config
|
||||
|
||||
stm32h5_test:
|
||||
uses: ./.github/workflows/test-build.yml
|
||||
with:
|
||||
|
|
|
|||
4
arch.mk
4
arch.mk
|
|
@ -167,6 +167,10 @@ ifeq ($(ARCH),ARM)
|
|||
ARCH_FLASH_OFFSET=0x08000000
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),stm32g4)
|
||||
ARCH_FLASH_OFFSET=0x08000000
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),stm32f1)
|
||||
CORTEX_M3=1
|
||||
NO_ARM_ASM=1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
ARCH?=ARM
|
||||
TARGET?=stm32g4
|
||||
SIGN?=ECC256
|
||||
HASH?=SHA256
|
||||
DEBUG?=0
|
||||
VTOR?=1
|
||||
NO_ASM?=0
|
||||
EXT_FLASH?=0
|
||||
SPI_FLASH?=0
|
||||
ALLOW_DOWNGRADE?=0
|
||||
NVM_FLASH_WRITEONCE?=1
|
||||
WOLFBOOT_VERSION?=0
|
||||
V?=0
|
||||
SPMATH?=1
|
||||
RAM_CODE?=1
|
||||
DUALBANK_SWAP?=0
|
||||
|
||||
# Single-bank 512KB flash, 2KB pages.
|
||||
# Layout: 32K boot, 232K app, 232K update, 16K swap.
|
||||
WOLFBOOT_SECTOR_SIZE?=0x800
|
||||
WOLFBOOT_PARTITION_SIZE?=0x3A000
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08008000
|
||||
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08042000
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0807C000
|
||||
|
|
@ -45,6 +45,7 @@ This README describes configuration of supported targets.
|
|||
* [STM32F4](#stm32f4)
|
||||
* [STM32F7](#stm32f7)
|
||||
* [STM32G0](#stm32g0)
|
||||
* [STM32G4](#stm32g4)
|
||||
* [STM32H5](#stm32h5)
|
||||
* [STM32N6](#stm32n6)
|
||||
* [STM32H7](#stm32h7)
|
||||
|
|
@ -529,6 +530,79 @@ add-symbol-file test-app/image.elf 0x08008100
|
|||
mon reset init
|
||||
```
|
||||
|
||||
## STM32G4
|
||||
|
||||
Supports STM32G4 single-bank Category 3 parts (verified on NUCLEO-G491RE,
|
||||
STM32G491RET6: 512KB flash, 96KB SRAM, Cortex-M4F).
|
||||
|
||||
The HAL boots at 170 MHz using HSI16 + PLL with PWR Range 1 Boost mode
|
||||
(RM0440 6.1.4), 4 flash wait states, prefetch + I/D-cache enabled.
|
||||
|
||||
Example 512KB partitioning on STM32G491RE:
|
||||
|
||||
- Sector size: 2KB
|
||||
- wolfBoot partition size: 32KB
|
||||
- Application partition size: 232KB
|
||||
|
||||
```C
|
||||
#define WOLFBOOT_SECTOR_SIZE 0x800 /* 2 KB */
|
||||
#define WOLFBOOT_PARTITION_BOOT_ADDRESS 0x08008000
|
||||
#define WOLFBOOT_PARTITION_SIZE 0x3A000 /* 232 KB */
|
||||
#define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x08042000
|
||||
#define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x0807C000 /* 16 KB swap */
|
||||
```
|
||||
|
||||
### Building STM32G4
|
||||
|
||||
Reference configuration (see [/config/examples/stm32g4.config](/config/examples/stm32g4.config)).
|
||||
You can copy this to wolfBoot root as `.config`: `cp ./config/examples/stm32g4.config .config`.
|
||||
To build you can use `make`.
|
||||
|
||||
The TARGET for this is `stm32g4`: `make TARGET=stm32g4`.
|
||||
Cortex-M4F is the default ARM core for this target.
|
||||
The option `NVM_FLASH_WRITEONCE=1` is mandatory: the IAP driver writes one
|
||||
64-bit doubleword per location and cannot rewrite without an erase first.
|
||||
The default signing scheme is ECC256 with SHA256.
|
||||
|
||||
NUCLEO-G491RE has no HSE, so HSI16 is used as the PLL source. The ST-LINK
|
||||
virtual COM port is wired to LPUART1 on PA2 (TX) / PA3 (RX) via AF12.
|
||||
Optional boot logs over LPUART1 at 115200 8N1 are enabled with
|
||||
`CFLAGS_EXTRA+=-DDEBUG_UART`.
|
||||
|
||||
This target is single-bank only -- keep `DUALBANK_SWAP=0`.
|
||||
|
||||
### STM32G4 Programming
|
||||
|
||||
Compile requirements: `make TARGET=stm32g4 NVM_FLASH_WRITEONCE=1`
|
||||
|
||||
The output is a single `factory.bin` that includes `wolfboot.bin` and
|
||||
`test-app/image_v1_signed.bin` combined together. This should be programmed
|
||||
to the flash start address `0x08000000`.
|
||||
|
||||
Flash using the STM32CubeProgrammer CLI:
|
||||
|
||||
```
|
||||
STM32_Programmer_CLI -c port=swd -d factory.bin 0x08000000
|
||||
```
|
||||
|
||||
### STM32G4 Debugging
|
||||
|
||||
Use `make DEBUG=1` and program firmware again.
|
||||
|
||||
Start GDB server on port 3333:
|
||||
|
||||
```
|
||||
ST-LINK_gdbserver -d -e -r 1 -p 3333
|
||||
OR
|
||||
st-util -p 3333
|
||||
```
|
||||
|
||||
```
|
||||
arm-none-eabi-gdb
|
||||
add-symbol-file test-app/image.elf 0x08008100
|
||||
mon reset init
|
||||
```
|
||||
|
||||
## STM32C0
|
||||
|
||||
Supports STM32C0x0/STM32C0x1. Instructions are for the STM Nucleo-C031C6 dev board.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,284 @@
|
|||
/* stm32g4.c
|
||||
*
|
||||
* Copyright (C) 2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <image.h>
|
||||
#include "stm32g4.h"
|
||||
|
||||
#ifndef NVM_FLASH_WRITEONCE
|
||||
# error "wolfBoot STM32G4 HAL: no WRITEONCE support detected. Please define NVM_FLASH_WRITEONCE"
|
||||
#endif
|
||||
|
||||
|
||||
static RAMFUNCTION void flash_wait_complete(void)
|
||||
{
|
||||
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY)
|
||||
;
|
||||
}
|
||||
|
||||
static void RAMFUNCTION flash_clear_errors(void)
|
||||
{
|
||||
FLASH_SR |= (FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR |
|
||||
FLASH_SR_PGAERR | FLASH_SR_SIZERR | FLASH_SR_PGSERR |
|
||||
FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR |
|
||||
FLASH_SR_OPTVERR);
|
||||
}
|
||||
|
||||
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||
{
|
||||
int i = 0;
|
||||
uint32_t *src, *dst;
|
||||
flash_clear_errors();
|
||||
FLASH_CR |= FLASH_CR_PG;
|
||||
|
||||
while (i < len) {
|
||||
flash_clear_errors();
|
||||
if ((len - i > 3) && ((((address + i) & 0x07) == 0) &&
|
||||
((((uint32_t)data) + i) & 0x07) == 0)) {
|
||||
src = (uint32_t *)data;
|
||||
dst = (uint32_t *)address;
|
||||
flash_wait_complete();
|
||||
dst[i >> 2] = src[i >> 2];
|
||||
dst[(i >> 2) + 1] = src[(i >> 2) + 1];
|
||||
flash_wait_complete();
|
||||
i += 8;
|
||||
} else {
|
||||
uint32_t val[2];
|
||||
uint8_t *vbytes = (uint8_t *)(val);
|
||||
int off = (address + i) - (((address + i) >> 3) << 3);
|
||||
uint32_t base_addr = address & (~0x07); /* aligned to 64 bit */
|
||||
int u32_idx = (i >> 2);
|
||||
dst = (uint32_t *)(base_addr);
|
||||
val[0] = dst[u32_idx];
|
||||
val[1] = dst[u32_idx + 1];
|
||||
while ((off < 8) && (i < len))
|
||||
vbytes[off++] = data[i++];
|
||||
dst[u32_idx] = val[0];
|
||||
dst[u32_idx + 1] = val[1];
|
||||
flash_wait_complete();
|
||||
}
|
||||
}
|
||||
if ((FLASH_SR & FLASH_SR_EOP) == FLASH_SR_EOP)
|
||||
FLASH_SR |= FLASH_SR_EOP;
|
||||
FLASH_CR &= ~FLASH_CR_PG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RAMFUNCTION hal_flash_unlock(void)
|
||||
{
|
||||
flash_wait_complete();
|
||||
if ((FLASH_CR & FLASH_CR_LOCK) != 0) {
|
||||
FLASH_KEY = FLASH_KEY1;
|
||||
DMB();
|
||||
FLASH_KEY = FLASH_KEY2;
|
||||
DMB();
|
||||
while ((FLASH_CR & FLASH_CR_LOCK) != 0)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void RAMFUNCTION hal_flash_lock(void)
|
||||
{
|
||||
flash_wait_complete();
|
||||
if ((FLASH_CR & FLASH_CR_LOCK) == 0)
|
||||
FLASH_CR |= FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
|
||||
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
|
||||
{
|
||||
uint32_t end_address;
|
||||
uint32_t p;
|
||||
uint32_t page_number;
|
||||
uint32_t reg;
|
||||
|
||||
if (len == 0)
|
||||
return -1;
|
||||
address -= FLASHMEM_ADDRESS_SPACE;
|
||||
end_address = address + len - 1;
|
||||
for (p = address; p < end_address; p += FLASH_PAGE_SIZE) {
|
||||
flash_wait_complete();
|
||||
flash_clear_errors();
|
||||
page_number = (p >> 11) & FLASH_CR_PNB_MASK;
|
||||
reg = FLASH_CR & ~(FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT);
|
||||
FLASH_CR = reg | (page_number << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER;
|
||||
DMB();
|
||||
FLASH_CR |= FLASH_CR_STRT;
|
||||
flash_wait_complete();
|
||||
FLASH_CR &= ~FLASH_CR_PER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clock_pll_off(void)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
/* Switch back to HSI16 as SYSCLK source before turning off the PLL. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~RCC_CFGR_SW_MASK;
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
|
||||
DMB();
|
||||
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SW_MASK)
|
||||
!= RCC_CFGR_SW_HSI)
|
||||
;
|
||||
RCC_CR &= ~RCC_CR_PLLON;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_PLLRDY) != 0)
|
||||
;
|
||||
}
|
||||
|
||||
/* Bring SYSCLK up to 170 MHz from HSI16 + PLL with Range 1 Boost mode.
|
||||
* Sequence per RM0440 - 6.1.4: PWR boost must precede flash wait states
|
||||
* and PLL enable. */
|
||||
static void clock_pll_on(int powersave)
|
||||
{
|
||||
uint32_t reg32;
|
||||
uint32_t pllm = 4;
|
||||
uint32_t plln = 85;
|
||||
uint32_t pllr = 2;
|
||||
uint32_t flash_waitstates = FLASH_ACR_LATENCY_4WS;
|
||||
|
||||
(void)powersave;
|
||||
|
||||
/* Enable PWR clock so VOS/R1MODE writes take effect. */
|
||||
RCC_APB1ENR1 |= RCC_APB1ENR1_PWREN;
|
||||
(void)RCC_APB1ENR1;
|
||||
|
||||
/* Voltage scaling Range 1 (boost-capable). */
|
||||
reg32 = PWR_CR1;
|
||||
reg32 = (reg32 & ~PWR_CR1_VOS_MASK) | PWR_CR1_VOS_RANGE1;
|
||||
PWR_CR1 = reg32;
|
||||
while ((PWR_SR2 & PWR_SR2_VOSF) != 0)
|
||||
;
|
||||
/* Clear R1MODE to enable Boost (required above 150 MHz). */
|
||||
PWR_CR5 &= ~PWR_CR5_R1MODE;
|
||||
|
||||
/* HSI16 already on at reset; be explicit. */
|
||||
RCC_CR |= RCC_CR_HSION;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSIRDY) == 0)
|
||||
;
|
||||
|
||||
/* Set flash wait states + caches before raising CPU frequency. */
|
||||
FLASH_ACR = (FLASH_ACR & ~FLASH_ACR_LATENCY_MASK)
|
||||
| flash_waitstates
|
||||
| FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
|
||||
while ((FLASH_ACR & FLASH_ACR_LATENCY_MASK) != flash_waitstates)
|
||||
;
|
||||
|
||||
/* PLL must be off before reprogramming PLLCFGR. */
|
||||
RCC_CR &= ~RCC_CR_PLLON;
|
||||
while ((RCC_CR & RCC_CR_PLLRDY) != 0)
|
||||
;
|
||||
|
||||
/* PLL: SRC=HSI16, M=4 (raw 3), N=85, R=2 (raw 0), enable R output.
|
||||
* VCO = 16 MHz / 4 * 85 = 340 MHz. SYSCLK = 340 / 2 = 170 MHz. */
|
||||
reg32 = RCC_PLLCFGR_PLLSRC_HSI16;
|
||||
reg32 |= ((pllm - 1) << RCC_PLLCFGR_PLLM_SHIFT);
|
||||
reg32 |= (plln << RCC_PLLCFGR_PLLN_SHIFT);
|
||||
reg32 |= (((pllr >> 1) - 1) << RCC_PLLCFGR_PLLR_SHIFT);
|
||||
reg32 |= RCC_PLLCFGR_PLLREN;
|
||||
RCC_PLLCFGR = reg32;
|
||||
DMB();
|
||||
|
||||
RCC_CR |= RCC_CR_PLLON;
|
||||
while ((RCC_CR & RCC_CR_PLLRDY) == 0)
|
||||
;
|
||||
|
||||
/* Switch SYSCLK source to PLL R. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 = (reg32 & ~RCC_CFGR_SW_MASK) | RCC_CFGR_SW_PLL;
|
||||
RCC_CFGR = reg32;
|
||||
DMB();
|
||||
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SW_MASK)
|
||||
!= RCC_CFGR_SW_PLL)
|
||||
;
|
||||
|
||||
/* SYSCFG clock for any post-init configuration. */
|
||||
RCC_APB2ENR |= RCC_APB2ENR_SYSCFGEN;
|
||||
}
|
||||
|
||||
|
||||
/* Optional debug UART on NUCLEO-G491RE ST-LINK VCP: LPUART1 PA2/PA3 AF12.
|
||||
* Available when: wolfBoot with DEBUG_UART, or test-app (always). */
|
||||
#if defined(DEBUG_UART) || !defined(__WOLFBOOT)
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
const uint32_t tx_pin = NUCLEO_G491_UART_TX_PIN;
|
||||
const uint32_t rx_pin = NUCLEO_G491_UART_RX_PIN;
|
||||
|
||||
RCC_AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
|
||||
(void)RCC_AHB2ENR;
|
||||
RCC_APB1ENR2 |= RCC_APB1ENR2_LPUART1EN;
|
||||
(void)RCC_APB1ENR2;
|
||||
|
||||
/* PA2, PA3 -> alternate function (MODER = 10b). */
|
||||
reg = GPIOA_MODER & ~((0x3u << (tx_pin * 2)) | (0x3u << (rx_pin * 2)));
|
||||
GPIOA_MODER = reg | ((0x2u << (tx_pin * 2)) | (0x2u << (rx_pin * 2)));
|
||||
|
||||
/* High speed (11b) so 115200 edges are clean even at 170 MHz. */
|
||||
GPIOA_OSPEEDR |= (0x3u << (tx_pin * 2)) | (0x3u << (rx_pin * 2));
|
||||
|
||||
/* AF12 (LPUART1) on PA2 and PA3 - AFRL bits [11:8] and [15:12]. */
|
||||
reg = GPIOA_AFRL & ~((0xFu << (tx_pin * 4)) | (0xFu << (rx_pin * 4)));
|
||||
GPIOA_AFRL = reg | ((NUCLEO_G491_UART_AF << (tx_pin * 4))
|
||||
| (NUCLEO_G491_UART_AF << (rx_pin * 4)));
|
||||
|
||||
LPUART1_CR1 = 0;
|
||||
LPUART1_BRR = STM32G4_LPUART1_BRR(STM32G4_UART_BAUD);
|
||||
LPUART1_CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||
while ((LPUART1_ISR & USART_ISR_TEACK) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
void uart_write(const char *buf, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
while ((LPUART1_ISR & USART_ISR_TXE) == 0)
|
||||
;
|
||||
LPUART1_TDR = (uint32_t)buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEBUG_UART || !__WOLFBOOT */
|
||||
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
clock_pll_on(0);
|
||||
#if defined(DEBUG_UART) && defined(__WOLFBOOT)
|
||||
uart_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void RAMFUNCTION hal_prepare_boot(void)
|
||||
{
|
||||
#ifdef SPI_FLASH
|
||||
spi_flash_release();
|
||||
#endif
|
||||
#ifdef WOLFBOOT_RESTORE_CLOCK
|
||||
clock_pll_off();
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/* stm32g4.h
|
||||
*
|
||||
* Copyright (C) 2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* STM32G4 family (e.g. STM32G491RE on NUCLEO-G491RE).
|
||||
* Cortex-M4F, no TrustZone. Single-bank 512 KB flash, 2 KB pages.
|
||||
* Reference: RM0440. Shared register map for the wolfBoot HAL and
|
||||
* the test-app -- both pull in the same definitions so wire-up
|
||||
* doesn't drift between them. */
|
||||
|
||||
#ifndef _STM32G4_H_
|
||||
#define _STM32G4_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Assembly helpers */
|
||||
#define DMB() __asm__ volatile ("dmb")
|
||||
#define ISB() __asm__ volatile ("isb")
|
||||
#define DSB() __asm__ volatile ("dsb")
|
||||
|
||||
|
||||
/* -------- RCC (AHB1 + 0x1000 = 0x40021000) -------- RM0440 - 7.4 -------- */
|
||||
#define RCC_BASE (0x40021000)
|
||||
#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00))
|
||||
#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x08))
|
||||
#define RCC_PLLCFGR (*(volatile uint32_t *)(RCC_BASE + 0x0C))
|
||||
#define RCC_CRRCR (*(volatile uint32_t *)(RCC_BASE + 0x98))
|
||||
#define RCC_CCIPR (*(volatile uint32_t *)(RCC_BASE + 0x88))
|
||||
#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x4C))
|
||||
#define RCC_APB1ENR1 (*(volatile uint32_t *)(RCC_BASE + 0x58))
|
||||
#define RCC_APB1ENR2 (*(volatile uint32_t *)(RCC_BASE + 0x5C))
|
||||
#define RCC_APB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x60))
|
||||
|
||||
#define RCC_CR_PLLRDY (1 << 25)
|
||||
#define RCC_CR_PLLON (1 << 24)
|
||||
#define RCC_CR_HSIRDY (1 << 10)
|
||||
#define RCC_CR_HSION (1 << 8)
|
||||
|
||||
#define RCC_CFGR_SW_HSI 0x1
|
||||
#define RCC_CFGR_SW_PLL 0x3
|
||||
#define RCC_CFGR_SW_MASK 0x3
|
||||
#define RCC_CFGR_SWS_SHIFT 2
|
||||
|
||||
#define RCC_PLLCFGR_PLLREN (1 << 24)
|
||||
#define RCC_PLLCFGR_PLLR_SHIFT 25
|
||||
#define RCC_PLLCFGR_PLLN_SHIFT 8
|
||||
#define RCC_PLLCFGR_PLLM_SHIFT 4
|
||||
#define RCC_PLLCFGR_PLLSRC_HSI16 0x2
|
||||
|
||||
#define RCC_CRRCR_HSI48ON (1 << 0)
|
||||
#define RCC_CRRCR_HSI48RDY (1 << 1)
|
||||
|
||||
#define RCC_AHB2ENR_GPIOAEN (1 << 0)
|
||||
#define RCC_APB1ENR1_PWREN (1 << 28)
|
||||
#define RCC_APB1ENR2_LPUART1EN (1 << 0)
|
||||
#define RCC_APB2ENR_SYSCFGEN (1 << 0)
|
||||
|
||||
|
||||
/* -------- PWR (APB1 = 0x40007000) -------- RM0440 - 6.4 -------- */
|
||||
#define PWR_BASE (0x40007000)
|
||||
#define PWR_CR1 (*(volatile uint32_t *)(PWR_BASE + 0x00))
|
||||
#define PWR_CR5 (*(volatile uint32_t *)(PWR_BASE + 0x80))
|
||||
#define PWR_SR2 (*(volatile uint32_t *)(PWR_BASE + 0x14))
|
||||
|
||||
#define PWR_CR1_VOS_SHIFT 9
|
||||
#define PWR_CR1_VOS_MASK (0x3 << PWR_CR1_VOS_SHIFT)
|
||||
#define PWR_CR1_VOS_RANGE1 (0x1 << PWR_CR1_VOS_SHIFT)
|
||||
#define PWR_CR5_R1MODE (1 << 0) /* 0 = Range 1 Boost */
|
||||
#define PWR_SR2_VOSF (1 << 10)
|
||||
|
||||
|
||||
/* -------- FLASH (AHB1 + 0x2000 = 0x40022000) -------- RM0440 - 3.7 -------- */
|
||||
#define FLASH_BASE (0x40022000)
|
||||
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00))
|
||||
#define FLASH_KEY (*(volatile uint32_t *)(FLASH_BASE + 0x08))
|
||||
#define FLASH_SR (*(volatile uint32_t *)(FLASH_BASE + 0x10))
|
||||
#define FLASH_CR (*(volatile uint32_t *)(FLASH_BASE + 0x14))
|
||||
|
||||
#define FLASHMEM_ADDRESS_SPACE (0x08000000)
|
||||
#define FLASH_PAGE_SIZE (0x800) /* 2KB */
|
||||
|
||||
#define FLASH_ACR_LATENCY_MASK (0x7)
|
||||
#define FLASH_ACR_PRFTEN (1 << 8)
|
||||
#define FLASH_ACR_ICEN (1 << 9)
|
||||
#define FLASH_ACR_DCEN (1 << 10)
|
||||
#define FLASH_ACR_LATENCY_4WS (0x4)
|
||||
|
||||
/* G4 has a single BSY at bit 16 (no BSY1/BSY2 like G0). */
|
||||
#define FLASH_SR_BSY (1 << 16)
|
||||
#define FLASH_SR_OPTVERR (1 << 15)
|
||||
#define FLASH_SR_RDERR (1 << 14)
|
||||
#define FLASH_SR_FASTERR (1 << 9)
|
||||
#define FLASH_SR_MISERR (1 << 8)
|
||||
#define FLASH_SR_PGSERR (1 << 7)
|
||||
#define FLASH_SR_SIZERR (1 << 6)
|
||||
#define FLASH_SR_PGAERR (1 << 5)
|
||||
#define FLASH_SR_WRPERR (1 << 4)
|
||||
#define FLASH_SR_PROGERR (1 << 3)
|
||||
#define FLASH_SR_OPERR (1 << 1)
|
||||
#define FLASH_SR_EOP (1 << 0)
|
||||
|
||||
/* G491 (Cat 3) is single-bank: PNB is 8 bits at [10:3], no BKER. */
|
||||
#define FLASH_CR_LOCK (1UL << 31)
|
||||
#define FLASH_CR_STRT (1 << 16)
|
||||
#define FLASH_CR_PER (1 << 1)
|
||||
#define FLASH_CR_PG (1 << 0)
|
||||
#define FLASH_CR_PNB_SHIFT 3
|
||||
#define FLASH_CR_PNB_MASK 0xFF
|
||||
|
||||
#define FLASH_KEY1 (0x45670123)
|
||||
#define FLASH_KEY2 (0xCDEF89AB)
|
||||
|
||||
|
||||
/* -------- GPIOA (AHB2 = 0x48000000) -------- RM0440 - 9.4 -------- */
|
||||
#define GPIOA_BASE (0x48000000)
|
||||
#define GPIOA_MODER (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
|
||||
#define GPIOA_OTYPER (*(volatile uint32_t *)(GPIOA_BASE + 0x04))
|
||||
#define GPIOA_OSPEEDR (*(volatile uint32_t *)(GPIOA_BASE + 0x08))
|
||||
#define GPIOA_PUPDR (*(volatile uint32_t *)(GPIOA_BASE + 0x0C))
|
||||
#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + 0x14))
|
||||
#define GPIOA_BSRR (*(volatile uint32_t *)(GPIOA_BASE + 0x18))
|
||||
#define GPIOA_AFRL (*(volatile uint32_t *)(GPIOA_BASE + 0x20))
|
||||
#define GPIOA_AFRH (*(volatile uint32_t *)(GPIOA_BASE + 0x24))
|
||||
|
||||
|
||||
/* -------- LPUART1 (APB1 = 0x40008000) -------- RM0440 - 38.7 -------- */
|
||||
#define LPUART1_BASE (0x40008000)
|
||||
#define LPUART1_CR1 (*(volatile uint32_t *)(LPUART1_BASE + 0x00))
|
||||
#define LPUART1_BRR (*(volatile uint32_t *)(LPUART1_BASE + 0x0C))
|
||||
#define LPUART1_ISR (*(volatile uint32_t *)(LPUART1_BASE + 0x1C))
|
||||
#define LPUART1_TDR (*(volatile uint32_t *)(LPUART1_BASE + 0x28))
|
||||
|
||||
#define USART_CR1_UE (1 << 0)
|
||||
#define USART_CR1_RE (1 << 2)
|
||||
#define USART_CR1_TE (1 << 3)
|
||||
#define USART_ISR_TEACK (1 << 21)
|
||||
#define USART_ISR_TXE (1 << 7)
|
||||
|
||||
|
||||
/* -------- SYSCLK / boot defaults -------- */
|
||||
#define STM32G4_SYSCLK_HZ (170000000UL)
|
||||
#define STM32G4_UART_BAUD (115200UL)
|
||||
/* LPUART_BRR = (256 * f_LPUART) / baud. PCLK1 = SYSCLK on default prescalers. */
|
||||
#define STM32G4_LPUART1_BRR(baud) \
|
||||
((uint32_t)(((uint64_t)256u * STM32G4_SYSCLK_HZ) / (baud)))
|
||||
|
||||
|
||||
/* -------- NUCLEO-G491RE board specifics -------- */
|
||||
#define NUCLEO_G491_LED_LD2_PIN (5) /* PA5 */
|
||||
#define NUCLEO_G491_UART_TX_PIN (2) /* PA2 - LPUART1_TX */
|
||||
#define NUCLEO_G491_UART_RX_PIN (3) /* PA3 - LPUART1_RX */
|
||||
#define NUCLEO_G491_UART_AF (12)
|
||||
|
||||
|
||||
/* Public helpers implemented in hal/stm32g4.c. Available to wolfBoot when
|
||||
* DEBUG_UART is set, and to the test-app at all times. */
|
||||
void uart_init(void);
|
||||
void uart_write(const char *buf, unsigned int len);
|
||||
|
||||
#endif /* _STM32G4_H_ */
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00018000 /* 96 KB on G491RE */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_start_text = .;
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_end_text = .;
|
||||
} > FLASH
|
||||
|
||||
.edidx :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
} > FLASH
|
||||
|
||||
_stored_data = .;
|
||||
.data : AT (_stored_data)
|
||||
{
|
||||
_start_data = .;
|
||||
KEEP(*(.data*))
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.ramcode))
|
||||
. = ALIGN(4);
|
||||
_end_data = .;
|
||||
} > RAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_start_bss = .;
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_end_bss = .;
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
} > RAM
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
END_STACK = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
|
@ -919,6 +919,23 @@ endif
|
|||
ifeq ($(TARGET),stm32g0)
|
||||
CFLAGS+=-DNVM_FLASH_WRITEONCE=1
|
||||
endif
|
||||
ifeq ($(TARGET),stm32g4)
|
||||
CFLAGS+=-DNVM_FLASH_WRITEONCE=1
|
||||
CFLAGS+=-I../hal
|
||||
LDFLAGS+=-Wl,-gc-sections
|
||||
# Test app uses printf via syscalls.o (routes _write -> uart_write).
|
||||
# syscalls.c references uart_write/uart_vprintf from string.o; string.o
|
||||
# is already pulled in when DEBUG_UART=1. Pull it in unconditionally so
|
||||
# printf is available even when DEBUG_UART is off.
|
||||
ifeq ($(DEBUG_UART),)
|
||||
APP_OBJS+=../src/string.o
|
||||
endif
|
||||
APP_OBJS+=syscalls.o
|
||||
# _Min_Heap_Size is consumed by syscalls.c _sbrk(); ARM.ld does not
|
||||
# define a heap, so anchor it at zero. _sbrk is gc'd when malloc is
|
||||
# unused, but the symbol must still resolve.
|
||||
LDFLAGS+=-Wl,--defsym=_Min_Heap_Size=0
|
||||
endif
|
||||
ifeq ($(TARGET),stm32c0)
|
||||
CFLAGS+=-DNVM_FLASH_WRITEONCE=1
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/* app_stm32g4.c
|
||||
*
|
||||
* Test bare-metal application for the STM32G4 (NUCLEO-G491RE).
|
||||
*
|
||||
* Copyright (C) 2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "hal.h"
|
||||
#include "stm32g4.h"
|
||||
#include "wolfboot/wolfboot.h"
|
||||
#include "target.h"
|
||||
|
||||
#ifdef TARGET_stm32g4
|
||||
|
||||
static void led_init(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
RCC_AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
|
||||
reg = RCC_AHB2ENR;
|
||||
(void)reg;
|
||||
|
||||
reg = GPIOA_MODER & ~(0x3u << (NUCLEO_G491_LED_LD2_PIN * 2));
|
||||
GPIOA_MODER = reg | (0x1u << (NUCLEO_G491_LED_LD2_PIN * 2));
|
||||
GPIOA_PUPDR &= ~(0x3u << (NUCLEO_G491_LED_LD2_PIN * 2));
|
||||
}
|
||||
|
||||
static void led_on(void)
|
||||
{
|
||||
GPIOA_BSRR = (1u << NUCLEO_G491_LED_LD2_PIN);
|
||||
}
|
||||
|
||||
static void led_off(void)
|
||||
{
|
||||
GPIOA_BSRR = (1u << (NUCLEO_G491_LED_LD2_PIN + 16));
|
||||
}
|
||||
|
||||
static void busy_delay(uint32_t count)
|
||||
{
|
||||
volatile uint32_t i;
|
||||
for (i = 0; i < count; i++)
|
||||
__asm__ volatile ("nop");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
uint32_t version;
|
||||
uint32_t on_ticks, off_ticks;
|
||||
|
||||
hal_init();
|
||||
led_init();
|
||||
uart_init();
|
||||
|
||||
version = wolfBoot_current_firmware_version();
|
||||
printf("TEST APP\r\n");
|
||||
printf("App version: %lu\r\n", (unsigned long)version);
|
||||
|
||||
/* v1: slow blink. v2+: fast blink + mark update successful. */
|
||||
if (version >= 2) {
|
||||
wolfBoot_success();
|
||||
printf("Update confirmed.\r\n");
|
||||
on_ticks = 200000;
|
||||
off_ticks = 200000;
|
||||
} else {
|
||||
on_ticks = 600000;
|
||||
off_ticks = 600000;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
led_on();
|
||||
busy_delay(on_ticks);
|
||||
led_off();
|
||||
busy_delay(off_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* TARGET_stm32g4 */
|
||||
|
|
@ -230,3 +230,28 @@ void boot_led_off(void)
|
|||
}
|
||||
|
||||
#endif /* TARGET_stm32l4 */
|
||||
|
||||
#ifdef TARGET_stm32g4
|
||||
#include "stm32g4.h"
|
||||
/* NUCLEO-G491RE user LED LD2 on PA5. */
|
||||
|
||||
void boot_led_on(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
const uint32_t pin = NUCLEO_G491_LED_LD2_PIN;
|
||||
RCC_AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
|
||||
reg = RCC_AHB2ENR; /* read-back so GPIOA clock is live before MODER write */
|
||||
(void)reg;
|
||||
reg = GPIOA_MODER & ~(0x03 << (pin * 2));
|
||||
GPIOA_MODER = reg | (1 << (pin * 2));
|
||||
reg = GPIOA_PUPDR & ~(0x03 << (pin * 2));
|
||||
GPIOA_PUPDR = reg | (1 << (pin * 2));
|
||||
GPIOA_BSRR = (1 << pin); /* BSRR is write-only; bare assignment, not |= */
|
||||
}
|
||||
|
||||
void boot_led_off(void)
|
||||
{
|
||||
GPIOA_BSRR = (1 << (NUCLEO_G491_LED_LD2_PIN + 16));
|
||||
}
|
||||
|
||||
#endif /* TARGET_stm32g4 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue