From 4be958987efdd59b066c4b9068b0206355f7012e Mon Sep 17 00:00:00 2001 From: hypercube Date: Thu, 26 Mar 2026 22:35:02 +0000 Subject: [PATCH] Upload files to "/" --- CMakeLists.txt | 9 +++ blink.c | 175 ++++++++++++++++++++++++++++++++++++++++++ pico_sdk_import.cmake | 121 +++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 blink.c create mode 100644 pico_sdk_import.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c43381a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.13) + +include(pico_sdk_import.cmake) +project(hello_world) +pico_sdk_init() + +add_executable(blink blink.c) +target_link_libraries(blink pico_stdlib hardware_pwm hardware_i2c) +pico_add_extra_outputs(blink) diff --git a/blink.c b/blink.c new file mode 100644 index 0000000..8d798dc --- /dev/null +++ b/blink.c @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include "pico/stdlib.h" +#include "hardware/pwm.h" +#include "hardware/i2c.h" + +#define PI 3.14159265358979323433 +#define STEPS_PER_SECOND 100 +#define STEP_SLEEP_DURATION (1000 / STEPS_PER_SECOND) +#define EXTERNAL_LED_PIN 22 + +#define SSD1306_I2C_SDA_PIN 12 +#define SSD1306_I2C_SCL_PIN 13 +#define SSD1306_I2C_ADDRESS 0x3C +#define SSD1306_I2C_BAUDRATE 1000000 +#define SSD1306_WIDTH 128 +#define SSD1306_HEIGHT 64 +#define SSD1306_FRAME_SIZE (SSD1306_WIDTH * SSD1306_HEIGHT / 8) + +static uint8_t ssd1306_framebuffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8] = {0}; + + +void setupUART(){ + uart_inst_t * UART_ID = uart0; + const uint BAUD = 115200; + const uint TX_PIN = 0; + const uint RX_PIN = 1; + uart_init(UART_ID, BAUD); + stdio_uart_init_full(UART_ID, BAUD, TX_PIN, RX_PIN); + gpio_set_function(TX_PIN, GPIO_FUNC_UART); + gpio_set_function(RX_PIN, GPIO_FUNC_UART); + uart_set_format(UART_ID, 8, 1, UART_PARITY_NONE); +} + +void ssd1306_write_command(i2c_inst_t *i2c_port, uint8_t command) { + uint8_t buf[2] = {0x00, command}; + int ret = i2c_write_blocking(i2c_port, SSD1306_I2C_ADDRESS, buf, 2, false); + if(ret != 2) printf("write command failed"); +} + +void ssd1306_init(i2c_inst_t *i2c_port) { + ssd1306_write_command(i2c_port, 0xAE); // Display OFF + ssd1306_write_command(i2c_port, 0x20); // Set Memory Addressing Mode + ssd1306_write_command(i2c_port, 0x00); // Horizontal addressing mode + ssd1306_write_command(i2c_port, 0xB0); // Page start address + ssd1306_write_command(i2c_port, 0xC8); // COM Output Scan Direction + ssd1306_write_command(i2c_port, 0x00); // Low column address + ssd1306_write_command(i2c_port, 0x10); // High column address + ssd1306_write_command(i2c_port, 0x40); // Start line address + ssd1306_write_command(i2c_port, 0x81); // Contrast control + ssd1306_write_command(i2c_port, 0xFF); // Max contrast + ssd1306_write_command(i2c_port, 0xA1); // Segment remap + ssd1306_write_command(i2c_port, 0xA6); // Normal display + ssd1306_write_command(i2c_port, 0xA8); // Multiplex ratio + ssd1306_write_command(i2c_port, 0x3F); // Duty = 1/64 + ssd1306_write_command(i2c_port, 0xA4); // Display follows RAM + ssd1306_write_command(i2c_port, 0xD3); // Display offset + ssd1306_write_command(i2c_port, 0x00); // No offset + ssd1306_write_command(i2c_port, 0xD5); // Display clock + ssd1306_write_command(i2c_port, 0xF0); + ssd1306_write_command(i2c_port, 0xD9); // Pre-charge period + ssd1306_write_command(i2c_port, 0x22); + ssd1306_write_command(i2c_port, 0xDA); // COM pins + ssd1306_write_command(i2c_port, 0x12); + ssd1306_write_command(i2c_port, 0xDB); // VCOMH deselect level + ssd1306_write_command(i2c_port, 0x20); + ssd1306_write_command(i2c_port, 0x8D); // Charge pump + ssd1306_write_command(i2c_port, 0x14); + ssd1306_write_command(i2c_port, 0xAF); // Display ON +} + +void ssd1306_flush(i2c_inst_t *i2c_port, uint8_t* data, uint data_len) { + // Set column address range: 0 to 127 + ssd1306_write_command(i2c_port, 0x21); // Set column address command + ssd1306_write_command(i2c_port, 0x00); // Start column + ssd1306_write_command(i2c_port, 0x7F); // End column (127) + // Set page address range: 0 to 7 + ssd1306_write_command(i2c_port, 0x22); // Set page address command + ssd1306_write_command(i2c_port, 0x00); // Start page + ssd1306_write_command(i2c_port, 0x07); // End page (7) + // Start I2C transaction to send full framebuffer + uint8_t tx[1 + data_len]; + tx[0] = 0x40; + memcpy(tx+1, ssd1306_framebuffer, data_len); + int ret = i2c_write_blocking(i2c_port, SSD1306_I2C_ADDRESS, tx, sizeof(tx), false); +} + +void ssd1306_flush_region(i2c_inst_t *i2c_port, uint8_t* data, uint data_len) { + uint8_t col_start = 0; + uint8_t col_end = 63; + uint8_t page_start = 0; + uint8_t page_end = 3; + + const uint width = (uint)(col_end - col_start + 1); + const uint pages = (uint)(page_end - page_start + 1); + + uint8_t tx[1 + width * pages]; + tx[0] = 0x40; + + for(int i = 0; i < pages; i++){ + memcpy(tx + 1 + i * width, data + SSD1306_WIDTH * i + col_start, width); + } + + + // Set column address range: 0 to 127 + ssd1306_write_command(i2c_port, 0x21); // Set column address command + ssd1306_write_command(i2c_port, col_start); // Start column + ssd1306_write_command(i2c_port, col_end); // End column (127) + // Set page address range: 0 to 7 + ssd1306_write_command(i2c_port, 0x22); // Set page address command + ssd1306_write_command(i2c_port, page_start); // Start page + ssd1306_write_command(i2c_port, page_end); // End page (7) + // Start I2C transaction to send full framebuffer + int ret = i2c_write_blocking(i2c_port, SSD1306_I2C_ADDRESS, tx, sizeof(tx), false); + +} + +void ssd1306_setpixel(uint8_t x, uint8_t y, bool value){ + int page = y / 8; + int bit_offset = y % 8; + int byte_idx = page * SSD1306_WIDTH + x; + ssd1306_framebuffer[byte_idx] &= ~(1 << bit_offset); + ssd1306_framebuffer[byte_idx] |= value << bit_offset; +} + +int main() { + setupUART(); + + i2c_inst_t * I2C_ID = i2c0; + i2c_init(I2C_ID, SSD1306_I2C_BAUDRATE); + gpio_set_function(SSD1306_I2C_SDA_PIN, GPIO_FUNC_I2C); + gpio_set_function(SSD1306_I2C_SCL_PIN, GPIO_FUNC_I2C); + gpio_pull_up(SSD1306_I2C_SDA_PIN); + gpio_pull_up(SSD1306_I2C_SCL_PIN); + + sleep_ms(100); + ssd1306_init(I2C_ID); + memset(ssd1306_framebuffer, 0x00, SSD1306_FRAME_SIZE); + ssd1306_flush(I2C_ID, ssd1306_framebuffer, SSD1306_FRAME_SIZE); + + printf("ssd1306 setup\n"); + sleep_ms(100); + + + const int SAMPLE_FRAMES = 100; + uint32_t start_ms = to_ms_since_boot(get_absolute_time()); + for (int i = 0; i < SAMPLE_FRAMES; ++i) { + memset(ssd1306_framebuffer, 0x00, SSD1306_FRAME_SIZE); + ssd1306_flush(I2C_ID, ssd1306_framebuffer, SSD1306_FRAME_SIZE); + memset(ssd1306_framebuffer, 0xFF, SSD1306_FRAME_SIZE); + ssd1306_flush(I2C_ID, ssd1306_framebuffer, SSD1306_FRAME_SIZE); + } + uint32_t end_ms = to_ms_since_boot(get_absolute_time()); + uint32_t elapsed_ms = end_ms - start_ms; + float frames = (float)SAMPLE_FRAMES * 2.0f; // two frames per loop iteration + float fps = frames * 1000.0f / (float)elapsed_ms; + printf("Elapsed: %u ms for %.0f frames -> FPS = %.2f\n", elapsed_ms, frames, fps); + + + memset(ssd1306_framebuffer, 0x0, SSD1306_FRAME_SIZE); + ssd1306_flush(I2C_ID, ssd1306_framebuffer, SSD1306_FRAME_SIZE); + + + while (true) tight_loop_contents(); +} diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake new file mode 100644 index 0000000..d493cc2 --- /dev/null +++ b/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})