├── .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 |
--------------------------------------------------------------------------------