Updated Drivers

This commit is contained in:
Kevin Thomas
2026-03-23 09:33:04 -04:00
parent 6ee30d0520
commit 91faba6800
31 changed files with 834 additions and 344 deletions
+9 -18
View File
@@ -46,32 +46,23 @@
#define UART_RX_PIN 1
#define UART_BAUD 115200
/**
* @brief Convert a lowercase ASCII character to uppercase
*
* Returns the uppercase equivalent if the character is in 'a'-'z';
* all other characters are passed through unchanged.
*
* @param c Input character
* @return char Uppercase equivalent, or the original character
*/
static char to_upper(char c) {
if (c >= 'a' && c <= 'z') {
return (char)(c - 32);
}
return c;
}
/**
* @brief Application entry point for the UART uppercase echo demo
*
* Initializes UART0 and enters an infinite loop that reads incoming
* characters, converts them to uppercase, and echoes them back.
*
* @return int Does not return
*/
int main(void) {
uart_driver_init(UART_TX_PIN, UART_RX_PIN, UART_BAUD);
uart_driver_puts("UART driver ready (115200 8N1)\r\n");
uart_driver_puts("Type characters to echo them back in UPPERCASE:\r\n");
while (true) {
if (uart_driver_is_readable()) {
char c = uart_driver_getchar();
char upper = to_upper(c);
char upper = uart_driver_to_upper(c);
uart_driver_putchar(upper);
}
}
+13
View File
@@ -34,26 +34,39 @@
#define UART_INST uart0
void uart_driver_init(uint32_t tx_pin, uint32_t rx_pin, uint32_t baud_rate) {
uart_init(UART_INST, baud_rate);
gpio_set_function(tx_pin, GPIO_FUNC_UART);
gpio_set_function(rx_pin, GPIO_FUNC_UART);
}
bool uart_driver_is_readable(void) {
return uart_is_readable(UART_INST);
}
char uart_driver_getchar(void) {
return (char)uart_getc(UART_INST);
}
void uart_driver_putchar(char c) {
uart_putc_raw(UART_INST, c);
}
void uart_driver_puts(const char *str) {
while (*str) {
uart_putc_raw(UART_INST, *str++);
}
}
char uart_driver_to_upper(char c) {
if (c >= 'a' && c <= 'z') {
return (char)(c - 32);
}
return c;
}
+11
View File
@@ -86,4 +86,15 @@ void uart_driver_putchar(char c);
*/
void uart_driver_puts(const char *str);
/**
* @brief Convert a lowercase ASCII character to uppercase
*
* Returns the uppercase equivalent if the character is in 'a'-'z';
* all other characters are passed through unchanged.
*
* @param c Input character
* @return char Uppercase equivalent, or the original character
*/
char uart_driver_to_upper(char c);
#endif // UART_H
+11 -2
View File
@@ -43,15 +43,24 @@
#define LED_PIN 25
#define BLINK_DELAY_MS 500
/**
* @brief Application entry point for the LED blink demo
*
* Initializes the onboard LED and enters an infinite loop that
* toggles the LED state every BLINK_DELAY_MS milliseconds.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
blink_init(LED_PIN);
printf("Blink driver initialized on GPIO %d\r\n", LED_PIN);
while (true) {
blink_toggle(LED_PIN);
printf("LED: %s\r\n", blink_get_state(LED_PIN) ? "ON" : "OFF");
sleep_ms(BLINK_DELAY_MS);
}
}
}
}
+5
View File
@@ -31,24 +31,29 @@
#include "pico/stdlib.h"
#include "hardware/gpio.h"
void blink_init(uint32_t pin) {
gpio_init(pin);
gpio_set_dir(pin, GPIO_OUT);
gpio_put(pin, false);
}
void blink_on(uint32_t pin) {
gpio_put(pin, true);
}
void blink_off(uint32_t pin) {
gpio_put(pin, false);
}
void blink_toggle(uint32_t pin) {
gpio_put(pin, !gpio_get(pin));
}
bool blink_get_state(uint32_t pin) {
return (bool)gpio_get(pin);
}
+29 -14
View File
@@ -46,26 +46,41 @@
#define LED_PIN 25
#define DEBOUNCE_MS 20
/**
* @brief Poll button state and report edge transitions over UART
*
* Reads the debounced button state, mirrors it to the LED, and prints
* a message when the state changes from the previous reading.
*
* @param last_state Pointer to the stored previous button state
*/
static void _poll_button(bool *last_state) {
bool pressed = button_is_pressed(BUTTON_PIN);
button_led_set(LED_PIN, pressed);
if (pressed != *last_state) {
printf("Button: %s\r\n", pressed ? "PRESSED" : "RELEASED");
*last_state = pressed;
}
}
/**
* @brief Application entry point for the button debounce demo
*
* Initializes button and LED, then continuously polls button state
* and mirrors it to the LED with UART reporting on edge transitions.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
button_init(BUTTON_PIN, DEBOUNCE_MS);
button_led_init(LED_PIN);
printf("Button driver initialized: button=GPIO%d led=GPIO%d\r\n",
BUTTON_PIN, LED_PIN);
printf("Button driver initialized: button=GPIO%d led=GPIO%d\r\n", BUTTON_PIN, LED_PIN);
bool last_state = false;
while (true) {
bool pressed = button_is_pressed(BUTTON_PIN);
button_led_set(LED_PIN, pressed);
if (pressed != last_state) {
printf("Button: %s\r\n", pressed ? "PRESSED" : "RELEASED");
last_state = pressed;
}
_poll_button(&last_state);
sleep_ms(10);
}
}
+11 -2
View File
@@ -33,6 +33,7 @@
static uint32_t debounce_delay_ms = 20;
/**
* @brief Confirm a raw active-low pin read by waiting for the debounce period
*
@@ -43,11 +44,12 @@ static uint32_t debounce_delay_ms = 20;
* @param pin GPIO pin number to re-sample
* @return bool true if the pin is still low after the debounce delay
*/
static bool debounce_confirm(uint32_t pin) {
static bool _debounce_confirm(uint32_t pin) {
sleep_ms(debounce_delay_ms);
return !gpio_get(pin);
}
void button_init(uint32_t pin, uint32_t debounce_ms) {
debounce_delay_ms = debounce_ms;
gpio_init(pin);
@@ -55,19 +57,26 @@ void button_init(uint32_t pin, uint32_t debounce_ms) {
gpio_pull_up(pin);
}
bool button_is_pressed(uint32_t pin) {
if (!gpio_get(pin)) {
return debounce_confirm(pin);
return _debounce_confirm(pin);
}
return false;
}
void button_led_init(uint32_t pin) {
gpio_init(pin);
gpio_set_dir(pin, GPIO_OUT);
gpio_put(pin, false);
}
void button_led_set(uint32_t pin, bool on) {
gpio_put(pin, on);
}
void button_led_set(uint32_t pin, bool on) {
gpio_put(pin, on);
}
+30 -12
View File
@@ -44,22 +44,40 @@
#define PWM_PIN 0
#define PWM_FREQ_HZ 1000
/**
* @brief Sweep the PWM duty cycle between start and end in given steps
*
* Iterates from start to end with the given step increment, updating
* the PWM duty cycle and printing each value with a 50 ms delay.
*
* @param start Starting duty percentage
* @param end Ending duty percentage
* @param step Increment per iteration (negative for descending)
*/
static void _sweep_duty(int start, int end, int step) {
for (int duty = start; (step > 0) ? duty <= end : duty >= end; duty += step) {
pwm_driver_set_duty_percent((uint8_t)duty);
printf("Duty: %3d%%\r\n", duty);
sleep_ms(50);
}
}
/**
* @brief Application entry point for the PWM LED breathing demo
*
* Initializes PWM at 1 kHz and sweeps the duty cycle up and down
* to produce a smooth LED breathing effect, reporting over UART.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
pwm_driver_init(PWM_PIN, PWM_FREQ_HZ);
printf("PWM driver initialized: GPIO%d @ %d Hz\r\n", PWM_PIN, PWM_FREQ_HZ);
while (true) {
for (int duty = 0; duty <= 100; duty += 5) {
pwm_driver_set_duty_percent((uint8_t)duty);
printf("Duty: %3d%%\r\n", duty);
sleep_ms(50);
}
for (int duty = 100; duty >= 0; duty -= 5) {
pwm_driver_set_duty_percent((uint8_t)duty);
printf("Duty: %3d%%\r\n", duty);
sleep_ms(50);
}
_sweep_duty(0, 100, 5);
_sweep_duty(100, 0, -5);
}
}
+23 -8
View File
@@ -36,6 +36,7 @@ static uint pwm_slice;
static uint pwm_chan;
static uint32_t pwm_wrap;
/**
* @brief Compute the PWM clock divider that yields the target frequency
*
@@ -47,24 +48,38 @@ static uint32_t pwm_wrap;
* @param wrap_val Chosen PWM counter wrap value (period - 1)
* @return float Clock divider to program into the PWM slice
*/
static float calc_clk_div(uint32_t freq_hz, uint32_t wrap_val) {
static float _calc_clk_div(uint32_t freq_hz, uint32_t wrap_val) {
uint32_t sys_hz = clock_get_hz(clk_sys);
return (float)sys_hz / ((float)freq_hz * (float)(wrap_val + 1));
}
/**
* @brief Apply the PWM configuration to the active slice
*
* Builds a default config, sets the clock divider for the target frequency,
* programs the wrap value, starts the slice, and zeroes the channel level.
*
* @param freq_hz Desired PWM output frequency in Hz
*/
static void _apply_pwm_config(uint32_t freq_hz) {
pwm_config cfg = pwm_get_default_config();
pwm_config_set_clkdiv(&cfg, _calc_clk_div(freq_hz, pwm_wrap));
pwm_config_set_wrap(&cfg, pwm_wrap);
pwm_init(pwm_slice, &cfg, true);
pwm_set_chan_level(pwm_slice, pwm_chan, 0);
}
void pwm_driver_init(uint32_t pin, uint32_t freq_hz) {
gpio_set_function(pin, GPIO_FUNC_PWM);
pwm_slice = pwm_gpio_to_slice_num(pin);
pwm_chan = pwm_gpio_to_channel(pin);
pwm_wrap = 10000 - 1; // resolution: 0.01% steps
pwm_config cfg = pwm_get_default_config();
pwm_config_set_clkdiv(&cfg, calc_clk_div(freq_hz, pwm_wrap));
pwm_config_set_wrap(&cfg, pwm_wrap);
pwm_init(pwm_slice, &cfg, true);
pwm_set_chan_level(pwm_slice, pwm_chan, 0);
pwm_wrap = 10000 - 1;
_apply_pwm_config(freq_hz);
}
void pwm_driver_set_duty_percent(uint8_t percent) {
if (percent > 100) {
percent = 100;
+33 -14
View File
@@ -47,24 +47,43 @@
#define STEP_DEGREES 10
#define STEP_DELAY_MS 150
/**
* @brief Sweep the servo between start and end angles in given steps
*
* Iterates from start to end with the given step increment, setting
* each angle and printing the current position with a delay between steps.
*
* @param start Starting angle in degrees
* @param end Ending angle in degrees
* @param step Increment per iteration (negative for descending)
*/
static void _sweep_angle(int start, int end, int step) {
for (int angle = start; (step > 0) ? angle <= end : angle >= end; angle += step) {
servo_set_angle((float)angle);
printf("Angle: %3d deg\r\n", angle);
sleep_ms(STEP_DELAY_MS);
}
}
/**
* @brief Application entry point for the servo sweep demo
*
* Initializes the servo on GPIO and continuously sweeps 0-180-0 degrees
* in STEP_DEGREES increments, reporting each angle over UART.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
servo_init(SERVO_GPIO);
printf("Servo driver initialized on GPIO %d\r\n", SERVO_GPIO);
printf("Sweeping 0 -> 180 -> 0 degrees in %d-degree steps\r\n",
STEP_DEGREES);
printf("Sweeping 0 -> 180 -> 0 degrees in %d-degree steps\r\n", STEP_DEGREES);
while (true) {
for (int angle = 0; angle <= 180; angle += STEP_DEGREES) {
servo_set_angle((float)angle);
printf("Angle: %3d deg\r\n", angle);
sleep_ms(STEP_DELAY_MS);
}
for (int angle = 180; angle >= 0; angle -= STEP_DEGREES) {
servo_set_angle((float)angle);
printf("Angle: %3d deg\r\n", angle);
sleep_ms(STEP_DELAY_MS);
}
_sweep_angle(0, 180, STEP_DEGREES);
_sweep_angle(180, 0, -STEP_DEGREES);
}
}
}
}
+25 -19
View File
@@ -32,18 +32,17 @@
#include "hardware/pwm.h"
#include "hardware/clocks.h"
// Default servo pulse range (SG90 typical)
static const uint16_t SERVO_DEFAULT_MIN_US = 1000;
static const uint16_t SERVO_DEFAULT_MAX_US = 2000;
// internal state
static uint8_t servo_pin = 0;
static uint servo_slice = 0;
static uint servo_chan = 0;
static uint32_t servo_wrap = 20000 - 1; // wrap to map microseconds for 50Hz
static uint32_t servo_wrap = 20000 - 1;
static float servo_hz = 50.0f;
static bool servo_initialized = false;
/**
* @brief Convert a pulse width in microseconds to a PWM counter level
*
@@ -53,45 +52,52 @@ static bool servo_initialized = false;
* @param pulse_us Pulse width in microseconds
* @return uint32_t PWM level suitable for pwm_set_chan_level()
*/
static uint32_t pulse_us_to_level(uint32_t pulse_us) {
const float period_us = 1000000.0f / servo_hz; // 20000us
static uint32_t _pulse_us_to_level(uint32_t pulse_us) {
const float period_us = 1000000.0f / servo_hz;
float counts_per_us = (servo_wrap + 1) / period_us;
return (uint32_t)(pulse_us * counts_per_us + 0.5f);
}
void servo_init(uint8_t pin) {
servo_pin = pin;
// Configure GPIO for PWM
gpio_set_function(servo_pin, GPIO_FUNC_PWM);
servo_slice = pwm_gpio_to_slice_num(servo_pin);
servo_chan = pwm_gpio_to_channel(servo_pin);
/**
* @brief Build and apply the PWM slice configuration for 50 Hz servo
*
* Computes the clock divider from the system clock to achieve the
* target servo frequency with the chosen wrap value, then starts
* the PWM slice.
*/
static void _apply_servo_config(void) {
pwm_config config = pwm_get_default_config();
// Calculate clock divider to achieve 50 Hz with our chosen wrap
const uint32_t sys_clock_hz = clock_get_hz(clk_sys);
float clock_div = (float)sys_clock_hz / (servo_hz * (servo_wrap + 1));
pwm_config_set_clkdiv(&config, clock_div);
pwm_config_set_wrap(&config, servo_wrap);
pwm_init(servo_slice, &config, true);
}
void servo_init(uint8_t pin) {
servo_pin = pin;
gpio_set_function(servo_pin, GPIO_FUNC_PWM);
servo_slice = pwm_gpio_to_slice_num(servo_pin);
servo_chan = pwm_gpio_to_channel(servo_pin);
_apply_servo_config();
servo_initialized = true;
}
void servo_set_pulse_us(uint16_t pulse_us) {
if (!servo_initialized) return; // not initialized
// clamp to defaults
if (!servo_initialized) return;
if (pulse_us < SERVO_DEFAULT_MIN_US) pulse_us = SERVO_DEFAULT_MIN_US;
if (pulse_us > SERVO_DEFAULT_MAX_US) pulse_us = SERVO_DEFAULT_MAX_US;
uint32_t level = pulse_us_to_level(pulse_us);
uint32_t level = _pulse_us_to_level(pulse_us);
pwm_set_chan_level(servo_slice, servo_chan, level);
}
void servo_set_angle(float degrees) {
if (degrees < 0.0f) degrees = 0.0f;
if (degrees > 180.0f) degrees = 180.0f;
// linear map 0..180 -> min_us..max_us
float ratio = degrees / 180.0f;
uint16_t pulse = (uint16_t)(SERVO_DEFAULT_MIN_US + ratio * (SERVO_DEFAULT_MAX_US - SERVO_DEFAULT_MIN_US) + 0.5f);
servo_set_pulse_us(pulse);
+24 -10
View File
@@ -45,20 +45,34 @@
#define ADC_GPIO 26
#define ADC_CHANNEL 0
/**
* @brief Read and print ADC voltage and chip temperature over UART
*
* Samples the ADC channel for voltage in millivolts and reads the
* on-chip temperature sensor, then prints both values.
*/
static void _print_adc_readings(void) {
uint32_t voltage_mv = adc_driver_read_mv();
float temp_c = adc_driver_read_temp_celsius();
printf("ADC0: %4lu mV | Chip temp: %.1f C\r\n", voltage_mv, temp_c);
}
/**
* @brief Application entry point for the ADC voltage and temperature demo
*
* Initializes the ADC on GPIO26 channel 0 and prints readings
* every 500 ms over UART.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
adc_driver_init(ADC_GPIO, ADC_CHANNEL);
printf("ADC driver initialized: GPIO%d (channel %d)\r\n",
ADC_GPIO, ADC_CHANNEL);
printf("ADC driver initialized: GPIO%d (channel %d)\r\n", ADC_GPIO, ADC_CHANNEL);
while (true) {
uint32_t voltage_mv = adc_driver_read_mv();
float temp_c = adc_driver_read_temp_celsius();
printf("ADC0: %4lu mV | Chip temp: %.1f C\r\n",
voltage_mv, temp_c);
_print_adc_readings();
sleep_ms(500);
}
}
+9 -4
View File
@@ -36,6 +36,7 @@
static uint8_t active_channel = 0;
/**
* @brief Convert a raw 12-bit ADC value to millivolts
*
@@ -44,10 +45,11 @@ static uint8_t active_channel = 0;
* @param raw 12-bit ADC conversion result (0 - 4095)
* @return uint32_t Equivalent voltage in millivolts (0 - 3300)
*/
static uint32_t raw_to_mv(uint16_t raw) {
static uint32_t _raw_to_mv(uint16_t raw) {
return (uint32_t)raw * ADC_VREF_MV / ADC_FULL_SCALE;
}
/**
* @brief Convert a raw temperature-sensor ADC value to degrees Celsius
*
@@ -57,11 +59,12 @@ static uint32_t raw_to_mv(uint16_t raw) {
* @param raw 12-bit ADC result from the internal temperature sensor (channel 4)
* @return float Die temperature in degrees Celsius
*/
static float raw_to_celsius(uint16_t raw) {
static float _raw_to_celsius(uint16_t raw) {
float voltage = (float)raw * 3.3f / (float)ADC_FULL_SCALE;
return 27.0f - (voltage - 0.706f) / 0.001721f;
}
void adc_driver_init(uint32_t gpio, uint8_t channel) {
active_channel = channel;
adc_init();
@@ -70,13 +73,15 @@ void adc_driver_init(uint32_t gpio, uint8_t channel) {
adc_select_input(channel);
}
uint32_t adc_driver_read_mv(void) {
return raw_to_mv(adc_read());
return _raw_to_mv(adc_read());
}
float adc_driver_read_temp_celsius(void) {
adc_select_input(4);
float result = raw_to_celsius(adc_read());
float result = _raw_to_celsius(adc_read());
adc_select_input(active_channel);
return result;
}
+10 -2
View File
@@ -49,13 +49,21 @@
#define I2C_SCL_PIN 3
#define I2C_BAUD 100000
/**
* @brief Application entry point for the I2C bus scanner demo
*
* Initializes I2C1 at 100 kHz on SDA=GPIO2 / SCL=GPIO3 and prints
* a formatted hex table of all responding device addresses over UART,
* repeating every 5 seconds.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
i2c_driver_init(I2C_PORT, I2C_SDA_PIN, I2C_SCL_PIN, I2C_BAUD);
printf("I2C driver initialized: I2C%d @ %d Hz SDA=GPIO%d SCL=GPIO%d\r\n",
I2C_PORT, I2C_BAUD, I2C_SDA_PIN, I2C_SCL_PIN);
while (true) {
i2c_driver_scan(I2C_PORT);
sleep_ms(5000);
+42 -20
View File
@@ -33,13 +33,20 @@
#include "hardware/i2c.h"
#include "hardware/gpio.h"
static i2c_inst_t *get_i2c_inst(uint8_t port) {
/**
* @brief Map an I2C port number to its hardware instance pointer
*
* @param port I2C port number (0 for i2c0, 1 for i2c1)
* @return i2c_inst_t* Pointer to the corresponding I2C hardware instance
*/
static i2c_inst_t *_get_i2c_inst(uint8_t port) {
return port == 0 ? i2c0 : i2c1;
}
void i2c_driver_init(uint8_t port, uint32_t sda_pin, uint32_t scl_pin,
uint32_t baud_hz) {
i2c_inst_t *inst = get_i2c_inst(port);
i2c_inst_t *inst = _get_i2c_inst(port);
i2c_init(inst, baud_hz);
gpio_set_function(sda_pin, GPIO_FUNC_I2C);
gpio_set_function(scl_pin, GPIO_FUNC_I2C);
@@ -47,29 +54,44 @@ void i2c_driver_init(uint8_t port, uint32_t sda_pin, uint32_t scl_pin,
gpio_pull_up(scl_pin);
}
bool i2c_driver_probe(uint8_t port, uint8_t addr) {
i2c_inst_t *inst = get_i2c_inst(port);
i2c_inst_t *inst = _get_i2c_inst(port);
uint8_t dummy;
return i2c_read_blocking(inst, addr, &dummy, 1, false) >= 0;
}
void i2c_driver_scan(uint8_t port) {
/**
* @brief Print the I2C scan table header over UART
*/
static void _print_scan_header(void) {
printf("\r\nI2C bus scan:\r\n");
printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n");
for (uint8_t addr = 0; addr < 128; addr++) {
if (addr % 16 == 0) {
printf("%02X: ", addr);
}
if (addr < 0x08 || addr > 0x77) {
printf(" ");
} else if (i2c_driver_probe(port, addr)) {
printf("%02X ", addr);
} else {
printf("-- ");
}
if (addr % 16 == 15) {
printf("\r\n");
}
}
}
/**
* @brief Print one cell of the scan table for a given address
*
* Prints the row label when the address is at a 16-byte boundary, then
* prints the address if a device responds, dashes if not, or blank if
* the address is in the reserved range. Ends the row at every 16th address.
*
* @param port I2C port number (0 for i2c0, 1 for i2c1)
* @param addr 7-bit I2C address being probed
*/
static void _print_scan_entry(uint8_t port, uint8_t addr) {
if (addr % 16 == 0) printf("%02X: ", addr);
if (addr < 0x08 || addr > 0x77) printf(" ");
else if (i2c_driver_probe(port, addr)) printf("%02X ", addr);
else printf("-- ");
if (addr % 16 == 15) printf("\r\n");
}
void i2c_driver_scan(uint8_t port) {
_print_scan_header();
for (uint8_t addr = 0; addr < 128; addr++)
_print_scan_entry(port, addr);
}
+37 -18
View File
@@ -51,26 +51,45 @@
#define I2C_BAUD_HZ 100000
#define LCD_I2C_ADDR 0x27
int main(void) {
stdio_init_all();
lcd_init(I2C_PORT, I2C_SDA_PIN, I2C_SCL_PIN, I2C_BAUD_HZ,
LCD_I2C_ADDR, 4, 0x08);
/**
* @brief Initialize the LCD, display the title, and log over UART
*/
static void _setup_display(void) {
lcd_init(I2C_PORT, I2C_SDA_PIN, I2C_SCL_PIN, I2C_BAUD_HZ, LCD_I2C_ADDR, 4, 0x08);
lcd_set_cursor(0, 0);
lcd_puts("Reverse Eng.");
printf("LCD 1602 driver initialized at I2C addr 0x%02X\r\n", LCD_I2C_ADDR);
uint32_t count = 0;
char buf[17];
while (true) {
snprintf(buf, sizeof(buf), "Count: %6lu", count++);
lcd_set_cursor(1, 0);
lcd_puts(buf);
printf("%s\r\n", buf);
sleep_ms(1000);
}
}
/**
* @brief Format and display the next counter value on LCD line 1
*
* @param count Pointer to the running counter (post-incremented)
*/
static void _update_counter(uint32_t *count) {
char buf[17];
snprintf(buf, sizeof(buf), "Count: %6lu", (*count)++);
lcd_set_cursor(1, 0);
lcd_puts(buf);
printf("%s\r\n", buf);
sleep_ms(1000);
}
/**
* @brief Application entry point for the LCD 1602 counter demo
*
* Initializes the LCD over I2C with a static title on line 0 and
* continuously increments a counter on line 1 every second.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
_setup_display();
uint32_t count = 0;
while (true)
_update_counter(&count);
}
+84 -47
View File
@@ -33,10 +33,17 @@
#include "pico/stdlib.h"
#include "hardware/i2c.h"
static i2c_inst_t *get_i2c_inst(uint8_t port) {
/**
* @brief Map an I2C port number to its hardware instance pointer
*
* @param port I2C port number (0 for i2c0, 1 for i2c1)
* @return i2c_inst_t* Pointer to the corresponding I2C hardware instance
*/
static i2c_inst_t *_get_i2c_inst(uint8_t port) {
return port == 0 ? i2c0 : i2c1;
}
static i2c_inst_t *lcd_i2c = NULL;
static uint8_t lcd_addr = 0x27;
static int lcd_nibble_shift = 4;
@@ -47,109 +54,139 @@ static uint8_t lcd_backlight_mask = 0x08;
#define PIN_RW 0x02
#define PIN_EN 0x04
/**
* @brief Write one raw byte to the PCF8574 expander over I2C
*
* @param data Output byte to send to the expander
*/
static void pcf_write_byte(uint8_t data) {
static void _pcf_write_byte(uint8_t data) {
if (!lcd_i2c) return;
i2c_write_blocking(lcd_i2c, lcd_addr, &data, 1, false);
}
/**
* @brief Toggle EN to latch a nibble into the LCD controller
*
* @param data Current control/data bus byte (with RS and backlight already set)
*/
static void pcf_pulse_enable(uint8_t data) {
pcf_write_byte(data | PIN_EN);
static void _pcf_pulse_enable(uint8_t data) {
_pcf_write_byte(data | PIN_EN);
sleep_us(1);
pcf_write_byte(data & ~PIN_EN);
_pcf_write_byte(data & ~PIN_EN);
sleep_us(50);
}
/**
* @brief Write one 4-bit nibble to the LCD
*
* @param nibble Lower 4 bits to write
* @param mode 0 for command, non-zero for character data
*/
static void lcd_write4(uint8_t nibble, uint8_t mode) {
static void _lcd_write4(uint8_t nibble, uint8_t mode) {
uint8_t data = (nibble & 0x0F) << lcd_nibble_shift;
data |= mode ? PIN_RS : 0;
data |= lcd_backlight_mask;
pcf_pulse_enable(data);
_pcf_pulse_enable(data);
}
/**
* @brief Send one full 8-bit command/data value as two nibbles
*
* @param value Byte to send to the LCD
* @param mode 0 for command, non-zero for character data
*/
static void lcd_send(uint8_t value, uint8_t mode) {
lcd_write4((value >> 4) & 0x0F, mode);
lcd_write4(value & 0x0F, mode);
static void _lcd_send(uint8_t value, uint8_t mode) {
_lcd_write4((value >> 4) & 0x0F, mode);
_lcd_write4(value & 0x0F, mode);
}
/**
* @brief Store LCD driver configuration in module-level state
*
* @param i2c_port I2C port number (0 or 1)
* @param pcf_addr 7-bit PCF8574 address
* @param nibble_shift Bit shift for 4-bit nibbles
* @param backlight_mask Backlight control bit mask
*/
static void _lcd_store_config(uint8_t i2c_port, uint8_t pcf_addr,
int nibble_shift, uint8_t backlight_mask) {
lcd_i2c = _get_i2c_inst(i2c_port);
lcd_addr = pcf_addr;
lcd_nibble_shift = nibble_shift;
lcd_backlight_mask = backlight_mask;
}
/**
* @brief Execute the HD44780 4-bit mode power-on reset sequence
*/
static void _lcd_hd44780_reset(void) {
_lcd_write4(0x03, 0);
sleep_ms(5);
_lcd_write4(0x03, 0);
sleep_us(150);
_lcd_write4(0x03, 0);
sleep_us(150);
_lcd_write4(0x02, 0);
sleep_us(150);
}
/**
* @brief Send post-reset configuration commands to the HD44780
*
* Sets 4-bit mode with 2 display lines, turns the display on with
* cursor hidden, clears the screen, and selects left-to-right entry mode.
*/
static void _lcd_hd44780_configure(void) {
_lcd_send(0x28, 0);
_lcd_send(0x0C, 0);
_lcd_send(0x01, 0);
sleep_ms(2);
_lcd_send(0x06, 0);
}
void lcd_i2c_init(uint8_t i2c_port, uint8_t pcf_addr, int nibble_shift,
uint8_t backlight_mask) {
_lcd_store_config(i2c_port, pcf_addr, nibble_shift, backlight_mask);
_lcd_hd44780_reset();
_lcd_hd44780_configure();
}
void lcd_init(uint8_t i2c_port, uint32_t sda_pin, uint32_t scl_pin,
uint32_t baud_hz, uint8_t pcf_addr, int nibble_shift,
uint8_t backlight_mask) {
i2c_inst_t *i2c = get_i2c_inst(i2c_port);
i2c_inst_t *i2c = _get_i2c_inst(i2c_port);
i2c_init(i2c, baud_hz);
gpio_set_function(sda_pin, GPIO_FUNC_I2C);
gpio_set_function(scl_pin, GPIO_FUNC_I2C);
gpio_pull_up(sda_pin);
gpio_pull_up(scl_pin);
lcd_i2c_init(i2c_port, pcf_addr, nibble_shift, backlight_mask);
}
void lcd_i2c_init(uint8_t i2c_port, uint8_t pcf_addr, int nibble_shift, uint8_t backlight_mask) {
lcd_i2c = get_i2c_inst(i2c_port);
lcd_addr = pcf_addr;
lcd_nibble_shift = nibble_shift;
lcd_backlight_mask = backlight_mask;
// Follow init sequence for HD44780 in 4-bit mode
lcd_write4(0x03, 0);
sleep_ms(5);
lcd_write4(0x03, 0);
sleep_us(150);
lcd_write4(0x03, 0);
sleep_us(150);
lcd_write4(0x02, 0);
sleep_us(150);
// Function set: 4-bit, 2 lines
lcd_send(0x28, 0);
// Display on, cursor off
lcd_send(0x0C, 0);
// Clear
lcd_send(0x01, 0);
sleep_ms(2);
// Entry mode set
lcd_send(0x06, 0);
}
void lcd_clear(void) {
lcd_send(0x01, 0);
_lcd_send(0x01, 0);
sleep_ms(2);
}
void lcd_set_cursor(int line, int position) {
const uint8_t row_offsets[] = {0x00, 0x40};
if (line > 1) line = 1;
lcd_send(0x80 | (position + row_offsets[line]), 0);
_lcd_send(0x80 | (position + row_offsets[line]), 0);
}
void lcd_puts(const char *s) {
while (*s) {
lcd_send((uint8_t)*s++, 1);
}
while (*s)
_lcd_send((uint8_t)*s++, 1);
}
+29 -16
View File
@@ -45,24 +45,37 @@
#define DHT11_GPIO 4
/**
* @brief Read the DHT11 sensor and print the result over UART
*
* Attempts a single read. On success prints humidity and temperature;
* on failure prints a wiring-check message. Waits 2 s before returning
* to respect the DHT11 minimum polling interval.
*/
static void _print_reading(void) {
float humidity = 0.0f;
float temperature = 0.0f;
if (dht11_read(&humidity, &temperature))
printf("Humidity: %.1f%% Temperature: %.1f C\r\n", humidity, temperature);
else
printf("DHT11 read failed - check wiring on GPIO %d\r\n", DHT11_GPIO);
sleep_ms(2000);
}
/**
* @brief Application entry point for the DHT11 sensor demo
*
* Initializes the DHT11 on GPIO4 and continuously reads temperature
* and humidity, printing results over UART every 2 seconds.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
dht11_init(DHT11_GPIO);
printf("DHT11 driver initialized on GPIO %d\r\n", DHT11_GPIO);
while (true) {
float humidity = 0.0f;
float temperature = 0.0f;
if (dht11_read(&humidity, &temperature)) {
printf("Humidity: %.1f%% Temperature: %.1f C\r\n",
humidity, temperature);
} else {
printf("DHT11 read failed - check wiring on GPIO %d\r\n",
DHT11_GPIO);
}
sleep_ms(2000);
}
while (true)
_print_reading();
}
+100 -32
View File
@@ -33,46 +33,114 @@
static uint dht_pin;
void dht11_init(uint8_t pin) {
dht_pin = pin;
gpio_init(pin);
gpio_pull_up(pin);
}
bool dht11_read(float *humidity, float *temperature) {
uint8_t data[5] = {0};
// Start signal
/**
* @brief Send the DHT11 start signal on the data pin
*
* Drives the pin LOW for 18 ms then HIGH for 40 us before switching
* the pin to input mode to listen for the sensor response.
*/
static void _send_start_signal(void) {
gpio_set_dir(dht_pin, GPIO_OUT);
gpio_put(dht_pin, 0);
sleep_ms(18);
gpio_put(dht_pin, 1);
sleep_us(40);
gpio_set_dir(dht_pin, GPIO_IN);
// Wait for response
}
/**
* @brief Wait for the pin to leave a given logic level
*
* Spins until the pin no longer reads the specified level, returning
* false if a timeout of 10 000 iterations is exceeded.
*
* @param level Logic level to wait through (0 or 1)
* @return bool true once the level changed, false on timeout
*/
static bool _wait_for_level(int level) {
uint32_t timeout = 10000;
while (gpio_get(dht_pin) == 1) if (--timeout == 0) return false;
timeout = 10000;
while (gpio_get(dht_pin) == 0) if (--timeout == 0) return false;
timeout = 10000;
while (gpio_get(dht_pin) == 1) if (--timeout == 0) return false;
// Read 40 bits
for (int i = 0; i < 40; i++) {
timeout = 10000;
while (gpio_get(dht_pin) == 0) if (--timeout == 0) return false;
uint32_t start = time_us_32();
timeout = 10000;
while (gpio_get(dht_pin) == 1) if (--timeout == 0) return false;
uint32_t duration = time_us_32() - start;
data[i / 8] <<= 1;
if (duration > 40) data[i / 8] |= 1;
}
// Check checksum
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) return false;
while (gpio_get(dht_pin) == level)
if (--timeout == 0) return false;
return true;
}
/**
* @brief Wait for the DHT11 response after the start signal
*
* The sensor pulls LOW then HIGH then LOW again; each transition
* is awaited with a timeout.
*
* @return bool true if the full response was received, false on timeout
*/
static bool _wait_response(void) {
if (!_wait_for_level(1)) return false;
if (!_wait_for_level(0)) return false;
if (!_wait_for_level(1)) return false;
return true;
}
/**
* @brief Read a single bit from the DHT11 data stream
*
* Waits for the low-period to end, measures the high-period duration,
* and shifts the result into the appropriate byte of the data array.
*
* @param data 5-byte array accumulating the received bits
* @param i Bit index (0-39)
* @return bool true on success, false on timeout
*/
static bool _read_bit(uint8_t *data, int i) {
if (!_wait_for_level(0)) return false;
uint32_t start = time_us_32();
if (!_wait_for_level(1)) return false;
uint32_t duration = time_us_32() - start;
data[i / 8] <<= 1;
if (duration > 40) data[i / 8] |= 1;
return true;
}
/**
* @brief Read all 40 data bits from the DHT11
*
* @param data 5-byte array filled with the received data
* @return bool true if all 40 bits were read, false on timeout
*/
static bool _read_40_bits(uint8_t *data) {
for (int i = 0; i < 40; i++)
if (!_read_bit(data, i)) return false;
return true;
}
/**
* @brief Verify the DHT11 checksum byte
*
* @param data 5-byte received data (bytes 0-3 plus checksum in byte 4)
* @return bool true if the checksum matches, false otherwise
*/
static bool _validate_checksum(const uint8_t *data) {
return data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF);
}
void dht11_init(uint8_t pin) {
dht_pin = pin;
gpio_init(pin);
gpio_pull_up(pin);
}
bool dht11_read(float *humidity, float *temperature) {
uint8_t data[5] = {0};
_send_start_signal();
if (!_wait_response()) return false;
if (!_read_40_bits(data)) return false;
if (!_validate_checksum(data)) return false;
*humidity = data[0] + data[1] * 0.1f;
*temperature = data[2] + data[3] * 0.1f;
return true;
+21 -8
View File
@@ -45,17 +45,30 @@
#define IR_GPIO 5
/**
* @brief Poll for an NEC frame and print the command if received
*/
static void _poll_and_print(void) {
int command = ir_getkey();
if (command >= 0)
printf("NEC command: 0x%02X (%d)\r\n", command, command);
}
/**
* @brief Application entry point for the NEC IR receiver demo
*
* Initializes the IR receiver on GPIO5 and continuously decodes
* NEC frames, printing each command byte over UART.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
ir_init(IR_GPIO);
printf("NEC IR driver initialized on GPIO %d\r\n", IR_GPIO);
printf("Press a button on your NEC remote...\r\n");
while (true) {
int command = ir_getkey();
if (command >= 0) {
printf("NEC command: 0x%02X (%d)\r\n", command, command);
}
}
while (true)
_poll_and_print();
}
+83 -27
View File
@@ -34,17 +34,92 @@
static unsigned int ir_pin = 0;
// Wait for 'gpio' to reach 'level' or timeout (microseconds). Return elapsed us or -1.
static int64_t wait_for_level(unsigned int gpio, bool level, uint32_t timeout_us) {
/**
* @brief Wait for a GPIO pin to reach a given logic level
*
* Spins until the pin matches the requested level or a microsecond timeout
* is exceeded. Returns the elapsed time in microseconds, or -1 on timeout.
*
* @param gpio GPIO pin to monitor
* @param level Desired logic level (true = HIGH, false = LOW)
* @param timeout_us Maximum wait in microseconds
* @return int64_t Elapsed microseconds, or -1 on timeout
*/
static int64_t _wait_for_level(unsigned int gpio, bool level, uint32_t timeout_us) {
absolute_time_t start = get_absolute_time();
while (gpio_get(gpio) != level) {
if (absolute_time_diff_us(start, get_absolute_time()) > (int64_t)timeout_us) {
if (absolute_time_diff_us(start, get_absolute_time()) > (int64_t)timeout_us)
return -1;
}
}
return absolute_time_diff_us(start, get_absolute_time());
}
/**
* @brief Wait for the NEC 9 ms leader pulse and 4.5 ms space
*
* @return bool true if a valid leader was detected, false on timeout
*/
static bool _wait_leader(void) {
if (_wait_for_level(ir_pin, 0, 150000) < 0) return false;
int64_t t = _wait_for_level(ir_pin, 1, 12000);
if (t < 8000 || t > 10000) return false;
t = _wait_for_level(ir_pin, 0, 7000);
if (t < 3500 || t > 5000) return false;
return true;
}
/**
* @brief Read a single NEC-encoded bit from the IR receiver
*
* Measures the mark/space timing and shifts the result into the
* appropriate byte of the data array.
*
* @param data 4-byte array accumulating received bits
* @param i Bit index (0-31)
* @return bool true on success, false on timeout or protocol error
*/
static bool _read_nec_bit(uint8_t *data, int i) {
if (_wait_for_level(ir_pin, 1, 1000) < 0) return false;
int64_t t = _wait_for_level(ir_pin, 0, 2500);
if (t < 200) return false;
int byte_idx = i / 8;
int bit_idx = i % 8;
if (t > 1200) data[byte_idx] |= (1 << bit_idx);
return true;
}
/**
* @brief Read all 32 data bits of an NEC frame
*
* @param data 4-byte array filled with the received address and command
* @return bool true if all 32 bits were read, false on timeout
*/
static bool _read_32_bits(uint8_t *data) {
for (int i = 0; i < 32; ++i)
if (!_read_nec_bit(data, i)) return false;
return true;
}
/**
* @brief Validate an NEC frame and extract the command byte
*
* Checks that the address and command pairs are bitwise-inverted.
*
* @param data 4-byte NEC frame (addr, ~addr, cmd, ~cmd)
* @return int Command byte (0-255) on success, -1 on validation failure
*/
static int _validate_nec_frame(const uint8_t *data) {
if ((uint8_t)(data[0] + data[1]) == 0xFF && (uint8_t)(data[2] + data[3]) == 0xFF)
return data[2];
return -1;
}
void ir_init(uint8_t pin) {
ir_pin = pin;
gpio_init(pin);
@@ -52,29 +127,10 @@ void ir_init(uint8_t pin) {
gpio_pull_up(pin);
}
int ir_getkey(void) {
// leader low (~9 ms)
if (wait_for_level(ir_pin, 0, 150000) < 0) return -1;
int64_t t = wait_for_level(ir_pin, 1, 12000);
if (t < 8000 || t > 10000) return -1;
t = wait_for_level(ir_pin, 0, 7000);
if (t < 3500 || t > 5000) return -1;
if (!_wait_leader()) return -1;
uint8_t data[4] = {0, 0, 0, 0};
for (int i = 0; i < 32; ++i) {
if (wait_for_level(ir_pin, 1, 1000) < 0) return -1;
t = wait_for_level(ir_pin, 0, 2500);
if (t < 200) return -1;
int byte_idx = i / 8;
int bit_idx = i % 8;
if (t > 1200) data[byte_idx] |= (1 << bit_idx); // logical '1'
}
// Validate address/data inverted pairs
if ((uint8_t)(data[0] + data[1]) == 0xFF && (uint8_t)(data[2] + data[3]) == 0xFF) {
return data[2];
}
return -1;
if (!_read_32_bits(data)) return -1;
return _validate_nec_frame(data);
}
+32 -14
View File
@@ -50,23 +50,41 @@
#define PIN_SCK 18
#define PIN_MOSI 19
/**
* @brief Perform one SPI loopback transfer and print the result
*
* Asserts chip-select, transfers the buffer, deasserts chip-select,
* prints TX and RX data over UART, then clears the receive buffer.
*
* @param tx_buf Transmit buffer
* @param rx_buf Receive buffer (cleared after printing)
* @param len Number of bytes to transfer
*/
static void _loopback_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, size_t len) {
spi_driver_cs_select(PIN_CS);
spi_driver_transfer(SPI_PORT, tx_buf, rx_buf, len);
spi_driver_cs_deselect(PIN_CS);
printf("TX: %s\r\n", tx_buf);
printf("RX: %s\r\n\r\n", rx_buf);
memset(rx_buf, 0, len);
sleep_ms(1000);
}
/**
* @brief Application entry point for the SPI loopback demo
*
* Initializes SPI0 in master mode and continuously performs
* full-duplex transfers with MOSI wired to MISO for loopback.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
spi_driver_init(SPI_PORT, PIN_MOSI, PIN_MISO, PIN_SCK, PIN_CS, SPI_BAUD_HZ);
const uint8_t tx_buf[] = "SPI loopback OK";
uint8_t rx_buf[sizeof(tx_buf)] = {0};
while (true) {
spi_driver_cs_select(PIN_CS);
spi_driver_transfer(SPI_PORT, tx_buf, rx_buf, sizeof(tx_buf));
spi_driver_cs_deselect(PIN_CS);
printf("TX: %s\r\n", tx_buf);
printf("RX: %s\r\n\r\n", rx_buf);
memset(rx_buf, 0, sizeof(rx_buf));
sleep_ms(1000);
}
while (true)
_loopback_transfer(tx_buf, rx_buf, sizeof(tx_buf));
}
+26 -6
View File
@@ -31,34 +31,54 @@
#include "pico/stdlib.h"
#include "hardware/spi.h"
static spi_inst_t *get_spi_inst(uint8_t port) {
/**
* @brief Map an SPI port number to its hardware instance pointer
*
* @param port SPI port number (0 for spi0, 1 for spi1)
* @return spi_inst_t* Pointer to the corresponding SPI hardware instance
*/
static spi_inst_t *_get_spi_inst(uint8_t port) {
return port == 0 ? spi0 : spi1;
}
void spi_driver_init(uint8_t port, uint32_t mosi, uint32_t miso,
uint32_t sck, uint32_t cs, uint32_t baud_hz) {
spi_inst_t *spi = get_spi_inst(port);
spi_init(spi, baud_hz);
/**
* @brief Assign GPIO alternate functions for the SPI data and clock pins
*
* @param mosi GPIO pin for MOSI
* @param miso GPIO pin for MISO
* @param sck GPIO pin for SCK
*/
static void _setup_spi_pins(uint32_t mosi, uint32_t miso, uint32_t sck) {
gpio_set_function(mosi, GPIO_FUNC_SPI);
gpio_set_function(miso, GPIO_FUNC_SPI);
gpio_set_function(sck, GPIO_FUNC_SPI);
}
void spi_driver_init(uint8_t port, uint32_t mosi, uint32_t miso,
uint32_t sck, uint32_t cs, uint32_t baud_hz) {
spi_inst_t *spi = _get_spi_inst(port);
spi_init(spi, baud_hz);
_setup_spi_pins(mosi, miso, sck);
gpio_init(cs);
gpio_set_dir(cs, GPIO_OUT);
gpio_put(cs, 1);
}
void spi_driver_cs_select(uint32_t cs) {
gpio_put(cs, 0);
}
void spi_driver_cs_deselect(uint32_t cs) {
gpio_put(cs, 1);
}
void spi_driver_transfer(uint8_t port, const uint8_t *tx, uint8_t *rx,
uint32_t len) {
spi_inst_t *spi = get_spi_inst(port);
spi_inst_t *spi = _get_spi_inst(port);
spi_write_read_blocking(spi, tx, rx, (size_t)len);
}
+35 -11
View File
@@ -41,24 +41,48 @@
#include "pico/stdlib.h"
#include "multicore.h"
static void core1_main(void) {
/**
* @brief Core 1 entry point: receive a value and return it incremented
*
* Blocks on the FIFO, adds one to each received value, and pushes
* the result back to core 0.
*/
static void _core1_main(void) {
while (true) {
uint32_t value = multicore_driver_pop();
multicore_driver_push(value + 1u);
}
}
/**
* @brief Send the counter to core 1 and print the round-trip result
*
* @param counter Pointer to the running counter (post-incremented)
*/
static void _send_and_print(uint32_t *counter) {
multicore_driver_push(*counter);
uint32_t response = multicore_driver_pop();
printf("core0 sent: %lu, core1 returned: %lu\r\n",
(unsigned long)*counter, (unsigned long)response);
(*counter)++;
sleep_ms(1000);
}
/**
* @brief Application entry point for the multicore FIFO demo
*
* Launches core 1 and continuously sends an incrementing counter
* through the inter-core FIFO, printing both sent and returned
* values over UART every second.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
multicore_driver_launch(core1_main);
multicore_driver_launch(_core1_main);
uint32_t counter = 0;
while (true) {
multicore_driver_push(counter);
uint32_t response = multicore_driver_pop();
printf("core0 sent: %lu, core1 returned: %lu\r\n",
(unsigned long)counter, (unsigned long)response);
counter++;
sleep_ms(1000);
}
while (true)
_send_and_print(&counter);
}
+2
View File
@@ -34,10 +34,12 @@ void multicore_driver_launch(void (*core1_entry)(void)) {
multicore_launch_core1(core1_entry);
}
void multicore_driver_push(uint32_t data) {
multicore_fifo_push_blocking(data);
}
uint32_t multicore_driver_pop(void) {
return multicore_fifo_pop_blocking();
}
+17 -6
View File
@@ -40,17 +40,28 @@
#include "pico/stdlib.h"
#include "timer.h"
static bool heartbeat_callback(void) {
/**
* @brief Heartbeat timer callback that prints a message over UART
*
* @return bool true to keep the repeating timer active
*/
static bool _heartbeat_callback(void) {
printf("Timer heartbeat\r\n");
return true;
}
/**
* @brief Application entry point for the repeating timer demo
*
* Starts a 1-second repeating timer whose callback prints a
* heartbeat message over UART.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
timer_driver_start(1000, heartbeat_callback);
while (true) {
timer_driver_start(1000, _heartbeat_callback);
while (true)
tight_loop_contents();
}
}
+14 -9
View File
@@ -34,29 +34,34 @@ static repeating_timer_t g_timer;
static bool g_timer_active = false;
static timer_driver_callback_t g_user_callback = NULL;
static bool timer_shim(repeating_timer_t *rt) {
/**
* @brief Internal repeating-timer callback that forwards to the user callback
*
* @param rt Unused repeating-timer handle provided by the SDK
* @return bool true to keep the timer running, false to cancel
*/
static bool _timer_shim(repeating_timer_t *rt) {
(void)rt;
if (g_user_callback) {
if (g_user_callback)
return g_user_callback();
}
return false;
}
void timer_driver_start(int32_t period_ms, timer_driver_callback_t callback) {
if (g_timer_active) {
cancel_repeating_timer(&g_timer);
g_timer_active = false;
}
g_user_callback = callback;
g_timer_active = add_repeating_timer_ms(period_ms, timer_shim, NULL, &g_timer);
g_timer_active = add_repeating_timer_ms(period_ms, _timer_shim, NULL, &g_timer);
}
void timer_driver_cancel(void) {
if (!g_timer_active) {
return;
}
void timer_driver_cancel(void) {
if (!g_timer_active)
return;
cancel_repeating_timer(&g_timer);
g_timer_active = false;
}
+32 -13
View File
@@ -41,21 +41,40 @@
#include "pico/stdlib.h"
#include "watchdog.h"
/**
* @brief Print whether the system booted normally or from a watchdog reset
*/
static void _print_reset_reason(void) {
if (watchdog_driver_caused_reboot())
printf("System rebooted by watchdog timeout\r\n");
else
printf("Normal power-on reset\r\n");
}
/**
* @brief Feed the watchdog and log over UART, then wait 1 second
*/
static void _feed_and_report(void) {
watchdog_driver_feed();
printf("Watchdog fed\r\n");
sleep_ms(1000);
}
/**
* @brief Application entry point for the watchdog demo
*
* Enables the watchdog with a 3-second timeout and feeds it every
* 1 second. Reports the reset reason on startup.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
if (watchdog_driver_caused_reboot()) {
printf("System rebooted by watchdog timeout\r\n");
} else {
printf("Normal power-on reset\r\n");
}
_print_reset_reason();
watchdog_driver_enable(3000);
printf("Watchdog enabled (3s timeout). Feeding every 1s...\r\n");
while (true) {
watchdog_driver_feed();
printf("Watchdog fed\r\n");
sleep_ms(1000);
}
while (true)
_feed_and_report();
}
+2
View File
@@ -34,10 +34,12 @@ void watchdog_driver_enable(uint32_t timeout_ms) {
watchdog_enable(timeout_ms, true);
}
void watchdog_driver_feed(void) {
watchdog_update();
}
bool watchdog_driver_caused_reboot(void) {
return watchdog_caused_reboot();
}
+34 -12
View File
@@ -44,22 +44,44 @@
#define FLASH_TARGET_OFFSET (FLASH_DRIVER_SIZE_BYTES - FLASH_DRIVER_SECTOR_SIZE)
#define FLASH_WRITE_LEN FLASH_DRIVER_PAGE_SIZE
int main(void) {
stdio_init_all();
/**
* @brief Fill a write buffer with 0xFF and copy the demo string into it
*
* @param buf Destination buffer
* @param buf_size Size of the buffer in bytes
*/
static void _prepare_write_buf(uint8_t *buf, size_t buf_size) {
memset(buf, 0xFF, buf_size);
const char *msg = "Embedded Hacking flash driver demo";
memcpy(buf, msg, strlen(msg));
}
/**
* @brief Write the demo string to flash and print the read-back result
*/
static void _write_and_verify(void) {
static uint8_t write_buf[FLASH_WRITE_LEN];
static uint8_t read_buf[FLASH_WRITE_LEN];
memset(write_buf, 0xFF, sizeof(write_buf));
const char *msg = "Embedded Hacking flash driver demo";
memcpy(write_buf, msg, strlen(msg));
_prepare_write_buf(write_buf, sizeof(write_buf));
flash_driver_write(FLASH_TARGET_OFFSET, write_buf, FLASH_WRITE_LEN);
flash_driver_read(FLASH_TARGET_OFFSET, read_buf, FLASH_WRITE_LEN);
printf("Flash readback: %s\r\n", read_buf);
while (true) {
tight_loop_contents();
}
}
/**
* @brief Application entry point for the on-chip flash demo
*
* Writes a demo string to the last flash sector, reads it back,
* and prints the result over UART.
*
* @return int Does not return
*/
int main(void) {
stdio_init_all();
_write_and_verify();
while (true)
tight_loop_contents();
}
+1
View File
@@ -40,6 +40,7 @@ void flash_driver_write(uint32_t flash_offset, const uint8_t *data, uint32_t len
restore_interrupts(ints);
}
void flash_driver_read(uint32_t flash_offset, uint8_t *out, uint32_t len) {
const uint8_t *flash_target_contents = (const uint8_t *)(XIP_BASE + flash_offset);
memcpy(out, flash_target_contents, len);