├── .gitignore ├── .vscode ├── .cortex-debug.peripherals.state.json ├── .cortex-debug.registers.state.json ├── launch.json └── settings.json ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── deploy.sh ├── pico-asm.code-workspace ├── pico-asm.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── pico_sdk_import.cmake └── source ├── asm_i2c ├── CMakeLists.txt ├── ht16k33.c ├── ht16k33.h ├── main.S └── main_no_stack.S ├── asm_led_sdk ├── CMakeLists.txt └── main.S ├── asm_ops ├── CMakeLists.txt └── main.S └── common └── sdk_inlines.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcworkspace/xcuserdata/*.xcuserdatad 2 | build 3 | -------------------------------------------------------------------------------- /.vscode/.cortex-debug.peripherals.state.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /.vscode/.cortex-debug.registers.state.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { "type": "cortex-debug", 5 | "name": "Pico Debug", 6 | "device": "RP2040", 7 | "gdbPath": "arm-none-eabi-gdb", 8 | "cwd": "${workspaceRoot}", 9 | "executable": "${command:cmake.launchTargetPath}", 10 | "request": "launch", 11 | "servertype": "openocd", 12 | "configFiles": [ 13 | "/interface/picoprobe.cfg", 14 | "/target/rp2040.cfg" 15 | ], 16 | "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", 17 | "runToEntryPoint": "main", 18 | "postRestartCommands": [ 19 | "break main", 20 | "continue" 21 | ] 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.environment": { 3 | "PICO_SDK_PATH": "${env:PICO_SDK_PATH}" 4 | }, 5 | "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" 6 | } 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | # Set project data 4 | set(PROJECT_NAME "RP2040_ASM_PROJECT") 5 | set(BUILD_NUMBER "0") 6 | 7 | # Set app name(s) and version(s) 8 | set(APP_1_NAME "LED_SDK") 9 | set(APP_1_VERSION_NUMBER "1.2.0") 10 | 11 | set(APP_2_NAME "MISC_OPS") 12 | set(APP_2_VERSION_NUMBER "1.2.0") 13 | 14 | set(APP_3_NAME "I2C_DEMO") 15 | set(APP_3_VERSION_NUMBER "1.2.0") 16 | 17 | # Specify the app(s) source code 18 | set(APP_1_SRC_DIRECTORY "${CMAKE_SOURCE_DIR}/source/asm_led_sdk") 19 | set(APP_2_SRC_DIRECTORY "${CMAKE_SOURCE_DIR}/source/asm_ops") 20 | set(APP_3_SRC_DIRECTORY "${CMAKE_SOURCE_DIR}/source/asm_i2c") 21 | 22 | # Set the common code source directory 23 | set(COMMON_SRC_DIRECTORY "${CMAKE_SOURCE_DIR}/source/common") 24 | 25 | # Set env variable 'PICO_SDK_PATH' to the local Pico SDK 26 | # Comment out the set() if you have a global copy of the 27 | # SDK set and $PICO_SDK_PATH defined in your $PATH 28 | #set(ENV{PICO_SDK_PATH} "${CMAKE_SOURCE_DIR}/pico-sdk") 29 | 30 | # Include the Pico SDK 31 | include(pico_sdk_import.cmake) 32 | 33 | # Name the project 34 | project(${PROJECT_NAME} 35 | LANGUAGES C CXX ASM 36 | DESCRIPTION "RP2040 applications coded in assembly" 37 | ) 38 | 39 | # Initialise the Pico SDK 40 | pico_sdk_init() 41 | 42 | # Include app source code directories 43 | add_subdirectory(${APP_1_SRC_DIRECTORY}) 44 | add_subdirectory(${APP_2_SRC_DIRECTORY}) 45 | add_subdirectory(${APP_3_SRC_DIRECTORY}) 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | ### Copyright © 2022 Tony Smith (@smittytone) 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RP2040 Assembly Demo 1.2.0 2 | 3 | Raspberry Pi Pico assembly language application demos. 4 | 5 | Please see [blog.smittytone.net](https://blog.smittytone.net) for details. 6 | 7 | Code in this repo uses the `.syntax unified` directive. 8 | 9 | ## Repo Structure 10 | 11 | ``` 12 | /pico-asm 13 | | 14 | |___/source 15 | | |___/asm_led_sdk // Flash the Pico LED by calling the Pico SDK 16 | | | |___CMakeLists.txt // App CMake config file 17 | | | |___main.S // App assembly source 18 | | | 19 | | |___/asm_ops // Demo various ops 20 | | | |___CMakeLists.txt // App CMake config file 21 | | | |___main.S // App assembly source 22 | | | 23 | | |___/asm_i2c // Demo I2C comms 24 | | | |___CMakeLists.txt // App CMake config file 25 | | | |___main.S // App assembly source 26 | | | |___main_no_stack.S // Alternative app assembly source 27 | | | 28 | | |___/common // Source files common to all apps 29 | | |___sdk_inlines.c // Wrappers for SDK inline C functions 30 | | 31 | |___CMakeLists.txt // Top-level project CMake config file 32 | |___pico_sdk_import.cmake // Raspberry Pi Pico SDK CMake import script 33 | |___deploy.sh // Build-and-deploy shell script 34 | | 35 | |___pico-asm.code-workspace // Visual Studio Code workspace 36 | |___pico-asm.xcworkspace // Xcode workspace 37 | | 38 | |___README.md 39 | |___LICENSE.md 40 | ``` 41 | 42 | Code © 2022, Tony Smith, and is licensed under the terms of the [MIT Licence](./LICENSE.md) 43 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Deploy RP2040 application code 5 | # 6 | # @copyright 2022, Tony Smith @smittytone 7 | # @version 1.3.0 8 | # @license MIT 9 | # 10 | 11 | # GLOBALS 12 | timeout=30 13 | do_build=0 14 | do_clean=0 15 | rpi_path="/Volumes/RPI-RP2" 16 | uf2_path="UNDEFINED" 17 | cmake_path="$PWD/CMakeLists.txt" 18 | 19 | set -e 20 | 21 | # FUNCTIONS 22 | show_help() { 23 | echo -e "Usage:\n" 24 | echo -e " deploy [-b][-h] /path/to/compiled/uf2/file\n" 25 | echo -e "Options:\n" 26 | echo " -b / --build Build the app first." 27 | echo " Default: use a pre-built version of the app" 28 | echo " -c / --clean If building the app, do a clean build." 29 | echo " -h / --help Show this help screen" 30 | echo 31 | } 32 | 33 | update_build_number() { 34 | build_val=$(grep 'set(BUILD_NUMBER "' ${cmake_path}) 35 | old_num=$(echo "${build_val}" | cut -d '"' -s -f 2) 36 | ((new_num=old_num+1)) 37 | 38 | if [[ "$OSTYPE" == "linux-gnu"* ]]; then 39 | sed -i "s|BUILD_NUMBER \"${old_num}\"|BUILD_NUMBER \"${new_num}\"|" "${cmake_path}" 40 | elif [[ "$OSTYPE" == "darwin"* ]]; then 41 | # macOS requires slightly different syntax from Unix 42 | sed -i '' "s|BUILD_NUMBER \"${old_num}\"|BUILD_NUMBER \"${new_num}\"|" "${cmake_path}" 43 | else 44 | show_error "Unknown OS... build number not incremented" 45 | fi 46 | } 47 | 48 | check_for_err() { 49 | if [[ ${1} -ne 0 ]]; then 50 | exit 1 51 | fi 52 | } 53 | 54 | show_error_and_exit() { 55 | echo "[ERROR] $1" 56 | } 57 | 58 | show_error_and_exit() { 59 | echo "[ERROR] $1... exiting" 60 | exit 1 61 | } 62 | 63 | check_prereqs() { 64 | prqs=(cmake) 65 | for prq in "${prqs[@]}"; do 66 | check=$(which ${prq}) || show_error_and_exit "Required utility ${prq} not installed" 67 | done 68 | } 69 | 70 | # RUNTIME START 71 | for arg in "$@"; do 72 | check_arg=${arg,,} 73 | if [[ "$check_arg" = "--help" || "$check_arg" = "-h" ]]; then 74 | show_help 75 | exit 0 76 | elif [[ "$check_arg" = "--build" || "$check_arg" = "-b" ]]; then 77 | do_build=1 78 | elif [[ "$check_arg" = "--clean" || "$check_arg" = "-c" ]]; then 79 | do_clean=1 80 | else 81 | uf2_path="$arg" 82 | fi 83 | done 84 | 85 | if [[ "${uf2_path}" == "UNDEFINED" ]]; then 86 | show_help 87 | exit 0 88 | fi 89 | 90 | # Check we have what looks like a UF2 91 | extension="${uf2_path##*.}" 92 | if [[ "${extension}" != "uf2" ]]; then 93 | show_error_and_exit "${uf2_path} does not indicate a .uf2 file" 94 | fi 95 | 96 | # Do we build first? 97 | err=0 98 | if [[ ${do_build} -eq 1 ]]; then 99 | # FROM 1.1.0 -- auto-update the build number 100 | update_build_number 101 | 102 | if [[ ${do_clean} -eq 1 && -d "./build" ]]; then 103 | rm -rf "./build" 104 | fi 105 | 106 | if [[ ! -e "./build" ]]; then 107 | # No build folder? Then create it 108 | # and configure the build 109 | cmake -S . -B build/ -D "CMAKE_C_COMPILER:FILEPATH=$(which arm-none-eabi-gcc)" -D CMAKE_BUILD_TYPE:STRING=Release 110 | check_for_err $? 111 | fi 112 | 113 | # Build the app 114 | cmake --build build 115 | check_for_err $? 116 | fi 117 | 118 | # Wait for the RPI_R2 mount 119 | count=0 120 | if [ ! -d "${rpi_path}" ]; then 121 | echo "Waiting for RP2040 device to mount" 122 | while [ ! -d "${rpi_path}" ]; do 123 | sleep 1 124 | ((count+=1)) 125 | if [[ $count -eq $timeout ]]; then 126 | show_error_and_exit "RP2040 device not mounted after ${timeout}s" 127 | fi 128 | done 129 | fi 130 | 131 | echo "RP2040 device mounted..." 132 | 133 | # Check for available app file 134 | if [ ! -f "${uf2_path}" ]; then 135 | show_error_and_exit "Cannot find file ${uf2_path}" 136 | fi 137 | 138 | echo "Copying ${uf2_path} to ${rpi_path}/${uf2_path##*/}" 139 | 140 | # Copy file 141 | if cp -f "${uf2_path}" "${rpi_path}/${uf2_path##*/}"; then 142 | echo "${uf2_path##*/} copied to ${rpi_path}" 143 | else 144 | show_error_and_exit " Could not copy ${uf2_path##*/} to ${rpi_path}/${uf2_path##*/}" 145 | fi 146 | 147 | exit 0 148 | -------------------------------------------------------------------------------- /pico-asm.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": {} 8 | } -------------------------------------------------------------------------------- /pico-asm.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /pico-asm.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | 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") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) 63 | -------------------------------------------------------------------------------- /source/asm_i2c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | # Include app source code file(s) 4 | add_executable(${APP_3_NAME} 5 | ${APP_3_SRC_DIRECTORY}/main.S 6 | ${APP_3_SRC_DIRECTORY}/ht16k33.c 7 | ${COMMON_SRC_DIRECTORY}/sdk_inlines.c 8 | ) 9 | 10 | # Link to built libraries 11 | target_link_libraries(${APP_3_NAME} LINK_PUBLIC 12 | pico_stdlib 13 | hardware_gpio 14 | hardware_i2c 15 | ) 16 | 17 | # Enable/disable STDIO via USB and UART 18 | pico_enable_stdio_usb(${APP_3_NAME} 1) 19 | pico_enable_stdio_uart(${APP_3_NAME} 1) 20 | 21 | # Enable extra build products 22 | pico_add_extra_outputs(${APP_3_NAME}) 23 | -------------------------------------------------------------------------------- /source/asm_i2c/ht16k33.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | #include "ht16k33.h" 11 | 12 | 13 | /* 14 | * Globals 15 | */ 16 | // Graphics buffer 17 | uint8_t buffer[8]; 18 | 19 | 20 | /* 21 | * HT16K33 LED Matrix Functions 22 | */ 23 | void ht16k33_init(void) { 24 | // Initialize the matrix by powering up 25 | ht16k33_power_on_or_off(ON); 26 | ht16k33_set_brightness(2); 27 | ht16k33_clear(); 28 | ht16k33_draw(); 29 | } 30 | 31 | void ht16k33_power_on_or_off(uint8_t on) { 32 | // Power the LED on or off 33 | i2c_write_byte(on == ON ? HT16K33_GENERIC_SYSTEM_ON : HT16K33_GENERIC_DISPLAY_OFF); 34 | i2c_write_byte(on == ON ? HT16K33_GENERIC_DISPLAY_ON : HT16K33_GENERIC_SYSTEM_OFF); 35 | } 36 | 37 | void ht16k33_set_brightness(uint8_t brightness) { 38 | // Set the LED brightness 39 | if (brightness < 0 || brightness > 15) brightness = 15; 40 | i2c_write_byte(HT16K33_GENERIC_CMD_BRIGHTNESS | brightness); 41 | } 42 | 43 | void ht16k33_plot(uint8_t x, uint8_t y, bool is_set) { 44 | // Set or unset the specified pixel 45 | uint8_t col = buffer[x]; 46 | 47 | if (is_set) { 48 | col = col | (1 << y); 49 | } else { 50 | col = col & ~(1 << y); 51 | } 52 | 53 | buffer[x] = col; 54 | } 55 | 56 | void ht16k33_clear(void) { 57 | // Clear the display buffer 58 | for (uint8_t i = 0 ; i < 8 ; ++i) buffer[i] = 0; 59 | } 60 | 61 | void ht16k33_draw(void) { 62 | // Set up the buffer holding the data to be 63 | // transmitted to the LED 64 | uint8_t output_buffer[17]; 65 | for (uint8_t i = 0 ; i < 17 ; ++i) output_buffer[i] = 0; 66 | 67 | // Span the 8 bytes of the graphics buffer 68 | // across the 16 bytes of the LED's buffer 69 | for (uint8_t i = 0 ; i < 8 ; ++i) { 70 | uint8_t a = buffer[i]; 71 | output_buffer[i * 2 + 1] = (a >> 1) + ((a << 7) & 0xFF); 72 | } 73 | 74 | // Write out the transmit buffer 75 | i2c_write_block(output_buffer, sizeof(output_buffer)); 76 | } 77 | 78 | 79 | /* 80 | * I2C Functions 81 | */ 82 | void i2c_config(void) { 83 | // Set up I2C 84 | // TODO Port to assembly 85 | i2c_init(I2C_PORT, I2C_FREQUENCY); 86 | gpio_set_function(PIN_SDA, GPIO_FUNC_I2C); 87 | gpio_set_function(PIN_SCL, GPIO_FUNC_I2C); 88 | gpio_pull_up(PIN_SDA); 89 | gpio_pull_up(PIN_SCL); 90 | } 91 | 92 | void i2c_write_byte(uint8_t byte) { 93 | // Convenience function to write a single byte to the matrix 94 | i2c_write_blocking(I2C_PORT, HT16K33_ADDRESS, &byte, 1, false); 95 | } 96 | 97 | void i2c_write_block(uint8_t *data, uint8_t count) { 98 | // Convenience function to write a 'count' bytes to the matrix 99 | i2c_write_blocking(I2C_PORT, HT16K33_ADDRESS, data, count, false); 100 | } 101 | -------------------------------------------------------------------------------- /source/asm_i2c/ht16k33.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | #ifndef _HT16K33_HEADER_ 11 | #define _HT16K33_HEADER_ 12 | 13 | 14 | /* 15 | * Includes 16 | */ 17 | #include 18 | #include 19 | #include 20 | #include "pico/stdlib.h" 21 | #include "pico/binary_info.h" 22 | #include "hardware/i2c.h" 23 | 24 | 25 | /* 26 | * Constants 27 | */ 28 | #define I2C_PORT i2c0 29 | #define I2C_FREQUENCY 400000 30 | 31 | #define PIN_SDA 8 32 | #define PIN_SCL 9 33 | 34 | #define ON 1 35 | #define OFF 0 36 | 37 | // HT16K33 LED Matrix Commands 38 | #define HT16K33_GENERIC_DISPLAY_ON 0x81 39 | #define HT16K33_GENERIC_DISPLAY_OFF 0x80 40 | #define HT16K33_GENERIC_SYSTEM_ON 0x21 41 | #define HT16K33_GENERIC_SYSTEM_OFF 0x20 42 | #define HT16K33_GENERIC_DISPLAY_ADDRESS 0x00 43 | #define HT16K33_GENERIC_CMD_BRIGHTNESS 0xE0 44 | #define HT16K33_GENERIC_CMD_BLINK 0x81 45 | #define HT16K33_ADDRESS 0x70 46 | 47 | 48 | /* 49 | * Function Prototypes 50 | */ 51 | // HT16K33 52 | void ht16k33_init(void); 53 | void ht16k33_power_on_or_off(uint8_t on); 54 | void ht16k33_set_brightness(uint8_t brightness); 55 | void ht16k33_plot(uint8_t x, uint8_t y, bool set); 56 | void ht16k33_clear(void); 57 | void ht16k33_draw(void); 58 | 59 | // I2C 60 | void i2c_config(void); 61 | void i2c_write_byte(uint8_t byte); 62 | void i2c_write_block(uint8_t *data, uint8_t count); 63 | 64 | 65 | #endif // _HT16K33_HEADER_ 66 | -------------------------------------------------------------------------------- /source/asm_i2c/main.S: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | 11 | 12 | /* 13 | * CONSTANTS 14 | */ 15 | .equ POP_X, 4 // Deltas for to set SP for pushing 16 | .equ POP_Y, 8 // and pulling X, Y, DX, DY to and 17 | .equ POP_DX, 12 // from the variable space within the 18 | .equ POP_DY, 16 // stack 19 | .equ PSX_X, 0 20 | .equ PSH_Y, 4 21 | .equ PSH_DX, 8 22 | .equ PSH_DY, 12 23 | 24 | 25 | /* 26 | * ASSEMBLY HEADER 27 | * 28 | * NOTE These macros need to be on separate lines 29 | */ 30 | .syntax unified // Use ARM unified syntax, ie. 31 | // mandate S suffix for lo registers 32 | .thumb_func // This code uses Thumb instructions 33 | .global main // Set entry point 34 | 35 | 36 | /* 37 | * RUNTIME START 38 | */ 39 | main: 40 | 41 | init: bl stdio_init_all // Jump to SDK STDIO initialisation routine 42 | movs r0, #0x80 // Set the delay period 43 | // NOTE This form assembles as PC offset addressing, 44 | // so make sure DELAY_TIME_MS is an address in the 45 | // .code space rather not the .data space 46 | lsls r0, #4 47 | bl sleep_ms // Delay to allow the STDIO-over-USB to ready 48 | 49 | bl i2c_config // Initialise the I2C peripheral 50 | bl ht16k33_init // Initialise the display 51 | 52 | /* 53 | * Set up the variable space 54 | */ 55 | mov r9, sp // r9 == SP, top of var store 56 | movs r0, #0 57 | push {r0} // Clear X... 58 | push {r0} // ...Y 59 | movs r0, #1 60 | push {r0} // Set DX... 61 | push {r0} // ...DY 62 | 63 | loop: bl ht16k33_clear // Clear the buffer 64 | 65 | /* 66 | * Get X, Y and plot a dot at the 67 | * current co-ordinates 68 | */ 69 | mov r10, sp // Record current SP 70 | mov sp, r9 71 | sub sp, #POP_Y 72 | pop {r1} // Get Y 73 | pop {r0} // Get X 74 | mov sp, r10 // Restore SP 75 | 76 | bl plot // Plot at (X, Y) 77 | 78 | /* 79 | * Get X, Y, DX and DY, and set the updated 80 | * co-ordinates and direction flags. 81 | */ 82 | mov r10, sp // Record current SP 83 | mov sp, r9 // Set SP to var store 84 | sub sp, #POP_DY // Get DY, DX, Y, X 85 | pop {r3} 86 | pop {r2} 87 | pop {r1} 88 | pop {r0} 89 | 90 | setx: cmp r2, #1 // DX == 1? 91 | bne subx // N: goto subx 92 | addx: adds r0, #1 // X += 1 93 | cmp r0, #6 // X <= 6 ? 94 | bls stx // YES goto stx 95 | movs r2, #0 // DX == 0 96 | mov sp, r9 97 | sub sp, #PSH_DX 98 | push {r2} 99 | b stx 100 | subx: subs r0, #1 // X -= 1 101 | bne stx // X > 0 ? YES goto stx 102 | movs r2, #1 // DX == 1 103 | mov sp, r9 104 | sub sp, #PSH_DX 105 | push {r2} 106 | stx: mov sp, r9 107 | push {r0} // Save X 108 | 109 | sety: cmp r3, #1 // DY == 1? 110 | bne suby // N: goto suby 111 | addy: adds r1, #1 // Y += 1 112 | cmp r1, #6 // Y <= 6 ? 113 | bls sty // YES goto sty 114 | movs r3, #0 // DY == 0 115 | mov sp, r9 116 | sub sp, #PSH_DY 117 | push {r3} 118 | b sty 119 | suby: subs r1, #1 // Y -= 1 120 | bne sty // Y > 0 ? YES goto sty 121 | movs r3, #1 // DY == 1 122 | mov sp, r9 123 | sub sp, #PSH_DY 124 | push {r3} 125 | sty: mov sp, r9 126 | sub sp, #PSH_Y 127 | push {r1} // Save Y 128 | 129 | mov sp, r10 // Restore SP 130 | 131 | /* 132 | * End of loop code 133 | */ 134 | bl print // Debug output 135 | 136 | ldr r0, DELAY_TIME_MS // Set the delay period r0 = [DELAy_TIME_MS] 137 | bl sleep_ms // Delay 138 | 139 | b loop // Loop infinitely back to start 140 | 141 | /* 142 | * Plot X, Y on the LED 143 | */ 144 | plot: push {LR} 145 | movs r2, #1 // Set the pixel 146 | bl ht16k33_plot // Plot the point 147 | bl ht16k33_draw // Draw the buffer 148 | pop {PC} // RTS 149 | 150 | /* 151 | * Print X, Y, DX, DY values for debugging. 152 | */ 153 | print: push {lr} 154 | 155 | ldr r0, =TEXT1 // Set the format string 156 | mov r10, sp // Record current SP 157 | mov sp, r9 // Get Y and X 158 | sub sp, #POP_Y 159 | pop {r2} 160 | pop {r1} 161 | mov sp, r10 // Restore SP 162 | bl printf // Output the string 163 | 164 | ldr r0, =TEXT2 // Set the format string 165 | mov r10, sp // Record current SP 166 | mov sp, r9 // Get DY and DX 167 | sub sp, #POP_DY 168 | pop {r2} 169 | pop {r1} 170 | mov sp, r10 // Restore SP 171 | bl printf // Output the string 172 | 173 | pop {pc} // RTS 174 | 175 | 176 | /* 177 | * READ-ONLY DATA in .CODE 178 | */ 179 | .balign 4 180 | DELAY_TIME_MS: .word 500 181 | TEXT1: .asciz "X: 0x%02X, Y: 0x%02X, " 182 | TEXT2: .asciz "DX: 0x%02X, DY: 0x%02X\n" 183 | -------------------------------------------------------------------------------- /source/asm_i2c/main_no_stack.S: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | 11 | 12 | /* 13 | * CONSTANTS 14 | */ 15 | .equ COORD_X, 0 // Deltas within the variable 16 | .equ COORD_Y, 4 // store for X, Y, DX, DY 17 | .equ DELTA_X, 8 18 | .equ DELTA_Y, 12 19 | 20 | 21 | /* 22 | * ASSEMBLY HEADER 23 | * 24 | * NOTE These macros need to be on separate lines 25 | */ 26 | .syntax unified // Use ARM unified syntax, ie. 27 | // mandate S suffix for lo registers 28 | .thumb_func // This code uses Thumb instructions 29 | .global main // Set entry point 30 | 31 | 32 | /* 33 | * RUNTIME START 34 | */ 35 | main: bl stdio_init_all // Jump to SDK STDIO initialisation routine 36 | movs r0, #0x80 // Set the delay period 37 | // NOTE This form assembles as PC offset addressing, 38 | // so make sure DELAY_TIME_MS is an address in the 39 | // .code space rather not the .data space 40 | lsls r0, #4 41 | bl sleep_ms // Delay to allow the STDIO-over-USB to ready 42 | 43 | bl i2c_config // Initialise the I2C peripheral 44 | bl ht16k33_init // Initialise the display 45 | 46 | /* 47 | * Set up the variable space 48 | */ 49 | ldr r4, =VAR_SPACE // r1 == &VAR_SPACE 50 | movs r0, #1 // r0 = 1 51 | str r0, [r4, #DELTA_X] // [r1 + 8] == 1 52 | str r0, [r4, #DELTA_Y] // [r1 + 12] == 1 53 | 54 | loop: bl ht16k33_clear // Clear the buffer 55 | 56 | /* 57 | * Get X, Y and plot a dot at the 58 | * current co-ordinates 59 | */ 60 | ldr r4, =VAR_SPACE 61 | ldr r0, [r4, #COORD_X] 62 | ldr r1, [r4, #COORD_Y] 63 | bl plot 64 | 65 | /* 66 | * Get X, Y, DX, DY and update their values 67 | * for the next loop 68 | */ 69 | ldr r4, =VAR_SPACE 70 | ldr r0, [r4, #COORD_X] 71 | ldr r1, [r4, #COORD_Y] 72 | ldr r2, [r4, #DELTA_X] 73 | ldr r3, [r4, #DELTA_Y] 74 | 75 | setx: cmp r2, #1 // DX == 1? 76 | bne subx // N: goto subx 77 | addx: adds r0, #1 // X += 1 78 | cmp r0, #6 // X <= 6 ? 79 | bls stx // YES goto stx 80 | movs r2, #0 // DX == 0 81 | str r2, [r4, #DELTA_X] 82 | b stx 83 | subx: subs r0, #1 // X -= 1 84 | bne stx // X > 0 ? YES goto stx 85 | movs r2, #1 // DX == 1 86 | str r2, [r4, #DELTA_X] 87 | stx: str r0, [r4, #COORD_X] // Save X 88 | 89 | sety: cmp r3, #1 // DY == 1? 90 | bne suby // N: goto suby 91 | addy: adds r1, #1 // Y += 1 92 | cmp r1, #6 // Y <= 6 ? 93 | bls sty // YES goto sty 94 | movs r3, #0 // DY == 0 95 | str r3, [r4, #DELTA_Y] 96 | b sty 97 | suby: subs r1, #1 // Y -= 1 98 | bne sty // Y > 0 ? YES goto sty 99 | movs r3, #1 // DY == 1 100 | str r3, [r4, #DELTA_Y] 101 | sty: str r1, [r4, #COORD_Y] // Save Y 102 | 103 | /* 104 | * End of loop code 105 | */ 106 | bl print // Debug output 107 | 108 | ldr r0, DELAY_TIME_MS // Set the delay period r0 = [DELAy_TIME_MS] 109 | bl sleep_ms // Delay 110 | 111 | b loop // Loop infinitely back to start 112 | 113 | /* 114 | * Plot X, Y on the LED 115 | */ 116 | plot: push {LR} 117 | movs r2, #1 // Set the pixel 118 | bl ht16k33_plot // Plot the point 119 | bl ht16k33_draw // Draw the buffer 120 | pop {PC} // RTS 121 | 122 | /* 123 | * Print X, Y, DX, DY values for debugging. 124 | */ 125 | print: push {lr} 126 | 127 | ldr r4, =VAR_SPACE 128 | ldr r0, =TEXT1 // Set the format string 129 | ldr r1, [r4, #COORD_X] 130 | ldr r2, [r4, #COORD_Y] 131 | bl printf // Output the string 132 | 133 | ldr r0, =TEXT2 // Set the format string 134 | ldr r1, [r4, #DELTA_X] 135 | ldr r2, [r4, #DELTA_Y] // Restore SP 136 | bl printf // Output the string 137 | 138 | pop {pc} // RTS 139 | 140 | 141 | /* 142 | * READ-ONLY DATA in .CODE 143 | */ 144 | .balign 4 145 | DELAY_TIME_MS: .word 500 146 | TEXT1: .asciz "X: 0x%02X, Y: 0x%02X, " 147 | TEXT2: .asciz "DX: 0x%02X, DY: 0x%02X\n" 148 | 149 | 150 | /* 151 | * READ/WRITE DATA in .DATA 152 | */ 153 | .data 154 | .balign 4 155 | VAR_SPACE: .fill 16, 1, 0 156 | -------------------------------------------------------------------------------- /source/asm_led_sdk/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | # Include app source code file(s) 4 | add_executable(${APP_1_NAME} 5 | ${APP_1_SRC_DIRECTORY}/main.S 6 | ${COMMON_SRC_DIRECTORY}/sdk_inlines.c 7 | ) 8 | 9 | # Link to built libraries 10 | target_link_libraries(${APP_1_NAME} LINK_PUBLIC 11 | pico_stdlib 12 | hardware_gpio 13 | ) 14 | 15 | # Enable/disable STDIO via USB and UART 16 | pico_enable_stdio_usb(${APP_1_NAME} 1) 17 | pico_enable_stdio_uart(${APP_1_NAME} 1) 18 | 19 | # Enable extra build products 20 | pico_add_extra_outputs(${APP_1_NAME}) 21 | -------------------------------------------------------------------------------- /source/asm_led_sdk/main.S: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | 11 | 12 | /* 13 | * CONSTANTS 14 | */ 15 | .equ LED_PIN, 25 16 | .equ GPIO_DIR_IN, 0 17 | .equ GPIO_DIR_OUT, 1 18 | .equ PIN_HIGH, 1 19 | .equ PIN_LOW, 0 20 | 21 | 22 | /* 23 | * ASSEMBLY HEADER 24 | * 25 | * NOTE These macros need to be on separate lines 26 | */ 27 | .syntax unified // Use ARM unified syntax, ie. 28 | // mandate S suffix for lo registers 29 | .thumb_func // This code uses Thumb instructions 30 | .global main // Set entry point 31 | 32 | /* 33 | * RUNTIME START 34 | */ 35 | main: 36 | init: bl stdio_init_all // Jump to SDK STDIO initialisation routine 37 | movs r0, #0x80 // Set the delay period 38 | lsls r0, #4 39 | bl sleep_ms // Delay to allow the STDIO-over-USB to ready 40 | 41 | movs r0, #LED_PIN // Set the pin number 42 | bl gpio_init // Jump to SDK GPIO initialisation routine 43 | 44 | movs r0, #LED_PIN // Set the pin number 45 | movs r1, #GPIO_DIR_OUT // Set the pin direction 46 | bl gpio_set_direction // Jump to SDK pin direction routine 47 | 48 | b info // Jump to the CPU info readout 49 | 50 | loop: movs r0, #LED_PIN // Set the pin number 51 | movs r1, #PIN_HIGH // Set the pin state 52 | bl gpio_set_state // Jump to SDK pin state routine 53 | 54 | ldr r0, DELAY_TIME_MS // Set the delay period 55 | // NOTE This form assembles as PC offset addressing, 56 | // so make sure DELAY_TIME_MS is an address in the 57 | // code space rather not the .data space 58 | bl sleep_ms // Delay 59 | 60 | movs r0, #LED_PIN // Set the pin number 61 | movs r1, #PIN_LOW // Set the pin state 62 | bl gpio_set_state // Jump to SDK pin state routine 63 | 64 | ldr r0, DELAY_TIME_MS // Set the delay period 65 | bl sleep_ms // Delay 66 | 67 | b loop // Loop infinitely 68 | 69 | info: ldr r5, CPUID // Get the address of CPUID 70 | ldr r5, [r5] // Get the contents of CPUID 71 | 72 | // Write out the CPUID register 73 | ldr r0, =TEXT0 // Set the printf format string 74 | movs r1, r5 // Set the printf value 75 | bl printf 76 | 77 | // Write out the part number 78 | ldr r0, =TEXT1 // Set the format string 79 | movs r1, r5 // Set the printf value to the CPUID value 80 | movs r3, #0xFF // Set the AND mask 81 | lsls r3, #8 82 | adds r3, #0xF0 83 | ands r1, r3 // Mask CPUID bits 15-4 84 | lsrs r3, #4 85 | bl printf 86 | 87 | // Write out the revision 88 | ldr r0, =TEXT2 // Set the format string 89 | movs r1, r5 // Set the printf value to the CPUID value 90 | movs r3, #0x0F // Set the AND mask 91 | lsls r3, #20 92 | ands r1, r3 // Mask CPUID bits 23-20 93 | lsrs r3, #20 94 | bl printf 95 | 96 | // Write out the variant number 97 | ldr r0, =TEXT3 // Set the format string 98 | movs r1, r5 // Set the printf value to the CPUID value 99 | movs r3, #0x0F // Set the AND mask 100 | ands r1, r3 // Mask CPUID bits 3-0 101 | bl printf 102 | 103 | // FROM 1.0.1 -- unified syntax test 104 | movs r0, #0 // Clear r0 105 | mvns r0, r0 // NOT r0 0x00000000 -> 0xFFFFFFFF 106 | movs r1, #1 // r1 = 1 107 | rsbs r1, #0 // r1 = 0 - r1 = 0xFFFFFFFF 108 | cmp r0, r1 // r1 == r2? 109 | bne xinfo // Jump out if r1 != r2 110 | 111 | ldr r0, =TEXT4 // Output match message 112 | bl printf 113 | 114 | xinfo: b loop // Jump back to the LED flash loop 115 | 116 | /* 117 | Use four-bytes to store the delay time so that we can load 118 | into r0 a 32-bit value, rather than move in an 8-bit value 119 | */ 120 | .align 4 121 | DELAY_TIME_MS: .word 500 122 | CPUID: .word 0xE000ED00 // Memory map address of CPUID register 123 | TEXT0: .asciz "CPUID: 0x%08X\n" 124 | TEXT1: .asciz "Part: 0x%08X\n" 125 | TEXT2: .asciz "Rev: 0x%08X\n" 126 | TEXT3: .asciz "Var: 0x%08X\n" 127 | TEXT4: .asciz "MATCH\n" 128 | -------------------------------------------------------------------------------- /source/asm_ops/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | # Include app source code file(s) 4 | add_executable(${APP_2_NAME} 5 | ${APP_2_SRC_DIRECTORY}/main.S 6 | ${COMMON_SRC_DIRECTORY}/sdk_inlines.c 7 | ) 8 | 9 | # Link to built libraries 10 | target_link_libraries(${APP_2_NAME} LINK_PUBLIC 11 | pico_stdlib 12 | hardware_gpio 13 | ) 14 | 15 | # Enable/disable STDIO via USB and UART 16 | pico_enable_stdio_usb(${APP_2_NAME} 1) 17 | pico_enable_stdio_uart(${APP_2_NAME} 1) 18 | 19 | # Enable extra build products 20 | pico_add_extra_outputs(${APP_2_NAME}) 21 | -------------------------------------------------------------------------------- /source/asm_ops/main.S: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | 11 | 12 | /* 13 | * CONSTANTS 14 | */ 15 | .equ LED_PIN, 25 16 | .equ GPIO_DIR_IN, 0 17 | .equ GPIO_DIR_OUT, 1 18 | .equ PIN_HIGH, 1 19 | .equ PIN_LOW, 0 20 | 21 | 22 | /* 23 | * ASSEMBLY HEADER 24 | * 25 | * NOTE These macros need to be on separate lines 26 | */ 27 | .syntax unified // Use ARM unified syntax, ie. 28 | // mandate S suffix for lo registers 29 | .thumb_func // This code uses Thumb instructions 30 | .global main // Set entry point 31 | 32 | /* 33 | * RUNTIME START 34 | */ 35 | main: 36 | init: bl stdio_init_all // Jump to SDK STDIO initialisation routine 37 | movs r0, #0x80 // Set the delay period 38 | lsls r0, #4 39 | bl sleep_ms // Delay to allow the STDIO-over-USB to ready 40 | 41 | movs r0, #LED_PIN // Set the pin number 42 | bl gpio_init // Jump to SDK GPIO initialisation routine 43 | 44 | movs r0, #LED_PIN // Set the pin number 45 | movs r1, #GPIO_DIR_OUT // Set the pin direction 46 | bl gpio_set_direction // Jump to SDK pin direction routine 47 | 48 | /* 49 | Set the flash delay time according to 50 | whether bits 15 and 7 of r0 are set. 51 | 52 | Change the value of TST_VAL to set 53 | different values of r0 54 | */ 55 | check_r0: ldr r0, TST_VAL 56 | movs r4, #0x80 // Set bit 7 57 | lsls r4, #0x08 // Shift r4 left 8 times to set bit 15 58 | adds r4, #0x08 // Re-set bit 7 59 | tst r0, r4 // R0 & R4 60 | beq set_delay // PSR-Z set indicates bits clear 61 | ldr r5, DELAY_TIME_FAST // Set the delay period 62 | b next 63 | 64 | set_delay: ldr r5, DELAY_TIME_SLOW // Set the delay period 65 | 66 | next: bl output // Sets the LR to loop: 67 | 68 | loop: movs r0, #LED_PIN // Set the pin number 69 | movs r1, #PIN_HIGH // Set the pin state 70 | bl gpio_set_state // Jump to SDK pin state routine 71 | 72 | movs r0, r5 // Set the delay period 73 | // NOTE This form assembles as PC offset addressing, 74 | // so make sure DELAY_TIME_MS is an address in the 75 | // code space rather not the .data space 76 | bl sleep_ms // Delay 77 | 78 | movs r0, #LED_PIN // Set the pin number 79 | movs r1, #PIN_LOW // Set the pin state 80 | bl gpio_set_state // Jump to SDK pin state routine 81 | 82 | movs r0, r5 // Set the delay period 83 | bl sleep_ms // Delay 84 | 85 | b loop // Loop infinitely 86 | 87 | output: ldr r6, DELAY_TIME_FAST // Set the comparison value 88 | cmp r5, r6 // Is r5 set to 'fast', ie. bits 15, 7 set? 89 | bne use_unset // No, jump to slow: 90 | 91 | use_set: ldr r0, =TEXT_SET // Set r0 to point to output text 92 | b print // Jump to print: 93 | 94 | use_unset: ldr r0, =TEXT_UNSET // Set r0 to point to output text 95 | 96 | print: push {LR} // Save the LR - it'll be changed by the next line 97 | bl printf // Call the Pico SDK's printf() 98 | pop {PC} // Get LR from the stack and put it in PC to jump back 99 | 100 | /* 101 | * DATA 102 | */ 103 | .align 4 104 | TST_VAL: .word 0xFFFFFFFF 105 | DELAY_TIME_SLOW: .word 750 106 | DELAY_TIME_FAST: .word 250 107 | TEXT_SET: .asciz "BITS 15 AND/OR 7 SET\n" 108 | TEXT_UNSET: .asciz "BITS 15 AND/OR 7 NOT SET\n" 109 | -------------------------------------------------------------------------------- /source/common/sdk_inlines.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pico-asm for Raspberry Pi Pico 3 | * 4 | * @version 1.2.0 5 | * @author smittytone 6 | * @copyright 2022 7 | * @licence MIT 8 | * 9 | */ 10 | 11 | 12 | #include "hardware/gpio.h" 13 | 14 | /* 15 | * These functions are placeholders for SDK functions 16 | * that are marked as inline, ie. to be compiled in place. 17 | */ 18 | 19 | void gpio_set_direction(int pin, int direction) { 20 | gpio_set_dir(pin, direction); 21 | } 22 | 23 | void gpio_set_state(int pin, int state) { 24 | gpio_put(pin, state); 25 | } 26 | --------------------------------------------------------------------------------