From 60e4cae25d3eab79f4ab4db6d779f06afe146857 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 18 Jun 2019 11:03:21 -0700 Subject: [PATCH] wolfBoot port example for STM32G071 --- contiki-nrf52/contiki | 2 +- wolfBoot | 2 +- wolfBoot_stm32g0_v0.1/README.md | 36 ++ wolfBoot_stm32g0_v0.1/hal/stm32g0.c | 565 ++++++++++++++++++++++ wolfBoot_stm32g0_v0.1/hal/stm32g0.ld | 50 ++ wolfBoot_stm32g0_v0.1/image003.png | Bin 0 -> 78481 bytes wolfBoot_stm32g0_v0.1/include/target_g0.h | 30 ++ wolfBoot_stm32g0_v0.1/test-app/ARM_g0.ld | 43 ++ wolfBoot_stm32g0_v0.1/test-app/led.c | 109 +++++ wolfBoot_stm32g0_v0.1/test-app/stm32g0.c | 82 ++++ wolfBoot_stm32g0_v0.1/test-app/system.c | 295 +++++++++++ 11 files changed, 1212 insertions(+), 2 deletions(-) create mode 100644 wolfBoot_stm32g0_v0.1/README.md create mode 100755 wolfBoot_stm32g0_v0.1/hal/stm32g0.c create mode 100755 wolfBoot_stm32g0_v0.1/hal/stm32g0.ld create mode 100644 wolfBoot_stm32g0_v0.1/image003.png create mode 100755 wolfBoot_stm32g0_v0.1/include/target_g0.h create mode 100755 wolfBoot_stm32g0_v0.1/test-app/ARM_g0.ld create mode 100755 wolfBoot_stm32g0_v0.1/test-app/led.c create mode 100755 wolfBoot_stm32g0_v0.1/test-app/stm32g0.c create mode 100755 wolfBoot_stm32g0_v0.1/test-app/system.c diff --git a/contiki-nrf52/contiki b/contiki-nrf52/contiki index 633b340..047bd48 160000 --- a/contiki-nrf52/contiki +++ b/contiki-nrf52/contiki @@ -1 +1 @@ -Subproject commit 633b3406f986d6b2b4039c55b7e53b8b58794779 +Subproject commit 047bd48299ff9fb815005623da4cddd33ae451ca diff --git a/wolfBoot b/wolfBoot index e6723ec..11dd4f1 160000 --- a/wolfBoot +++ b/wolfBoot @@ -1 +1 @@ -Subproject commit e6723ec831c1095bdbcf50a8cba636c72364e1c7 +Subproject commit 11dd4f184e6407440f128c5aa308be456a1bd3b7 diff --git a/wolfBoot_stm32g0_v0.1/README.md b/wolfBoot_stm32g0_v0.1/README.md new file mode 100644 index 0000000..e29f27b --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/README.md @@ -0,0 +1,36 @@ +# [wolfBoot] porting to STM32G071 + +Preliminary porting for STM32G0. + +## Attached zip file includes: +- hal + - stm32g0.c / stm32g0.ld + - porting adapted to G0 flash and clock implementation +- include + - target_g0.h + - To be renamed as target.h +- test-app + - ARM_g0. Ld + - To be renamed to ARM.ld + - led.c + - Including stm32g0 code + - stm32g0.c + - system.c + +## wolfboot parent + +- SHA-1: 11dd4f184e6407440f128c5aa308be456a1bd3b7 + +## Flash configuration + +![Example partitions in STM32G071RB](image003.png) + +- Note: this is a preliminary layout... can be optimized. + +## Compilation steps: + +- Rename target_g0.h > target.h +- Rename ARM_g0.ld > ARM.ld +- `make SIGN=ECC256 TARGET=stm32g0 CORTEX_M0=1 DEBUG=1` + +Tested test-app signature verification successfully. Firmware update has not been tested. diff --git a/wolfBoot_stm32g0_v0.1/hal/stm32g0.c b/wolfBoot_stm32g0_v0.1/hal/stm32g0.c new file mode 100755 index 0000000..c206ea3 --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/hal/stm32g0.c @@ -0,0 +1,565 @@ +/* stm32g0.c + * + * Copyright (C) 2018 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 2 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 +#include + + +/* STM32 G0 register configuration */ + +/* Assembly helpers */ +#define DMB() __asm__ volatile ("dmb") +//#define DMB() __asm volatile ("dmb") //TODO + +/*** RCC ***/ + +#define RCC_BASE (0x40021000) /*PERIPH_BASE + 0x00020000UL + 0x00001000UL */ //RM0444 - 5.4.1 +#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00)) //RM0444 - 5.4.1 +#define RCC_PLLCFGR (*(volatile uint32_t *)(RCC_BASE + 0x0C)) //RM0444 - 5.4.4 +#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x08)) //RM0444 - 5.4.3 + + +#define RCC_CR_PLLRDY (1 << 25) +#define RCC_CR_PLLON (1 << 24) +#define RCC_CR_HSERDY (1 << 17) +#define RCC_CR_HSEON (1 << 16) +#define RCC_CR_HSIRDY (1 << 10) +#define RCC_CR_HSION (1 << 8) + +#define RCC_CFGR_SW_HSI 0x0 +#define RCC_CFGR_SW_HSE 0x1 +#define RCC_CFGR_SW_PLL 0x2 + + +#define RCC_PLLCFGR_PLLR_EN (1 << 28) //RM0444 - 5.4.3 + +#define RCC_PLLCFGR_PLLSRC_NONE 0 +#define RCC_PLLCFGR_PLLSRC_HSI16 2 +#define RCC_PLLCFGR_PLLSRC_HSE 3 + + + + +/*** APB PRESCALER ***/ // TODO - confirm +#define RCC_PRESCALER_DIV_NONE 0 +#define RCC_PRESCALER_DIV_2 8 +#define RCC_PRESCALER_DIV_4 9 +#define PLL_FULL_MASK (0x7F037FFF) // TODO + +/*** FLASH ***/ +#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x4002103C)) //RM0444 - 5.4.14 - RCC_APBENR1 +#define APB1_CLOCK_RST (*(volatile uint32_t *)(0x4002102C)) //RM0444 - 5.4.10 - RCC_APBRSTR1 +#define TIM2_APB1_CLOCK_ER_VAL (1 << 0) +#define PWR_APB1_CLOCK_ER_VAL (1 << 28) + +#define APB2_CLOCK_ER (*(volatile uint32_t *)(0x40021040)) //RM0444 - 5.4.15 - RCC_APBENR2 +#define APB2_CLOCK_RST (*(volatile uint32_t *)(0x40021030)) //RM0444 - 5.4.11 - RCC_APBRSTR2 +#define SYSCFG_APB2_CLOCK_ER (1 << 0) //RM0444 - 5.4.15 - RCC_APBENR2 - SYSCFGEN + +#define FLASH_BASE (0x40022000) /*FLASH_R_BASE = 0x40000000UL + 0x00020000UL + 0x00002000UL */ +#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00)) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_KEYR (*(volatile uint32_t *)(FLASH_BASE + 0x08)) //RM0444 - 3.7.2 - FLASH_KEYR +#define FLASH_SR (*(volatile uint32_t *)(FLASH_BASE + 0x10)) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_CR (*(volatile uint32_t *)(FLASH_BASE + 0x14)) //RM0444 - 3.7.5 - FLASH_CR + +/* Register values */ +#define FLASH_ACR_DBG_SWEN (1 << 18) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_EMPTY (1 << 16) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_RESET_INST_CACHE (1 << 11) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_ENABLE_PRFT (1 << 8) //RM0444 - 3.7.1 - FLASH_ACR + +#define FLASH_SR_CFGBSY (1 << 18) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_BSY1 (1 << 16) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_OPTVERR (1 << 15) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_RDERR (1 << 14) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_FASTERR (1 << 9) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_MISERR (1 << 8) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_PGSERR (1 << 7) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_SIZERR (1 << 6) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_PGAERR (1 << 5) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_WRPERR (1 << 4) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_PROGERR (1 << 3) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_OPERR (1 << 1) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_SR_EOP (1 << 0) //RM0444 - 3.7.4 - FLASH_SR + +#define FLASH_CR_LOCK (1 << 31) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_OPTLOCK (1 << 30) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_SECPROT (1 << 28) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_OBL_LAUNCH (1 << 27) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_RDERRIE (1 << 26) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_ERRIE (1 << 25) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_EOPIE (1 << 24) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_FSTPG (1 << 18) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_OPTSTRT (1 << 17) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_STRT (1 << 16) //RM0444 - 3.7.5 - FLASH_CR + +#define FLASH_CR_MER1 (1 << 2) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_PER (1 << 1) //RM0444 - 3.7.5 - FLASH_CR +#define FLASH_CR_PG (1 << 0) //RM0444 - 3.7.5 - FLASH_CR + +#define FLASH_CR_PNB_SHIFT 3 //RM0444 - 3.7.5 - FLASH_CR - PNB bits 8:3 +#define FLASH_CR_PNB_MASK 0x3f //RM0444 - 3.7.5 - FLASH_CR - PNB bits 8:3 - 6 bits + +#define FLASH_KEY1 (0x45670123) +#define FLASH_KEY2 (0xCDEF89AB) + + +/* FLASH Geometry */ +#define FLASH_SECTOR_0 0x0000000 /* 2 Kb */ +#define FLASH_SECTOR_1 0x0000800 /* 2 Kb */ +#define FLASH_SECTOR_2 0x0001000 /* 2 Kb */ +#define FLASH_SECTOR_3 0x0001800 /* 2 Kb */ +#define FLASH_SECTOR_4 0x0002000 /* 2 Kb */ +#define FLASH_SECTOR_5 0x0002800 /* 2 Kb */ +#define FLASH_SECTOR_6 0x0003000 /* 2 Kb */ +#define FLASH_SECTOR_7 0x0003800 /* 2 Kb */ +#define FLASH_SECTOR_8 0x0004000 /* 2 Kb */ +#define FLASH_SECTOR_9 0x0004800 /* 2 Kb */ +#define FLASH_SECTOR_10 0x0005000 /* 2 Kb */ +#define FLASH_SECTOR_11 0x0005800 /* 2 Kb */ +#define FLASH_SECTOR_12 0x0006000 /* 2 Kb */ +#define FLASH_SECTOR_13 0x0006800 /* 2 Kb */ +#define FLASH_SECTOR_14 0x0007000 /* 2 Kb */ +#define FLASH_SECTOR_15 0x0007800 /* 2 Kb */ +#define FLASH_SECTOR_16 0x0008000 /* 2 Kb */ +#define FLASH_SECTOR_17 0x0008800 /* 2 Kb */ +#define FLASH_SECTOR_18 0x0009000 /* 2 Kb */ +#define FLASH_SECTOR_19 0x0009800 /* 2 Kb */ +#define FLASH_SECTOR_20 0x000A000 /* 2 Kb */ +#define FLASH_SECTOR_21 0x000A800 /* 2 Kb */ +#define FLASH_SECTOR_22 0x000B000 /* 2 Kb */ +#define FLASH_SECTOR_23 0x000B800 /* 2 Kb */ +#define FLASH_SECTOR_24 0x000C000 /* 2 Kb */ +#define FLASH_SECTOR_25 0x000C800 /* 2 Kb */ +#define FLASH_SECTOR_26 0x000D000 /* 2 Kb */ +#define FLASH_SECTOR_27 0x000D800 /* 2 Kb */ +#define FLASH_SECTOR_28 0x000E000 /* 2 Kb */ +#define FLASH_SECTOR_29 0x000E800 /* 2 Kb */ +#define FLASH_SECTOR_30 0x000F000 /* 2 Kb */ +#define FLASH_SECTOR_31 0x000F800 /* 2 Kb */ +#define FLASH_SECTOR_32 0x0010000 /* 2 Kb */ +#define FLASH_SECTOR_33 0x0010800 /* 2 Kb */ +#define FLASH_SECTOR_34 0x0011000 /* 2 Kb */ +#define FLASH_SECTOR_35 0x0011800 /* 2 Kb */ +#define FLASH_SECTOR_36 0x0012000 /* 2 Kb */ +#define FLASH_SECTOR_37 0x0012800 /* 2 Kb */ +#define FLASH_SECTOR_38 0x0013000 /* 2 Kb */ +#define FLASH_SECTOR_39 0x0013800 /* 2 Kb */ +#define FLASH_SECTOR_40 0x0014000 /* 2 Kb */ +#define FLASH_SECTOR_41 0x0014800 /* 2 Kb */ +#define FLASH_SECTOR_42 0x0015000 /* 2 Kb */ +#define FLASH_SECTOR_43 0x0015800 /* 2 Kb */ +#define FLASH_SECTOR_44 0x0016000 /* 2 Kb */ +#define FLASH_SECTOR_45 0x0016800 /* 2 Kb */ +#define FLASH_SECTOR_46 0x0017000 /* 2 Kb */ +#define FLASH_SECTOR_47 0x0017800 /* 2 Kb */ +#define FLASH_SECTOR_48 0x0018000 /* 2 Kb */ +#define FLASH_SECTOR_49 0x0018800 /* 2 Kb */ +#define FLASH_SECTOR_50 0x0019000 /* 2 Kb */ +#define FLASH_SECTOR_51 0x0019800 /* 2 Kb */ +#define FLASH_SECTOR_52 0x001A000 /* 2 Kb */ +#define FLASH_SECTOR_53 0x001A800 /* 2 Kb */ +#define FLASH_SECTOR_54 0x001B000 /* 2 Kb */ +#define FLASH_SECTOR_55 0x001B800 /* 2 Kb */ +#define FLASH_SECTOR_56 0x001C000 /* 2 Kb */ +#define FLASH_SECTOR_57 0x001C800 /* 2 Kb */ +#define FLASH_SECTOR_58 0x001D000 /* 2 Kb */ +#define FLASH_SECTOR_59 0x001D800 /* 2 Kb */ +#define FLASH_SECTOR_60 0x001E000 /* 2 Kb */ +#define FLASH_SECTOR_61 0x001E800 /* 2 Kb */ +#define FLASH_SECTOR_62 0x001F000 /* 2 Kb */ +#define FLASH_SECTOR_63 0x001F800 /* 2 Kb */ +#define FLASH_TOP 0x0200000 + +#define FLASH_SECTORS 64 +const uint32_t flash_sector[FLASH_SECTORS + 1] = { + FLASH_SECTOR_0, + FLASH_SECTOR_1, + FLASH_SECTOR_2, + FLASH_SECTOR_3, + FLASH_SECTOR_4, + FLASH_SECTOR_5, + FLASH_SECTOR_6, + FLASH_SECTOR_7, + FLASH_SECTOR_8, + FLASH_SECTOR_9, + FLASH_SECTOR_10, + FLASH_SECTOR_11, + FLASH_SECTOR_12, + FLASH_SECTOR_13, + FLASH_SECTOR_14, + FLASH_SECTOR_15, + FLASH_SECTOR_16, + FLASH_SECTOR_17, + FLASH_SECTOR_18, + FLASH_SECTOR_19, + FLASH_SECTOR_20, + FLASH_SECTOR_21, + FLASH_SECTOR_22, + FLASH_SECTOR_23, + FLASH_SECTOR_24, + FLASH_SECTOR_25, + FLASH_SECTOR_26, + FLASH_SECTOR_27, + FLASH_SECTOR_28, + FLASH_SECTOR_29, + FLASH_SECTOR_30, + FLASH_SECTOR_31, + FLASH_SECTOR_32, + FLASH_SECTOR_33, + FLASH_SECTOR_34, + FLASH_SECTOR_35, + FLASH_SECTOR_36, + FLASH_SECTOR_37, + FLASH_SECTOR_38, + FLASH_SECTOR_39, + FLASH_SECTOR_40, + FLASH_SECTOR_41, + FLASH_SECTOR_42, + FLASH_SECTOR_43, + FLASH_SECTOR_44, + FLASH_SECTOR_45, + FLASH_SECTOR_46, + FLASH_SECTOR_47, + FLASH_SECTOR_48, + FLASH_SECTOR_49, + FLASH_SECTOR_50, + FLASH_SECTOR_51, + FLASH_SECTOR_52, + FLASH_SECTOR_53, + FLASH_SECTOR_54, + FLASH_SECTOR_55, + FLASH_SECTOR_56, + FLASH_SECTOR_57, + FLASH_SECTOR_58, + FLASH_SECTOR_59, + FLASH_SECTOR_60, + FLASH_SECTOR_61, + FLASH_SECTOR_62, + FLASH_SECTOR_63, + FLASH_TOP +}; + +static void RAMFUNCTION flash_set_waitstates(int waitstates) //ok +{ + FLASH_ACR |= waitstates | FLASH_ACR_RESET_INST_CACHE | FLASH_ACR_ENABLE_INST_CACHE; +} + +static RAMFUNCTION void flash_wait_complete(void) //ok +{ + while ((FLASH_SR & FLASH_SR_BSY1) == FLASH_SR_BSY1) + ; +} +/* +static void mass_erase(void) +{ + FLASH_CR |= FLASH_CR_MER; + FLASH_CR |= FLASH_CR_STRT; + flash_wait_complete(); + FLASH_CR &= ~FLASH_CR_MER; +} +*/ + +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_OPTVERR /*| FLASH_SR_ECCC | FLASH_SR_ECCD*/); + + /*TODO : add ECC error handling*/ +} + +static void RAMFUNCTION flash_erase_page(uint32_t page) +{ + /* RM0444 - 3.3.7 To erase a page (2 Kbytes), follow the procedure below*/ + + /*1. Check that no Flash memory operation is ongoing by checking the BSY1 bit of the FLASH status register (FLASH_SR).*/ + flash_wait_complete(); + + /*2. Check and clear all error programming flags due to a previous programming. If not, PGSERR is set.*/ + flash_clear_errors(); + + /*3. Set the PER bit and select the page to erase (PNB) in the FLASH control register (FLASH_CR).*/ + FLASH_CR |= FLASH_CR_PER; + + uint32_t reg = FLASH_CR & (~(FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT)); + FLASH_CR = reg | (page & FLASH_CR_PNB_MASK) << FLASH_CR_PNB_SHIFT; + + /*4. Set the STRT bit of the FLASH control register (FLASH_CR).*/ + FLASH_CR |= FLASH_CR_STRT; + + /*5. Wait until the BSY1 bit of the FLASH status register (FLASH_SR) is cleared.*/ + flash_wait_complete(); + + /*Reset*/ + FLASH_CR &= ~FLASH_CR_PER; + FLASH_CR &= ~(FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT); + +} + + + + +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + + int i; + uint32_t len_64; + uint64_t data_64; + + + /*1. Check that no Main Flash memory operation is ongoing by checking the BSY1 bit of the FLASH status register (FLASH_SR).*/ + flash_wait_complete(); + + /*2. Check and clear all error programming flags due to a previous programming. If not, PGSERR is set.*/ + flash_clear_errors(); + + /*It is only possible to program a double word (2 x 32-bit data) */ + len_64 = len >> 3; + + for (i = 0; i < len_64 ; i++) { + + /*3. Set the PG bit of the FLASH control register (FLASH_CR).*/ + FLASH_CR |= FLASH_CR_PG; + + /*4. Perform the data write operation at the desired memory address, inside Main memory block or OTP area. Only double word (64 bits) can be programmed.*/ + data_64 = (*((uint64_t*)data)); + + /* Program first word */ + *(uint32_t *)address = (uint32_t)data_64; + + /* Barrier to ensure programming is performed in 2 steps, in right order(independently of compiler optimization behavior) */ + DMB(); + + /* Program second word */ + *(uint32_t *)(address + 4U) = (uint32_t)(data_64 >> 32U); + + /*5. Wait until the BSY1 bit of the FLASH status register (FLASH_SR) is cleared.*/ + flash_wait_complete(); + + /*6. Check that EOP flag of the FLASH status register (FLASH_SR) is set (programming operation succeeded), and clear it by software.*/ + while ((FLASH_SR & FLASH_SR_EOP) == FLASH_SR_EOP); + FLASH_SR &= ~FLASH_SR_EOP; + + /*7. Clear the PG bit of the FLASH control register (FLASH_CR) if there no more programming request anymore.*/ + FLASH_CR &= ~FLASH_CR_PG; + } + + return 0; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; + FLASH_KEYR = FLASH_KEY1; + FLASH_KEYR = FLASH_KEY2; +} + +void RAMFUNCTION hal_flash_lock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; +} + + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + int start = -1, end = -1; + uint32_t end_address; + int i; + if (len == 0) + return -1; + end_address = address + len - 1; + + if (address < flash_sector[0] || end_address > FLASH_TOP) + return -1; + for (i = 0; i < FLASH_SECTORS; i++) + { + if ((address >= flash_sector[i]) && (address < flash_sector[i + 1])) { + start = i; + } + if ((end_address >= flash_sector[i]) && (end_address < flash_sector[i + 1])) { + end = i; + } + if (start > 0 && end > 0) + break; + } + if (start < 0 || end < 0) + return -1; + for (i = start; i <= end; i++) + flash_erase_page(i); + return 0; +} + + +/*This implementation will setup HSI RC 16 MHz as SYSCLCK source and turn of PLLCLK*/ +static void clock_pll_off(void) +{ + uint32_t reg32; + + /* Select HSI as SYSCLK source. */ + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI); + DMB(); + + /* Turn off PLL */ + RCC_CR &= ~RCC_CR_PLLON; + DMB(); +} + +/*This implementation will setup HSI RC 16 MHz as PLL Source Mux, PLLCLK as System Clock Source*/ +static void clock_pll_on(int powersave) +{ + uint32_t reg32; + uint32_t cpu_freq, plln, pllm, pllq, pllp, pllr, hpre, ppre, flash_waitstates; + + /* Enable Power controller - APB1 */ + APB1_CLOCK_ER |= PWR_APB1_CLOCK_ER_VAL; + + /* Select clock parameters (CPU Speed = 56MHz) */ + cpu_freq = 56000000; + pllm = 4; + plln = 70; + pllp = 10; + pllq = 5; + pllr = 5; + hpre = RCC_PRESCALER_DIV_NONE; + ppre = RCC_PRESCALER_DIV_NONE; + flash_waitstates = 2; // FLASH_LATENCY_2 > FLASH_ACR_LATENCY_1 = 0x2UL + + flash_set_waitstates(flash_waitstates); + + /* Enable internal high-speed oscillator. */ + RCC_CR |= RCC_CR_HSION; + DMB(); + while ((RCC_CR & RCC_CR_HSIRDY) == 0) {}; + + /* Select PLLCLK as SYSCLK source. */ + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL); + DMB(); + + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + */ + reg32 = RCC_CFGR; + reg32 &= ~(0xF0); //don't change bits [0-3] that were previously set + RCC_CFGR = (reg32 | (hpre << 8)); //RM0444 - 5.4.3 - RCC_CFGR + DMB(); + reg32 = RCC_CFGR; + reg32 &= ~(0x1C00); //don't change bits [0-14] + RCC_CFGR = (reg32 | (ppre << 12)); //RM0444 - 5.4.3 - RCC_CFGR + DMB(); + + /* Set PLL config */ + reg32 = RCC_PLLCFGR; + reg32 &= ~(PLL_FULL_MASK); // TODO?? + reg32 |= RCC_PLLCFGR_PLLSRC_HSI16; + reg32 |= ((pllm - 1) << 4); + reg32 |= plln << 8; + reg32 |= ((pllp - 1) << 17); + reg32 |= ((pllq - 1) << 25); + reg32 |= ((pllr - 1) << 29); + RCC_PLLCFGR = reg32; + + DMB(); + /* Enable PLL oscillator and wait for it to stabilize. */ + RCC_PLLCFGR |= RCC_PLLCFGR_PLLR_EN; + RCC_CR |= RCC_CR_PLLON; + + DMB(); + while ((RCC_CR & RCC_CR_PLLRDY) == 0) {}; + + /* Select PLL as SYSCLK source. */ + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL); + DMB(); + + /* Wait for PLL clock to be selected. */ + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SW_PLL) {}; + + /* SYSCFG, COMP and VREFBUF clock enable */ + APB2_CLOCK_ER|=SYSCFG_APB2_CLOCK_ER; +} + +void hal_init(void) +{ + clock_pll_on(0); +} + + +/*GPIOA5*/ +#define RCC_IOPENR (*(volatile uint32_t *)(0x40021034)) // 40021034 +#define RCC_IOPENR_GPIOAEN (1 << 0) + +#define GPIOA_BASE 0x50000000 +#define GPIOA_MODE (*(volatile uint32_t *)(GPIOA_BASE + 0x00)) +#define GPIOA_OTYPE (*(volatile uint32_t *)(GPIOA_BASE + 0x04)) +#define GPIOA_OSPD (*(volatile uint32_t *)(GPIOA_BASE + 0x08)) +#define GPIOA_PUPD (*(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_AFL (*(volatile uint32_t *)(GPIOA_BASE + 0x20)) +#define GPIOA_AFH (*(volatile uint32_t *)(GPIOA_BASE + 0x24)) +#define GPIOA_BRR (*(volatile uint32_t *)(GPIOA_BASE + 0x28)) +#define LED_PIN (5) +#define LED_BOOT_PIN (5) +#define GPIO_OSPEED_100MHZ (0x03) + +void led_on(void) +{ + uint32_t reg; + uint32_t pin = LED_BOOT_PIN; + RCC_IOPENR |= RCC_IOPENR_GPIOAEN; + reg = GPIOA_MODE & ~(0x03 << (pin * 2)); + GPIOA_MODE = reg | (1 << (pin * 2)); // general purpose output mode + reg = GPIOA_PUPD & ~(0x03 << (pin * 2)); + GPIOA_PUPD = reg | (1 << (pin * 2)); // pull-up + GPIOA_BSRR |= (1 << pin); // set pin +} + +static void gpiotoggle(uint32_t pin) +{ + if ((GPIOA_ODR & (1 << pin)) != 0x00u) + { + GPIOA_BRR |= (1 << pin); + } + else + { + GPIOA_BSRR |= (1 << pin); + } +} + +void hal_prepare_boot(void) +{ +#ifdef SPI_FLASH + spi_release(); +#endif + led_on(); + gpiotoggle(5); + clock_pll_off(); +} + diff --git a/wolfBoot_stm32g0_v0.1/hal/stm32g0.ld b/wolfBoot_stm32g0_v0.1/hal/stm32g0.ld new file mode 100755 index 0000000..65409b8 --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/hal/stm32g0.ld @@ -0,0 +1,50 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x001FFFF + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008FFF +} + +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); diff --git a/wolfBoot_stm32g0_v0.1/image003.png b/wolfBoot_stm32g0_v0.1/image003.png new file mode 100644 index 0000000000000000000000000000000000000000..f99a7c94148c113fe64174aa2e90143779e0d4cd GIT binary patch literal 78481 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 cMJ$wBs#GLK>}2R~_BA7Mf*`uCZfajw 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 G^#1^d!0pcf literal 0 HcmV?d00001 diff --git a/wolfBoot_stm32g0_v0.1/include/target_g0.h b/wolfBoot_stm32g0_v0.1/include/target_g0.h new file mode 100755 index 0000000..517468d --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/include/target_g0.h @@ -0,0 +1,30 @@ +#ifndef H_TARGETS_TARGET_ +#define H_TARGETS_TARGET_ + + +/* Example flash partitioning. + * Ensure that your firmware entry point is + * at FLASH_AREA_IMAGE_0_OFFSET + 0x100 + */ +# define WOLFBOOT_SECTOR_SIZE 0x3000 +# define WOLFBOOT_PARTITION_BOOT_ADDRESS 0xC800 + +#ifdef EXT_FLASH +s +/* Test configuration with 1MB external memory */ +/* (Addresses are relative to the beginning of the ext)*/ + +# define WOLFBOOT_PARTITION_SIZE 0x80000 +# define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x00000 +# define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x80000 + +#else + +/* Test configuration with internal memory - 2kB page granularity*/ +# define WOLFBOOT_PARTITION_SIZE 0x8000 +# define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x14800 +# define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x1C800 + +#endif + +#endif /* H_TARGETS_TARGET_ */ diff --git a/wolfBoot_stm32g0_v0.1/test-app/ARM_g0.ld b/wolfBoot_stm32g0_v0.1/test-app/ARM_g0.ld new file mode 100755 index 0000000..2d3af53 --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/test-app/ARM_g0.ld @@ -0,0 +1,43 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x000C900, LENGTH = 0x00007FFF + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008100 +} + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + *(.init) + *(.fini) + *(.text*) + *(.rodata*) + . = ALIGN(4); + _end_text = .; + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + _end = .; + } > RAM +} + +PROVIDE(_start_heap = _end); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); diff --git a/wolfBoot_stm32g0_v0.1/test-app/led.c b/wolfBoot_stm32g0_v0.1/test-app/led.c new file mode 100755 index 0000000..29b264c --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/test-app/led.c @@ -0,0 +1,109 @@ +/* led.c + * + * Test bare-metal blinking led application + * + * Copyright (C) 2018 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 2 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 + */ + +#ifdef PLATFORM_stm32f4 +#include +#include "wolfboot/wolfboot.h" + +#define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830)) +#define GPIOD_AHB1_CLOCK_ER (1 << 3) + +#define GPIOD_BASE 0x40020c00 +#define GPIOD_MODE (*(volatile uint32_t *)(GPIOD_BASE + 0x00)) +#define GPIOD_OTYPE (*(volatile uint32_t *)(GPIOD_BASE + 0x04)) +#define GPIOD_OSPD (*(volatile uint32_t *)(GPIOD_BASE + 0x08)) +#define GPIOD_PUPD (*(volatile uint32_t *)(GPIOD_BASE + 0x0c)) +#define GPIOD_ODR (*(volatile uint32_t *)(GPIOD_BASE + 0x14)) +#define GPIOD_BSRR (*(volatile uint32_t *)(GPIOD_BASE + 0x18)) +#define GPIOD_AFL (*(volatile uint32_t *)(GPIOD_BASE + 0x20)) +#define GPIOD_AFH (*(volatile uint32_t *)(GPIOD_BASE + 0x24)) +#define LED_PIN (15) +#define LED_BOOT_PIN (14) +#define GPIO_OSPEED_100MHZ (0x03) +void led_pwm_setup(void) +{ + uint32_t reg; + AHB1_CLOCK_ER |= GPIOD_AHB1_CLOCK_ER; + reg = GPIOD_MODE & ~ (0x03 << (LED_PIN * 2)); + GPIOD_MODE = reg | (2 << (LED_PIN * 2)); + + reg = GPIOD_OSPD & ~(0x03 << (LED_PIN * 2)); + GPIOD_OSPD = reg | (0x03 << (LED_PIN * 2)); + + reg = GPIOD_PUPD & ~(0x03 << (LED_PIN * 2)); + GPIOD_PUPD = reg | (0x02 << (LED_PIN * 2)); + + /* Alternate function: use high pin */ + reg = GPIOD_AFH & ~(0xf << ((LED_PIN - 8) * 4)); + GPIOD_AFH = reg | (0x2 << ((LED_PIN - 8) * 4)); +} + +void boot_led_on(void) +{ + uint32_t reg; + uint32_t pin = LED_BOOT_PIN - 2 * (wolfBoot_current_firmware_version() & 0x01); + AHB1_CLOCK_ER |= GPIOD_AHB1_CLOCK_ER; + reg = GPIOD_MODE & ~(0x03 << (pin * 2)); + GPIOD_MODE = reg | (1 << (pin * 2)); + reg = GPIOD_PUPD & ~(0x03 << (pin * 2)); + GPIOD_PUPD = reg | (1 << (pin * 2)); + GPIOD_BSRR |= (1 << pin); +} + +#endif /** PLATFORM_stm32f4 **/ + +#ifdef PLATFORM_stm32g0 +#include +#include "wolfboot/wolfboot.h" + + +/*GPIOA5*/ +#define RCC_IOPENR (*(volatile uint32_t *)(0x40021034)) // 40021034 +#define RCC_IOPENR_GPIOAEN (1 << 0) + +#define GPIOA_BASE 0x50000000 +#define GPIOA_MODE (*(volatile uint32_t *)(GPIOA_BASE + 0x00)) +#define GPIOA_OTYPE (*(volatile uint32_t *)(GPIOA_BASE + 0x04)) +#define GPIOA_OSPD (*(volatile uint32_t *)(GPIOA_BASE + 0x08)) +#define GPIOA_PUPD (*(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_AFL (*(volatile uint32_t *)(GPIOA_BASE + 0x20)) +#define GPIOA_AFH (*(volatile uint32_t *)(GPIOA_BASE + 0x24)) +#define LED_PIN (5) +#define LED_BOOT_PIN (5) +#define GPIO_OSPEED_100MHZ (0x03) + +void boot_led_on(void) +{ + uint32_t reg; + uint32_t pin = LED_BOOT_PIN; + RCC_IOPENR |= RCC_IOPENR_GPIOAEN; + reg = GPIOA_MODE & ~(0x03 << (pin * 2)); + GPIOA_MODE = reg | (1 << (pin * 2)); // general purpose output mode + reg = GPIOA_PUPD & ~(0x03 << (pin * 2)); + GPIOA_PUPD = reg | (1 << (pin * 2)); // pull-up + GPIOA_BSRR |= (1 << pin); // set pin +} + +#endif /** PLATFORM_stm32g0 **/ diff --git a/wolfBoot_stm32g0_v0.1/test-app/stm32g0.c b/wolfBoot_stm32g0_v0.1/test-app/stm32g0.c new file mode 100755 index 0000000..4cbe7a1 --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/test-app/stm32g0.c @@ -0,0 +1,82 @@ +/* main.c + * + * Test bare-metal blinking led application + * + * Copyright (C) 2018 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 2 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 +#include +#include +#include "system.h" +#include "timer.h" +#include "led.h" +#include "hal.h" +#include "wolfboot/wolfboot.h" + + +#ifdef PLATFORM_stm32g0 + +#define RCC_IOPENR (*(volatile uint32_t *)(0x40021034)) // 40021034 +#define RCC_IOPENR_GPIOAEN (1 << 0) + +#define GPIOA_BASE 0x50000000 +#define GPIOA_MODE (*(volatile uint32_t *)(GPIOA_BASE + 0x00)) +#define GPIOA_OTYPE (*(volatile uint32_t *)(GPIOA_BASE + 0x04)) +#define GPIOA_OSPD (*(volatile uint32_t *)(GPIOA_BASE + 0x08)) +#define GPIOA_PUPD (*(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_AFL (*(volatile uint32_t *)(GPIOA_BASE + 0x20)) +#define GPIOA_AFH (*(volatile uint32_t *)(GPIOA_BASE + 0x24)) +#define GPIOA_BRR (*(volatile uint32_t *)(GPIOA_BASE + 0x28)) +#define LED_PIN (5) +#define LED_BOOT_PIN (5) +#define GPIO_OSPEED_100MHZ (0x03) + +static void gpiotoggle(uint32_t pin) +{ + if ((GPIOA_ODR & (1 << pin)) != 0x00u) + { + GPIOA_BRR |= (1 << pin); + } + else + { + GPIOA_BSRR |= (1 << pin); + } +} + + +void main(void) +{ + uint32_t pin = 0; + uint32_t i = 0; + + boot_led_on(); + gpiotoggle(5); + flash_set_waitstates(); +// clock_config(); + + while(1) { + gpiotoggle(5); + for (i = 0; i < 800000; i++) // Wait a bit. + asm volatile ("nop"); + } +} +#endif /*PLATFORM_stm32g0*/ diff --git a/wolfBoot_stm32g0_v0.1/test-app/system.c b/wolfBoot_stm32g0_v0.1/test-app/system.c new file mode 100755 index 0000000..c040366 --- /dev/null +++ b/wolfBoot_stm32g0_v0.1/test-app/system.c @@ -0,0 +1,295 @@ +/* system.c + * + * Test bare-metal blinking led application + * + * Copyright (C) 2018 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 2 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 + */ +#ifdef PLATFORM_stm32f4 +#include +#include "system.h" + +/*** FLASH ***/ +#define FLASH_BASE (0x40023C00) +#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00)) +#define FLASH_ACR_ENABLE_DATA_CACHE (1 << 10) +#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9) + +/*** RCC ***/ + +#define RCC_BASE (0x40023800) +#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00)) +#define RCC_PLLCFGR (*(volatile uint32_t *)(RCC_BASE + 0x04)) +#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x08)) +#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00)) + +#define RCC_CR_PLLRDY (1 << 25) +#define RCC_CR_PLLON (1 << 24) +#define RCC_CR_HSERDY (1 << 17) +#define RCC_CR_HSEON (1 << 16) +#define RCC_CR_HSIRDY (1 << 1) +#define RCC_CR_HSION (1 << 0) + +#define RCC_CFGR_SW_HSI 0x0 +#define RCC_CFGR_SW_HSE 0x1 +#define RCC_CFGR_SW_PLL 0x2 + + +#define RCC_PLLCFGR_PLLSRC (1 << 22) + +#define RCC_PRESCALER_DIV_NONE 0 +#define RCC_PRESCALER_DIV_2 8 +#define RCC_PRESCALER_DIV_4 9 + + + +#define PLLM 8 +#define PLLN 336 +#define PLLP 2 +#define PLLQ 7 +#define PLLR 0 + +void flash_set_waitstates(void) +{ + FLASH_ACR |= 5 | FLASH_ACR_ENABLE_DATA_CACHE | FLASH_ACR_ENABLE_INST_CACHE; +} + + +void clock_config(void) +{ + uint32_t reg32; + /* Enable internal high-speed oscillator. */ + RCC_CR |= RCC_CR_HSION; + DMB(); + while ((RCC_CR & RCC_CR_HSIRDY) == 0) {}; + + /* Select HSI as SYSCLK source. */ + + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI); + DMB(); + + /* Enable external high-speed oscillator 8MHz. */ + RCC_CR |= RCC_CR_HSEON; + DMB(); + while ((RCC_CR & RCC_CR_HSERDY) == 0) {}; + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + */ + reg32 = RCC_CFGR; + reg32 &= ~(0xF0); + RCC_CFGR = (reg32 | (RCC_PRESCALER_DIV_NONE << 4)); + DMB(); + reg32 = RCC_CFGR; + reg32 &= ~(0x1C00); + RCC_CFGR = (reg32 | (RCC_PRESCALER_DIV_2 << 10)); + DMB(); + reg32 = RCC_CFGR; + reg32 &= ~(0x07 << 13); + RCC_CFGR = (reg32 | (RCC_PRESCALER_DIV_4 << 13)); + DMB(); + + /* Set PLL config */ + reg32 = RCC_PLLCFGR; + reg32 &= ~(PLL_FULL_MASK); + RCC_PLLCFGR = reg32 | RCC_PLLCFGR_PLLSRC | PLLM | + (PLLN << 6) | (((PLLP >> 1) - 1) << 16) | + (PLLQ << 24); + DMB(); + /* Enable PLL oscillator and wait for it to stabilize. */ + RCC_CR |= RCC_CR_PLLON; + DMB(); + while ((RCC_CR & RCC_CR_PLLRDY) == 0) {}; + + /* Select PLL as SYSCLK source. */ + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL); + DMB(); + + /* Wait for PLL clock to be selected. */ + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SW_PLL) {}; + + /* Disable internal high-speed oscillator. */ + RCC_CR &= ~RCC_CR_HSION; +} + +#endif /** PLATFORM_stm32f4 **/ + + +#ifdef PLATFORM_stm32g0 +#include +#include "system.h" + +/*** RCC ***/ + +#define RCC_BASE (0x40021000) /*PERIPH_BASE + 0x00020000UL + 0x00001000UL */ //RM0444 - 5.4.1 +#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00)) //RM0444 - 5.4.1 +#define RCC_PLLCFGR (*(volatile uint32_t *)(RCC_BASE + 0x0C)) //RM0444 - 5.4.4 +#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x08)) //RM0444 - 5.4.3 + + +#define RCC_CR_PLLRDY (1 << 25) +#define RCC_CR_PLLON (1 << 24) +#define RCC_CR_HSERDY (1 << 17) +#define RCC_CR_HSEON (1 << 16) +#define RCC_CR_HSIRDY (1 << 10) +#define RCC_CR_HSION (1 << 8) + +#define RCC_CFGR_SW_HSI 0x0 +#define RCC_CFGR_SW_HSE 0x1 +#define RCC_CFGR_SW_PLL 0x2 + + +#define RCC_PLLCFGR_PLLR_EN (1 << 28) //RM0444 - 5.4.3 + +#define RCC_PLLCFGR_PLLSRC_NONE 0 +#define RCC_PLLCFGR_PLLSRC_HSI16 2 +#define RCC_PLLCFGR_PLLSRC_HSE 3 + + + + +/*** APB PRESCALER ***/ // TODO - confirm +#define RCC_PRESCALER_DIV_NONE 0 +#define RCC_PRESCALER_DIV_2 8 +#define RCC_PRESCALER_DIV_4 9 +#define PLL_FULL_MASK (0x7F037FFF) // TODO + +/*** FLASH ***/ +#define APB1_CLOCK_ER (*(volatile uint32_t *)(0x4002103C)) //RM0444 - 5.4.14 - RCC_APBENR1 +#define APB1_CLOCK_RST (*(volatile uint32_t *)(0x4002102C)) //RM0444 - 5.4.10 - RCC_APBRSTR1 +#define TIM2_APB1_CLOCK_ER_VAL (1 << 0) +#define PWR_APB1_CLOCK_ER_VAL (1 << 28) + +#define APB2_CLOCK_ER (*(volatile uint32_t *)(0x40021040)) //RM0444 - 5.4.15 - RCC_APBENR2 +#define APB2_CLOCK_RST (*(volatile uint32_t *)(0x40021030)) //RM0444 - 5.4.11 - RCC_APBRSTR2 +#define SYSCFG_APB2_CLOCK_ER (1 << 0) //RM0444 - 5.4.15 - RCC_APBENR2 - SYSCFGEN + +#define FLASH_BASE (0x40022000) /*FLASH_R_BASE = 0x40000000UL + 0x00020000UL + 0x00002000UL */ +#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00)) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_KEYR (*(volatile uint32_t *)(FLASH_BASE + 0x08)) //RM0444 - 3.7.2 - FLASH_KEYR +#define FLASH_SR (*(volatile uint32_t *)(FLASH_BASE + 0x10)) //RM0444 - 3.7.4 - FLASH_SR +#define FLASH_CR (*(volatile uint32_t *)(FLASH_BASE + 0x14)) //RM0444 - 3.7.5 - FLASH_CR + +/* Register values */ +#define FLASH_ACR_DBG_SWEN (1 << 18) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_EMPTY (1 << 16) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_RESET_INST_CACHE (1 << 11) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_ENABLE_INST_CACHE (1 << 9) //RM0444 - 3.7.1 - FLASH_ACR +#define FLASH_ACR_ENABLE_PRFT (1 << 8) //RM0444 - 3.7.1 - FLASH_ACR + + +#define RCC_PRESCALER_DIV_NONE 0 +#define RCC_PRESCALER_DIV_2 8 +#define RCC_PRESCALER_DIV_4 9 + + + +#define PLLM 4 +#define PLLN 70 +#define PLLP 10 +#define PLLQ 5 +#define PLLR 5 + +void flash_set_waitstates(void) +{ + FLASH_ACR |= 2 | FLASH_ACR_RESET_INST_CACHE | FLASH_ACR_ENABLE_INST_CACHE; +} + + +void clock_config(void) +{ + uint32_t reg32; + uint32_t cpu_freq, plln, pllm, pllq, pllp, pllr, hpre, ppre, flash_waitstates; + + /* Enable Power controller - APB1 */ + APB1_CLOCK_ER |= PWR_APB1_CLOCK_ER_VAL; + + /* Select clock parameters (CPU Speed = 56MHz) */ + cpu_freq = 56000000; + pllm = 4; + plln = 70; + pllp = 10; + pllq = 5; + pllr = 5; + hpre = RCC_PRESCALER_DIV_NONE; + ppre = RCC_PRESCALER_DIV_NONE; + flash_waitstates = 2; // FLASH_LATENCY_2 > FLASH_ACR_LATENCY_1 = 0x2UL + + flash_set_waitstates(); + + /* Enable internal high-speed oscillator. */ + RCC_CR |= RCC_CR_HSION; + DMB(); + while ((RCC_CR & RCC_CR_HSIRDY) == 0) {}; + + /* Select PLLCLK as SYSCLK source. */ + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL); + DMB(); + + + /* + * Set prescalers for AHB, ADC, ABP1, ABP2. + */ + reg32 = RCC_CFGR; + reg32 &= ~(0xF0); //don't change bits [0-3] that were previously set + RCC_CFGR = (reg32 | (hpre << 8)); //RM0444 - 5.4.3 - RCC_CFGR + DMB(); + reg32 = RCC_CFGR; + reg32 &= ~(0x1C00); //don't change bits [0-14] + RCC_CFGR = (reg32 | (ppre << 12)); //RM0444 - 5.4.3 - RCC_CFGR + DMB(); + + /* Set PLL config */ + reg32 = RCC_PLLCFGR; + reg32 &= ~(PLL_FULL_MASK); // TODO?? + reg32 |= RCC_PLLCFGR_PLLSRC_HSI16; + reg32 |= ((PLLM - 1) << 4); + reg32 |= PLLN << 8; + reg32 |= ((PLLP - 1) << 17); + reg32 |= ((PLLQ - 1) << 25); + reg32 |= ((PLLR - 1) << 29); + RCC_PLLCFGR = reg32; + + DMB(); + /* Enable PLL oscillator and wait for it to stabilize. */ + RCC_PLLCFGR |= RCC_PLLCFGR_PLLR_EN; + RCC_CR |= RCC_CR_PLLON; + + DMB(); + while ((RCC_CR & RCC_CR_PLLRDY) == 0) {}; + + /* Select PLL as SYSCLK source. */ + reg32 = RCC_CFGR; + reg32 &= ~((1 << 1) | (1 << 0)); + RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL); + DMB(); + + /* Wait for PLL clock to be selected. */ + while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SW_PLL) {}; + + /* SYSCFG, COMP and VREFBUF clock enable */ + APB2_CLOCK_ER|=SYSCFG_APB2_CLOCK_ER; +} + +#endif /** PLATFORM_stm32f4 **/