mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-08-27 21:30:37 +02:00
feat: add 0x0b_spi_cbm bare-metal SPI loopback driver
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file image_def.c
|
||||
* @author Kevin Thomas
|
||||
* @brief RP2350 IMAGE_DEF block for boot ROM image recognition.
|
||||
*
|
||||
* Must appear within the first 4 KB of flash for the boot ROM
|
||||
* to accept the image.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief IMAGE_DEF block structure placed in flash
|
||||
*/
|
||||
__attribute__((section(".embedded_block"), used))
|
||||
const uint8_t picobin_block[] = {
|
||||
0xD3, 0xDE, 0xFF, 0xFF,
|
||||
0x42, 0x01, 0x21, 0x10,
|
||||
0xFF, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x79, 0x35, 0x12, 0xAB
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file main.c
|
||||
* @author Kevin Thomas
|
||||
* @brief SPI loopback demonstration.
|
||||
*
|
||||
* Performs a full-duplex SPI0 transfer in master mode with
|
||||
* MOSI wired to MISO for loopback verification. Prints TX
|
||||
* and RX data over UART every second.
|
||||
*
|
||||
* Wiring (loopback test):
|
||||
* GPIO0 -> UART TX (USB-to-UART adapter RX)
|
||||
* GPIO1 -> UART RX (USB-to-UART adapter TX)
|
||||
* GPIO19 (MOSI) -> GPIO16 (MISO)
|
||||
* GPIO18 (SCK) -> logic analyzer (optional)
|
||||
* GPIO17 (CS) -> active-low slave (optional)
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_spi.h"
|
||||
#include "rp2350_uart.h"
|
||||
#include "rp2350_delay.h"
|
||||
#include "rp2350_xosc.h"
|
||||
|
||||
/**
|
||||
* @brief Hex digit lookup table for byte-to-hex conversion.
|
||||
*/
|
||||
static const char _hex_lut[16] = "0123456789ABCDEF";
|
||||
|
||||
/**
|
||||
* @brief Print a byte as a two-digit hex string over UART.
|
||||
* @param value byte to print
|
||||
* @retval None
|
||||
*/
|
||||
static void _print_hex(uint8_t value)
|
||||
{
|
||||
char buf[3];
|
||||
buf[0] = _hex_lut[value >> 4];
|
||||
buf[1] = _hex_lut[value & 0x0FU];
|
||||
buf[2] = '\0';
|
||||
uart_puts(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a buffer as hex bytes separated by spaces over UART.
|
||||
* @param label text label to print before the data
|
||||
* @param buf byte buffer to print
|
||||
* @param len number of bytes in buffer
|
||||
* @retval None
|
||||
*/
|
||||
static void _print_buffer(const char *label, const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
uart_puts(label);
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
_print_hex(buf[i]);
|
||||
if (i + 1 < len)
|
||||
uart_putchar(' ');
|
||||
}
|
||||
uart_puts("\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform one SPI loopback transfer and print TX/RX over UART.
|
||||
* @param tx_buf transmit buffer
|
||||
* @param rx_buf receive buffer (cleared after printing)
|
||||
* @param len number of bytes to transfer
|
||||
* @retval None
|
||||
*/
|
||||
static void _loopback_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t len)
|
||||
{
|
||||
spi_cs_select();
|
||||
spi_transfer(tx_buf, rx_buf, len);
|
||||
spi_cs_deselect();
|
||||
_print_buffer("TX: ", tx_buf, len);
|
||||
_print_buffer("RX: ", rx_buf, len);
|
||||
uart_puts("\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear a byte buffer to zero.
|
||||
* @param buf pointer to buffer
|
||||
* @param len number of bytes to clear
|
||||
* @retval None
|
||||
*/
|
||||
static void _clear_buffer(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Application entry point for the SPI loopback demo.
|
||||
* @retval int does not return
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/** @brief Transmit test pattern for SPI loopback. */
|
||||
static const uint8_t tx[] = {0xDE, 0xAD, 0xBE, 0xEF};
|
||||
/** @brief Buffer length for SPI loopback transfer. */
|
||||
static const uint32_t len = sizeof(tx);
|
||||
uint8_t rx[sizeof(tx)] = {0};
|
||||
xosc_set_clk_ref();
|
||||
spi_release_reset();
|
||||
spi_init();
|
||||
uart_puts("SPI loopback initialized (MOSI->MISO on GPIO19->GPIO16)\r\n");
|
||||
while (1) {
|
||||
_loopback_transfer(tx, rx, len);
|
||||
_clear_buffer(rx, len);
|
||||
delay_ms(1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_coprocessor.c
|
||||
* @author Kevin Thomas
|
||||
* @brief Coprocessor access control driver implementation for RP2350.
|
||||
*
|
||||
* Grants access to coprocessors 0 and 1 by setting the
|
||||
* corresponding bits in CPACR with DSB/ISB barriers.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_coprocessor.h"
|
||||
|
||||
void coprocessor_enable(void)
|
||||
{
|
||||
uint32_t value;
|
||||
value = *CPACR;
|
||||
value |= (1U << CPACR_CP1_SHIFT);
|
||||
value |= (1U << CPACR_CP0_SHIFT);
|
||||
*CPACR = value;
|
||||
__asm__ volatile ("dsb");
|
||||
__asm__ volatile ("isb");
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_delay.c
|
||||
* @author Kevin Thomas
|
||||
* @brief Delay driver implementation for RP2350.
|
||||
*
|
||||
* Busy-wait millisecond and microsecond delays calibrated for
|
||||
* a 12 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_delay.h"
|
||||
|
||||
void delay_ms(uint32_t ms)
|
||||
{
|
||||
if (ms == 0)
|
||||
return;
|
||||
__asm__ volatile (
|
||||
"mov r4, #3600\n\t"
|
||||
"mul r5, %0, r4\n\t"
|
||||
"1:\n\t"
|
||||
"subs r5, #1\n\t"
|
||||
"bne 1b\n\t"
|
||||
:
|
||||
: "r" (ms)
|
||||
: "r4", "r5", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
void delay_us(uint32_t us)
|
||||
{
|
||||
if (us == 0)
|
||||
return;
|
||||
__asm__ volatile (
|
||||
"mov r4, #4\n\t"
|
||||
"mul r5, %0, r4\n\t"
|
||||
"1:\n\t"
|
||||
"subs r5, #1\n\t"
|
||||
"bne 1b\n\t"
|
||||
:
|
||||
: "r" (us)
|
||||
: "r4", "r5", "cc"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_reset.c
|
||||
* @author Kevin Thomas
|
||||
* @brief Reset controller driver implementation for RP2350.
|
||||
*
|
||||
* Releases IO_BANK0 from reset and waits until the subsystem
|
||||
* is ready.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_reset.h"
|
||||
|
||||
void reset_init_subsystem(void)
|
||||
{
|
||||
uint32_t value;
|
||||
value = RESETS->RESET;
|
||||
value &= ~(1U << RESETS_RESET_IO_BANK0_SHIFT);
|
||||
RESETS->RESET = value;
|
||||
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_IO_BANK0_SHIFT)) == 0) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_reset_handler.c
|
||||
* @author Kevin Thomas
|
||||
* @brief Reset handler implementation for RP2350.
|
||||
*
|
||||
* Entry point after power-on or system reset. Initializes the
|
||||
* stack, XOSC, subsystem resets, UART, coprocessor, then
|
||||
* 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_reset_handler.h"
|
||||
#include "rp2350_stack.h"
|
||||
#include "rp2350_xosc.h"
|
||||
#include "rp2350_reset.h"
|
||||
#include "rp2350_spi.h"
|
||||
#include "rp2350_uart.h"
|
||||
#include "rp2350_coprocessor.h"
|
||||
|
||||
extern int main(void);
|
||||
|
||||
void __attribute__((naked, noreturn)) Reset_Handler(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"bl stack_init\n\t"
|
||||
"bl xosc_init\n\t"
|
||||
"bl xosc_enable_peri_clk\n\t"
|
||||
"bl reset_init_subsystem\n\t"
|
||||
"bl spi_release_reset\n\t"
|
||||
"bl uart_release_reset\n\t"
|
||||
"bl uart_init\n\t"
|
||||
"bl coprocessor_enable\n\t"
|
||||
"b main\n\t"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_spi.c
|
||||
* @author Kevin Thomas
|
||||
* @brief SPI0 master driver implementation for RP2350.
|
||||
*
|
||||
* Full-duplex SPI0 master on GPIO16 (MISO), GPIO17 (CS),
|
||||
* GPIO18 (SCK), GPIO19 (MOSI). Motorola SPI frame format,
|
||||
* 8-bit data, CPOL=0, CPHA=0, 1 MHz clock from 12 MHz
|
||||
* clk_peri.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_spi.h"
|
||||
|
||||
/**
|
||||
* @brief Bit mask for the chip-select pin.
|
||||
*/
|
||||
#define CS_PIN_MASK (1U << SPI_CS_PIN)
|
||||
|
||||
/**
|
||||
* @brief Clear the SPI0 reset bit in the reset controller.
|
||||
* @retval None
|
||||
*/
|
||||
static void _spi_clear_reset(void)
|
||||
{
|
||||
uint32_t value;
|
||||
value = RESETS->RESET;
|
||||
value &= ~(1U << RESETS_RESET_SPI0_SHIFT);
|
||||
RESETS->RESET = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait until SPI0 is out of reset.
|
||||
* @retval None
|
||||
*/
|
||||
static void _spi_wait_reset_done(void)
|
||||
{
|
||||
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_SPI0_SHIFT)) == 0) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure a GPIO pad for SPI: input enabled, no pull, no isolation.
|
||||
* @param pin GPIO pin number to configure
|
||||
* @retval None
|
||||
*/
|
||||
static void _configure_spi_pad(uint8_t pin)
|
||||
{
|
||||
uint32_t value;
|
||||
value = PADS_BANK0->GPIO[pin];
|
||||
value &= ~(1U << PADS_BANK0_OD_SHIFT);
|
||||
value |= (1U << PADS_BANK0_IE_SHIFT);
|
||||
value &= ~(1U << PADS_BANK0_ISO_SHIFT);
|
||||
PADS_BANK0->GPIO[pin] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure a GPIO pad for CS: output enabled, pull-up, no isolation.
|
||||
* @param pin GPIO pin number to configure
|
||||
* @retval None
|
||||
*/
|
||||
static void _configure_cs_pad(uint8_t pin)
|
||||
{
|
||||
uint32_t value;
|
||||
value = PADS_BANK0->GPIO[pin];
|
||||
value &= ~(1U << PADS_BANK0_OD_SHIFT);
|
||||
value |= (1U << PADS_BANK0_IE_SHIFT);
|
||||
value |= (1U << PADS_BANK0_PUE_SHIFT);
|
||||
value &= ~(1U << PADS_BANK0_ISO_SHIFT);
|
||||
PADS_BANK0->GPIO[pin] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a GPIO funcsel to SPI alternate function.
|
||||
* @param pin GPIO pin number
|
||||
* @retval None
|
||||
*/
|
||||
static void _set_funcsel_spi(uint8_t pin)
|
||||
{
|
||||
IO_BANK0->GPIO[pin].CTRL = IO_BANK0_CTRL_FUNCSEL_SPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a GPIO funcsel to SIO for software control (CS pin).
|
||||
* @param pin GPIO pin number
|
||||
* @retval None
|
||||
*/
|
||||
static void _set_funcsel_sio(uint8_t pin)
|
||||
{
|
||||
IO_BANK0->GPIO[pin].CTRL = IO_BANK0_CTRL_FUNCSEL_SIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure CS pin as output, initially deasserted (high).
|
||||
* @retval None
|
||||
*/
|
||||
static void _cs_init(void)
|
||||
{
|
||||
SIO[SIO_GPIO_OUT_SET_OFFSET] = CS_PIN_MASK;
|
||||
SIO[SIO_GPIO_OE_SET_OFFSET] = CS_PIN_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure SSPCR0 for 8-bit Motorola SPI, SCR=0.
|
||||
* @retval None
|
||||
*/
|
||||
static void _configure_cr0(void)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
value |= (SPI_SSPCR0_DSS_8BIT << SPI_SSPCR0_DSS_SHIFT);
|
||||
value |= (SPI_SCR_1MHZ << SPI_SSPCR0_SCR_SHIFT);
|
||||
SPI0->SSPCR0 = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure SSPCPSR clock prescaler for 1 MHz.
|
||||
* @retval None
|
||||
*/
|
||||
static void _configure_prescaler(void)
|
||||
{
|
||||
SPI0->SSPCPSR = SPI_CPSDVSR_1MHZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the SPI0 peripheral (SSE=1 in SSPCR1).
|
||||
* @retval None
|
||||
*/
|
||||
static void _enable_spi(void)
|
||||
{
|
||||
SPI0->SSPCR1 = (1U << SPI_SSPCR1_SSE_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait until the SPI transmit FIFO has space.
|
||||
* @retval None
|
||||
*/
|
||||
static void _wait_tx_not_full(void)
|
||||
{
|
||||
while ((SPI0->SSPSR & SPI_SSPSR_TNF_MASK) == 0) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait until the SPI receive FIFO has data.
|
||||
* @retval None
|
||||
*/
|
||||
static void _wait_rx_not_empty(void)
|
||||
{
|
||||
while ((SPI0->SSPSR & SPI_SSPSR_RNE_MASK) == 0) {
|
||||
}
|
||||
}
|
||||
|
||||
void spi_release_reset(void)
|
||||
{
|
||||
_spi_clear_reset();
|
||||
_spi_wait_reset_done();
|
||||
}
|
||||
|
||||
void spi_init(void)
|
||||
{
|
||||
_configure_spi_pad(SPI_MOSI_PIN);
|
||||
_configure_spi_pad(SPI_MISO_PIN);
|
||||
_configure_spi_pad(SPI_SCK_PIN);
|
||||
_configure_cs_pad(SPI_CS_PIN);
|
||||
_set_funcsel_spi(SPI_MOSI_PIN);
|
||||
_set_funcsel_spi(SPI_MISO_PIN);
|
||||
_set_funcsel_spi(SPI_SCK_PIN);
|
||||
_set_funcsel_sio(SPI_CS_PIN);
|
||||
_cs_init();
|
||||
_configure_cr0();
|
||||
_configure_prescaler();
|
||||
_enable_spi();
|
||||
}
|
||||
|
||||
void spi_cs_select(void)
|
||||
{
|
||||
SIO[SIO_GPIO_OUT_CLR_OFFSET] = CS_PIN_MASK;
|
||||
}
|
||||
|
||||
void spi_cs_deselect(void)
|
||||
{
|
||||
SIO[SIO_GPIO_OUT_SET_OFFSET] = CS_PIN_MASK;
|
||||
}
|
||||
|
||||
void spi_transfer(const uint8_t *tx, uint8_t *rx, uint32_t len)
|
||||
{
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
_wait_tx_not_full();
|
||||
SPI0->SSPDR = tx[i];
|
||||
_wait_rx_not_empty();
|
||||
rx[i] = (uint8_t)SPI0->SSPDR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_stack.c
|
||||
* @author Kevin Thomas
|
||||
* @brief Stack pointer initialization for RP2350.
|
||||
*
|
||||
* Sets MSP, PSP, MSPLIM, and PSPLIM using inline assembly.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_stack.h"
|
||||
|
||||
void stack_init(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"ldr r0, =%0\n\t"
|
||||
"msr PSP, r0\n\t"
|
||||
"ldr r0, =%1\n\t"
|
||||
"msr MSPLIM, r0\n\t"
|
||||
"msr PSPLIM, r0\n\t"
|
||||
"ldr r0, =%0\n\t"
|
||||
"msr MSP, r0\n\t"
|
||||
:
|
||||
: "i" (STACK_TOP), "i" (STACK_LIMIT)
|
||||
: "r0"
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_uart.c
|
||||
* @author Kevin Thomas
|
||||
* @brief UART0 driver implementation for RP2350.
|
||||
*
|
||||
* Configures UART0 on GPIO 0 (TX) and GPIO 1 (RX) at 115200
|
||||
* baud using the 12 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_uart.h"
|
||||
|
||||
#define UART_BASE ((volatile uint32_t *) UART0_BASE)
|
||||
|
||||
/**
|
||||
* @brief Clear the UART0 reset bit in the reset controller.
|
||||
* @retval None
|
||||
*/
|
||||
static void _uart_clear_reset_bit(void)
|
||||
{
|
||||
uint32_t value;
|
||||
value = RESETS->RESET;
|
||||
value &= ~(1U << RESETS_RESET_UART0_SHIFT);
|
||||
RESETS->RESET = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait until the UART0 block is out of reset.
|
||||
* @retval None
|
||||
*/
|
||||
static void _uart_wait_reset_done(void)
|
||||
{
|
||||
while ((RESETS->RESET_DONE & (1U << RESETS_RESET_UART0_SHIFT)) == 0) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure GPIO pins 0 (TX) and 1 (RX) for UART function.
|
||||
* @retval None
|
||||
*/
|
||||
static void _uart_configure_pins(void)
|
||||
{
|
||||
IO_BANK0->GPIO[0].CTRL = IO_BANK0_CTRL_FUNCSEL_UART;
|
||||
IO_BANK0->GPIO[1].CTRL = IO_BANK0_CTRL_FUNCSEL_UART;
|
||||
PADS_BANK0->GPIO[0] = 0x04;
|
||||
PADS_BANK0->GPIO[1] = 0x40;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set UART0 baud rate divisors for 115200 at 12 MHz.
|
||||
* @retval None
|
||||
*/
|
||||
static void _uart_set_baud(void)
|
||||
{
|
||||
UART_BASE[UART_CR_OFFSET] = 0;
|
||||
UART_BASE[UART_IBRD_OFFSET] = 6;
|
||||
UART_BASE[UART_FBRD_OFFSET] = 33;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure line control and enable UART0.
|
||||
* @retval None
|
||||
*/
|
||||
static void _uart_enable(void)
|
||||
{
|
||||
UART_BASE[UART_LCR_H_OFFSET] = UART_LCR_H_8N1_FIFO;
|
||||
UART_BASE[UART_CR_OFFSET] = UART_CR_ENABLE;
|
||||
}
|
||||
|
||||
void uart_release_reset(void)
|
||||
{
|
||||
_uart_clear_reset_bit();
|
||||
_uart_wait_reset_done();
|
||||
}
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
_uart_configure_pins();
|
||||
_uart_set_baud();
|
||||
_uart_enable();
|
||||
}
|
||||
|
||||
bool uart_is_readable(void)
|
||||
{
|
||||
return (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) == 0;
|
||||
}
|
||||
|
||||
char uart_getchar(void)
|
||||
{
|
||||
while (UART_BASE[UART_FR_OFFSET] & UART_FR_RXFE_MASK) {
|
||||
}
|
||||
return (char)(UART_BASE[UART_DR_OFFSET] & 0xFF);
|
||||
}
|
||||
|
||||
void uart_putchar(char c)
|
||||
{
|
||||
while (UART_BASE[UART_FR_OFFSET] & UART_FR_TXFF_MASK) {
|
||||
}
|
||||
UART_BASE[UART_DR_OFFSET] = (uint32_t)c;
|
||||
}
|
||||
|
||||
void uart_puts(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
uart_putchar(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
char uart_to_upper(char c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return (char)(c - 32);
|
||||
return c;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_xosc.c
|
||||
* @author Kevin Thomas
|
||||
* @brief XOSC driver implementation for RP2350.
|
||||
*
|
||||
* Configures the external crystal oscillator and enables the
|
||||
* peripheral clock sourced from XOSC.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_xosc.h"
|
||||
|
||||
void xosc_init(void)
|
||||
{
|
||||
XOSC->STARTUP = 0x00C4U;
|
||||
XOSC->CTRL = 0x00FABAA0U;
|
||||
while ((XOSC->STATUS & (1U << XOSC_STATUS_STABLE_SHIFT)) == 0) {
|
||||
}
|
||||
}
|
||||
|
||||
void xosc_enable_peri_clk(void)
|
||||
{
|
||||
uint32_t value;
|
||||
value = CLOCKS->CLK_PERI_CTRL;
|
||||
value &= ~CLK_PERI_CTRL_AUXSRC_MASK;
|
||||
value |= (1U << CLK_PERI_CTRL_ENABLE_SHIFT);
|
||||
value |= (CLK_PERI_CTRL_AUXSRC_XOSC << CLK_PERI_CTRL_AUXSRC_SHIFT);
|
||||
CLOCKS->CLK_PERI_CTRL = value;
|
||||
}
|
||||
|
||||
void xosc_set_clk_ref(void)
|
||||
{
|
||||
CLOCKS->CLK_REF_CTRL = CLK_REF_CTRL_SRC_XOSC;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file vector_table.c
|
||||
* @author Kevin Thomas
|
||||
* @brief Vector table with initial stack pointer and reset handler.
|
||||
*
|
||||
* Placed in the .vectors section at the start of flash.
|
||||
* The Thumb bit (bit 0 = 1) is automatically set by the
|
||||
* linker for function pointers in Thumb mode.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint32_t _stack_top;
|
||||
extern void Reset_Handler(void);
|
||||
|
||||
typedef void (*vector_func_t)(void);
|
||||
|
||||
/**
|
||||
* @brief Vector table placed in .vectors section
|
||||
*/
|
||||
__attribute__((section(".vectors"), used))
|
||||
const void *_vectors[2] = {
|
||||
&_stack_top,
|
||||
Reset_Handler
|
||||
};
|
||||
Reference in New Issue
Block a user