Add 0x04_pwm_cbm: bare-metal RP2350 PWM driver

- PWM slice 4, channel B on GPIO25 (onboard LED)
- Duty cycle sweep 0-100% in 5% steps for breathing effect
- Wrap 9999 with no clock division (~650 Hz from ROSC)
- UART reports each duty step
- 1390B FLASH, 11 source files, zero warnings
This commit is contained in:
Kevin Thomas
2026-04-05 16:21:47 -04:00
parent d912771a5e
commit 7a42b2e088
33 changed files with 2385 additions and 0 deletions
+214
View File
@@ -0,0 +1,214 @@
/**
******************************************************************************
* @file rp2350.h
* @author Kevin Thomas
* @brief RP2350 Device Peripheral Access Layer Header File.
*
* Memory-mapped register structures and peripheral base addresses
* for the RP2350 microcontroller (Cortex-M33 dual-core). All
* register offsets verified against the RP2350 datasheet
* (RP-008373-DS-2).
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_H
#define __RP2350_H
#include <stdint.h>
#include <stdbool.h>
/*!< Defines 'read / write' permissions */
#define __IO volatile
/*!< Stack addresses */
#define STACK_TOP 0x20082000UL
#define STACK_LIMIT 0x2007A000UL
/*!< Memory map */
#define XIP_BASE 0x10000000UL
#define SRAM_BASE 0x20000000UL
#define SIO_BASE 0xD0000000UL
#define PPB_BASE 0xE0000000UL
/*!< APB peripherals */
#define CLOCKS_BASE 0x40010000UL
#define RESETS_BASE 0x40020000UL
#define IO_BANK0_BASE 0x40028000UL
#define PADS_BANK0_BASE 0x40038000UL
#define XOSC_BASE 0x40048000UL
#define UART0_BASE 0x40070000UL
#define PWM_BASE 0x400A8000UL
/**
* @brief XOSC (External Crystal Oscillator)
*/
typedef struct
{
__IO uint32_t CTRL; // Control register Address offset: 0x00
__IO uint32_t STATUS; // Status register Address offset: 0x04
__IO uint32_t DORMANT; // Dormant mode Address offset: 0x08
__IO uint32_t STARTUP; // Startup delay Address offset: 0x0C
__IO uint32_t COUNT; // Frequency count Address offset: 0x10
} XOSC_TypeDef;
/**
* @brief CLOCKS
*/
typedef struct
{
__IO uint32_t RESERVED0[18]; // Other clock registers Address offset: 0x00-0x44
__IO uint32_t CLK_PERI_CTRL; // Peripheral clock control Address offset: 0x48
} CLOCKS_TypeDef;
/**
* @brief RESETS
*/
typedef struct
{
__IO uint32_t RESET; // Reset control Address offset: 0x00
__IO uint32_t WDSEL; // Watchdog select Address offset: 0x04
__IO uint32_t RESET_DONE; // Reset done status Address offset: 0x08
} RESETS_TypeDef;
/**
* @brief IO_BANK0 GPIO Control (one per GPIO)
*/
typedef struct
{
__IO uint32_t STATUS; // GPIO status Address offset: 0x00
__IO uint32_t CTRL; // GPIO control Address offset: 0x04
} IO_BANK0_GPIO_TypeDef;
/**
* @brief IO_BANK0
*/
typedef struct
{
IO_BANK0_GPIO_TypeDef GPIO[30]; // GPIO 0-29 status/ctrl pairs Address offset: 0x000-0x0E8
} IO_BANK0_TypeDef;
/**
* @brief PADS_BANK0
*/
typedef struct
{
__IO uint32_t VOLTAGE_SELECT; // Voltage select Address offset: 0x00
__IO uint32_t GPIO[30]; // GPIO 0-29 pad control Address offset: 0x04-0x78
} PADS_BANK0_TypeDef;
/**
* @brief Peripheral Definitions
*/
#define XOSC ((XOSC_TypeDef *) XOSC_BASE)
#define CLOCKS ((CLOCKS_TypeDef *) CLOCKS_BASE)
#define RESETS ((RESETS_TypeDef *) RESETS_BASE)
#define IO_BANK0 ((IO_BANK0_TypeDef *) IO_BANK0_BASE)
#define PADS_BANK0 ((PADS_BANK0_TypeDef *) PADS_BANK0_BASE)
#define SIO ((volatile uint32_t *) SIO_BASE)
#define CPACR ((volatile uint32_t *) (PPB_BASE + 0x0ED88UL))
/**
* @brief XOSC bit definitions
*/
#define XOSC_STATUS_STABLE_SHIFT 31U
/**
* @brief CPACR bit definitions
*/
#define CPACR_CP0_SHIFT 0U
#define CPACR_CP1_SHIFT 1U
/**
* @brief CLOCKS bit definitions
*/
#define CLK_PERI_CTRL_ENABLE_SHIFT 11U
#define CLK_PERI_CTRL_AUXSRC_SHIFT 5U
#define CLK_PERI_CTRL_AUXSRC_XOSC 4U
/**
* @brief RESETS bit definitions
*/
#define RESETS_RESET_IO_BANK0_SHIFT 6U
#define RESETS_RESET_PWM_SHIFT 16U
#define RESETS_RESET_UART0_SHIFT 26U
/**
* @brief IO_BANK0 bit definitions
*/
#define IO_BANK0_CTRL_FUNCSEL_MASK 0x1FU
#define IO_BANK0_CTRL_FUNCSEL_UART 0x02U
#define IO_BANK0_CTRL_FUNCSEL_PWM 0x04U
#define IO_BANK0_CTRL_FUNCSEL_SIO 0x05U
/**
* @brief PADS_BANK0 bit definitions
*/
#define PADS_BANK0_OD_SHIFT 7U
#define PADS_BANK0_IE_SHIFT 6U
#define PADS_BANK0_ISO_SHIFT 8U
/**
* @brief UART register offsets (word indices from UART0_BASE)
*/
#define UART_DR_OFFSET (0x000U / 4U)
#define UART_FR_OFFSET (0x018U / 4U)
#define UART_IBRD_OFFSET (0x024U / 4U)
#define UART_FBRD_OFFSET (0x028U / 4U)
#define UART_LCR_H_OFFSET (0x02CU / 4U)
#define UART_CR_OFFSET (0x030U / 4U)
/**
* @brief UART flag register bit definitions
*/
#define UART_FR_TXFF_MASK 32U
#define UART_FR_RXFE_MASK 16U
/**
* @brief UART line control and enable values
*/
#define UART_LCR_H_8N1_FIFO 0x70U
#define UART_CR_ENABLE ((3U << 8) | 1U)
/**
* @brief GPIO pin definitions
*/
#define LED_PIN 25U
/**
* @brief SIO GPIO register offsets (word indices from SIO_BASE)
*/
#define SIO_GPIO_IN_OFFSET (0x004U / 4U)
#define SIO_GPIO_OUT_SET_OFFSET (0x018U / 4U)
#define SIO_GPIO_OUT_CLR_OFFSET (0x020U / 4U)
#define SIO_GPIO_OUT_XOR_OFFSET (0x028U / 4U)
#define SIO_GPIO_OE_SET_OFFSET (0x038U / 4U)
/**
* @brief PWM register offsets (per slice, stride 0x14)
*/
#define PWM_CH_CSR_OFFSET 0x00U
#define PWM_CH_DIV_OFFSET 0x04U
#define PWM_CH_CC_OFFSET 0x0CU
#define PWM_CH_TOP_OFFSET 0x10U
#define PWM_CH_STRIDE 0x14U
/**
* @brief PWM bit definitions
*/
#define PWM_CSR_EN_SHIFT 0U
#define PWM_DIV_INT_SHIFT 4U
#define PWM_CC_B_SHIFT 16U
#define PWM_WRAP_DEFAULT 9999U
#endif /* __RP2350_H */
@@ -0,0 +1,33 @@
/**
******************************************************************************
* @file rp2350_coprocessor.h
* @author Kevin Thomas
* @brief Coprocessor access control driver header for RP2350.
*
* Enables coprocessor access via the CPACR register.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_COPROCESSOR_H
#define __RP2350_COPROCESSOR_H
#include "rp2350.h"
/**
* @brief Enable coprocessor access via CPACR with DSB/ISB barriers.
* @retval None
*/
void coprocessor_enable(void);
#endif /* __RP2350_COPROCESSOR_H */
+34
View File
@@ -0,0 +1,34 @@
/**
******************************************************************************
* @file rp2350_delay.h
* @author Kevin Thomas
* @brief Delay driver header for RP2350.
*
* Millisecond busy-wait delay calibrated for a 14.5 MHz clock.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_DELAY_H
#define __RP2350_DELAY_H
#include "rp2350.h"
/**
* @brief Delay for the specified number of milliseconds.
* @param ms number of milliseconds to delay
* @retval None
*/
void delay_ms(uint32_t ms);
#endif /* __RP2350_DELAY_H */
+63
View File
@@ -0,0 +1,63 @@
/**
******************************************************************************
* @file rp2350_gpio.h
* @author Kevin Thomas
* @brief GPIO driver header for RP2350.
*
* SIO-based GPIO configuration, set, clear, toggle, and read
* functions for the RP2350 GPIO pins 0-29.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_GPIO_H
#define __RP2350_GPIO_H
#include "rp2350.h"
/**
* @brief Configure a GPIO pin as SIO output.
* @param gpio_num GPIO pin number (0-29)
* @retval None
*/
void gpio_config(uint32_t gpio_num);
/**
* @brief Drive a GPIO output high.
* @param gpio_num GPIO pin number (0-29)
* @retval None
*/
void gpio_set(uint32_t gpio_num);
/**
* @brief Drive a GPIO output low.
* @param gpio_num GPIO pin number (0-29)
* @retval None
*/
void gpio_clear(uint32_t gpio_num);
/**
* @brief Toggle a GPIO output.
* @param gpio_num GPIO pin number (0-29)
* @retval None
*/
void gpio_toggle(uint32_t gpio_num);
/**
* @brief Read the current input level of a GPIO pin.
* @param gpio_num GPIO pin number (0-29)
* @retval bool true if pin is high, false if low
*/
bool gpio_get(uint32_t gpio_num);
#endif /* __RP2350_GPIO_H */
+63
View File
@@ -0,0 +1,63 @@
/**
******************************************************************************
* @file rp2350_led.h
* @author Kevin Thomas
* @brief LED driver header for RP2350.
*
* High-level GPIO output / LED driver wrapping the
* low-level GPIO functions.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_LED_H
#define __RP2350_LED_H
#include "rp2350.h"
/**
* @brief Initialize a GPIO pin as a push-pull digital output.
* @param pin GPIO pin number to configure
* @retval None
*/
void led_init(uint32_t pin);
/**
* @brief Drive the output pin high (LED on).
* @param pin GPIO pin number
* @retval None
*/
void led_on(uint32_t pin);
/**
* @brief Drive the output pin low (LED off).
* @param pin GPIO pin number
* @retval None
*/
void led_off(uint32_t pin);
/**
* @brief Toggle the current state of the output pin.
* @param pin GPIO pin number
* @retval None
*/
void led_toggle(uint32_t pin);
/**
* @brief Query the current drive state of the output pin.
* @param pin GPIO pin number
* @retval bool true if the pin is driven high, false if low
*/
bool led_get_state(uint32_t pin);
#endif /* __RP2350_LED_H */
+48
View File
@@ -0,0 +1,48 @@
/**
******************************************************************************
* @file rp2350_pwm.h
* @author Kevin Thomas
* @brief PWM driver header for RP2350.
*
* Provides PWM output on GPIO 25 (onboard LED) at approximately
* 1 kHz using PWM slice 4, channel B. Duty cycle is controllable
* from 0 to 100 percent.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_PWM_H
#define __RP2350_PWM_H
#include "rp2350.h"
/**
* @brief Release PWM from reset and wait until ready.
* @retval None
*/
void pwm_release_reset(void);
/**
* @brief Initialize PWM on GPIO 25 at approximately 1 kHz.
* @retval None
*/
void pwm_init(void);
/**
* @brief Set the PWM duty cycle as an integer percentage.
* @param percent duty cycle from 0 (off) to 100 (fully on)
* @retval None
*/
void pwm_set_duty(uint8_t percent);
#endif /* __RP2350_PWM_H */
+33
View File
@@ -0,0 +1,33 @@
/**
******************************************************************************
* @file rp2350_reset.h
* @author Kevin Thomas
* @brief Reset controller driver header for RP2350.
*
* Provides subsystem reset release for IO_BANK0.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_RESET_H
#define __RP2350_RESET_H
#include "rp2350.h"
/**
* @brief Release IO_BANK0 from reset and wait until ready.
* @retval None
*/
void reset_init_subsystem(void);
#endif /* __RP2350_RESET_H */
@@ -0,0 +1,33 @@
/**
******************************************************************************
* @file rp2350_reset_handler.h
* @author Kevin Thomas
* @brief Reset handler header for RP2350.
*
* Entry point after reset. Performs stack initialization, XOSC
* setup, subsystem reset release, UART initialization,
* coprocessor enable, and branches to main().
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_RESET_HANDLER_H
#define __RP2350_RESET_HANDLER_H
/**
* @brief Reset handler entry point (naked, noreturn).
* @retval None
*/
void Reset_Handler(void) __attribute__((noreturn));
#endif /* __RP2350_RESET_HANDLER_H */
+34
View File
@@ -0,0 +1,34 @@
/**
******************************************************************************
* @file rp2350_stack.h
* @author Kevin Thomas
* @brief Stack pointer initialization header for RP2350.
*
* Sets MSP, PSP, MSPLIM, and PSPLIM from the STACK_TOP and
* STACK_LIMIT values defined in rp2350.h.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_STACK_H
#define __RP2350_STACK_H
#include "rp2350.h"
/**
* @brief Initialize MSP, PSP, MSPLIM, and PSPLIM stack pointers.
* @retval None
*/
void stack_init(void);
#endif /* __RP2350_STACK_H */
+73
View File
@@ -0,0 +1,73 @@
/**
******************************************************************************
* @file rp2350_uart.h
* @author Kevin Thomas
* @brief UART0 driver header for RP2350.
*
* Bare-metal UART0 driver supporting TX/RX on GPIO 0/1 at
* 115200 baud (14.5 MHz XOSC clock).
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_UART_H
#define __RP2350_UART_H
#include "rp2350.h"
/**
* @brief Release UART0 from reset and wait until ready.
* @retval None
*/
void uart_release_reset(void);
/**
* @brief Initialize UART0 pins, baud rate, line control, and enable.
* @retval None
*/
void uart_init(void);
/**
* @brief Check whether a received byte is waiting in the UART FIFO.
* @retval bool true if at least one byte is available
*/
bool uart_is_readable(void);
/**
* @brief Read one character from UART0 (blocking).
* @retval char the received character
*/
char uart_getchar(void);
/**
* @brief Transmit one character over UART0 (blocking).
* @param c character to transmit
* @retval None
*/
void uart_putchar(char c);
/**
* @brief Transmit a null-terminated string over UART0.
* @param str pointer to the string to send
* @retval None
*/
void uart_puts(const char *str);
/**
* @brief Convert a lowercase ASCII character to uppercase.
* @param c input character
* @retval char uppercase equivalent or original character
*/
char uart_to_upper(char c);
#endif /* __RP2350_UART_H */
+40
View File
@@ -0,0 +1,40 @@
/**
******************************************************************************
* @file rp2350_xosc.h
* @author Kevin Thomas
* @brief XOSC driver header for RP2350.
*
* External crystal oscillator initialization and peripheral
* clock enable using the XOSC registers.
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 Kevin Thomas.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef __RP2350_XOSC_H
#define __RP2350_XOSC_H
#include "rp2350.h"
/**
* @brief Initialize the external crystal oscillator and wait until stable.
* @retval None
*/
void xosc_init(void);
/**
* @brief Enable the XOSC peripheral clock via CLK_PERI_CTRL.
* @retval None
*/
void xosc_enable_peri_clk(void);
#endif /* __RP2350_XOSC_H */