From a729ede7e7718cdc8dfc3c352642f557c9941c96 Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Mon, 13 May 2024 19:20:39 +0200 Subject: [PATCH] you know what let's just paste code --- .gitmodules | 3 - .vscode/c_cpp_properties.json | 18 ++-- .vscode/cmake-kits.json | 16 ++++ .vscode/extensions.json | 9 ++ .vscode/launch.json | 68 +++++++++++++++ .vscode/settings.json | 39 +++++++++ .vscode/tasks.json | 38 +++++++++ CMakeLists.txt | 26 ++++-- README.md | 10 ++- include/display.h | 1 + pico-sdk | 1 - src/display.c | 11 --- src/main.c | 8 -- src/st7789_lcd.c | 153 ++++++++++++++++++++++++++++++++++ src/st7789_lcd.pio | 57 +++++++++++++ 15 files changed, 417 insertions(+), 41 deletions(-) delete mode 100644 .gitmodules create mode 100644 .vscode/cmake-kits.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 include/display.h delete mode 160000 pico-sdk delete mode 100644 src/display.c delete mode 100644 src/main.c create mode 100644 src/st7789_lcd.c create mode 100644 src/st7789_lcd.pio diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 643f237..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "pico-sdk"] - path = pico-sdk - url = https://github.com/raspberrypi/pico-sdk diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 3a3e27d..3f6fe3d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,18 +1,22 @@ { "configurations": [ { - "name": "Linux", + "name": "Pico", "includePath": [ "${workspaceFolder}/**", - "${workspaceFolder}/pico-sdk" + "${env:HOME}/.pico-sdk/sdk/1.5.1/**" + ], + "forcedInclude": [ + "${env:HOME}/.pico-sdk/sdk/1.5.1/src/common/pico_base/include/pico.h", + "${workspaceFolder}/build/generated/pico_base/pico/config_autogen.h" ], "defines": [], - "compilerPath": "/usr/bin/gcc", + "compilerPath": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1/bin/arm-none-eabi-gcc", + "compileCommands": "${workspaceFolder}/build/compile_commands.json", "cStandard": "c17", - "cppStandard": "gnu++17", - "intelliSenseMode": "linux-gcc-x64", - "configurationProvider": "none" + "cppStandard": "c++14", + "intelliSenseMode": "linux-gcc-arm" } ], "version": 4 -} \ No newline at end of file +} diff --git a/.vscode/cmake-kits.json b/.vscode/cmake-kits.json new file mode 100644 index 0000000..6ccb0f2 --- /dev/null +++ b/.vscode/cmake-kits.json @@ -0,0 +1,16 @@ +[ + { + "name": "Pico", + "compilers": { + "C": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1/bin/arm-none-eabi-gcc", + "CXX": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1/bin/arm-none-eabi-gcc" + }, + "toolchainFile": "${env:HOME}/.pico-sdk/sdk/1.5.1/cmake/preload/toolchains/pico_arm_gcc.cmake", + "environmentVariables": { + "PATH": "${command:raspberry-pi-pico.getEnvPath};${env:PATH}" + }, + "cmakeSettings": { + "Python3_EXECUTABLE": "${command:raspberry-pi-pico.getPythonPath}" + } + } +] \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..2354cf2 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "marus25.cortex-debug", + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "ms-vscode.vscode-serial-monitor", + "raspberry-pi.raspberry-pi-pico", + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..af7cd09 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,68 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Pico Debug (Cortex-Debug)", + "cwd": "${workspaceRoot}", + "executable": "${command:raspberry-pi-pico.launchTargetPath}", + "request": "launch", + "type": "cortex-debug", + "servertype": "openocd", + "serverpath": "${userHome}/.pico-sdk/openocd/v0.12.0-2/bin/openocd.exe", + "gdbPath": "gdb", + "device": "RP2040", + "configFiles": [ + "interface/cmsis-dap.cfg", + "target/rp2040.cfg" + ], + "svdFile": "${userHome}/.pico-sdk/sdk/1.5.1/src/rp2040/hardware_regs/rp2040.svd", + "runToEntryPoint": "main", + // Give restart the same functionality as runToEntryPoint - main + "postRestartCommands": [ + "break main", + "continue" + ], + "openOCDLaunchCommands": [ + "adapter speed 5000" + ] + }, + { + "name": "Pico Debug (Cortex-Debug with external OpenOCD)", + "cwd": "${workspaceRoot}", + "executable": "${command:raspberry-pi-pico.launchTargetPath}", + "request": "launch", + "type": "cortex-debug", + "servertype": "external", + "gdbTarget": "localhost:3333", + "gdbPath": "gdb", + "device": "RP2040", + "svdFile": "${userHome}/.pico-sdk/sdk/1.5.1/src/rp2040/hardware_regs/rp2040.svd", + "runToEntryPoint": "main", + // Give restart the same functionality as runToEntryPoint - main + "postRestartCommands": [ + "break main", + "continue" + ] + }, + { + "name": "Pico Debug (C++ Debugger)", + "type": "cppdbg", + "request": "launch", + "cwd": "${workspaceRoot}", + "program": "${command:raspberry-pi-pico.launchTargetPath}", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "miDebuggerServerAddress": "localhost:3333", + "debugServerPath": "${userHome}/.pico-sdk/openocd/v0.12.0-2/bin/openocd.exe", + "debugServerArgs": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"", + "serverStarted": "Listening on port .* for gdb connections", + "filterStderr": true, + "hardwareBreakpoints": { + "require": true, + "limit": 4 + }, + "preLaunchTask": "Flash", + "svdPath": "${userHome}/.pico-sdk/sdk/1.5.1/src/rp2040/hardware_regs/rp2040.svd" + }, + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7d8103a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,39 @@ +{ + "cmake.options.statusBarVisibility": "hidden", + "cmake.options.advanced": { + "build": { + "statusBarVisibility": "hidden" + }, + "launch": { + "statusBarVisibility": "hidden" + }, + "debug": { + "statusBarVisibility": "hidden" + } + }, + "cmake.configureOnEdit": false, + "cmake.automaticReconfigure": false, + "cmake.configureOnOpen": false, + "cmake.generator": "Ninja", + "cmake.cmakePath": "${userHome}/.pico-sdk/cmake/v3.28.0-rc6/bin/cmake", + "C_Cpp.debugShortcut": false, + "terminal.integrated.env.windows": { + "PICO_SDK_PATH": "${env:USERPROFILE}/.pico-sdk/sdk/1.5.1", + "PICO_TOOLCHAIN_PATH": "${env:USERPROFILE}/.pico-sdk/toolchain/13_2_Rel1", + "Path": "${env:USERPROFILE}/.pico-sdk/toolchain/13_2_Rel1/bin;${env:USERPROFILE}/.pico-sdk/cmake/v3.28.0-rc6/bin;${env:USERPROFILE}/.pico-sdk/ninja/v1.11.1;${env:PATH}" + }, + "terminal.integrated.env.osx": { + "PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/1.5.1", + "PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1", + "PATH": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1/bin:${env:HOME}/.pico-sdk/cmake/v3.28.0-rc6/bin:${env:HOME}/.pico-sdk/ninja/v1.11.1:${env:PATH}" + }, + "terminal.integrated.env.linux": { + "PICO_SDK_PATH": "${env:HOME}/.pico-sdk/sdk/1.5.1", + "PICO_TOOLCHAIN_PATH": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1", + "PATH": "${env:HOME}/.pico-sdk/toolchain/13_2_Rel1/bin:${env:HOME}/.pico-sdk/cmake/v3.28.0-rc6/bin:${env:HOME}/.pico-sdk/ninja/v1.11.1:${env:PATH}" + }, + "raspberry-pi-pico.cmakeAutoConfigure": true, + "raspberry-pi-pico.useCmakeTools": false, + "raspberry-pi-pico.cmakePath": "${HOME}/.pico-sdk/cmake/v3.28.0-rc6/bin/cmake", + "raspberry-pi-pico.ninjaPath": "${HOME}/.pico-sdk/ninja/v1.11.1/ninja" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..11e5891 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,38 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Compile Project", + "type": "process", + "isBuildCommand": true, + "command": "${userHome}/.pico-sdk/ninja/v1.11.1/ninja", + "args": ["-C", "${workspaceFolder}/build"], + "group": "build", + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "problemMatcher": "$gcc", + "windows": { + "command": "${env:USERPROFILE}/.pico-sdk/ninja/v1.11.1/ninja.exe" + } + }, + { + "label": "Flash", + "type": "process", + "command": "${userHome}/.pico-sdk/openocd/v0.12.0-2/bin/openocd.exe", + "args": [ + "-f", + "interface/cmsis-dap.cfg", + "-f", + "target/rp2040.cfg", + "-c", + "adapter speed 5000; program \"${command:raspberry-pi-pico.launchTargetPath}\" verify reset exit" + ], + "problemMatcher": [], + "windows": { + "command": "${env:USERPROFILE}/.pico-sdk/openocd/v0.12.0-2/bin/openocd.exe", + } + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 12dc50c..9fd5781 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,19 @@ +# == DO NEVER EDIT THE NEXT LINES for Raspberry Pi Pico VS Code Extension to work == +if(WIN32) + set(USERHOME $ENV{USERPROFILE}) +else() + set(USERHOME $ENV{HOME}) +endif() +set(PICO_SDK_PATH ${USERHOME}/.pico-sdk/sdk/1.5.1) +set(PICO_TOOLCHAIN_PATH ${USERHOME}/.pico-sdk/toolchain/13_2_Rel1) +if(WIN32) + set(pico-sdk-tools_DIR ${USERHOME}/.pico-sdk/tools/1.5.1) + include(${pico-sdk-tools_DIR}/pico-sdk-tools-config.cmake) + include(${pico-sdk-tools_DIR}/pico-sdk-tools-config-version.cmake) +endif() +# ==================================================================================== cmake_minimum_required(VERSION 3.13) -set(PICO_SDK_PATH ../pico-sdk) - # initialize the SDK based on PICO_SDK_PATH # note: this must happen before project() include(pico_sdk_import.cmake) @@ -11,13 +23,13 @@ project(dp) # initialize the Raspberry Pi Pico SDK pico_sdk_init() -add_executable(dp - src/main.c - src/display.c -) +file(GLOB SOURCES "src/*.c") +add_executable(dp ${SOURCES}) +target_include_directories(dp PRIVATE "${PROJECT_SOURCE_DIR}/include") +pico_generate_pio_header(pio_st7789_lcd ${CMAKE_CURRENT_LIST_DIR}/st7789_lcd.pio) # Add pico_stdlib library which aggregates commonly used features -target_link_libraries(dp pico_stdlib hardware_spi) +target_link_libraries(dp pico_stdlib hardware_pio hardware_interp) # create map/bin/hex/uf2 file in addition to ELF. pico_add_extra_outputs(dp) \ No newline at end of file diff --git a/README.md b/README.md index 08f42c3..eb9e509 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ### Usage -1. `git submodule update --init --recursive` -2. `mkdir build && cd build` -3. `cmake ..` -4. `make` \ No newline at end of file +1. create a new directory and enter it +2. `git clone --recursive https://github.com/raspberrypi/pico-sdk` +3. git clone this repo and cd into it +4. `mkdir build && cd build` +5. `cmake ..` +6. `make` \ No newline at end of file diff --git a/include/display.h b/include/display.h new file mode 100644 index 0000000..32559c3 --- /dev/null +++ b/include/display.h @@ -0,0 +1 @@ +void init_display(); \ No newline at end of file diff --git a/pico-sdk b/pico-sdk deleted file mode 160000 index 6a7db34..0000000 --- a/pico-sdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6a7db34ff63345a7badec79ebea3aaef1712f374 diff --git a/src/display.c b/src/display.c deleted file mode 100644 index 84aa5fc..0000000 --- a/src/display.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "pico/stdlib.h" -#include "hardware/spi.h" - -#define TX_PIN 19 -#define CLK_PIN 18 -#define CS_PIN 17 -#define DC_PIN 20 - -void init_display() { - -} \ No newline at end of file diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 42fca18..0000000 --- a/src/main.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include "pico/stdlib.h" - -int main() { - setup_default_uart(); - printf("Hello, world!\n"); - return 0; -} \ No newline at end of file diff --git a/src/st7789_lcd.c b/src/st7789_lcd.c new file mode 100644 index 0000000..1704a0c --- /dev/null +++ b/src/st7789_lcd.c @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "hardware/gpio.h" +#include "hardware/interp.h" + +#include "st7789_lcd.pio.h" +#include "raspberry_256x256_rgb565.h" + +// Tested with the parts that have the height of 240 and 320 +#define SCREEN_WIDTH 240 +#define SCREEN_HEIGHT 320 +#define IMAGE_SIZE 256 +#define LOG_IMAGE_SIZE 8 + +#define PIN_DIN 0 +#define PIN_CLK 1 +#define PIN_CS 2 +#define PIN_DC 3 +#define PIN_RESET 4 +#define PIN_BL 5 + +#define SERIAL_CLK_DIV 1.f + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +// Format: cmd length (including cmd byte), post delay in units of 5 ms, then cmd payload +// Note the delays have been shortened a little +static const uint8_t st7789_init_seq[] = { + 1, 20, 0x01, // Software reset + 1, 10, 0x11, // Exit sleep mode + 2, 2, 0x3a, 0x55, // Set colour mode to 16 bit + 2, 0, 0x36, 0x00, // Set MADCTL: row then column, refresh is bottom to top ???? + 5, 0, 0x2a, 0x00, 0x00, SCREEN_WIDTH >> 8, SCREEN_WIDTH & 0xff, // CASET: column addresses + 5, 0, 0x2b, 0x00, 0x00, SCREEN_HEIGHT >> 8, SCREEN_HEIGHT & 0xff, // RASET: row addresses + 1, 2, 0x21, // Inversion on, then 10 ms delay (supposedly a hack?) + 1, 2, 0x13, // Normal display on, then 10 ms delay + 1, 2, 0x29, // Main screen turn on, then wait 500 ms + 0 // Terminate list +}; + +static inline void lcd_set_dc_cs(bool dc, bool cs) { + sleep_us(1); + gpio_put_masked((1u << PIN_DC) | (1u << PIN_CS), !!dc << PIN_DC | !!cs << PIN_CS); + sleep_us(1); +} + +static inline void lcd_write_cmd(PIO pio, uint sm, const uint8_t *cmd, size_t count) { + st7789_lcd_wait_idle(pio, sm); + lcd_set_dc_cs(0, 0); + st7789_lcd_put(pio, sm, *cmd++); + if (count >= 2) { + st7789_lcd_wait_idle(pio, sm); + lcd_set_dc_cs(1, 0); + for (size_t i = 0; i < count - 1; ++i) + st7789_lcd_put(pio, sm, *cmd++); + } + st7789_lcd_wait_idle(pio, sm); + lcd_set_dc_cs(1, 1); +} + +static inline void lcd_init(PIO pio, uint sm, const uint8_t *init_seq) { + const uint8_t *cmd = init_seq; + while (*cmd) { + lcd_write_cmd(pio, sm, cmd + 2, *cmd); + sleep_ms(*(cmd + 1) * 5); + cmd += *cmd + 2; + } +} + +static inline void st7789_start_pixels(PIO pio, uint sm) { + uint8_t cmd = 0x2c; // RAMWR + lcd_write_cmd(pio, sm, &cmd, 1); + lcd_set_dc_cs(1, 0); +} + +int main() { + stdio_init_all(); + + PIO pio = pio0; + uint sm = 0; + uint offset = pio_add_program(pio, &st7789_lcd_program); + st7789_lcd_program_init(pio, sm, offset, PIN_DIN, PIN_CLK, SERIAL_CLK_DIV); + + gpio_init(PIN_CS); + gpio_init(PIN_DC); + gpio_init(PIN_RESET); + gpio_init(PIN_BL); + gpio_set_dir(PIN_CS, GPIO_OUT); + gpio_set_dir(PIN_DC, GPIO_OUT); + gpio_set_dir(PIN_RESET, GPIO_OUT); + gpio_set_dir(PIN_BL, GPIO_OUT); + + gpio_put(PIN_CS, 1); + gpio_put(PIN_RESET, 1); + lcd_init(pio, sm, st7789_init_seq); + gpio_put(PIN_BL, 1); + + // Other SDKs: static image on screen, lame, boring + // Raspberry Pi Pico SDK: spinning image on screen, bold, exciting + + // Lane 0 will be u coords (bits 8:1 of addr offset), lane 1 will be v + // coords (bits 16:9 of addr offset), and we'll represent coords with + // 16.16 fixed point. ACCUM0,1 will contain current coord, BASE0/1 will + // contain increment vector, and BASE2 will contain image base pointer +#define UNIT_LSB 16 + interp_config lane0_cfg = interp_default_config(); + interp_config_set_shift(&lane0_cfg, UNIT_LSB - 1); // -1 because 2 bytes per pixel + interp_config_set_mask(&lane0_cfg, 1, 1 + (LOG_IMAGE_SIZE - 1)); + interp_config_set_add_raw(&lane0_cfg, true); // Add full accumulator to base with each POP + interp_config lane1_cfg = interp_default_config(); + interp_config_set_shift(&lane1_cfg, UNIT_LSB - (1 + LOG_IMAGE_SIZE)); + interp_config_set_mask(&lane1_cfg, 1 + LOG_IMAGE_SIZE, 1 + (2 * LOG_IMAGE_SIZE - 1)); + interp_config_set_add_raw(&lane1_cfg, true); + + interp_set_config(interp0, 0, &lane0_cfg); + interp_set_config(interp0, 1, &lane1_cfg); + interp0->base[2] = (uint32_t) raspberry_256x256; + + float theta = 0.f; + float theta_max = 2.f * (float) M_PI; + while (1) { + theta += 0.02f; + if (theta > theta_max) + theta -= theta_max; + int32_t rotate[4] = { + (int32_t) (cosf(theta) * (1 << UNIT_LSB)), (int32_t) (-sinf(theta) * (1 << UNIT_LSB)), + (int32_t) (sinf(theta) * (1 << UNIT_LSB)), (int32_t) (cosf(theta) * (1 << UNIT_LSB)) + }; + interp0->base[0] = rotate[0]; + interp0->base[1] = rotate[2]; + st7789_start_pixels(pio, sm); + for (int y = 0; y < SCREEN_HEIGHT; ++y) { + interp0->accum[0] = rotate[1] * y; + interp0->accum[1] = rotate[3] * y; + for (int x = 0; x < SCREEN_WIDTH; ++x) { + uint16_t colour = *(uint16_t *) (interp0->pop[2]); + st7789_lcd_put(pio, sm, colour >> 8); + st7789_lcd_put(pio, sm, colour & 0xff); + } + } + } +} diff --git a/src/st7789_lcd.pio b/src/st7789_lcd.pio new file mode 100644 index 0000000..aa35c68 --- /dev/null +++ b/src/st7789_lcd.pio @@ -0,0 +1,57 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program st7789_lcd +.side_set 1 + +; This is just a simple clocked serial TX. At 125 MHz system clock we can +; sustain up to 62.5 Mbps. +; Data on OUT pin 0 +; Clock on side-set pin 0 + +.wrap_target + out pins, 1 side 0 ; stall here if no data (clock low) + nop side 1 +.wrap + +% c-sdk { +// For optimal use of DMA bandwidth we would use an autopull threshold of 32, +// but we are using a threshold of 8 here (consume 1 byte from each FIFO entry +// and discard the remainder) to make things easier for software on the other side + +static inline void st7789_lcd_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clk_pin, float clk_div) { + pio_gpio_init(pio, data_pin); + pio_gpio_init(pio, clk_pin); + pio_sm_set_consecutive_pindirs(pio, sm, data_pin, 1, true); + pio_sm_set_consecutive_pindirs(pio, sm, clk_pin, 1, true); + pio_sm_config c = st7789_lcd_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_out_pins(&c, data_pin, 1); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_clkdiv(&c, clk_div); + sm_config_set_out_shift(&c, false, true, 8); + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +// Making use of the narrow store replication behaviour on RP2040 to get the +// data left-justified (as we are using shift-to-left to get MSB-first serial) + +static inline void st7789_lcd_put(PIO pio, uint sm, uint8_t x) { + while (pio_sm_is_tx_fifo_full(pio, sm)) + ; + *(volatile uint8_t*)&pio->txf[sm] = x; +} + +// SM is done when it stalls on an empty FIFO + +static inline void st7789_lcd_wait_idle(PIO pio, uint sm) { + uint32_t sm_stall_mask = 1u << (sm + PIO_FDEBUG_TXSTALL_LSB); + pio->fdebug = sm_stall_mask; + while (!(pio->fdebug & sm_stall_mask)) + ; +} +%}