From 7601201d66da97606a1f34a856df7165052f0149 Mon Sep 17 00:00:00 2001 From: Kevin Thomas Date: Sun, 22 Mar 2026 20:39:16 -0400 Subject: [PATCH] Drivers --- README.md | 23 +++ drivers/0x01_uart/0x01_uart.c | 78 ++++++++++ drivers/0x01_uart/CMakeLists.txt | 57 +++++++ drivers/0x01_uart/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x01_uart/uart.c | 59 +++++++ drivers/0x01_uart/uart.h | 89 +++++++++++ drivers/0x02_blink/0x02_blink.c | 57 +++++++ drivers/0x02_blink/CMakeLists.txt | 56 +++++++ drivers/0x02_blink/blink.c | 54 +++++++ drivers/0x02_blink/blink.h | 78 ++++++++++ drivers/0x02_blink/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x03_button/0x03_button.c | 71 +++++++++ drivers/0x03_button/CMakeLists.txt | 56 +++++++ drivers/0x03_button/button.c | 73 +++++++++ drivers/0x03_button/button.h | 80 ++++++++++ drivers/0x03_button/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x04_pwm/0x04_pwm.c | 65 ++++++++ drivers/0x04_pwm/CMakeLists.txt | 58 +++++++ drivers/0x04_pwm/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x04_pwm/pwm.c | 74 +++++++++ drivers/0x04_pwm/pwm.h | 59 +++++++ drivers/0x05_servo/0x05_servo.c | 70 +++++++++ drivers/0x05_servo/CMakeLists.txt | 58 +++++++ drivers/0x05_servo/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x05_servo/servo.c | 98 ++++++++++++ drivers/0x05_servo/servo.h | 62 ++++++++ drivers/0x06_adc/0x06_adc.c | 64 ++++++++ drivers/0x06_adc/CMakeLists.txt | 57 +++++++ drivers/0x06_adc/adc.c | 82 ++++++++++ drivers/0x06_adc/adc.h | 69 +++++++++ drivers/0x06_adc/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x07_i2c/0x07_i2c.c | 63 ++++++++ drivers/0x07_i2c/CMakeLists.txt | 57 +++++++ drivers/0x07_i2c/i2c.c | 75 +++++++++ drivers/0x07_i2c/i2c.h | 75 +++++++++ drivers/0x07_i2c/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x08_lcd1602/0x08_lcd1602.c | 76 +++++++++ drivers/0x08_lcd1602/CMakeLists.txt | 57 +++++++ drivers/0x08_lcd1602/lcd1602.c | 155 +++++++++++++++++++ drivers/0x08_lcd1602/lcd1602.h | 93 +++++++++++ drivers/0x08_lcd1602/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x09_dht11/0x09_dht11.c | 68 ++++++++ drivers/0x09_dht11/CMakeLists.txt | 56 +++++++ drivers/0x09_dht11/dht11.c | 79 ++++++++++ drivers/0x09_dht11/dht11.h | 57 +++++++ drivers/0x09_dht11/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x0a_ir/0x0a_ir.c | 61 ++++++++ drivers/0x0a_ir/CMakeLists.txt | 56 +++++++ drivers/0x0a_ir/ir.c | 80 ++++++++++ drivers/0x0a_ir/ir.h | 56 +++++++ drivers/0x0a_ir/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x0b_spi/0x0b_spi.c | 72 +++++++++ drivers/0x0b_spi/CMakeLists.txt | 57 +++++++ drivers/0x0b_spi/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x0b_spi/spi.c | 64 ++++++++ drivers/0x0b_spi/spi.h | 82 ++++++++++ drivers/0x0c_multicore/0x0c_multicore.c | 64 ++++++++ drivers/0x0c_multicore/CMakeLists.txt | 57 +++++++ drivers/0x0c_multicore/multicore.c | 43 +++++ drivers/0x0c_multicore/multicore.h | 66 ++++++++ drivers/0x0c_multicore/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x0d_timer/0x0d_timer.c | 56 +++++++ drivers/0x0d_timer/CMakeLists.txt | 56 +++++++ drivers/0x0d_timer/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x0d_timer/timer.c | 62 ++++++++ drivers/0x0d_timer/timer.h | 64 ++++++++ drivers/0x0e_watchdog/0x0e_watchdog.c | 61 ++++++++ drivers/0x0e_watchdog/CMakeLists.txt | 57 +++++++ drivers/0x0e_watchdog/pico_sdk_import.cmake | 121 +++++++++++++++ drivers/0x0e_watchdog/watchdog.c | 43 +++++ drivers/0x0e_watchdog/watchdog.h | 65 ++++++++ drivers/0x0f_flash/0x0f_flash.c | 65 ++++++++ drivers/0x0f_flash/CMakeLists.txt | 58 +++++++ drivers/0x0f_flash/flash.c | 46 ++++++ drivers/0x0f_flash/flash.h | 68 ++++++++ drivers/0x0f_flash/pico_sdk_import.cmake | 121 +++++++++++++++ 76 files changed, 5832 insertions(+) create mode 100644 drivers/0x01_uart/0x01_uart.c create mode 100644 drivers/0x01_uart/CMakeLists.txt create mode 100644 drivers/0x01_uart/pico_sdk_import.cmake create mode 100644 drivers/0x01_uart/uart.c create mode 100644 drivers/0x01_uart/uart.h create mode 100644 drivers/0x02_blink/0x02_blink.c create mode 100644 drivers/0x02_blink/CMakeLists.txt create mode 100644 drivers/0x02_blink/blink.c create mode 100644 drivers/0x02_blink/blink.h create mode 100644 drivers/0x02_blink/pico_sdk_import.cmake create mode 100644 drivers/0x03_button/0x03_button.c create mode 100644 drivers/0x03_button/CMakeLists.txt create mode 100644 drivers/0x03_button/button.c create mode 100644 drivers/0x03_button/button.h create mode 100644 drivers/0x03_button/pico_sdk_import.cmake create mode 100644 drivers/0x04_pwm/0x04_pwm.c create mode 100644 drivers/0x04_pwm/CMakeLists.txt create mode 100644 drivers/0x04_pwm/pico_sdk_import.cmake create mode 100644 drivers/0x04_pwm/pwm.c create mode 100644 drivers/0x04_pwm/pwm.h create mode 100644 drivers/0x05_servo/0x05_servo.c create mode 100644 drivers/0x05_servo/CMakeLists.txt create mode 100644 drivers/0x05_servo/pico_sdk_import.cmake create mode 100644 drivers/0x05_servo/servo.c create mode 100644 drivers/0x05_servo/servo.h create mode 100644 drivers/0x06_adc/0x06_adc.c create mode 100644 drivers/0x06_adc/CMakeLists.txt create mode 100644 drivers/0x06_adc/adc.c create mode 100644 drivers/0x06_adc/adc.h create mode 100644 drivers/0x06_adc/pico_sdk_import.cmake create mode 100644 drivers/0x07_i2c/0x07_i2c.c create mode 100644 drivers/0x07_i2c/CMakeLists.txt create mode 100644 drivers/0x07_i2c/i2c.c create mode 100644 drivers/0x07_i2c/i2c.h create mode 100644 drivers/0x07_i2c/pico_sdk_import.cmake create mode 100644 drivers/0x08_lcd1602/0x08_lcd1602.c create mode 100644 drivers/0x08_lcd1602/CMakeLists.txt create mode 100644 drivers/0x08_lcd1602/lcd1602.c create mode 100644 drivers/0x08_lcd1602/lcd1602.h create mode 100644 drivers/0x08_lcd1602/pico_sdk_import.cmake create mode 100644 drivers/0x09_dht11/0x09_dht11.c create mode 100644 drivers/0x09_dht11/CMakeLists.txt create mode 100644 drivers/0x09_dht11/dht11.c create mode 100644 drivers/0x09_dht11/dht11.h create mode 100644 drivers/0x09_dht11/pico_sdk_import.cmake create mode 100644 drivers/0x0a_ir/0x0a_ir.c create mode 100644 drivers/0x0a_ir/CMakeLists.txt create mode 100644 drivers/0x0a_ir/ir.c create mode 100644 drivers/0x0a_ir/ir.h create mode 100644 drivers/0x0a_ir/pico_sdk_import.cmake create mode 100644 drivers/0x0b_spi/0x0b_spi.c create mode 100644 drivers/0x0b_spi/CMakeLists.txt create mode 100644 drivers/0x0b_spi/pico_sdk_import.cmake create mode 100644 drivers/0x0b_spi/spi.c create mode 100644 drivers/0x0b_spi/spi.h create mode 100644 drivers/0x0c_multicore/0x0c_multicore.c create mode 100644 drivers/0x0c_multicore/CMakeLists.txt create mode 100644 drivers/0x0c_multicore/multicore.c create mode 100644 drivers/0x0c_multicore/multicore.h create mode 100644 drivers/0x0c_multicore/pico_sdk_import.cmake create mode 100644 drivers/0x0d_timer/0x0d_timer.c create mode 100644 drivers/0x0d_timer/CMakeLists.txt create mode 100644 drivers/0x0d_timer/pico_sdk_import.cmake create mode 100644 drivers/0x0d_timer/timer.c create mode 100644 drivers/0x0d_timer/timer.h create mode 100644 drivers/0x0e_watchdog/0x0e_watchdog.c create mode 100644 drivers/0x0e_watchdog/CMakeLists.txt create mode 100644 drivers/0x0e_watchdog/pico_sdk_import.cmake create mode 100644 drivers/0x0e_watchdog/watchdog.c create mode 100644 drivers/0x0e_watchdog/watchdog.h create mode 100644 drivers/0x0f_flash/0x0f_flash.c create mode 100644 drivers/0x0f_flash/CMakeLists.txt create mode 100644 drivers/0x0f_flash/flash.c create mode 100644 drivers/0x0f_flash/flash.h create mode 100644 drivers/0x0f_flash/pico_sdk_import.cmake diff --git a/README.md b/README.md index 420a143..8fe3f5e 100644 --- a/README.md +++ b/README.md @@ -504,5 +504,28 @@ An RP2350 button driver written entirely in RISC-V Assembler.
+# Drivers +Self-contained C driver libraries for the Raspberry Pi Pico 2 (RP2350). Each driver folder contains a thin demo (`0xNN_name.c`), a reusable library implementation (`name.c`), and a library header with full Doxygen docstrings (`name.h`). + +| Driver | Description | Key Hardware | +|--------|-------------|--------------| +| [0x01_uart](drivers/0x01_uart) | Raw UART transmit / receive | `hardware_uart` | +| [0x02_blink](drivers/0x02_blink) | GPIO output LED blink | `pico_stdlib` | +| [0x03_button](drivers/0x03_button) | GPIO input with debounce | `pico_stdlib` | +| [0x04_pwm](drivers/0x04_pwm) | PWM output with frequency & duty control | `hardware_pwm`, `hardware_clocks` | +| [0x05_servo](drivers/0x05_servo) | SG90 servo angle & pulse control | `hardware_pwm`, `hardware_clocks` | +| [0x06_adc](drivers/0x06_adc) | ADC voltage & on-chip temperature reading | `hardware_adc` | +| [0x07_i2c](drivers/0x07_i2c) | I2C bus init, probe & scan | `hardware_i2c` | +| [0x08_lcd1602](drivers/0x08_lcd1602) | 1602 LCD over I2C (PCF8574 backpack) | `hardware_i2c` | +| [0x09_dht11](drivers/0x09_dht11) | DHT11 temperature & humidity (single-wire) | `pico_stdlib` | +| [0x0a_ir](drivers/0x0a_ir) | IR remote NEC protocol decoder | `pico_stdlib` | +| [0x0b_spi](drivers/0x0b_spi) | SPI bus init & bidirectional transfer | `hardware_spi` | +| [0x0c_multicore](drivers/0x0c_multicore) | Dual-core launch & FIFO messaging | `pico_multicore` | +| [0x0d_timer](drivers/0x0d_timer) | Repeating timer callbacks | `pico_stdlib` | +| [0x0e_watchdog](drivers/0x0e_watchdog) | Watchdog enable, feed & reboot detection | `hardware_watchdog` | +| [0x0f_flash](drivers/0x0f_flash) | On-board flash erase, write & read | `hardware_flash`, `hardware_sync` | + +
+ # License [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) diff --git a/drivers/0x01_uart/0x01_uart.c b/drivers/0x01_uart/0x01_uart.c new file mode 100644 index 0000000..c375604 --- /dev/null +++ b/drivers/0x01_uart/0x01_uart.c @@ -0,0 +1,78 @@ +/** + * @file 0x01_uart.c + * @brief UART demonstration: echo received characters back in uppercase + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates hardware UART0 using the uart driver (uart.h / uart.c). + * Characters typed into a terminal via a USB-to-UART adapter are echoed + * back in uppercase, illustrating full-duplex raw UART operation without + * going through the stdio layer. + * + * Wiring: + * GPIO0 (TX) -> USB-to-UART adapter RX + * GPIO1 (RX) -> USB-to-UART adapter TX + * GND -> USB-to-UART adapter GND + */ + +#include "pico/stdlib.h" +#include "uart.h" + +#define UART_TX_PIN 0 +#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; +} + +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); + uart_driver_putchar(upper); + } + } +} diff --git a/drivers/0x01_uart/CMakeLists.txt b/drivers/0x01_uart/CMakeLists.txt new file mode 100644 index 0000000..6816052 --- /dev/null +++ b/drivers/0x01_uart/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x01_uart C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x01_uart 0x01_uart.c uart.c) + +pico_set_program_name(0x01_uart "0x01_uart") +pico_set_program_version(0x01_uart "0.1") + +# Disable stdio routing - driver uses hardware UART0 directly (GPIO0/GPIO1) +pico_enable_stdio_uart(0x01_uart 0) +pico_enable_stdio_usb(0x01_uart 0) + +# Add the standard library to the build +target_link_libraries(0x01_uart + pico_stdlib + hardware_uart) + +# Add the standard include files to the build +target_include_directories(0x01_uart PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x01_uart) diff --git a/drivers/0x01_uart/pico_sdk_import.cmake b/drivers/0x01_uart/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x01_uart/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x01_uart/uart.c b/drivers/0x01_uart/uart.c new file mode 100644 index 0000000..0dfbf51 --- /dev/null +++ b/drivers/0x01_uart/uart.c @@ -0,0 +1,59 @@ +/** + * @file uart.c + * @brief Implementation of the hardware UART0 driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "uart.h" +#include "pico/stdlib.h" +#include "hardware/uart.h" +#include "hardware/gpio.h" + +#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++); + } +} diff --git a/drivers/0x01_uart/uart.h b/drivers/0x01_uart/uart.h new file mode 100644 index 0000000..f366a05 --- /dev/null +++ b/drivers/0x01_uart/uart.h @@ -0,0 +1,89 @@ +/** + * @file uart.h + * @brief Header for hardware UART0 driver (raw TX/RX, GPIO 0/1) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef UART_H +#define UART_H + +#include +#include + +/** + * @brief Initialize hardware UART0 on the specified TX and RX GPIO pins + * + * Configures UART0 at the requested baud rate, sets the GPIO alternate + * functions for TX and RX, and enables 8N1 framing. Must be called once + * before using any other uart_driver_* functions. + * + * @param tx_pin GPIO pin number to use as UART0 TX (typically 0) + * @param rx_pin GPIO pin number to use as UART0 RX (typically 1) + * @param baud_rate Desired baud rate in bits per second (e.g. 115200) + */ +void uart_driver_init(uint32_t tx_pin, uint32_t rx_pin, uint32_t baud_rate); + +/** + * @brief Check whether a received character is waiting in the UART FIFO + * + * Returns immediately without blocking. Use this to poll for incoming + * data before calling uart_driver_getchar(). + * + * @return bool true if at least one byte is available to read, false otherwise + */ +bool uart_driver_is_readable(void); + +/** + * @brief Read one character from UART0 (blocking) + * + * Blocks until a byte arrives in the receive FIFO, then returns it. + * Prefer pairing with uart_driver_is_readable() to avoid indefinite blocking. + * + * @return char The received character + */ +char uart_driver_getchar(void); + +/** + * @brief Transmit one character over UART0 (blocking) + * + * Waits until the transmit FIFO has space, then places the character into the + * FIFO. Returns once the byte has been accepted by the hardware. + * + * @param c Character to transmit + */ +void uart_driver_putchar(char c); + +/** + * @brief Transmit a null-terminated string over UART0 + * + * Calls uart_driver_putchar() for every character in the string up to and + * not including the null terminator. + * + * @param str Pointer to the null-terminated ASCII string to send + */ +void uart_driver_puts(const char *str); + +#endif // UART_H diff --git a/drivers/0x02_blink/0x02_blink.c b/drivers/0x02_blink/0x02_blink.c new file mode 100644 index 0000000..16fb1ae --- /dev/null +++ b/drivers/0x02_blink/0x02_blink.c @@ -0,0 +1,57 @@ +/** + * @file 0x02_blink.c + * @brief Blink demonstration: toggle onboard LED every 500 ms + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates GPIO output control using the blink driver (blink.h / blink.c). + * The onboard LED on GPIO 25 is toggled every BLINK_DELAY_MS milliseconds and + * the current state is reported over UART. + * + * Wiring: + * GPIO25 -> Onboard LED (no external wiring needed) + */ + +#include +#include "pico/stdlib.h" +#include "blink.h" + +#define LED_PIN 25 +#define BLINK_DELAY_MS 500 + +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); + } +} diff --git a/drivers/0x02_blink/CMakeLists.txt b/drivers/0x02_blink/CMakeLists.txt new file mode 100644 index 0000000..adcca84 --- /dev/null +++ b/drivers/0x02_blink/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x02_blink C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x02_blink 0x02_blink.c blink.c) + +pico_set_program_name(0x02_blink "0x02_blink") +pico_set_program_version(0x02_blink "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x02_blink 1) +pico_enable_stdio_usb(0x02_blink 0) + +# Add the standard library to the build +target_link_libraries(0x02_blink + pico_stdlib) + +# Add the standard include files to the build +target_include_directories(0x02_blink PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x02_blink) diff --git a/drivers/0x02_blink/blink.c b/drivers/0x02_blink/blink.c new file mode 100644 index 0000000..d3f0af4 --- /dev/null +++ b/drivers/0x02_blink/blink.c @@ -0,0 +1,54 @@ +/** + * @file blink.c + * @brief Implementation of the GPIO output / LED blink driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "blink.h" +#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); +} diff --git a/drivers/0x02_blink/blink.h b/drivers/0x02_blink/blink.h new file mode 100644 index 0000000..a373a5d --- /dev/null +++ b/drivers/0x02_blink/blink.h @@ -0,0 +1,78 @@ +/** + * @file blink.h + * @brief Header for GPIO output / LED blink driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BLINK_H +#define BLINK_H + +#include +#include + +/** + * @brief Initialize a GPIO pin as a push-pull digital output + * + * Calls gpio_init() and gpio_set_dir() to configure the pin for output. + * The initial drive level is low (LED off). + * + * @param pin GPIO pin number to configure as a digital output + */ +void blink_init(uint32_t pin); + +/** + * @brief Drive the output pin high (LED on) + * + * @param pin GPIO pin number previously initialized with blink_init() + */ +void blink_on(uint32_t pin); + +/** + * @brief Drive the output pin low (LED off) + * + * @param pin GPIO pin number previously initialized with blink_init() + */ +void blink_off(uint32_t pin); + +/** + * @brief Toggle the current state of the output pin + * + * Reads the current GPIO output level and inverts it. If the LED was on + * it is turned off, and vice versa. + * + * @param pin GPIO pin number previously initialized with blink_init() + */ +void blink_toggle(uint32_t pin); + +/** + * @brief Query the current drive state of the output pin + * + * @param pin GPIO pin number previously initialized with blink_init() + * @return bool true if the pin is driven high, false if driven low + */ +bool blink_get_state(uint32_t pin); + +#endif // BLINK_H diff --git a/drivers/0x02_blink/pico_sdk_import.cmake b/drivers/0x02_blink/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x02_blink/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x03_button/0x03_button.c b/drivers/0x03_button/0x03_button.c new file mode 100644 index 0000000..aa1b558 --- /dev/null +++ b/drivers/0x03_button/0x03_button.c @@ -0,0 +1,71 @@ +/** + * @file 0x03_button.c + * @brief Button demonstration: debounced press mirrors to LED + UART report + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates GPIO input using the button driver (button.h / button.c). + * The onboard LED mirrors the button state and every edge transition is + * reported over UART. + * + * Wiring: + * GPIO15 -> One leg of push button + * GND -> Other leg of push button + * GPIO25 -> Onboard LED (no external wiring needed) + */ + +#include +#include "pico/stdlib.h" +#include "button.h" + +#define BUTTON_PIN 15 +#define LED_PIN 25 +#define DEBOUNCE_MS 20 + +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); + + 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; + } + + sleep_ms(10); + } +} diff --git a/drivers/0x03_button/CMakeLists.txt b/drivers/0x03_button/CMakeLists.txt new file mode 100644 index 0000000..b6442bd --- /dev/null +++ b/drivers/0x03_button/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x03_button C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x03_button 0x03_button.c button.c) + +pico_set_program_name(0x03_button "0x03_button") +pico_set_program_version(0x03_button "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x03_button 1) +pico_enable_stdio_usb(0x03_button 0) + +# Add the standard library to the build +target_link_libraries(0x03_button + pico_stdlib) + +# Add the standard include files to the build +target_include_directories(0x03_button PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x03_button) diff --git a/drivers/0x03_button/button.c b/drivers/0x03_button/button.c new file mode 100644 index 0000000..e0bb2df --- /dev/null +++ b/drivers/0x03_button/button.c @@ -0,0 +1,73 @@ +/** + * @file button.c + * @brief Implementation of the push-button GPIO input driver with debounce + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "button.h" +#include "pico/stdlib.h" +#include "hardware/gpio.h" + +static uint32_t debounce_delay_ms = 20; + +/** + * @brief Confirm a raw active-low pin read by waiting for the debounce period + * + * After an initial low reading on the pin, this helper re-samples the pin + * after debounce_delay_ms milliseconds to confirm the reading is stable. + * This eliminates false triggers caused by mechanical contact bounce. + * + * @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) { + 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); + gpio_set_dir(pin, GPIO_IN); + gpio_pull_up(pin); +} + +bool button_is_pressed(uint32_t pin) { + if (!gpio_get(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); +} diff --git a/drivers/0x03_button/button.h b/drivers/0x03_button/button.h new file mode 100644 index 0000000..7bc1de5 --- /dev/null +++ b/drivers/0x03_button/button.h @@ -0,0 +1,80 @@ +/** + * @file button.h + * @brief Header for push-button GPIO input driver with debounce + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef BUTTON_H +#define BUTTON_H + +#include +#include + +/** + * @brief Initialize a GPIO pin as an active-low button input with pull-up + * + * Configures the pin as an input and enables the internal pull-up resistor. + * The pin reads logic high when the button is open and logic low when the + * button connects the pin to GND. + * + * @param pin GPIO pin number to configure as a button input + * @param debounce_ms Debounce settling time in milliseconds (e.g. 20) + */ +void button_init(uint32_t pin, uint32_t debounce_ms); + +/** + * @brief Read the debounced state of the button + * + * Returns true only when the pin reads low continuously for the debounce + * period configured in button_init(). This prevents mechanical contact + * bounce from registering as multiple rapid presses. + * + * @param pin GPIO pin number previously initialized with button_init() + * @return bool true if the button is firmly pressed, false if released + */ +bool button_is_pressed(uint32_t pin); + +/** + * @brief Initialize a GPIO pin as a push-pull digital output for an indicator LED + * + * Configures the pin as a digital output and drives it low (LED off). Use + * together with button_led_set() to mirror button state visually. + * + * @param pin GPIO pin number to configure as an LED output + */ +void button_led_init(uint32_t pin); + +/** + * @brief Set the indicator LED state + * + * Drives the output pin high (LED on) or low (LED off). + * + * @param pin GPIO pin number previously initialized with button_led_init() + * @param on true to turn the LED on, false to turn it off + */ +void button_led_set(uint32_t pin, bool on); + +#endif // BUTTON_H diff --git a/drivers/0x03_button/pico_sdk_import.cmake b/drivers/0x03_button/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x03_button/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x04_pwm/0x04_pwm.c b/drivers/0x04_pwm/0x04_pwm.c new file mode 100644 index 0000000..1688519 --- /dev/null +++ b/drivers/0x04_pwm/0x04_pwm.c @@ -0,0 +1,65 @@ +/** + * @file 0x04_pwm.c + * @brief PWM demonstration: LED breathing effect via duty-cycle sweep + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates PWM output using the pwm driver (pwm.h / pwm.c). A 1 kHz + * signal on GPIO 0 sweeps its duty cycle from 0% to 100% and back to + * produce a smooth LED breathing effect. The current duty is reported + * over UART. + * + * Wiring: + * GPIO0 -> LED anode (with 330 ohm series resistor to GND) + */ + +#include +#include "pico/stdlib.h" +#include "pwm.h" + +#define PWM_PIN 0 +#define PWM_FREQ_HZ 1000 + +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); + } + } +} diff --git a/drivers/0x04_pwm/CMakeLists.txt b/drivers/0x04_pwm/CMakeLists.txt new file mode 100644 index 0000000..f9fa8ef --- /dev/null +++ b/drivers/0x04_pwm/CMakeLists.txt @@ -0,0 +1,58 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x04_pwm C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x04_pwm 0x04_pwm.c pwm.c) + +pico_set_program_name(0x04_pwm "0x04_pwm") +pico_set_program_version(0x04_pwm "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x04_pwm 1) +pico_enable_stdio_usb(0x04_pwm 0) + +# Add the standard library to the build +target_link_libraries(0x04_pwm + pico_stdlib + hardware_pwm + hardware_clocks) + +# Add the standard include files to the build +target_include_directories(0x04_pwm PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x04_pwm) diff --git a/drivers/0x04_pwm/pico_sdk_import.cmake b/drivers/0x04_pwm/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x04_pwm/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x04_pwm/pwm.c b/drivers/0x04_pwm/pwm.c new file mode 100644 index 0000000..541132a --- /dev/null +++ b/drivers/0x04_pwm/pwm.c @@ -0,0 +1,74 @@ +/** + * @file pwm.c + * @brief Implementation of the generic PWM output driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "pwm.h" +#include "pico/stdlib.h" +#include "hardware/pwm.h" +#include "hardware/clocks.h" + +static uint pwm_slice; +static uint pwm_chan; +static uint32_t pwm_wrap; + +/** + * @brief Compute the PWM clock divider that yields the target frequency + * + * Derives a floating-point divider from the current system clock frequency, + * the desired output frequency, and the chosen wrap value so that the PWM + * counter overflows exactly freq_hz times per second. + * + * @param freq_hz Desired PWM output frequency in Hz + * @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) { + uint32_t sys_hz = clock_get_hz(clk_sys); + return (float)sys_hz / ((float)freq_hz * (float)(wrap_val + 1)); +} + +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); +} + +void pwm_driver_set_duty_percent(uint8_t percent) { + if (percent > 100) { + percent = 100; + } + uint32_t level = ((uint32_t)percent * (pwm_wrap + 1)) / 100; + pwm_set_chan_level(pwm_slice, pwm_chan, level); +} diff --git a/drivers/0x04_pwm/pwm.h b/drivers/0x04_pwm/pwm.h new file mode 100644 index 0000000..fc9e0a2 --- /dev/null +++ b/drivers/0x04_pwm/pwm.h @@ -0,0 +1,59 @@ +/** + * @file pwm.h + * @brief Header for generic PWM output driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef PWM_H +#define PWM_H + +#include + +/** + * @brief Initialize PWM output on the specified GPIO pin at a target frequency + * + * Assigns the GPIO pin to the PWM function, calculates the clock divider and + * wrap value from the system clock to achieve the requested frequency, then + * starts the PWM slice with a 0% duty cycle. Must be called once before using + * pwm_driver_set_duty_percent(). + * + * @param pin GPIO pin number to drive with PWM output + * @param freq_hz Desired PWM frequency in Hz (e.g. 1000 for 1 kHz) + */ +void pwm_driver_init(uint32_t pin, uint32_t freq_hz); + +/** + * @brief Set the PWM duty cycle as an integer percentage + * + * Maps the percentage value to the internal PWM counter range and writes + * the result to the channel level register. Values above 100 are clamped + * to 100. + * + * @param percent Duty cycle from 0 (always low) to 100 (always high) + */ +void pwm_driver_set_duty_percent(uint8_t percent); + +#endif // PWM_H diff --git a/drivers/0x05_servo/0x05_servo.c b/drivers/0x05_servo/0x05_servo.c new file mode 100644 index 0000000..3e7a41a --- /dev/null +++ b/drivers/0x05_servo/0x05_servo.c @@ -0,0 +1,70 @@ +/** + * @file 0x05_servo.c + * @brief SG90 servo motor driver for the Raspberry Pi Pico 2 + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * This driver demonstrates SG90 servo control using the servo.c/servo.h + * driver (PWM at 50 Hz on GPIO 6). The servo sweeps from 0 degrees to + * 180 degrees and back in 10-degree increments, printing each angle over + * UART. + * + * Wiring: + * GPIO6 -> Servo signal wire (orange or yellow) + * 5V -> Servo power wire (red) -- use external 5 V supply for load + * GND -> Servo ground wire (brown or black) + */ + +#include +#include "pico/stdlib.h" +#include "servo.h" + +#define SERVO_GPIO 6 +#define STEP_DEGREES 10 +#define STEP_DELAY_MS 150 + +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); + + 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); + } + } +} diff --git a/drivers/0x05_servo/CMakeLists.txt b/drivers/0x05_servo/CMakeLists.txt new file mode 100644 index 0000000..55266bd --- /dev/null +++ b/drivers/0x05_servo/CMakeLists.txt @@ -0,0 +1,58 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x05_servo C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x05_servo 0x05_servo.c servo.c) + +pico_set_program_name(0x05_servo "0x05_servo") +pico_set_program_version(0x05_servo "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x05_servo 1) +pico_enable_stdio_usb(0x05_servo 0) + +# Add the standard library to the build +target_link_libraries(0x05_servo + pico_stdlib + hardware_pwm + hardware_clocks) + +# Add the standard include files to the build +target_include_directories(0x05_servo PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x05_servo) diff --git a/drivers/0x05_servo/pico_sdk_import.cmake b/drivers/0x05_servo/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x05_servo/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x05_servo/servo.c b/drivers/0x05_servo/servo.c new file mode 100644 index 0000000..4cf3481 --- /dev/null +++ b/drivers/0x05_servo/servo.c @@ -0,0 +1,98 @@ +/** + * @file servo.c + * @brief Implementation of a simple SG90 servo driver using PWM (50Hz) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "servo.h" +#include "pico/stdlib.h" +#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 float servo_hz = 50.0f; +static bool servo_initialized = false; + +/** + * @brief Convert a pulse width in microseconds to a PWM counter level + * + * Uses the configured PWM wrap and servo frequency to map pulse time + * into the channel compare value expected by the PWM hardware. + * + * @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 + 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); + + 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); + servo_initialized = true; +} + +void servo_set_pulse_us(uint16_t pulse_us) { + if (!servo_initialized) return; // not initialized + // clamp to defaults + 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); + 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); +} \ No newline at end of file diff --git a/drivers/0x05_servo/servo.h b/drivers/0x05_servo/servo.h new file mode 100644 index 0000000..878d029 --- /dev/null +++ b/drivers/0x05_servo/servo.h @@ -0,0 +1,62 @@ +/** + * @file servo.h + * @brief Header for SG90 servo driver (PWM) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SERVO_H +#define SERVO_H + +#include +#include + +/** + * @brief Initialize servo driver on a given GPIO pin + * + * Configures PWM for a 50 Hz servo (SG90). Call once before using other API. + * + * @param pin GPIO pin number to use for servo PWM + */ +void servo_init(uint8_t pin); + +/** + * @brief Set servo pulse width in microseconds (typical 1000-2000) + * + * @param pulse_us Pulse width in microseconds + */ +void servo_set_pulse_us(uint16_t pulse_us); + +/** + * @brief Set servo angle in degrees (0 to 180) + * + * Maps 0..180 degrees to the configured pulse range (default 1000..2000 us). + * Values outside [0,180] will be clamped. + * + * @param degrees Angle in degrees + */ +void servo_set_angle(float degrees); + +#endif // SERVO_H diff --git a/drivers/0x06_adc/0x06_adc.c b/drivers/0x06_adc/0x06_adc.c new file mode 100644 index 0000000..750db77 --- /dev/null +++ b/drivers/0x06_adc/0x06_adc.c @@ -0,0 +1,64 @@ +/** + * @file 0x06_adc.c + * @brief ADC demonstration: potentiometer voltage + on-chip temperature + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates 12-bit ADC using the adc driver (adc.h / adc.c). Reads + * ADC channel 0 (GPIO 26) and reports the voltage in millivolts alongside + * the on-chip temperature sensor reading every 500 ms over UART. + * + * Wiring: + * GPIO26 -> Wiper of a 10 kohm potentiometer + * 3.3V -> One end of the potentiometer + * GND -> Other end of the potentiometer + */ + +#include +#include "pico/stdlib.h" +#include "adc.h" + +#define ADC_GPIO 26 +#define ADC_CHANNEL 0 + +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); + + 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); + + sleep_ms(500); + } +} diff --git a/drivers/0x06_adc/CMakeLists.txt b/drivers/0x06_adc/CMakeLists.txt new file mode 100644 index 0000000..72fe0a2 --- /dev/null +++ b/drivers/0x06_adc/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x06_adc C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x06_adc 0x06_adc.c adc.c) + +pico_set_program_name(0x06_adc "0x06_adc") +pico_set_program_version(0x06_adc "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x06_adc 1) +pico_enable_stdio_usb(0x06_adc 0) + +# Add the standard library to the build +target_link_libraries(0x06_adc + pico_stdlib + hardware_adc) + +# Add the standard include files to the build +target_include_directories(0x06_adc PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x06_adc) diff --git a/drivers/0x06_adc/adc.c b/drivers/0x06_adc/adc.c new file mode 100644 index 0000000..5e19e06 --- /dev/null +++ b/drivers/0x06_adc/adc.c @@ -0,0 +1,82 @@ +/** + * @file adc.c + * @brief Implementation of the 12-bit ADC driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "adc.h" +#include "pico/stdlib.h" +#include "hardware/adc.h" + +#define ADC_VREF_MV 3300 +#define ADC_FULL_SCALE 4095 + +static uint8_t active_channel = 0; + +/** + * @brief Convert a raw 12-bit ADC value to millivolts + * + * Scales the raw value linearly against the 3.3 V reference. + * + * @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) { + return (uint32_t)raw * ADC_VREF_MV / ADC_FULL_SCALE; +} + +/** + * @brief Convert a raw temperature-sensor ADC value to degrees Celsius + * + * Applies the RP2350 datasheet formula: + * T = 27 - (V - 0.706) / 0.001721 + * + * @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) { + 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(); + adc_gpio_init(gpio); + adc_set_temp_sensor_enabled(true); + adc_select_input(channel); +} + +uint32_t adc_driver_read_mv(void) { + return raw_to_mv(adc_read()); +} + +float adc_driver_read_temp_celsius(void) { + adc_select_input(4); + float result = raw_to_celsius(adc_read()); + adc_select_input(active_channel); + return result; +} diff --git a/drivers/0x06_adc/adc.h b/drivers/0x06_adc/adc.h new file mode 100644 index 0000000..b607551 --- /dev/null +++ b/drivers/0x06_adc/adc.h @@ -0,0 +1,69 @@ +/** + * @file adc.h + * @brief Header for 12-bit ADC driver (analog pin + internal temperature sensor) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef ADC_H +#define ADC_H + +#include + +/** + * @brief Initialize the ADC peripheral and configure an analog GPIO pin + * + * Powers on the ADC block, configures the specified GPIO as an analog input, + * enables the internal temperature sensor on channel 4, and selects the + * given channel as the active input. Must be called once before using any + * other adc_driver_* functions. + * + * @param gpio GPIO pin number for the analog input (26 = ch0, 27 = ch1, 28 = ch2) + * @param channel ADC channel number corresponding to the GPIO (0, 1, or 2) + */ +void adc_driver_init(uint32_t gpio, uint8_t channel); + +/** + * @brief Perform a single ADC conversion on the active channel and return millivolts + * + * Reads the 12-bit raw value from the currently selected channel and scales + * it to millivolts using the 3.3 V (3300 mV) full-scale reference. + * + * @return uint32_t Measured voltage in millivolts (0 to 3300) + */ +uint32_t adc_driver_read_mv(void); + +/** + * @brief Read the on-chip temperature sensor and return degrees Celsius + * + * Temporarily switches to ADC channel 4 (internal temperature sensor), + * performs a conversion, applies the formula from the RP2350 datasheet, + * then restores the channel that was active before the call. + * + * @return float Die temperature in degrees Celsius + */ +float adc_driver_read_temp_celsius(void); + +#endif // ADC_H diff --git a/drivers/0x06_adc/pico_sdk_import.cmake b/drivers/0x06_adc/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x06_adc/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x07_i2c/0x07_i2c.c b/drivers/0x07_i2c/0x07_i2c.c new file mode 100644 index 0000000..cf47b80 --- /dev/null +++ b/drivers/0x07_i2c/0x07_i2c.c @@ -0,0 +1,63 @@ +/** + * @file 0x07_i2c.c + * @brief I2C demonstration: scan all 7-bit addresses and report devices + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates I2C bus scanning using the i2c driver (i2c.h / i2c.c). I2C1 + * is configured at 100 kHz on SDA=GPIO2 / SCL=GPIO3. A formatted hex table + * of all responding device addresses is printed over UART and repeated + * every 5 seconds. + * + * Wiring: + * GPIO2 (SDA) -> I2C device SDA (4.7 kohm pull-up to 3.3 V recommended) + * GPIO3 (SCL) -> I2C device SCL (4.7 kohm pull-up to 3.3 V recommended) + * 3.3V -> I2C device VCC + * GND -> I2C device GND + */ + +#include +#include "pico/stdlib.h" +#include "i2c.h" + +#define I2C_PORT 1 +#define I2C_SDA_PIN 2 +#define I2C_SCL_PIN 3 +#define I2C_BAUD 100000 + +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); + } +} diff --git a/drivers/0x07_i2c/CMakeLists.txt b/drivers/0x07_i2c/CMakeLists.txt new file mode 100644 index 0000000..30a6ff6 --- /dev/null +++ b/drivers/0x07_i2c/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x07_i2c C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x07_i2c 0x07_i2c.c i2c.c) + +pico_set_program_name(0x07_i2c "0x07_i2c") +pico_set_program_version(0x07_i2c "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x07_i2c 1) +pico_enable_stdio_usb(0x07_i2c 0) + +# Add the standard library to the build +target_link_libraries(0x07_i2c + pico_stdlib + hardware_i2c) + +# Add the standard include files to the build +target_include_directories(0x07_i2c PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x07_i2c) diff --git a/drivers/0x07_i2c/i2c.c b/drivers/0x07_i2c/i2c.c new file mode 100644 index 0000000..1a09d4f --- /dev/null +++ b/drivers/0x07_i2c/i2c.c @@ -0,0 +1,75 @@ +/** + * @file i2c.c + * @brief Implementation of the I2C bus driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "i2c.h" +#include +#include "pico/stdlib.h" +#include "hardware/i2c.h" +#include "hardware/gpio.h" + +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_init(inst, 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); +} + +bool i2c_driver_probe(uint8_t port, uint8_t addr) { + 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) { + 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"); + } + } +} diff --git a/drivers/0x07_i2c/i2c.h b/drivers/0x07_i2c/i2c.h new file mode 100644 index 0000000..c5add58 --- /dev/null +++ b/drivers/0x07_i2c/i2c.h @@ -0,0 +1,75 @@ +/** + * @file i2c.h + * @brief Header for I2C bus driver (init + 7-bit address scanner) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef I2C_H +#define I2C_H + +#include +#include + +/** + * @brief Initialize an I2C peripheral at the requested baud rate + * + * Calls i2c_init() for the given instance, assigns the GPIO alternate + * functions for SDA and SCL, and enables the internal pull-ups on both + * pins so that short buses operate without external resistors. + * + * @param port I2C port number (0 for i2c0, 1 for i2c1) + * @param sda_pin GPIO pin number for SDA + * @param scl_pin GPIO pin number for SCL + * @param baud_hz Bus clock frequency in Hz (e.g. 100000 for standard mode) + */ +void i2c_driver_init(uint8_t port, uint32_t sda_pin, uint32_t scl_pin, + uint32_t baud_hz); + +/** + * @brief Probe a 7-bit I2C address and return whether a device responds + * + * Attempts a 1-byte read to the target address. A non-negative return from + * i2c_read_blocking() means the device sent an ACK. A negative return means + * the address is unoccupied. + * + * @param port I2C port number (0 for i2c0, 1 for i2c1) + * @param addr 7-bit I2C address to probe (0x00 - 0x7F) + * @return bool true if a device acknowledged, false otherwise + */ +bool i2c_driver_probe(uint8_t port, uint8_t addr); + +/** + * @brief Scan all valid 7-bit addresses and print a formatted table over UART + * + * Iterates addresses 0x08 through 0x77, probes each one via i2c_driver_probe(), + * and prints a 16-column hex grid showing discovered device addresses. + * The reserved ranges (0x00-0x07 and 0x78-0x7F) are shown as blank. + * + * @param port I2C port number (0 for i2c0, 1 for i2c1) + */ +void i2c_driver_scan(uint8_t port); + +#endif // I2C_H diff --git a/drivers/0x07_i2c/pico_sdk_import.cmake b/drivers/0x07_i2c/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x07_i2c/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x08_lcd1602/0x08_lcd1602.c b/drivers/0x08_lcd1602/0x08_lcd1602.c new file mode 100644 index 0000000..6a1ca59 --- /dev/null +++ b/drivers/0x08_lcd1602/0x08_lcd1602.c @@ -0,0 +1,76 @@ +/** + * @file 0x08_lcd1602.c + * @brief HD44780 16x2 LCD (PCF8574 I2C backpack) driver for the Raspberry Pi Pico 2 + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * This driver demonstrates how to drive a 16x2 HD44780 LCD connected via a + * PCF8574 I2C backpack using the lcd1602.c/lcd1602.h driver. Line 0 shows + * a static title and line 1 displays a live up-counter that increments every + * second. The counter value is also printed over UART for debugging. + * + * Wiring: + * GPIO2 (SDA) -> PCF8574 backpack SDA (4.7 kohm pull-up to 3.3 V) + * GPIO3 (SCL) -> PCF8574 backpack SCL (4.7 kohm pull-up to 3.3 V) + * 3.3V or 5V -> PCF8574 backpack VCC + * GND -> PCF8574 backpack GND + */ + +#include +#include +#include "pico/stdlib.h" +#include "lcd1602.h" + +#define I2C_PORT 1 +#define I2C_SDA_PIN 2 +#define I2C_SCL_PIN 3 +#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); + + 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); + } +} diff --git a/drivers/0x08_lcd1602/CMakeLists.txt b/drivers/0x08_lcd1602/CMakeLists.txt new file mode 100644 index 0000000..7767c8b --- /dev/null +++ b/drivers/0x08_lcd1602/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x08_lcd1602 C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x08_lcd1602 0x08_lcd1602.c lcd1602.c) + +pico_set_program_name(0x08_lcd1602 "0x08_lcd1602") +pico_set_program_version(0x08_lcd1602 "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x08_lcd1602 1) +pico_enable_stdio_usb(0x08_lcd1602 0) + +# Add the standard library to the build +target_link_libraries(0x08_lcd1602 + pico_stdlib + hardware_i2c) + +# Add the standard include files to the build +target_include_directories(0x08_lcd1602 PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x08_lcd1602) diff --git a/drivers/0x08_lcd1602/lcd1602.c b/drivers/0x08_lcd1602/lcd1602.c new file mode 100644 index 0000000..01bca34 --- /dev/null +++ b/drivers/0x08_lcd1602/lcd1602.c @@ -0,0 +1,155 @@ +/** + * @file lcd1602.c + * @brief Implementation of PCF8574-backed HD44780 (16x2) LCD driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "lcd1602.h" +#include +#include +#include "pico/stdlib.h" +#include "hardware/i2c.h" + +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; +static uint8_t lcd_backlight_mask = 0x08; + +/* PCF8574 -> LCD control pins */ +#define PIN_RS 0x01 +#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) { + 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); + sleep_us(1); + 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) { + uint8_t data = (nibble & 0x0F) << lcd_nibble_shift; + data |= mode ? PIN_RS : 0; + data |= lcd_backlight_mask; + 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); +} + +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_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); + 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); +} + +void lcd_puts(const char *s) { + while (*s) { + lcd_send((uint8_t)*s++, 1); + } +} diff --git a/drivers/0x08_lcd1602/lcd1602.h b/drivers/0x08_lcd1602/lcd1602.h new file mode 100644 index 0000000..d99ad8f --- /dev/null +++ b/drivers/0x08_lcd1602/lcd1602.h @@ -0,0 +1,93 @@ +/** + * @file lcd1602.h + * @brief Header for PCF8574-backed HD44780 (16x2) LCD driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef LCD1602_H +#define LCD1602_H + +#include +#include + +/** + * @brief Initialize I2C bus and the LCD driver in one call + * + * Configures the I2C peripheral at the given baud rate, assigns GPIO + * alternate functions for SDA and SCL with internal pull-ups, and then + * performs the full HD44780 4-bit initialization sequence through the + * PCF8574 backpack. This is a convenience wrapper around lcd_i2c_init(). + * + * @param i2c_port I2C port number (0 for i2c0, 1 for i2c1) + * @param sda_pin GPIO pin number for SDA + * @param scl_pin GPIO pin number for SCL + * @param baud_hz I2C clock rate in Hz (e.g. 100000) + * @param pcf_addr PCF8574 I2C address (commonly 0x27 or 0x3F) + * @param nibble_shift Bit shift applied to 4-bit nibbles (commonly 4 or 0) + * @param backlight_mask PCF8574 bit mask that controls the backlight + */ +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); + +/** + * @brief Initialize the LCD driver over I2C + * + * Configures the internal driver state and performs the HD44780 initialization + * sequence. The driver does not configure I2C pins or call i2c_init; that + * must be done by the caller prior to calling this function. + * + * @param i2c_port I2C port number (0 for i2c0, 1 for i2c1) + * @param pcf_addr PCF8574 I2C address (commonly 0x27 or 0x3F) + * @param nibble_shift Bit shift applied to 4-bit nibbles (commonly 4 or 0) + * @param backlight_mask PCF8574 bit mask that controls the backlight + */ +void lcd_i2c_init(uint8_t i2c_port, uint8_t pcf_addr, int nibble_shift, uint8_t backlight_mask); + +/** + * @brief Clear the LCD display + * + * Clears the display and returns the cursor to the home position. This + * call blocks for the duration required by the HD44780 controller. + */ +void lcd_clear(void); + +/** + * @brief Set the cursor position + * + * @param line Line number (0 or 1) + * @param position Column (0..15) + */ +void lcd_set_cursor(int line, int position); + +/** + * @brief Write a null-terminated string to the display + * + * @param s The string to write (ASCII) + */ +void lcd_puts(const char *s); + +#endif // LCD1602_H diff --git a/drivers/0x08_lcd1602/pico_sdk_import.cmake b/drivers/0x08_lcd1602/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x08_lcd1602/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x09_dht11/0x09_dht11.c b/drivers/0x09_dht11/0x09_dht11.c new file mode 100644 index 0000000..12fbc24 --- /dev/null +++ b/drivers/0x09_dht11/0x09_dht11.c @@ -0,0 +1,68 @@ +/** + * @file 0x09_dht11.c + * @brief DHT11 temperature and humidity sensor driver for the Raspberry Pi Pico 2 + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * This driver demonstrates how to read temperature and humidity from a DHT11 + * sensor using the dht11.c/dht11.h driver. The sensor is polled every 2 + * seconds (the minimum safe interval for the DHT11) and the results are + * printed over UART. A failed read is reported so wiring issues are visible. + * + * Wiring: + * GPIO4 -> DHT11 DATA pin (10 kohm pull-up to 3.3 V recommended) + * 3.3V -> DHT11 VCC + * GND -> DHT11 GND + */ + +#include +#include "pico/stdlib.h" +#include "dht11.h" + +#define DHT11_GPIO 4 + +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); + } +} diff --git a/drivers/0x09_dht11/CMakeLists.txt b/drivers/0x09_dht11/CMakeLists.txt new file mode 100644 index 0000000..e739b77 --- /dev/null +++ b/drivers/0x09_dht11/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x09_dht11 C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x09_dht11 0x09_dht11.c dht11.c) + +pico_set_program_name(0x09_dht11 "0x09_dht11") +pico_set_program_version(0x09_dht11 "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x09_dht11 1) +pico_enable_stdio_usb(0x09_dht11 0) + +# Add the standard library to the build +target_link_libraries(0x09_dht11 + pico_stdlib) + +# Add the standard include files to the build +target_include_directories(0x09_dht11 PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x09_dht11) diff --git a/drivers/0x09_dht11/dht11.c b/drivers/0x09_dht11/dht11.c new file mode 100644 index 0000000..9a52ba8 --- /dev/null +++ b/drivers/0x09_dht11/dht11.c @@ -0,0 +1,79 @@ +/** + * @file dht11.c + * @brief Implementation of DHT11 temperature and humidity sensor driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "dht11.h" +#include "hardware/gpio.h" +#include "pico/time.h" + +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 + 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 + 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; + + *humidity = data[0] + data[1] * 0.1f; + *temperature = data[2] + data[3] * 0.1f; + return true; +} diff --git a/drivers/0x09_dht11/dht11.h b/drivers/0x09_dht11/dht11.h new file mode 100644 index 0000000..30e298c --- /dev/null +++ b/drivers/0x09_dht11/dht11.h @@ -0,0 +1,57 @@ +/** + * @file dht11.h + * @brief Header for DHT11 temperature and humidity sensor driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef DHT11_H +#define DHT11_H + +#include +#include + +/** + * @brief Initialize the DHT11 driver + * + * Configures the GPIO pin for the DHT11 sensor. This must be called before + * using dht11_read(). + * + * @param pin GPIO pin number connected to DHT11 signal + */ +void dht11_init(uint8_t pin); + +/** + * @brief Read temperature and humidity from DHT11 sensor + * + * Performs the DHT11 communication protocol to read sensor data. + * + * @param humidity Pointer to store humidity value (0-100%) + * @param temperature Pointer to store temperature value in Celsius + * @return true if read successful, false on error or timeout + */ +bool dht11_read(float *humidity, float *temperature); + +#endif // DHT11_H diff --git a/drivers/0x09_dht11/pico_sdk_import.cmake b/drivers/0x09_dht11/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x09_dht11/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x0a_ir/0x0a_ir.c b/drivers/0x0a_ir/0x0a_ir.c new file mode 100644 index 0000000..36aa2dc --- /dev/null +++ b/drivers/0x0a_ir/0x0a_ir.c @@ -0,0 +1,61 @@ +/** + * @file 0x0a_ir.c + * @brief NEC IR (infrared) receiver driver for the Raspberry Pi Pico 2 + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * This driver demonstrates NEC infrared remote decoding using the + * ir.c/ir.h driver. The IR receiver module output is connected to GPIO 5. + * ir_getkey() blocks until a valid NEC frame is received or a timeout + * occurs. Each decoded command byte is printed over UART in hex and decimal. + * + * Wiring: + * GPIO5 -> IR receiver module OUT pin (e.g. VS1838B or TSOP4838) + * 3.3V -> IR receiver module VCC + * GND -> IR receiver module GND + */ + +#include +#include "pico/stdlib.h" +#include "ir.h" + +#define IR_GPIO 5 + +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); + } + } +} diff --git a/drivers/0x0a_ir/CMakeLists.txt b/drivers/0x0a_ir/CMakeLists.txt new file mode 100644 index 0000000..e28c847 --- /dev/null +++ b/drivers/0x0a_ir/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x0a_ir C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x0a_ir 0x0a_ir.c ir.c) + +pico_set_program_name(0x0a_ir "0x0a_ir") +pico_set_program_version(0x0a_ir "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x0a_ir 1) +pico_enable_stdio_usb(0x0a_ir 0) + +# Add the standard library to the build +target_link_libraries(0x0a_ir + pico_stdlib) + +# Add the standard include files to the build +target_include_directories(0x0a_ir PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x0a_ir) diff --git a/drivers/0x0a_ir/ir.c b/drivers/0x0a_ir/ir.c new file mode 100644 index 0000000..b89bd4e --- /dev/null +++ b/drivers/0x0a_ir/ir.c @@ -0,0 +1,80 @@ +/** + * @file ir.c + * @brief Implementation of NEC IR receiver (decoder) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ir.h" +#include "pico/stdlib.h" +#include "pico/time.h" +#include "hardware/gpio.h" + +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) { + 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) { + return -1; + } + } + return absolute_time_diff_us(start, get_absolute_time()); +} + +void ir_init(uint8_t pin) { + ir_pin = pin; + gpio_init(pin); + gpio_set_dir(pin, GPIO_IN); + 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; + + 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; +} diff --git a/drivers/0x0a_ir/ir.h b/drivers/0x0a_ir/ir.h new file mode 100644 index 0000000..fba6521 --- /dev/null +++ b/drivers/0x0a_ir/ir.h @@ -0,0 +1,56 @@ +/** + * @file ir.h + * @brief Header for NEC IR receiver (decoder) API + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IR_H +#define IR_H + +#include +#include + +/** + * @brief Initialize the IR receiver GPIO + * + * Configures the given `pin` as an input with pull-up for the NEC IR receiver. + * Call this once during board initialization before calling `ir_getkey()`. + * + * @param pin GPIO pin number connected to IR receiver output + */ +void ir_init(uint8_t pin); + +/** + * @brief Blocking NEC IR decoder + * + * Blocks while waiting for a complete NEC frame. On success returns the + * decoded command byte (0..255). On timeout or protocol error returns -1. + * + * @return decoded command byte (0..255) or -1 on failure + */ +int ir_getkey(void); + +#endif // IR_H diff --git a/drivers/0x0a_ir/pico_sdk_import.cmake b/drivers/0x0a_ir/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x0a_ir/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x0b_spi/0x0b_spi.c b/drivers/0x0b_spi/0x0b_spi.c new file mode 100644 index 0000000..0b71d19 --- /dev/null +++ b/drivers/0x0b_spi/0x0b_spi.c @@ -0,0 +1,72 @@ +/** + * @file 0x0b_spi.c + * @brief SPI loopback demo using spi.c/spi.h driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates SPI in master mode using the spi driver (spi.h / spi.c). + * A loopback wiring (MOSI -> MISO) is used to verify full-duplex transfer. + * Transmitted and received data is printed over UART every second. + * + * Wiring (loopback test): + * GPIO19 (MOSI) -> GPIO16 (MISO) + * GPIO18 (SCK) -> logic analyzer or slave SCK + * GPIO17 (CS) -> slave CS (active-low) + */ + +#include +#include +#include "pico/stdlib.h" +#include "spi.h" + +#define SPI_PORT 0 +#define SPI_BAUD_HZ (1000 * 1000) +#define PIN_MISO 16 +#define PIN_CS 17 +#define PIN_SCK 18 +#define PIN_MOSI 19 + +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); + } +} diff --git a/drivers/0x0b_spi/CMakeLists.txt b/drivers/0x0b_spi/CMakeLists.txt new file mode 100644 index 0000000..8c19e5c --- /dev/null +++ b/drivers/0x0b_spi/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x0b_spi C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x0b_spi 0x0b_spi.c spi.c) + +pico_set_program_name(0x0b_spi "0x0b_spi") +pico_set_program_version(0x0b_spi "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x0b_spi 1) +pico_enable_stdio_usb(0x0b_spi 0) + +# Add the standard library to the build +target_link_libraries(0x0b_spi + pico_stdlib + hardware_spi) + +# Add the standard include files to the build +target_include_directories(0x0b_spi PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x0b_spi) diff --git a/drivers/0x0b_spi/pico_sdk_import.cmake b/drivers/0x0b_spi/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x0b_spi/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x0b_spi/spi.c b/drivers/0x0b_spi/spi.c new file mode 100644 index 0000000..baba27f --- /dev/null +++ b/drivers/0x0b_spi/spi.c @@ -0,0 +1,64 @@ +/** + * @file spi.c + * @brief Implementation of SPI bus driver (master mode) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "spi.h" +#include "pico/stdlib.h" +#include "hardware/spi.h" + +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); + + gpio_set_function(mosi, GPIO_FUNC_SPI); + gpio_set_function(miso, GPIO_FUNC_SPI); + gpio_set_function(sck, GPIO_FUNC_SPI); + + 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_write_read_blocking(spi, tx, rx, (size_t)len); +} diff --git a/drivers/0x0b_spi/spi.h b/drivers/0x0b_spi/spi.h new file mode 100644 index 0000000..2ff3bba --- /dev/null +++ b/drivers/0x0b_spi/spi.h @@ -0,0 +1,82 @@ +/** + * @file spi.h + * @brief Header for SPI bus driver (full-duplex transfer with CS control) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SPI_H +#define SPI_H + +#include +#include + +/** + * @brief Initialize an SPI peripheral in master mode + * + * Configures the SPI instance at the requested baud rate, assigns GPIO + * alternate functions for MOSI, MISO, and SCK, and configures the chip + * select pin as a GPIO output deasserted (high) by default. + * + * @param port SPI port number (0 for spi0, 1 for spi1) + * @param mosi GPIO pin number for MOSI (controller TX) + * @param miso GPIO pin number for MISO (controller RX) + * @param sck GPIO pin number for SCK (clock) + * @param cs GPIO pin number for chip select (active-low) + * @param baud_hz Desired SPI clock frequency in Hz (e.g. 1000000 for 1 MHz) + */ +void spi_driver_init(uint8_t port, uint32_t mosi, uint32_t miso, + uint32_t sck, uint32_t cs, uint32_t baud_hz); + +/** + * @brief Assert the chip-select line (drive CS low) + * + * @param cs GPIO pin number of the chip-select output + */ +void spi_driver_cs_select(uint32_t cs); + +/** + * @brief Deassert the chip-select line (drive CS high) + * + * @param cs GPIO pin number of the chip-select output + */ +void spi_driver_cs_deselect(uint32_t cs); + +/** + * @brief Perform a full-duplex SPI transfer + * + * Sends @p len bytes from @p tx while simultaneously receiving @p len bytes + * into @p rx. Both buffers must hold at least @p len bytes. The caller is + * responsible for asserting and deasserting CS around this call. + * + * @param port SPI port number (0 for spi0, 1 for spi1) + * @param tx Pointer to the transmit buffer (must be @p len bytes) + * @param rx Pointer to the receive buffer (must be @p len bytes) + * @param len Number of bytes to transfer + */ +void spi_driver_transfer(uint8_t port, const uint8_t *tx, uint8_t *rx, + uint32_t len); + +#endif // SPI_H diff --git a/drivers/0x0c_multicore/0x0c_multicore.c b/drivers/0x0c_multicore/0x0c_multicore.c new file mode 100644 index 0000000..b68c6b2 --- /dev/null +++ b/drivers/0x0c_multicore/0x0c_multicore.c @@ -0,0 +1,64 @@ +/** + * @file 0x0c_multicore.c + * @brief Multicore FIFO messaging demo using multicore.c/multicore.h + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates dual-core operation using the multicore driver + * (multicore.h / multicore.c). Core 0 sends an incrementing counter to + * core 1 via the FIFO; core 1 returns the value plus one. Both values + * are printed over UART every second. + * + * Wiring: + * No external wiring required (dual-core communication is on-chip) + */ + +#include +#include "pico/stdlib.h" +#include "multicore.h" + +static void core1_main(void) { + while (true) { + uint32_t value = multicore_driver_pop(); + multicore_driver_push(value + 1u); + } +} + +int main(void) { + stdio_init_all(); + 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); + } +} diff --git a/drivers/0x0c_multicore/CMakeLists.txt b/drivers/0x0c_multicore/CMakeLists.txt new file mode 100644 index 0000000..75b2ad2 --- /dev/null +++ b/drivers/0x0c_multicore/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x0c_multicore C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x0c_multicore 0x0c_multicore.c multicore.c) + +pico_set_program_name(0x0c_multicore "0x0c_multicore") +pico_set_program_version(0x0c_multicore "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x0c_multicore 1) +pico_enable_stdio_usb(0x0c_multicore 0) + +# Add the standard library to the build +target_link_libraries(0x0c_multicore + pico_stdlib + pico_multicore) + +# Add the standard include files to the build +target_include_directories(0x0c_multicore PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x0c_multicore) diff --git a/drivers/0x0c_multicore/multicore.c b/drivers/0x0c_multicore/multicore.c new file mode 100644 index 0000000..d0a93f9 --- /dev/null +++ b/drivers/0x0c_multicore/multicore.c @@ -0,0 +1,43 @@ +/** + * @file multicore.c + * @brief Implementation of multicore FIFO driver for RP2350 + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "multicore.h" +#include "pico/multicore.h" + +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(); +} diff --git a/drivers/0x0c_multicore/multicore.h b/drivers/0x0c_multicore/multicore.h new file mode 100644 index 0000000..2618038 --- /dev/null +++ b/drivers/0x0c_multicore/multicore.h @@ -0,0 +1,66 @@ +/** + * @file multicore.h + * @brief Header for dual-core (multicore) driver using the FIFO mailbox + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MULTICORE_H +#define MULTICORE_H + +#include + +/** + * @brief Start the provided function on core 1 + * + * Launches the given entry function on the second RP2350 core using the + * Pico SDK multicore_launch_core1() API. The function will run + * concurrently with core 0 from the moment this call returns. + * + * @param core1_entry Pointer to the void(void) function to run on core 1 + */ +void multicore_driver_launch(void (*core1_entry)(void)); + +/** + * @brief Push a 32-bit value into the inter-core FIFO (blocking) + * + * Writes @p data to the FIFO that core 1 reads from. Blocks until + * there is space in the hardware FIFO. + * + * @param data 32-bit value to send to core 1 + */ +void multicore_driver_push(uint32_t data); + +/** + * @brief Pop a 32-bit value from the inter-core FIFO (blocking) + * + * Reads one entry from the FIFO that core 1 writes into. Blocks until + * a value is available. + * + * @return uint32_t Value received from core 1 + */ +uint32_t multicore_driver_pop(void); + +#endif // MULTICORE_H diff --git a/drivers/0x0c_multicore/pico_sdk_import.cmake b/drivers/0x0c_multicore/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x0c_multicore/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x0d_timer/0x0d_timer.c b/drivers/0x0d_timer/0x0d_timer.c new file mode 100644 index 0000000..400df78 --- /dev/null +++ b/drivers/0x0d_timer/0x0d_timer.c @@ -0,0 +1,56 @@ +/** + * @file 0x0d_timer.c + * @brief Repeating timer demo using timer.c/timer.h + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates repeating timer callbacks using the timer driver + * (timer.h / timer.c). A one-second heartbeat timer prints a message + * over UART to confirm the timer is firing. + * + * Wiring: + * No external wiring required + */ + +#include +#include "pico/stdlib.h" +#include "timer.h" + +static bool heartbeat_callback(void) { + printf("Timer heartbeat\r\n"); + return true; +} + +int main(void) { + stdio_init_all(); + + timer_driver_start(1000, heartbeat_callback); + + while (true) { + tight_loop_contents(); + } +} diff --git a/drivers/0x0d_timer/CMakeLists.txt b/drivers/0x0d_timer/CMakeLists.txt new file mode 100644 index 0000000..3306ced --- /dev/null +++ b/drivers/0x0d_timer/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x0d_timer C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x0d_timer 0x0d_timer.c timer.c) + +pico_set_program_name(0x0d_timer "0x0d_timer") +pico_set_program_version(0x0d_timer "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x0d_timer 1) +pico_enable_stdio_usb(0x0d_timer 0) + +# Add the standard library to the build +target_link_libraries(0x0d_timer + pico_stdlib) + +# Add the standard include files to the build +target_include_directories(0x0d_timer PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x0d_timer) diff --git a/drivers/0x0d_timer/pico_sdk_import.cmake b/drivers/0x0d_timer/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x0d_timer/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x0d_timer/timer.c b/drivers/0x0d_timer/timer.c new file mode 100644 index 0000000..f8ce692 --- /dev/null +++ b/drivers/0x0d_timer/timer.c @@ -0,0 +1,62 @@ +/** + * @file timer.c + * @brief Implementation of repeating timer driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "timer.h" +#include "pico/time.h" + +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) { + (void)rt; + 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); +} + +void timer_driver_cancel(void) { + if (!g_timer_active) { + return; + } + + cancel_repeating_timer(&g_timer); + g_timer_active = false; +} diff --git a/drivers/0x0d_timer/timer.h b/drivers/0x0d_timer/timer.h new file mode 100644 index 0000000..2141a62 --- /dev/null +++ b/drivers/0x0d_timer/timer.h @@ -0,0 +1,64 @@ +/** + * @file timer.h + * @brief Header for repeating hardware timer driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TIMER_H +#define TIMER_H + +#include +#include + +/** + * @brief Timer callback function signature + * + * Must return true to keep the timer repeating, or false to stop. + */ +typedef bool (*timer_driver_callback_t)(void); + +/** + * @brief Start a repeating hardware timer that fires the given callback + * + * Schedules @p callback to be invoked every @p period_ms milliseconds using + * the Pico SDK add_repeating_timer_ms() API. The timer continues firing + * until timer_driver_cancel() is called. + * + * @param period_ms Interval between callbacks in milliseconds (positive value) + * @param callback Function to call on each timer expiry; must return true to + * continue repeating, false to stop + */ +void timer_driver_start(int32_t period_ms, timer_driver_callback_t callback); + +/** + * @brief Cancel the active repeating timer + * + * Stops the timer started by timer_driver_start(). Safe to call even if the + * timer has already fired and self-cancelled. + */ +void timer_driver_cancel(void); + +#endif // TIMER_H diff --git a/drivers/0x0e_watchdog/0x0e_watchdog.c b/drivers/0x0e_watchdog/0x0e_watchdog.c new file mode 100644 index 0000000..0b9d556 --- /dev/null +++ b/drivers/0x0e_watchdog/0x0e_watchdog.c @@ -0,0 +1,61 @@ +/** + * @file 0x0e_watchdog.c + * @brief Watchdog feed demo using watchdog.c/watchdog.h + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates the hardware watchdog using the watchdog driver + * (watchdog.h / watchdog.c). The watchdog is enabled with a 3-second + * timeout and fed every second. If the feed loop were removed, the + * chip would automatically reboot after 3 seconds. + * + * Wiring: + * No external wiring required + */ + +#include +#include "pico/stdlib.h" +#include "watchdog.h" + +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"); + } + + 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); + } +} diff --git a/drivers/0x0e_watchdog/CMakeLists.txt b/drivers/0x0e_watchdog/CMakeLists.txt new file mode 100644 index 0000000..a4a5159 --- /dev/null +++ b/drivers/0x0e_watchdog/CMakeLists.txt @@ -0,0 +1,57 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x0e_watchdog C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x0e_watchdog 0x0e_watchdog.c watchdog.c) + +pico_set_program_name(0x0e_watchdog "0x0e_watchdog") +pico_set_program_version(0x0e_watchdog "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x0e_watchdog 1) +pico_enable_stdio_usb(0x0e_watchdog 0) + +# Add the standard library to the build +target_link_libraries(0x0e_watchdog + pico_stdlib + hardware_watchdog) + +# Add the standard include files to the build +target_include_directories(0x0e_watchdog PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x0e_watchdog) diff --git a/drivers/0x0e_watchdog/pico_sdk_import.cmake b/drivers/0x0e_watchdog/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x0e_watchdog/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/drivers/0x0e_watchdog/watchdog.c b/drivers/0x0e_watchdog/watchdog.c new file mode 100644 index 0000000..fb677de --- /dev/null +++ b/drivers/0x0e_watchdog/watchdog.c @@ -0,0 +1,43 @@ +/** + * @file watchdog.c + * @brief Implementation of hardware watchdog driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "watchdog.h" +#include "hardware/watchdog.h" + +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(); +} diff --git a/drivers/0x0e_watchdog/watchdog.h b/drivers/0x0e_watchdog/watchdog.h new file mode 100644 index 0000000..3ff42cf --- /dev/null +++ b/drivers/0x0e_watchdog/watchdog.h @@ -0,0 +1,65 @@ +/** + * @file watchdog.h + * @brief Header for hardware watchdog timer driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef WATCHDOG_H +#define WATCHDOG_H + +#include +#include + +/** + * @brief Enable the hardware watchdog with the specified timeout + * + * Starts the watchdog timer. If watchdog_driver_feed() is not called within + * @p timeout_ms milliseconds, the RP2350 will perform a hard reset. + * The maximum supported timeout is 8388 ms. + * + * @param timeout_ms Watchdog timeout in milliseconds (1 - 8388) + */ +void watchdog_driver_enable(uint32_t timeout_ms); + +/** + * @brief Reset ("feed") the watchdog timer to prevent a reboot + * + * Must be called periodically within the timeout window configured by + * watchdog_driver_enable(). Each call restarts the countdown. + */ +void watchdog_driver_feed(void); + +/** + * @brief Check whether the last reset was caused by the watchdog + * + * Reads the reset reason register to determine if the watchdog timer + * expired and forced the most recent reboot. + * + * @return bool true if the watchdog triggered the last reset, false otherwise + */ +bool watchdog_driver_caused_reboot(void); + +#endif // WATCHDOG_H diff --git a/drivers/0x0f_flash/0x0f_flash.c b/drivers/0x0f_flash/0x0f_flash.c new file mode 100644 index 0000000..2231f57 --- /dev/null +++ b/drivers/0x0f_flash/0x0f_flash.c @@ -0,0 +1,65 @@ +/** + * @file 0x0f_flash.c + * @brief On-chip flash write/read demo using flash.c/flash.h + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * ----------------------------------------------------------------------------- + * + * Demonstrates on-chip flash read/write using the flash driver + * (flash.h / flash.c). A string is written to the last sector of flash + * and then read back to verify. The result is printed over UART. + * + * Wiring: + * No external wiring required + */ + +#include +#include +#include "pico/stdlib.h" +#include "flash.h" + +#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(); + + 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)); + + 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(); + } +} diff --git a/drivers/0x0f_flash/CMakeLists.txt b/drivers/0x0f_flash/CMakeLists.txt new file mode 100644 index 0000000..636b971 --- /dev/null +++ b/drivers/0x0f_flash/CMakeLists.txt @@ -0,0 +1,58 @@ +# Generated Cmake Pico project file + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Initialise pico_sdk from installed location +# (note this can come from environment, CMake cache etc) + +# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(sdkVersion 2.2.0) +set(toolchainVersion 14_2_Rel1) +set(picotoolVersion 2.2.0) +set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake) +if (EXISTS ${picoVscode}) + include(${picoVscode}) +endif() +# ==================================================================================== +set(PICO_BOARD pico2 CACHE STRING "Board type") + +# Pull in Raspberry Pi Pico SDK (must be before project) +include(pico_sdk_import.cmake) + +project(0x0f_flash C CXX ASM) + +# Initialise the Raspberry Pi Pico SDK +pico_sdk_init() + +# Add executable. Default name is the project name, version 0.1 + +add_executable(0x0f_flash 0x0f_flash.c flash.c) + +pico_set_program_name(0x0f_flash "0x0f_flash") +pico_set_program_version(0x0f_flash "0.1") + +# Modify the below lines to enable/disable output over UART/USB +pico_enable_stdio_uart(0x0f_flash 1) +pico_enable_stdio_usb(0x0f_flash 0) + +# Add the standard library to the build +target_link_libraries(0x0f_flash + pico_stdlib + hardware_flash + hardware_sync) + +# Add the standard include files to the build +target_include_directories(0x0f_flash PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +pico_add_extra_outputs(0x0f_flash) diff --git a/drivers/0x0f_flash/flash.c b/drivers/0x0f_flash/flash.c new file mode 100644 index 0000000..ad010cb --- /dev/null +++ b/drivers/0x0f_flash/flash.c @@ -0,0 +1,46 @@ +/** + * @file flash.c + * @brief Implementation of on-chip flash read/write driver + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "flash.h" +#include +#include "hardware/flash.h" +#include "hardware/sync.h" +#include "pico/stdlib.h" + +void flash_driver_write(uint32_t flash_offset, const uint8_t *data, uint32_t len) { + uint32_t ints = save_and_disable_interrupts(); + flash_range_erase(flash_offset, FLASH_SECTOR_SIZE); + flash_range_program(flash_offset, data, 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); +} diff --git a/drivers/0x0f_flash/flash.h b/drivers/0x0f_flash/flash.h new file mode 100644 index 0000000..19241f9 --- /dev/null +++ b/drivers/0x0f_flash/flash.h @@ -0,0 +1,68 @@ +/** + * @file flash.h + * @brief Header for on-chip flash read/write driver (XIP memory-mapped) + * @author Kevin Thomas + * @date 2025 + * + * MIT License + * + * Copyright (c) 2025 Kevin Thomas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef FLASH_H +#define FLASH_H + +#include +#include + +#define FLASH_DRIVER_SIZE_BYTES (4 * 1024 * 1024) +#define FLASH_DRIVER_SECTOR_SIZE 4096 +#define FLASH_DRIVER_PAGE_SIZE 256 + +/** + * @brief Erase one 4096-byte sector and write data to on-chip flash + * + * The target address must be aligned to a 4096-byte sector boundary. + * The function disables interrupts, erases the containing sector, + * programs up to @p len bytes from @p data, and re-enables interrupts. The + * write length must be a multiple of FLASH_DRIVER_PAGE_SIZE (256 bytes); + * pad with 0xFF if necessary. + * + * @param flash_offset Byte offset from the start of flash (must be sector-aligned) + * @param data Pointer to the data buffer to write + * @param len Number of bytes to write (multiple of FLASH_DRIVER_PAGE_SIZE) + */ +void flash_driver_write(uint32_t flash_offset, const uint8_t *data, uint32_t len); + +/** + * @brief Read bytes from on-chip flash via the XIP memory map + * + * Flash is memory-mapped starting at XIP_BASE (0x10000000). This function + * copies @p len bytes beginning at @p flash_offset into @p out using the + * XIP read path, which is always available without erasing. + * + * @param flash_offset Byte offset from the start of flash + * @param out Pointer to the destination buffer (must be @p len bytes) + * @param len Number of bytes to read + */ +void flash_driver_read(uint32_t flash_offset, uint8_t *out, uint32_t len); + +#endif // FLASH_H diff --git a/drivers/0x0f_flash/pico_sdk_import.cmake b/drivers/0x0f_flash/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/drivers/0x0f_flash/pico_sdk_import.cmake @@ -0,0 +1,121 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE})