mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-07-16 17:07:34 +02:00
Add 0x08_lcd1602_cbm bare-metal LCD1602 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,117 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file main.c
|
||||
* @author Kevin Thomas
|
||||
* @brief LCD1602 demonstration: static title and live counter display.
|
||||
*
|
||||
* Drives a 16x2 HD44780 LCD via a PCF8574 I2C backpack. Line 0
|
||||
* shows a static title ("Reverse Eng.") and line 1 displays a
|
||||
* counter that increments every second. The counter value is
|
||||
* also printed over UART for debugging.
|
||||
*
|
||||
* Wiring:
|
||||
* GPIO0 -> UART TX (USB-to-UART adapter RX)
|
||||
* GPIO1 -> UART RX (USB-to-UART adapter TX)
|
||||
* GPIO2 -> PCF8574 backpack SDA (4.7 kohm pull-up to 3.3 V)
|
||||
* GPIO3 -> PCF8574 backpack SCL (4.7 kohm pull-up to 3.3 V)
|
||||
* 3.3V -> PCF8574 backpack VCC
|
||||
* GND -> PCF8574 backpack GND
|
||||
*
|
||||
******************************************************************************
|
||||
* @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_i2c.h"
|
||||
#include "rp2350_lcd1602.h"
|
||||
#include "rp2350_uart.h"
|
||||
#include "rp2350_xosc.h"
|
||||
#include "rp2350_delay.h"
|
||||
|
||||
#define COUNT_DELAY_MS 1000
|
||||
|
||||
/**
|
||||
* @brief Convert an unsigned 32-bit integer to a decimal string.
|
||||
*
|
||||
* Writes at most 10 decimal digits plus a null terminator
|
||||
* into the provided buffer. The buffer must be at least
|
||||
* 11 bytes.
|
||||
*
|
||||
* @param val value to convert
|
||||
* @param buf destination buffer (minimum 11 bytes)
|
||||
* @retval None
|
||||
*/
|
||||
static void _uint_to_str(uint32_t val, char *buf)
|
||||
{
|
||||
char tmp[11];
|
||||
int i = 0;
|
||||
if (val == 0) {
|
||||
buf[0] = '0';
|
||||
buf[1] = '\0';
|
||||
return;
|
||||
}
|
||||
while (val > 0) {
|
||||
tmp[i++] = (char)('0' + (val % 10));
|
||||
val /= 10;
|
||||
}
|
||||
for (int j = 0; j < i; j++)
|
||||
buf[j] = tmp[i - 1 - j];
|
||||
buf[i] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Format "Count: " followed by a right-justified counter value.
|
||||
*
|
||||
* Writes the formatted string into a 17-byte buffer and pads
|
||||
* with spaces to fill the 16-column display width.
|
||||
*
|
||||
* @param count current counter value
|
||||
* @param buf destination buffer (minimum 17 bytes)
|
||||
* @retval None
|
||||
*/
|
||||
static void _format_counter(uint32_t count, char *buf)
|
||||
{
|
||||
char num[11];
|
||||
_uint_to_str(count, num);
|
||||
const char *prefix = "Count: ";
|
||||
int i = 0;
|
||||
while (prefix[i]) { buf[i] = prefix[i]; i++; }
|
||||
int j = 0;
|
||||
while (num[j]) buf[i++] = num[j++];
|
||||
while (i < 16) buf[i++] = ' ';
|
||||
buf[i] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Application entry point for the LCD 1602 counter demo.
|
||||
* @retval int does not return
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
xosc_set_clk_ref();
|
||||
i2c_release_reset();
|
||||
i2c_init();
|
||||
lcd_init();
|
||||
uart_puts("LCD 1602 driver initialized at I2C addr 0x27\r\n");
|
||||
lcd_set_cursor(0, 0);
|
||||
lcd_puts("Reverse Eng.");
|
||||
uint32_t count = 0;
|
||||
while (1) {
|
||||
char buf[17];
|
||||
_format_counter(count, buf);
|
||||
lcd_set_cursor(1, 0);
|
||||
lcd_puts(buf);
|
||||
uart_puts(buf);
|
||||
uart_puts("\r\n");
|
||||
count++;
|
||||
delay_ms(COUNT_DELAY_MS);
|
||||
}
|
||||
}
|
||||
@@ -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,138 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_i2c.c
|
||||
* @author Kevin Thomas
|
||||
* @brief RP2350 I2C1 master-mode driver implementation.
|
||||
*
|
||||
* Bare-metal driver for the RP2350 Synopsys DW APB I2C controller.
|
||||
* Configures I2C1 at 100 kHz on SDA=GPIO2 / SCL=GPIO3 with
|
||||
* internal pull-ups. Provides target selection and single-byte
|
||||
* write. All register accesses 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "rp2350_i2c.h"
|
||||
|
||||
/**
|
||||
* @brief Configure GPIO2 and GPIO3 pads for I2C (input enabled, pull-up).
|
||||
*
|
||||
* Clears pad isolation, enables input, enables pull-up, and sets
|
||||
* drive strength to 4 mA on both SDA and SCL pins.
|
||||
*
|
||||
* @retval None
|
||||
*/
|
||||
static void _i2c_config_pads(void)
|
||||
{
|
||||
uint32_t pad_val = (1U << PADS_BANK0_IE_SHIFT) | (1U << PADS_BANK0_PUE_SHIFT) | (1U << 4);
|
||||
PADS_BANK0->GPIO[I2C_SDA_PIN] = pad_val;
|
||||
PADS_BANK0->GPIO[I2C_SCL_PIN] = pad_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set GPIO2 and GPIO3 IO mux function to I2C (FUNCSEL=3).
|
||||
* @retval None
|
||||
*/
|
||||
static void _i2c_config_gpio(void)
|
||||
{
|
||||
IO_BANK0->GPIO[I2C_SDA_PIN].CTRL = IO_BANK0_CTRL_FUNCSEL_I2C;
|
||||
IO_BANK0->GPIO[I2C_SCL_PIN].CTRL = IO_BANK0_CTRL_FUNCSEL_I2C;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C1 as fast-mode master with 7-bit addressing.
|
||||
*
|
||||
* Sets MASTER_MODE, SPEED=FAST, IC_SLAVE_DISABLE, IC_RESTART_EN,
|
||||
* and TX_EMPTY_CTRL bits in the CON register.
|
||||
*
|
||||
* @retval None
|
||||
*/
|
||||
static void _i2c_config_con(void)
|
||||
{
|
||||
I2C1->CON = (1U << I2C_CON_MASTER_MODE_SHIFT)
|
||||
| (I2C_CON_SPEED_FAST << I2C_CON_SPEED_SHIFT)
|
||||
| (1U << I2C_CON_IC_RESTART_EN_SHIFT)
|
||||
| (1U << I2C_CON_IC_SLAVE_DISABLE_SHIFT)
|
||||
| (1U << I2C_CON_TX_EMPTY_CTRL_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program SCL timing for 100 kHz at 12 MHz clk_sys.
|
||||
*
|
||||
* Sets fast-mode SCL high/low counts, SDA hold time, and
|
||||
* spike suppression length.
|
||||
*
|
||||
* @retval None
|
||||
*/
|
||||
static void _i2c_config_timing(void)
|
||||
{
|
||||
I2C1->FS_SCL_HCNT = I2C_FS_SCL_HCNT_VAL;
|
||||
I2C1->FS_SCL_LCNT = I2C_FS_SCL_LCNT_VAL;
|
||||
I2C1->FS_SPKLEN = I2C_FS_SPKLEN_VAL;
|
||||
I2C1->SDA_HOLD = I2C_SDA_TX_HOLD_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait for a STOP_DET or TX_ABRT interrupt, then clear it.
|
||||
* @retval None
|
||||
*/
|
||||
static void _i2c_wait_done(void)
|
||||
{
|
||||
uint32_t timeout = I2C_TIMEOUT;
|
||||
while (timeout > 0U) {
|
||||
if (I2C1->RAW_INTR_STAT & I2C_RAW_INTR_TX_ABRT) {
|
||||
(void)I2C1->CLR_TX_ABRT;
|
||||
break;
|
||||
}
|
||||
if (I2C1->RAW_INTR_STAT & I2C_RAW_INTR_STOP_DET) {
|
||||
(void)I2C1->CLR_STOP_DET;
|
||||
break;
|
||||
}
|
||||
timeout--;
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_release_reset(void)
|
||||
{
|
||||
RESETS->RESET |= (1U << RESETS_RESET_I2C1_SHIFT);
|
||||
RESETS->RESET &= ~(1U << RESETS_RESET_I2C1_SHIFT);
|
||||
while (!(RESETS->RESET_DONE & (1U << RESETS_RESET_I2C1_SHIFT))) {
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_init(void)
|
||||
{
|
||||
_i2c_config_pads();
|
||||
_i2c_config_gpio();
|
||||
I2C1->ENABLE = 0U;
|
||||
_i2c_config_con();
|
||||
I2C1->TX_TL = 0U;
|
||||
I2C1->RX_TL = 0U;
|
||||
_i2c_config_timing();
|
||||
I2C1->ENABLE = 1U;
|
||||
}
|
||||
|
||||
void i2c_set_target(uint8_t addr)
|
||||
{
|
||||
I2C1->ENABLE = 0U;
|
||||
I2C1->TAR = addr;
|
||||
I2C1->ENABLE = 1U;
|
||||
}
|
||||
|
||||
void i2c_write_byte(uint8_t data)
|
||||
{
|
||||
(void)I2C1->CLR_TX_ABRT;
|
||||
I2C1->DATA_CMD = data | (1U << I2C_DATA_CMD_STOP_SHIFT);
|
||||
_i2c_wait_done();
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rp2350_lcd1602.c
|
||||
* @author Kevin Thomas
|
||||
* @brief LCD1602 driver implementation for RP2350.
|
||||
*
|
||||
* Drives a 16x2 HD44780 LCD through a PCF8574 I2C backpack
|
||||
* in 4-bit mode. Each nibble is latched by pulsing the EN
|
||||
* line via single-byte I2C writes to the PCF8574. All
|
||||
* timing margins exceed HD44780 datasheet minimums.
|
||||
*
|
||||
******************************************************************************
|
||||
* @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_lcd1602.h"
|
||||
#include "rp2350_i2c.h"
|
||||
#include "rp2350_delay.h"
|
||||
|
||||
/**
|
||||
* @brief Pulse the EN line to latch a nibble into the HD44780.
|
||||
*
|
||||
* Writes the data byte with EN set, waits 1 us, then writes
|
||||
* with EN cleared and waits 50 us for the controller to process.
|
||||
*
|
||||
* @param data PCF8574 output byte (RS, backlight, and nibble already set)
|
||||
* @retval None
|
||||
*/
|
||||
static void _lcd_pulse_enable(uint8_t data)
|
||||
{
|
||||
i2c_write_byte(data | LCD_PIN_EN);
|
||||
delay_us(1);
|
||||
i2c_write_byte(data & ~LCD_PIN_EN);
|
||||
delay_us(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write one 4-bit nibble to the LCD controller.
|
||||
* @param nibble lower 4 bits to send
|
||||
* @param mode 0 for command, non-zero for character data
|
||||
* @retval None
|
||||
*/
|
||||
static void _lcd_write4(uint8_t nibble, uint8_t mode)
|
||||
{
|
||||
uint8_t data = (nibble & 0x0FU) << LCD_NIBBLE_SHIFT;
|
||||
data |= mode ? LCD_PIN_RS : 0U;
|
||||
data |= LCD_BACKLIGHT;
|
||||
_lcd_pulse_enable(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a full 8-bit value as two nibbles (high then low).
|
||||
* @param value byte to send to the LCD
|
||||
* @param mode 0 for command, non-zero for character data
|
||||
* @retval None
|
||||
*/
|
||||
static void _lcd_send(uint8_t value, uint8_t mode)
|
||||
{
|
||||
_lcd_write4((value >> 4) & 0x0FU, mode);
|
||||
_lcd_write4(value & 0x0FU, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute the HD44780 4-bit mode power-on reset sequence.
|
||||
*
|
||||
* Sends 0x03 three times with required inter-command delays,
|
||||
* then sends 0x02 to switch from 8-bit to 4-bit interface.
|
||||
*
|
||||
* @retval None
|
||||
*/
|
||||
static void _lcd_hd44780_reset(void)
|
||||
{
|
||||
_lcd_write4(0x03, 0);
|
||||
delay_ms(5);
|
||||
_lcd_write4(0x03, 0);
|
||||
delay_us(150);
|
||||
_lcd_write4(0x03, 0);
|
||||
delay_us(150);
|
||||
_lcd_write4(0x02, 0);
|
||||
delay_us(150);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send post-reset configuration commands to the HD44780.
|
||||
*
|
||||
* Sets 4-bit mode with 2 display lines and 5x8 font, turns
|
||||
* display on with cursor hidden, clears the screen, and
|
||||
* selects left-to-right entry mode.
|
||||
*
|
||||
* @retval None
|
||||
*/
|
||||
static void _lcd_hd44780_configure(void)
|
||||
{
|
||||
_lcd_send(LCD_CMD_FUNCTION_SET_4BIT, 0);
|
||||
_lcd_send(LCD_CMD_DISPLAY_ON, 0);
|
||||
_lcd_send(LCD_CMD_CLEAR, 0);
|
||||
delay_ms(2);
|
||||
_lcd_send(LCD_CMD_ENTRY_MODE, 0);
|
||||
}
|
||||
|
||||
void lcd_init(void)
|
||||
{
|
||||
i2c_set_target(LCD_I2C_ADDR);
|
||||
_lcd_hd44780_reset();
|
||||
_lcd_hd44780_configure();
|
||||
}
|
||||
|
||||
void lcd_clear(void)
|
||||
{
|
||||
_lcd_send(LCD_CMD_CLEAR, 0);
|
||||
delay_ms(2);
|
||||
}
|
||||
|
||||
void lcd_set_cursor(uint8_t line, uint8_t position)
|
||||
{
|
||||
uint8_t offset = (line == 0U) ? LCD_ROW0_OFFSET : LCD_ROW1_OFFSET;
|
||||
_lcd_send(LCD_CMD_SET_DDRAM | (position + offset), 0);
|
||||
}
|
||||
|
||||
void lcd_puts(const char *str)
|
||||
{
|
||||
while (*str)
|
||||
_lcd_send((uint8_t)*str++, 1);
|
||||
}
|
||||
@@ -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,45 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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_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 uart_release_reset\n\t"
|
||||
"bl uart_init\n\t"
|
||||
"bl coprocessor_enable\n\t"
|
||||
"b main\n\t"
|
||||
);
|
||||
}
|
||||
@@ -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 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#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 14.5 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