add support for PIC32CZ and PIC32CK

master
Marco Oliverio 2025-05-14 07:58:09 +02:00 committed by Daniele Lacamera
parent 4154057649
commit 2d6cf95c20
16 changed files with 1286 additions and 1 deletions

View File

@ -0,0 +1,21 @@
name: Test PIC32CZ and PIC32CK Build
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-pic32cz:
uses: ./.github/workflows/test-build.yml
with:
arch: ARM
config-file: config/examples/pic32cz.config
make-args: "TARGET=pic32cz"
build-pic32ck:
uses: ./.github/workflows/test-build.yml
with:
arch: ARM
config-file: config/examples/pic32ck.config
make-args: "TARGET=pic32ck"

12
arch.mk
View File

@ -156,6 +156,18 @@ ifeq ($(ARCH),ARM)
SPI_TARGET=stm32
endif
ifeq ($(TARGET),pic32cz)
ARCH_FLASH_OFFSET=0x08000000
CORTEX_M7=1
OBJS+=hal/pic32c.o
endif
ifeq ($(TARGET),pic32ck)
ARCH_FLASH_OFFSET=0x08000000
CORTEX_M33=1
OBJS+=hal/pic32c.o
endif
ifeq ($(TARGET),stm32l4)
SPI_TARGET=stm32
ARCH_FLASH_OFFSET=0x08000000

View File

@ -0,0 +1,14 @@
ARCH=ARM
TARGET=pic32ck
SIGN?=ED25519
HASH?=SHA256
VTOR?=1
SPMATH?=1
NO_MPU=1
WOLFBOOT_PARTITION_SIZE=0x10000
BOOTLOADER_PARTITION_SIZE=0x20000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x0c000000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0c07f000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0c0fe000
TZEN=0

View File

@ -0,0 +1,13 @@
ARCH=ARM
TARGET=pic32cz
SIGN?=ED25519
HASH?=SHA256
VTOR?=1
SPMATH?=1
NO_MPU=1
WOLFBOOT_PARTITION_SIZE=0x10000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x0c000000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0c200000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0c030000
#DUALBANK_SWAP=0

View File

@ -44,7 +44,8 @@ This README describes configuration of supported targets.
* [STM32WB55](#stm32wb55)
* [TI Hercules TMS570LC435](#ti-hercules-tms570lc435)
* [Xilinx Zynq UltraScale](#xilinx-zynq-ultrascale)
* [Microchip PIC32CZ](#microchip-pic32cz)
* [Microchip PIC32CK](#microchip-pic32ck)
## STM32F4
@ -3402,3 +3403,145 @@ wolfBoot supports the AURIX TC3xx family of devices, and provides a demo applica
For detailed instructions on using wolfBoot with the AURIX TC3xx, please refer to [IDE/AURIX/README.md](../IDE/AURIX/README.md).
wolfBoot can also integrate with [wolfHSM](https://www.wolfssl.com/products/wolfhsm/) on AURIX TC3xx devices, offloading cryptographic operations and key storage to the AURIX HSM core. For more information on using wolfBoot with wolfHSM on AURIX devices, please contact us at facts@wolfssl.com.
## Microchip PIC32CZ
The PIC32CZ is a high-performance 32-bit microcontroller family from Microchip featuring an ARM Cortex-M7 core. wolfBoot has been tested on the PIC32CZCA91 Curiosity board, which has GPIO pins PB21 and PB22 connected to LED0 and LED1, respectively, for status indication.
### Configuration
The PIC32CZ supports a dual-bank update mechanism that can be activated using the `DUALBANK_SWAP=1` option in the configuration file. When activated, the boot partition must be configured to reside in the lower Program Flash Memory (PFM) area, while the update partition should be in the upper PFM area. An example configuration for the PIC32CZ with 4MB RAM is provided in `config/examples/pic32cz.config`.
### Building
To build wolfBoot for the PIC32CZ:
1. Configure the build using the example configuration file:
```sh
cp config/examples/pic32cz.config .config
make clean
make
```
2. Sign the application:
```sh
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 1
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 2
```
### Programming and Testing
To program the flash chip using the JLink tool:
Identify the correct JLink device for your PIC32CZ board. In the examples the model is PIC32CZ4010CA90.
1. Run the following command:
```sh
JLinkExe -device PIC32CZ4010CA90 -if SWD -speed 4000 -autoconnect 1
```
2. At the JLink prompt, use the following commands:
```
halt
reset
erase
loadfile wolfboot.bin 0x08000000
loadfile test-app/image_v1_signed.bin 0x0c000000
loadfile test-app/image_v2_signed.bin 0x0c200000
reset
q
```
### Programming with MPlab IPE
In order to program using the MPlab IPE, you need to create the hex files for wolfBoot, and the signed application images:
```bash
arm-none-eabi-objcopy -O ihex wolfboot.elf wolfboot.hex
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C000000 test-app/image_v1_signed.bin image_v1_signed.hex
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C200000 test-app/image_v2_signed.bin image_v2_signed.hex
```
Then enable advanced setting in the MPLAB IPE Gui, and enable the "Allow Import Multiple Hex file" option in the Production view.
After that load the hex files into the MPLAB IPE Gui (File -> Import -> Multiple hex) and program the device.
### Behavior During Testing
The test behavior depends on whether the `DUALBANK_SWAP` feature is enabled:
- **If `DUALBANK_SWAP=1`:** The higher version of the application will be automatically selected, and LED1 will turn on.
- **If `DUALBANK_SWAP=0`:** The application version 1 will boot first. The application will trigger the update and light LED0. On the next reset, wolfBoot will update the application, boot application version 2, and turn on LED1.
## Microchip PIC32CK
The PIC32CK is a high-performance 32-bit microcontroller family from Microchip featuring an ARM Cortex-M33 core. wolfBoot has been tested on the PIC32CKSG Curiosity board, which has GPIO pins PD20 and PB25 connected to LED0 and LED1, respectively, for status indication.
### Configuration
The PIC32CK SG family models support TrustZone. The flash and memory areas marked as secure or non secure depend on configuration settings. If setting `TZEN=0`, wolfBoot ignores TrustZone configuration, with the net effect to stage the application in the secure domain. In this case the flash area used to store BOOT and UPDATE partition should be marked as secure. The config file provided in `config/examples/pic32ck.config` sets `TZEN=0` and uses flash partition addresses that are marked as secure under default settings.
The PIC32CK supports a dual-bank update mechanism but, based on configuration settings, the swap may cause an area marked as secure to be mapped in non-secure flash space. For this reason `DUALBANK_SWAP` feature should be only used after precise configuration.
### Building
To build wolfBoot for the PIC32CK:
1. Configure the build using the example configuration file:
```sh
cp config/examples/pic32ck.config .config
make clean
make
```
2. Sign the application:
```sh
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 1
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 2
```
### Programming and Testing
To program the flash chip using the JLink tool:
Identify the correct JLink device for your PIC32CK. In the examples the model is PIC32CK2051SG.
1. Run the following command:
```sh
JLinkExe -device PIC32CK2051SG -if SWD -speed 4000 -autoconnect 1
```
2. At the JLink prompt, use the following commands:
```
halt
reset
erase
loadfile wolfboot.bin 0x08000000
loadfile test-app/image_v1_signed.bin 0x0c000000
loadfile test-app/image_v2_signed.bin 0x0c07f000
reset
q
```
### Programming with MPlab IPE
In order to program using the MPlab IPE, you need to create the hex files for wolfBoot, and the signed application images:
```bash
arm-none-eabi-objcopy -O ihex wolfboot.elf wolfboot.hex
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C000000 test-app/image_v1_signed.bin image_v1_signed.hex
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C07F000 test-app/image_v2_signed.bin image_v2_signed.hex
```
Then enable advanced setting in the MPLAB IPE Gui, and enable the "Allow Import Multiple Hex file" option in the Production view.
After that load the hex files into the MPLAB IPE Gui (File -> Import -> Multiple hex) and program the device.
### Behavior During Testing
- The application version 1 will boot first. The application will trigger the update and light LED0. On the next reset, wolfBoot will update the application, boot application version 2, and turn on LED1.

513
hal/pic32c.c 100644
View File

@ -0,0 +1,513 @@
/* pic32c.c
*
* Copyright (C) 2025 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 "image.h"
#include "loader.h"
#include <stdint.h>
#include <string.h>
#if defined(TARGET_pic32cz)
#include "pic32cz_registers.h"
#elif defined(TARGET_pic32ck)
#include "pic32ck_registers.h"
#endif
#define FCW_CTRLA (*(volatile uint32_t *)(FCW_BASE + 0x00U))
#define FCW_CTRLB (*(volatile uint32_t *)(FCW_BASE + 0x04U))
#define FCW_MUTEX (*(volatile uint32_t *)(FCW_BASE + 0x08U))
#define FCW_INTENCLR (*(volatile uint32_t *)(FCW_BASE + 0x0CU))
#define FCW_INTENSET (*(volatile uint32_t *)(FCW_BASE + 0x10U))
#define FCW_INTFLAG (*(volatile uint32_t *)(FCW_BASE + 0x14U))
#define FCW_STATUS (*(volatile uint32_t *)(FCW_BASE + 0x18U))
#define FCW_KEY (*(volatile uint32_t *)(FCW_BASE + 0x1CU))
#define FCW_ADDR (*(volatile uint32_t *)(FCW_BASE + 0x20U))
#define FCW_SRCADDR (*(volatile uint32_t *)(FCW_BASE + 0x24U))
#define FCW_DATA ((volatile uint32_t *)(FCW_BASE + 0x28U))
#define FCW_SWAP (*(volatile uint32_t *)(FCW_BASE + 0x48U))
#define FCW_PWP ((volatile uint32_t *)(FCW_BASE + 0x4CU))
#define FCW_LBWP (*(volatile uint32_t *)(FCW_BASE + 0x6CU))
#define FCW_UBWP (*(volatile uint32_t *)(FCW_BASE + 0x70U))
#define FCW_UOWP (*(volatile uint32_t *)(FCW_BASE + 0x74U))
#define FCW_CWP (*(volatile uint32_t *)(FCW_BASE + 0x78U))
#define FCW_HSMINTENCLR (*(volatile uint32_t *)(FCW_BASE + 0x80U))
#define FCW_HSMINTENSET (*(volatile uint32_t *)(FCW_BASE + 0x84U))
#define FCW_HSMINTFLAG (*(volatile uint32_t *)(FCW_BASE + 0x88U))
#define FCW_HSMCWP (*(volatile uint32_t *)(FCW_BASE + 0x8CU))
#define FCW_HSMLDAT ((volatile uint32_t *)(FCW_BASE + 0x90U))
#define FCW_HSMUDAT ((volatile uint32_t *)(FCW_BASE + 0xB0U))
#define FCW_UNLOCK_WRKEY 0x91C32C01
#define FCW_UNLOCK_SWAPKEY 0x91C32C02
#define FCW_UNLOCK_CFGKEY 0x91C32C04
#define FCW_OP_ERASE_SECTOR 0x4
#define FCW_OP_QUAD_DOUBLE_WORD_WRITE 0x2
#define FCW_OP_NOOP 0x0
#define FCW_BUSY_MASK (1 << 0)
#define FCW_CTRLA_PREPG_BIT (1 << 7)
#define FCW_CTRLA_NVMOP_MASK ((1 << 4) - 1)
#define FCW_INTFLAG_DONE_BIT (1 << 0)
#define FCW_SWAP_PFSWAP (1 << 8)
/*
* bit 0 lock
* bit [1:2] owner (01 = mcu)
*/
#define FCW_OWN_MCU (0x1 << 1)
#define FCW_OWN_AND_LOCK 0x3
#define FCW_MUTEX_LOCK_MASK 0x1
#define FCW_WRITE_SIZE (4 * 8)
static uint32_t pic32_last_err = 0;
#define OSCCTRL_STATUS (*(volatile uint32_t *)(OSCCTRL_BASE + 0x10U))
#define OSCCTRL_INTFLAG (*(volatile uint32_t *)(OSCCTRL_BASE + 0x0CU))
#define OSCCTRL_PLL0CTRL (*(volatile uint32_t *)(OSCCTRL_BASE + 0x40U))
#define OSCCTRL_PLL0FBDIV (*(volatile uint32_t *)(OSCCTRL_BASE + 0x44U))
#define OSCCTRL_PLL0REFDIV (*(volatile uint32_t *)(OSCCTRL_BASE + 0x48U))
#define OSCCTRL_PLL0POSTDIV0 (*(volatile uint32_t *)(OSCCTRL_BASE + 0x4CU))
#define OSCCTRL_FRACDIV0 (*(volatile uint32_t *)(OSCCTRL_BASE + 0x6CU))
#define OSCCTRL_SYNCBUSY (*(volatile uint32_t *)(OSCCTRL_BASE + 0x78U))
#define OSCCTRL_SYNCBUSY_FRACDIV0_MASK (1 << 6)
#define OSCCTRL_FRACDIV0_REMDIV_SHIFT (7)
#define OSCCTRL_FRACDIV0_REMDIV(X) ((X) << OSCCTRL_FRACDIV0_REMDIV_SHIFT)
#define OSCCTRL_FRACDIV0_INTDIV_SHIFT (16)
#define OSCCTRL_FRACDIV0_INTDIV(X) ((X) << OSCCTRL_FRACDIV0_INTDIV_SHIFT)
#define OSCCTRL_PLL0POSTDIV0_EN (1 << 0x7)
#define OSCCTRL_PLL0CTRL_BWSEL_SHIFT (11)
#define OSCCTRL_PLL0CTRL_BWSEL(X) ((X) << OSCCTRL_PLL0CTRL_BWSEL_SHIFT)
#define OSCCTRL_PLL0CTRL_REFSEL_SHIFT (8)
#define OSCCTRL_PLL0CTRL_REFSEL(X) ((X) << OSCCTRL_PLL0CTRL_REFSEL_SHIFT)
#define OSCCTRL_PLL0CTRL_EN (1 << 1)
#define OSCCTRL_STATUS_PLL0LOCK (1 << 24)
#define OSCCTRL_INTFLAG_PLL0LOCKR (1 << 24)
#define OSCCTRL_FRACDIV0 (*(volatile uint32_t *)(OSCCTRL_BASE + 0x6CU))
#define OSCCTRL_FRACDIV0_REMDIV_SHIFT (7)
#define OSCCTRL_FRACDIV0_REMDIV(X) ((X) << OSCCTRL_FRACDIV0_REMDIV_SHIFT)
#define OSCCTRL_FRACDIV0_INTDIV_SHIFT (16)
#define OSCCTRL_FRACDIV0_INTDIV(X) ((X) << OSCCTRL_FRACDIV0_INTDIV_SHIFT)
#define OSCCTRL_SYNCBUSY (*(volatile uint32_t *)(OSCCTRL_BASE + 0x78U))
#define OSCCTRL_SYNCBUSY_FRACDIV0_MASK (1 << 6)
#define GCLK_CTRLA (*(volatile uint32_t *)(GCLK_BASE + 0x00U))
#define GCLK_SYNCBUSY (*(volatile uint32_t *)(GCLK_BASE + 0x4U))
#define GCLK_GENCTRL ((volatile uint32_t *)(GCLK_BASE + 0x20U))
#define GCLK_GENCTRL_SRC_PLL0 (6)
#define GCLK_GENCTRL_GENEN (1 << 8)
#define GCLK_GENCTRL_DIV_SHIFT (16)
#define GCLK_GENCTRL_DIV(X) ((X) << GCLK_GENCTRL_DIV_SHIFT)
#define GCLK_SYNCBUSY_GENCTRL0 (1 << 2)
#define GCLK_CTRLA_SWRST (1)
#define MCLK_INTFLAG (*(volatile uint32_t *)(MCLK_BASE + 0x08U))
#define MCLK_DIV0 (*(volatile uint32_t *)(MCLK_BASE + 0x0CU))
#define MCLK_DIV1 (*(volatile uint32_t *)(MCLK_BASE + 0x10U))
#define MCLK_INTFLAG_CKRDY (1)
void pic32_fcw_grab(void)
{
do {
while (FCW_MUTEX & FCW_MUTEX_LOCK_MASK) {
/* wait for ownership */
/* if mutex is locked by us, we can unlock it */
if ((FCW_MUTEX & FCW_OWN_MCU) == FCW_OWN_MCU) {
FCW_MUTEX = FCW_OWN_MCU;
}
}
FCW_MUTEX = FCW_OWN_AND_LOCK;
} while (FCW_MUTEX != FCW_OWN_AND_LOCK);
}
void pic32_fcw_release(void)
{
FCW_MUTEX = FCW_OWN_MCU;
}
static void pic32_fcw_start_op(uint32_t op)
{
FCW_CTRLA = FCW_CTRLA_PREPG_BIT | (op & FCW_CTRLA_NVMOP_MASK);
}
static uint32_t pic32_get_errs(void)
{
return FCW_INTFLAG;
}
static void pic32_clear_errs(void)
{
FCW_INTFLAG = 0xffffffff;
}
static void pic32_fcw_wait_complete(void)
{
while (FCW_STATUS & FCW_BUSY_MASK) {}
}
static int pic32_write_dqword_aligned(uint32_t addr, const uint8_t *data)
{
uint32_t i;
uint32_t *_data = (uint32_t *)data;
uint32_t err;
pic32_fcw_wait_complete();
FCW_ADDR = addr;
for (i = 0; i < 8; i++) {
FCW_DATA[i] = _data[i];
}
FCW_KEY = FCW_UNLOCK_WRKEY;
pic32_fcw_start_op(FCW_OP_QUAD_DOUBLE_WORD_WRITE);
pic32_fcw_wait_complete();
err = pic32_get_errs();
pic32_last_err = err;
err &= ~FCW_INTFLAG_DONE_BIT;
pic32_clear_errs();
return err;
}
static int pic32_addr_is_dqword_aligned(uint32_t addr)
{
return ((addr & 0x1F) == 0);
}
static uint32_t pic32_addr_dqword_align(uint32_t addr)
{
return (addr & ~0x1F);
}
static void pic32_copy_dqword(uint8_t *dst, uint32_t addr)
{
int i;
for (i = 0; i < FCW_WRITE_SIZE; i++) {
dst[i] = *(volatile uint8_t *)(addr + i);
}
}
static int pic32_fcw_erase_sector(uint32_t addr)
{
uint32_t err;
pic32_fcw_wait_complete();
FCW_ADDR = addr;
FCW_KEY = FCW_UNLOCK_WRKEY;
pic32_fcw_start_op(FCW_OP_ERASE_SECTOR);
pic32_fcw_wait_complete();
err = pic32_get_errs();
pic32_clear_errs();
pic32_last_err = err;
err &= ~FCW_INTFLAG_DONE_BIT;
return err;
}
static void pic32_delay_cnt(uint32_t ticks)
{
uint32_t i = 0;
for (i = 0; i < ticks; i++) {
__asm__("nop");
}
}
static uint8_t pic32_mask_zeros(uint8_t programmed, uint8_t to_program)
{
return to_program | (~programmed);
}
int pic32_flash_write(uint32_t address, const uint8_t *data, int len)
{
uint8_t buff[FCW_WRITE_SIZE], curr[FCW_WRITE_SIZE];
uint32_t _addr;
uint8_t i;
int ret;
while (len > 0) {
if (!pic32_addr_is_dqword_aligned(address) || len < FCW_WRITE_SIZE) {
_addr = pic32_addr_dqword_align(address);
/* Setup an aligned buffer with the following rules:
* - For bytes outside the writing range: 0xFF (no change)
* - For bytes inside the writing range: data | !current_data
*
* This approach ensures we only flip bits from 1 to 0 when writing
* without an erase operation. When the address is aligned and length
* is at least WOLFBOOT_SECTOR_SIZE, an erase was already performed,
* so we can write data directly.
*/
pic32_copy_dqword(curr, _addr);
memset(buff, 0xff, FCW_WRITE_SIZE);
i = address - _addr;
for (; i < FCW_WRITE_SIZE && len > 0; i++, len--) {
buff[i] = pic32_mask_zeros(curr[i], *data);
data++;
address++;
}
ret = pic32_write_dqword_aligned(_addr, buff);
if (ret != 0)
return ret;
continue;
}
ret = pic32_write_dqword_aligned(address, data);
if (ret != 0)
return ret;
address += FCW_WRITE_SIZE;
data += FCW_WRITE_SIZE;
len -= FCW_WRITE_SIZE;
}
return 0;
}
int pic32_flash_erase(uint32_t addr, int len)
{
int err;
while (len > 0) {
if (len < WOLFBOOT_SECTOR_SIZE) {
return -1;
}
err = pic32_fcw_erase_sector(addr);
if (err != 0)
return err;
addr += WOLFBOOT_SECTOR_SIZE;
len -= WOLFBOOT_SECTOR_SIZE;
}
return 0;
}
#ifdef DUALBANK_SWAP
static int pic32_fcw_pfswap_get()
{
return !!(FCW_SWAP & FCW_SWAP_PFSWAP);
}
static void pic32_fcw_pfswap_set(int sw)
{
uint32_t reg;
reg = FCW_SWAP;
reg &= FCW_SWAP_PFSWAP;
if (sw)
reg |= FCW_SWAP_PFSWAP;
FCW_KEY = FCW_UNLOCK_SWAPKEY;
FCW_SWAP = reg;
}
void pic32_flash_dualbank_swap(void)
{
uint32_t sw;
uint32_t reg;
pic32_fcw_wait_complete();
sw = pic32_fcw_pfswap_get();
pic32_fcw_pfswap_set(!sw);
}
#endif /* DUALBANK_SWAP */
void pic32_clock_fracdiv0_set(int intdiv, int remdiv)
{
OSCCTRL_FRACDIV0 =
OSCCTRL_FRACDIV0_INTDIV(intdiv) | OSCCTRL_FRACDIV0_REMDIV(remdiv);
while (OSCCTRL_SYNCBUSY & OSCCTRL_SYNCBUSY_FRACDIV0_MASK) {}
}
void pic32_clock_pll0_init(int refdiv, int fbdiv, int bw, int postdiv)
{
uint32_t reg;
/* configure pll0 */
OSCCTRL_PLL0CTRL = 0;
OSCCTRL_PLL0REFDIV = refdiv;
OSCCTRL_PLL0FBDIV = fbdiv;
/* enable PLL0 output 0 divied by 3 (300Mhz) */
OSCCTRL_PLL0POSTDIV0 = OSCCTRL_PLL0POSTDIV0_EN | postdiv;
reg = OSCCTRL_PLL0CTRL;
/* set the bandwith value */
reg |= OSCCTRL_PLL0CTRL_BWSEL(bw);
reg |= OSCCTRL_PLL0CTRL_REFSEL(0x2);
reg |= OSCCTRL_PLL0CTRL_EN;
OSCCTRL_PLL0CTRL |= reg;
/* wait to the PLL to lock */
#if defined(TARGET_pic32cz)
while (!(OSCCTRL_STATUS & OSCCTRL_STATUS_PLL0LOCK)) {}
#endif
#if defined(TARGET_pic32ck)
while (!(OSCCTRL_INTFLAG & OSCCTRL_INTFLAG_PLL0LOCKR)) {}
#endif
}
void pic32_clock_gclk_gen0(int mclk_div1, int cpudiv)
{
uint32_t reg;
/* setup clock division before changing the generator */
if (mclk_div1 != 1)
MCLK_DIV1 = mclk_div1;
while (!(MCLK_INTFLAG & MCLK_INTFLAG_CKRDY)) {}
GCLK_GENCTRL[0] =
GCLK_GENCTRL_SRC_PLL0 | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(cpudiv);
while (GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL0) {}
}
void pic32_clock_reset(void)
{
/* reset GCLK module */
GCLK_CTRLA = GCLK_CTRLA_SWRST;
/* wait for the reset to complete */
while (GCLK_CTRLA & GCLK_CTRLA_SWRST) {}
/* reset MCLK_DIV1 to reset value */
MCLK_DIV1 = 1;
while (!(MCLK_INTFLAG & MCLK_INTFLAG_CKRDY)) {}
/* turn off PLL0 */
OSCCTRL_PLL0CTRL = 0;
OSCCTRL_PLL0POSTDIV0 = 0x20202020;
/* reset PLL0 values */
OSCCTRL_PLL0REFDIV = 0;
OSCCTRL_PLL0FBDIV = 0;
/* reset the fracdiv0 to reset value */
pic32_clock_fracdiv0_set(32, 0);
}
#if defined(TEST_FLASH)
int hal_flash_test_align(void);
int hal_flash_test_write_once(void);
int hal_flash_test(void);
int hal_flash_test_dualbank(void);
void pic32_flash_test(void)
{
int ret;
ret = hal_flash_test();
if (ret != 0)
wolfBoot_panic();
ret = hal_flash_test_align();
if (ret != 0)
wolfBoot_panic();
ret = hal_flash_test_write_once();
if (ret != 0)
wolfBoot_panic();
#ifdef DUALBANK_SWAP
ret = hal_flash_test_dualbank();
if (ret != 0)
wolfBoot_panic();
#endif
}
#endif /* TEST_FLASH */
#ifdef TEST_CLOCK
/* SysTick registers and constants */
#define SYSTICK_BASE (0xE000E010U)
#define SYSTICK_RVR_MASK (0x00FFFFFF)
#define SYSTICK_CSR (*(volatile uint32_t *)(SYSTICK_BASE + 0x00U))
#define SYSTICK_RVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x04U))
#define SYSTICK_CVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x08U))
#define SYSTICK_CSR_ENABLE (1 << 0)
#define SYSTICK_CSR_CLKSOURCE (1 << 2)
#define SYSTICK_CSR_COUNTFLAG (1 << 16)
#if defined(TARGET_pic32ck)
#define PORT_BASE (0x44801000U)
#define LED_NO 25
#elif defined(TARGET_pic32cz)
#define PORT_BASE (0x44840000U)
#define LED_NO 21
#endif
#define PORTB_BASE (PORT_BASE + 0x80 * 1)
#define PORTB_DIRSET (*(volatile uint32_t *)(PORTB_BASE + 0x08))
#define PORTB_DIRSET_OUT(X) (1 << (X))
#define PORTB_OUTTGL (*(volatile uint32_t *)(PORTB_BASE + 0x1C))
#define PORTB_OUTTGL_PIN(X) (1 << (X))
static int systick_init_1ms(uint32_t cpu_freq)
{
/* Calculate the reload value for 1ms period */
uint32_t reload_value = (cpu_freq / 1000) - 1;
/* Check if reload value fits in 24 bits */
if (reload_value > SYSTICK_RVR_MASK) {
return -1;
}
/* Set reload value */
SYSTICK_RVR = reload_value;
/* Clear current value */
SYSTICK_CVR = 0;
/* Configure SysTick: enable counter, no interrupt, use CPU clock */
SYSTICK_CSR = SYSTICK_CSR_ENABLE | SYSTICK_CSR_CLKSOURCE;
return 0;
}
static void systick_delay_ms(uint32_t ms)
{
uint32_t i;
for (i = 0; i < ms; i++) {
/* Wait until COUNTFLAG is set */
while (!(SYSTICK_CSR & SYSTICK_CSR_COUNTFLAG)) {
/* Wait */
}
}
}
/**
* Tests clock configuration using SysTick. Initializes 1ms ticks,
* toggles LED every 1s for 10s, then every 100ms for 2s.
*/
void pic32_clock_test(unsigned long cpu_freq)
{
int i;
PORTB_DIRSET = PORTB_DIRSET_OUT(LED_NO);
/* Initialize SysTick with 1ms period based on target frequency */
if (systick_init_1ms(cpu_freq) != 0) {
wolfBoot_panic();
}
for (i = 0; i < 10; i++) {
systick_delay_ms(1000);
/* Wait for 1 second */
PORTB_OUTTGL = PORTB_OUTTGL_PIN(LED_NO);
}
/* end test by fast toggling */
for (i = 0; i < 20; i++) {
systick_delay_ms(100);
/* Wait for 1 second */
PORTB_OUTTGL = PORTB_OUTTGL_PIN(LED_NO);
}
}
#endif /* TEST_CLOCK */

46
hal/pic32c.h 100644
View File

@ -0,0 +1,46 @@
/* pic32c.h
*
* Copyright (C) 2025 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
*/
#ifndef PIC32C_H
#define PIC32C_H
#include <stdint.h>
#if defined(TEST_FLASH)
void pic32_flash_test(void);
#endif
#if defined(DUALBANK_SWAP)
void pic32_flash_dualbank_swap(void);
#endif
void pic32_fcw_grab(void);
void pic32_fcw_release(void);
int pic32_flash_erase(uint32_t addr, int len);
int pic32_flash_write(uint32_t address, const uint8_t *data, int len);
void pic32_clock_pll0_init(int refdiv, int fbdiv, int bw, int postdiv);
void pic32_clock_fracdiv0_set(int intdiv, int remdiv);
void pic32_clock_gclk_gen0(int mclk_div1, int cpudiv);
void pic32_clock_reset(void);
#if defined(TEST_CLOCK)
void pic32_clock_test(unsigned long cpu_freq);
#endif /* TEST_CLOCK */
#endif /* PIC32C_H */

79
hal/pic32ck.c 100644
View File

@ -0,0 +1,79 @@
/* pic32ck.c
*
* Copyright (C) 2025 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 <hal/pic32c.h>
#include <stdint.h>
int hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
return pic32_flash_write(address, data, len);
}
void hal_flash_lock(void)
{
pic32_fcw_grab();
}
void hal_flash_unlock(void)
{
pic32_fcw_release();
}
int hal_flash_erase(uint32_t addr, int len)
{
return pic32_flash_erase(addr, len);
}
#ifdef DUALBANK_SWAP
void hal_flash_dualbank_swap(void)
{
pic32_flash_dualbank_swap();
}
#endif /* DUALBANK_SWAP */
void hal_init(void)
{
#if defined(TEST_CLOCK)
/* toogle led at 1hz for 10sec */
pic32_clock_test(48000000U);
#endif
pic32_clock_fracdiv0_set(0, 0);
pic32_clock_pll0_init(12, 240, 1, 8);
pic32_clock_gclk_gen0(1, 1);
#if defined(TEST_FLASH)
pic32_flash_test();
while (1) {}
#endif
#if defined(TEST_CLOCK)
/* toogle led at 1hz */
pic32_clock_test(120000000U);
pic32_clock_reset();
pic32_clock_test(48000000U);
while (1) {};
#endif
}
void hal_prepare_boot(void)
{
#ifndef TZEN
pic32_clock_reset();
#endif
}

61
hal/pic32ck.ld 100644
View File

@ -0,0 +1,61 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}
SECTIONS
{
.text :
{
_start_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
. = ALIGN(4);
_end_text = .;
} > FLASH
.edidx :
{
. = ALIGN(4);
*(.ARM.exidx*)
} > 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);
}
_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@;
_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@;
_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@;
_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@;
END_STACK = ORIGIN(RAM) + LENGTH(RAM);

View File

@ -0,0 +1,30 @@
/* pic32ck_registers.h
*
* Copyright (C) 2025 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
*/
#ifndef PIC32CK_REGISTERS_H
#define PIC32CK_REGISTERS_H
#define FCW_BASE (0x44004000U)
#define OSCCTRL_BASE (0x4400C000U)
#define GCLK_BASE (0x44010000U)
#define MCLK_BASE (0x44012000U)
#endif /* PIC32CZ_REGISTERS_H */

108
hal/pic32cz.c 100644
View File

@ -0,0 +1,108 @@
/* pic32cz.c
*
* Copyright (C) 2021 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 "image.h"
#include <stdint.h>
#include <string.h>
#include <hal/pic32c.h>
#define SUPC_BASE (0x44020000U)
#define SUPC_VREGCTRL (*(volatile uint32_t *)(SUPC_BASE + 0x1CU))
#define SUPC_STATUS (*(volatile uint32_t *)(SUPC_BASE + 0x0CU))
#define SUPC_VREGCTRL_AVREGEN_PLLREG_EN (4)
#define SUPC_VREGCTRL_AVREGEN_SHIFT (16)
#define SUPC_STATUS_ADDVREGRDY_PLL (4)
#define SUPC_STATUS_ADDVREGRDY_SHIFT (8)
static void pic32_supc_vreg_pll_enable(void)
{
uint32_t reg;
SUPC_VREGCTRL |= SUPC_VREGCTRL_AVREGEN_PLLREG_EN
<< SUPC_VREGCTRL_AVREGEN_SHIFT;
/* wait for the vreg to be ready */
while (!(SUPC_STATUS &
(SUPC_STATUS_ADDVREGRDY_PLL << SUPC_STATUS_ADDVREGRDY_SHIFT))) {}
}
#ifdef DUALBANK_SWAP
void hal_flash_dualbank_swap(void)
{
pic32_flash_dualbank_swap();
}
#endif /* DUALBANK_SWAP */
int hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
return pic32_flash_write(address, data, len);
}
void hal_flash_unlock(void)
{
pic32_fcw_grab();
}
void hal_flash_lock(void)
{
pic32_fcw_release();
}
int hal_flash_erase(uint32_t addr, int len)
{
return pic32_flash_erase(addr, len);
}
static void pic32_delay_cnt(uint32_t ticks)
{
uint32_t i = 0;
for (i = 0; i < ticks; i++) {
__asm__("nop");
}
}
void hal_init(void)
{
#if defined(TEST_CLOCK)
pic32_clock_test(48000000);
#endif
pic32_supc_vreg_pll_enable();
pic32_clock_pll0_init(12, 225, 1, 3);
pic32_clock_gclk_gen0(2, 1);
pic32_delay_cnt(700);
#if defined(TEST_FLASH)
pic32_flash_test();
while (1) {}
#endif
#if defined(TEST_CLOCK)
pic32_clock_test(300000000);
pic32_clock_reset();
pic32_clock_test(48000000);
while (1) {};
#endif
}
void hal_prepare_boot(void)
{
pic32_clock_reset();
}

61
hal/pic32cz.ld 100644
View File

@ -0,0 +1,61 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}
SECTIONS
{
.text :
{
_start_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
. = ALIGN(4);
_end_text = .;
} > FLASH
.edidx :
{
. = ALIGN(4);
*(.ARM.exidx*)
} > 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);
}
_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@;
_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@;
_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@;
_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@;
END_STACK = ORIGIN(RAM) + LENGTH(RAM);

View File

@ -0,0 +1,30 @@
/* pic32cz_registers.h
*
* Copyright (C) 2025 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
*/
#ifndef PIC32CZ_REGISTERS_H
#define PIC32CZ_REGISTERS_H
#define FCW_BASE (0x44002000U)
#define OSCCTRL_BASE (0x44040000U)
#define GCLK_BASE (0x44050000U)
#define MCLK_BASE (0x44052000U)
#endif /* PIC32CZ_REGISTERS_H */

View File

@ -451,6 +451,14 @@ ifeq ($(TARGET),nxp_ls1028a)
LSCRIPT_TEMPLATE:=AARCH64-ls1028a.ld
endif
ifeq ($(TARGET),pic32ck)
APP_OBJS+=../hal/pic32c.o
endif
ifeq ($(TARGET), pic32cz)
APP_OBJS+=../hal/pic32c.o
endif
CFLAGS+=-I../lib/wolfssl
ifeq ($(WOLFHSM_CLIENT),1)

View File

@ -0,0 +1,77 @@
/* app_pic32cz.c
*
* Test bare-metal boot-led-on application
*
* Copyright (C) 2025 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 "hal.h"
#include "target.h"
#include "wolfboot/wolfboot.h"
#include <stdint.h>
#if defined(TARGET_pic32ck)
#define PORT_BASE (0x44801000U)
#define PORTB_BASE (PORT_BASE + 0x80 * 1)
#define PORTB_DIRSET (*(volatile uint32_t *)(PORTB_BASE + 0x08))
#define PORTB_DIRSET_OUT(X) (1 << (X))
#define PORTB_OUTSET (*(volatile uint32_t *)(PORTB_BASE + 0x18))
#define PORTB_OUTSET_OUT(X) (1 << (X))
#define PORTB_OUTCLR (*(volatile uint32_t *)(PORTB_BASE + 0x14))
#define PORTB_OUTCLR_OUT(X) (1 << (X))
#define PORTD_BASE (PORT_BASE + 0x80 * 3)
#define PORTD_DIRSET (*(volatile uint32_t *)(PORTD_BASE + 0x08))
#define PORTD_DIRSET_OUT(X) (1 << (X))
#define PORTD_OUTSET (*(volatile uint32_t *)(PORTD_BASE + 0x18))
#define PORTD_OUTSET_OUT(X) (1 << (X))
#define PORTD_OUTCLR (*(volatile uint32_t *)(PORTD_BASE + 0x14))
#define PORTD_OUTCLR_OUT(X) (1 << (X))
static void led0_on(void)
{
PORTD_DIRSET = PORTD_DIRSET_OUT(20);
PORTD_OUTCLR = PORTD_OUTCLR_OUT(20);
}
static void led1_on(void)
{
PORTB_DIRSET = PORTB_DIRSET_OUT(25);
PORTB_OUTCLR = PORTB_OUTCLR_OUT(25);
}
void main(void)
{
uint32_t boot_version;
hal_init();
boot_version = wolfBoot_current_firmware_version();
if (boot_version == 1) {
wolfBoot_update_trigger();
led0_on();
} else if (boot_version >= 2) {
wolfBoot_success();
led1_on();
}
/* Wait for reboot */
while (1) {}
}
#endif /* TARGET_pic32ck */

View File

@ -0,0 +1,69 @@
/* app_pic32cz.c
*
* Test bare-metal boot-led-on application
*
* Copyright (C) 2025 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 "hal.h"
#include "target.h"
#include "wolfboot/wolfboot.h"
#include <stdint.h>
#if defined(TARGET_pic32cz)
#define PORT_BASE (0x44840000U)
#define PORTB_BASE (PORT_BASE + 0x80 * 1)
#define PORTB_DIRSET (*(volatile uint32_t *)(PORTB_BASE + 0x08))
#define PORTB_DIRSET_OUT(X) (1 << (X))
#define PORTB_OUTSET (*(volatile uint32_t *)(PORTB_BASE + 0x18))
#define PORTB_OUTSET_OUT(X) (1 << (X))
#define PORTB_OUTCLR (*(volatile uint32_t *)(PORTB_BASE + 0x14))
#define PORTB_OUTCLR_OUT(X) (1 << (X))
static void led0_on(void)
{
PORTB_DIRSET = PORTB_DIRSET_OUT(21);
PORTB_OUTCLR = PORTB_OUTCLR_OUT(21);
}
static void led1_on(void)
{
PORTB_DIRSET = PORTB_DIRSET_OUT(22);
PORTB_OUTCLR = PORTB_OUTCLR_OUT(22);
}
void main(void)
{
uint32_t boot_version;
hal_init();
boot_version = wolfBoot_current_firmware_version();
if (boot_version == 1) {
wolfBoot_update_trigger();
led0_on();
} else if (boot_version >= 2) {
wolfBoot_success();
led1_on();
}
/* Wait for reboot */
while (1) {}
}
#endif /* TARGET_pic32cz */