diff --git a/.github/workflows/micropython-badger2040w.yml b/.github/workflows/micropython-badger2040w.yml new file mode 100644 index 00000000..8c0c6f94 --- /dev/null +++ b/.github/workflows/micropython-badger2040w.yml @@ -0,0 +1,172 @@ +name: MicroPython for Badger2040W + +on: + push: + pull_request: + release: + types: [created] + +env: + MICROPYTHON_VERSION: eefd946e60aba3ac61c7bfbd0272d07be289e3f3 + BOARD_TYPE: PIMORONI_BADGER2040W + # MicroPython version will be contained in github.event.release.tag_name for releases + RELEASE_FILE: pimoroni-badger2040w-${{github.event.release.tag_name || github.sha}}-micropython + +jobs: + deps: + runs-on: ubuntu-20.04 + name: Dependencies + steps: + - name: Workspace Cache + id: cache + uses: actions/cache@v2 + with: + path: ${{runner.workspace}} + key: workspace-micropython-${{env.MICROPYTHON_VERSION}} + restore-keys: | + workspace-micropython-${{env.MICROPYTHON_VERSION}} + + # Check out MicroPython + - name: Checkout MicroPython + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + repository: micropython/micropython + ref: ${{env.MICROPYTHON_VERSION}} + submodules: false # MicroPython submodules are hideously broken + path: micropython + + - name: Fetch base MicroPython submodules + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + working-directory: micropython + run: git submodule update --init + + - name: Fetch Pico SDK submodules + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + working-directory: micropython/lib/pico-sdk + run: git submodule update --init + + - name: Build mpy-cross + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + working-directory: micropython/mpy-cross + run: make + + build: + needs: deps + name: Build Badger 2040W + runs-on: ubuntu-20.04 + + steps: + - name: Compiler Cache + uses: actions/cache@v2 + with: + path: /home/runner/.ccache + key: ccache-micropython-badger2040w-${{github.ref}}-${{github.sha}} + restore-keys: | + ccache-micropython-badger2040w-${{github.ref}} + ccache-micropython-badger2040w- + + - name: Workspace Cache + uses: actions/cache@v2 + with: + path: ${{runner.workspace}} + key: workspace-micropython-${{env.MICROPYTHON_VERSION}} + restore-keys: | + workspace-micropython-${{env.MICROPYTHON_VERSION}} + + - uses: actions/checkout@v2 + with: + submodules: true + path: pimoroni-pico-${{ github.sha }} + + - name: "HACK: MicroPython Board Fixups" + shell: bash + working-directory: micropython/ports/rp2 + run: | + ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh badger2040w ${{env.BOARD_TYPE}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board + + # Linux deps + - name: Install Compiler & CCache + if: runner.os == 'Linux' + run: | + sudo apt update && sudo apt install ccache gcc-arm-none-eabi + python3 -m pip install pillow + + # Build without BadgerOS + - name: Configure MicroPython (No BadgerOS) + shell: bash + working-directory: micropython/ports/rp2 + run: | + cmake -S . -B build-${{env.BOARD_TYPE}}-without-badger-os -DBADGER2040_NO_MODULES=1 -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: Build MicroPython (No BadgerOS) + shell: bash + working-directory: micropython/ports/rp2 + run: | + ccache --zero-stats || true + cmake --build build-${{env.BOARD_TYPE}}-without-badger-os -j 2 + ccache --show-stats || true + + - name: Rename .uf2 for artifact (No BadgerOS) + shell: bash + working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os + run: | + cp firmware.uf2 ${{env.RELEASE_FILE}}-without-badger-os.uf2 + + - name: Store .uf2 as artifact (No BadgerOS) + uses: actions/upload-artifact@v2 + with: + name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 + path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 + + - name: Upload .uf2 (No BadgerOS) + if: github.event_name == 'release' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + with: + asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}-without-badger-os/${{env.RELEASE_FILE}}-without-badger-os.uf2 + upload_url: ${{github.event.release.upload_url}} + asset_name: ${{env.RELEASE_FILE}}-without-badger-os.uf2 + asset_content_type: application/octet-stream + + # Build with BadgerOS + - name: Configure MicroPython + shell: bash + working-directory: micropython/ports/rp2 + run: | + cmake -S . -B build-${{env.BOARD_TYPE}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-badger2040w.cmake -DMICROPY_BOARD=${{env.BOARD_TYPE}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: Build MicroPython + shell: bash + working-directory: micropython/ports/rp2 + run: | + ccache --zero-stats || true + cmake --build build-${{env.BOARD_TYPE}} -j 2 + ccache --show-stats || true + + - name: Rename .uf2 for artifact + shell: bash + working-directory: micropython/ports/rp2/build-${{env.BOARD_TYPE}} + run: | + cp firmware.uf2 ${{env.RELEASE_FILE}}.uf2 + + - name: Store .uf2 as artifact + uses: actions/upload-artifact@v2 + with: + name: ${{env.RELEASE_FILE}}.uf2 + path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 + + - name: Upload .uf2 + if: github.event_name == 'release' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + with: + asset_path: micropython/ports/rp2/build-${{env.BOARD_TYPE}}/${{env.RELEASE_FILE}}.uf2 + upload_url: ${{github.event.release.upload_url}} + asset_name: ${{env.RELEASE_FILE}}.uf2 + asset_content_type: application/octet-stream diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json new file mode 100644 index 00000000..d5d4332e --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/board.json @@ -0,0 +1,17 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "296*128 e-Ink", + "Buttons" + ], + "images": [ + ], + "mcu": "rp2040", + "product": "Badger2040 W (2MiB)", + "thumbnail": "", + "url": "https://shop.pimoroni.com/products/badger-2040w", + "vendor": "Pimoroni" +} diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake new file mode 100644 index 00000000..c16e3204 --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.cmake @@ -0,0 +1,8 @@ +# cmake file for Pimoroni Badger 2040W +set(MICROPY_BOARD PICO_W) + +set(MICROPY_PY_LWIP ON) +set(MICROPY_PY_NETWORK_CYW43 ON) + +# Board specific version of the frozen manifest +set(MICROPY_FROZEN_MANIFEST ${CMAKE_SOURCE_DIR}/boards/PICO_W/manifest.py) \ No newline at end of file diff --git a/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h new file mode 100644 index 00000000..888d1cad --- /dev/null +++ b/micropython/_board/badger2040w/PIMORONI_BADGER2040W/mpconfigboard.h @@ -0,0 +1,23 @@ +// This is a hack! Need to replace with upstream board definition. +#define MICROPY_HW_BOARD_NAME "Pimoroni Badger2040W 2MB" +#define MICROPY_HW_FLASH_STORAGE_BYTES (848 * 1024) + +// Enable networking. +#define MICROPY_PY_NETWORK 1 + +// CYW43 driver configuration. +#define CYW43_USE_SPI (1) +#define CYW43_LWIP (1) +#define CYW43_GPIO (1) +#define CYW43_SPI_PIO (1) + +// For debugging mbedtls - also set +// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose +// #define MODUSSL_MBEDTLS_DEBUG_LEVEL 1 + +#define MICROPY_HW_PIN_CYW43_COUNT CYW43_WL_GPIO_COUNT +#ifdef CYW43_WL_GPIO_LED_PIN +#define MICROPY_HW_PIN_CYW43_LED_PIN_NUM CYW43_WL_GPIO_LED_PIN +#endif + +#define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON) \ No newline at end of file diff --git a/micropython/_board/badger2040w/fixup.sh b/micropython/_board/badger2040w/fixup.sh new file mode 100644 index 00000000..6acb551d --- /dev/null +++ b/micropython/_board/badger2040w/fixup.sh @@ -0,0 +1,6 @@ +SRC_DIR=$1 +DST_DIR=$2 + +echo "Applying wakeup_gpio.patch" +cd "$DST_DIR/../../lib/pico-sdk" +git apply "$SRC_DIR/wakeup_gpio.patch" \ No newline at end of file diff --git a/micropython/_board/badger2040w/pimoroni_badger2040w.h b/micropython/_board/badger2040w/pimoroni_badger2040w.h new file mode 100644 index 00000000..88610e7b --- /dev/null +++ b/micropython/_board/badger2040w/pimoroni_badger2040w.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// ----------------------------------------------------- +// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO +// SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES +// ----------------------------------------------------- + +#ifndef _BOARDS_PIMORONI_BADGER2040_H +#define _BOARDS_PIMORONI_BADGER2040_H + +// For board detection +#define RASPBERRYPI_PICO_W +#define PIMORONI_BADGER2040 +#define PIMORONI_BADGER2040W + +// --- BOARD SPECIFIC --- +#define BADGER2040_UART 0 +#define BADGER2040_TX_PIN 0 +#define BADGER2040_RX_PIN 1 + +#define BADGER2040_I2C 0 +#define BADGER2040_INT_PIN 3 +#define BADGER2040_SDA_PIN 4 +#define BADGER2040_SCL_PIN 5 + +#define BADGER2040_3V3_EN_PIN 10 + +#define BADGER2040_SW_DOWN_PIN 11 +#define BADGER2040_SW_A_PIN 12 +#define BADGER2040_SW_B_PIN 13 +#define BADGER2040_SW_C_PIN 14 +#define BADGER2040_SW_UP_PIN 15 + +#define BADGER2040_INKY_SPI 0 +#define BADGER2040_INKY_MISO_PIN 16 +#define BADGER2040_INKY_CSN_PIN 17 +#define BADGER2040_INKY_SCK_PIN 18 +#define BADGER2040_INKY_MOSI_PIN 19 +#define BADGER2040_INKY_DC_PIN 20 +#define BADGER2040_INKY_RESET_PIN 21 +#define BADGER2040_INKY_BUSY_PIN 26 + +#define BADGER2040_USER_SW_PIN 23 +#define BADGER2040_USER_LED_PIN 25 + +#define BADGER2040_VBUS_DETECT_PIN 24 +#define BADGER2040_VREF_POWER_PIN 27 +#define BADGER2040_1V2_REF_PIN 28 +#define BADGER2040_BAT_SENSE_PIN 29 + +// --- UART --- +#ifndef PICO_DEFAULT_UART +#define PICO_DEFAULT_UART BADGER2040_UART +#endif + +#ifndef PICO_DEFAULT_UART_TX_PIN +#define PICO_DEFAULT_UART_TX_PIN BADGER2040_TX_PIN +#endif + +#ifndef PICO_DEFAULT_UART_RX_PIN +#define PICO_DEFAULT_UART_RX_PIN BADGER2040_RX_PIN +#endif + +// --- LED --- +#ifndef PICO_DEFAULT_LED_PIN +#define PICO_DEFAULT_LED_PIN BADGER2040_USER_LED_PIN +#endif +// no PICO_DEFAULT_WS2812_PIN + +// --- I2C --- +#ifndef PICO_DEFAULT_I2C +#define PICO_DEFAULT_I2C BADGER2040_I2C +#endif +#ifndef PICO_DEFAULT_I2C_SDA_PIN +#define PICO_DEFAULT_I2C_SDA_PIN BADGER2040_SDA_PIN +#endif +#ifndef PICO_DEFAULT_I2C_SCL_PIN +#define PICO_DEFAULT_I2C_SCL_PIN BADGER2040_SCL_PIN +#endif + +// --- SPI --- +#ifndef PICO_DEFAULT_SPI +#define PICO_DEFAULT_SPI BADGER2040_INKY_SPI +#endif +#ifndef PICO_DEFAULT_SPI_SCK_PIN +#define PICO_DEFAULT_SPI_SCK_PIN BADGER2040_INKY_SCK_PIN +#endif +#ifndef PICO_DEFAULT_SPI_TX_PIN +#define PICO_DEFAULT_SPI_TX_PIN BADGER2040_INKY_MOSI_PIN +#endif +#ifndef PICO_DEFAULT_SPI_RX_PIN +#define PICO_DEFAULT_SPI_RX_PIN BADGER2040_INKY_MISO_PIN +#endif +#ifndef PICO_DEFAULT_SPI_CSN_PIN +#define PICO_DEFAULT_SPI_CSN_PIN BADGER2040_INKY_CSN_PIN +#endif + +// --- FLASH --- +#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1 + +#ifndef PICO_FLASH_SPI_CLKDIV +#define PICO_FLASH_SPI_CLKDIV 2 +#endif + +#ifndef PICO_FLASH_SIZE_BYTES +#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024) +#endif + +#ifndef PICO_RP2040_B0_SUPPORTED +#define PICO_RP2040_B0_SUPPORTED 0 +#endif + +#ifndef PICO_RP2040_B1_SUPPORTED +#define PICO_RP2040_B1_SUPPORTED 0 +#endif + +#ifndef CYW43_PIN_WL_HOST_WAKE +#define CYW43_PIN_WL_HOST_WAKE 24 +#endif + +#ifndef CYW43_PIN_WL_REG_ON +#define CYW43_PIN_WL_REG_ON 23 +#endif + +#ifndef CYW43_WL_GPIO_COUNT +#define CYW43_WL_GPIO_COUNT 3 +#endif + +#ifndef CYW43_WL_GPIO_LED_PIN +#define CYW43_WL_GPIO_LED_PIN 0 +#endif + +#endif \ No newline at end of file diff --git a/micropython/_board/badger2040w/wakeup_gpio.patch b/micropython/_board/badger2040w/wakeup_gpio.patch new file mode 100644 index 00000000..abaef7f0 --- /dev/null +++ b/micropython/_board/badger2040w/wakeup_gpio.patch @@ -0,0 +1,143 @@ +diff --git a/src/rp2_common/pico_runtime/runtime.c b/src/rp2_common/pico_runtime/runtime.c +index 70dd3bb..b8c1ed0 100644 +--- a/src/rp2_common/pico_runtime/runtime.c ++++ b/src/rp2_common/pico_runtime/runtime.c +@@ -17,6 +17,7 @@ + #include "hardware/clocks.h" + #include "hardware/irq.h" + #include "hardware/resets.h" ++#include "hardware/gpio.h" + + #include "pico/mutex.h" + #include "pico/time.h" +@@ -32,6 +33,21 @@ + #include "pico/bootrom.h" + #endif + ++// Pins to toggle on wakeup ++#ifndef PICO_WAKEUP_PIN_MASK ++#define PICO_WAKEUP_PIN_MASK ((0b1 << 10) | (0b1 << 25)) ++#endif ++ ++// Direction ++#ifndef PICO_WAKEUP_PIN_DIR ++#define PICO_WAKEUP_PIN_DIR ((0b1 << 10) | (0b1 << 25)) ++#endif ++ ++// Value ++#ifndef PICO_WAKEUP_PIN_VALUE ++#define PICO_WAKEUP_PIN_VALUE ((0b1 << 10) | (0b1 << 25)) ++#endif ++ + extern char __StackLimit; /* Set by linker. */ + + uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[48]; +@@ -61,11 +77,18 @@ void runtime_install_stack_guard(void *stack_bottom) { + | 0x10000000; // XN = disable instruction fetch; no other bits means no permissions + } + +-void runtime_init(void) { ++void runtime_user_init(void) { ++ gpio_init_mask(PICO_WAKEUP_PIN_MASK); ++ gpio_set_dir_masked(PICO_WAKEUP_PIN_MASK, PICO_WAKEUP_PIN_DIR); ++ gpio_put_masked(PICO_WAKEUP_PIN_MASK, PICO_WAKEUP_PIN_VALUE); ++} ++ ++void runtime_reset_peripherals(void) { + // Reset all peripherals to put system into a known state, + // - except for QSPI pads and the XIP IO bank, as this is fatal if running from flash + // - and the PLLs, as this is fatal if clock muxing has not been reset on this boot + // - and USB, syscfg, as this disturbs USB-to-SWD on core 1 ++ + reset_block(~( + RESETS_RESET_IO_QSPI_BITS | + RESETS_RESET_PADS_QSPI_BITS | +@@ -86,7 +109,9 @@ void runtime_init(void) { + RESETS_RESET_UART1_BITS | + RESETS_RESET_USBCTRL_BITS + )); ++} + ++void runtime_init(void) { + // pre-init runs really early since we need it even for memcpy and divide! + // (basically anything in aeabi that uses bootrom) + +diff --git a/src/rp2_common/pico_standard_link/crt0.S b/src/rp2_common/pico_standard_link/crt0.S +index b2992f6..6091e70 100644 +--- a/src/rp2_common/pico_standard_link/crt0.S ++++ b/src/rp2_common/pico_standard_link/crt0.S +@@ -9,6 +9,8 @@ + #include "hardware/regs/addressmap.h" + #include "hardware/regs/sio.h" + #include "pico/binary_info/defs.h" ++#include "hardware/regs/resets.h" ++#include "hardware/regs/rosc.h" + + #ifdef NDEBUG + #ifndef COLLAPSE_IRQS +@@ -225,6 +227,23 @@ _reset_handler: + cmp r0, #0 + bne hold_non_core0_in_bootrom + ++ // Increase ROSC frequency to ~48MHz (range 14.4 - 96) ++ // Startup drops from ~160ms to ~32ms on Pico W MicroPython ++ ldr r0, =(ROSC_BASE + ROSC_DIV_OFFSET) ++ ldr r1, =0xaa2 ++ str r1, [r0] ++ ++ ldr r1, =runtime_reset_peripherals ++ blx r1 ++ ++ ldr r1, =runtime_user_init ++ blx r1 ++ ++ // Read GPIO state for front buttons and store ++ movs r3, 0xd0 // Load 0xd0 into r3 ++ lsls r3, r3, 24 // Shift left 24 to get 0xd0000000 ++ ldr r6, [r3, 4] // Load GPIO state (0xd0000004) into r6 ++ + // In a NO_FLASH binary, don't perform .data copy, since it's loaded + // in-place by the SRAM load. Still need to clear .bss + #if !PICO_NO_FLASH +@@ -251,6 +270,10 @@ bss_fill_test: + cmp r1, r2 + bne bss_fill_loop + ++ // runtime_wakeup_gpio_state gets zero init above ++ ldr r2, =runtime_wakeup_gpio_state // Load output var addr into r2 ++ str r6, [r2] // Store r6 to r2 ++ + platform_entry: // symbol for stack traces + // Use 32-bit jumps, in case these symbols are moved out of branch range + // (e.g. if main is in SRAM and crt0 in flash) +@@ -314,6 +337,19 @@ data_cpy_table: + runtime_init: + bx lr + ++.weak runtime_user_init ++.type runtime_user_init,%function ++.thumb_func ++runtime_user_init: ++ bx lr ++ ++.weak runtime_reset_peripherals ++.type runtime_reset_peripherals,%function ++.thumb_func ++runtime_reset_peripherals: ++ bx lr ++ ++ + // ---------------------------------------------------------------------------- + // If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to + // catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't +@@ -345,3 +381,9 @@ __get_current_exception: + .align 2 + .equ HeapSize, PICO_HEAP_SIZE + .space HeapSize ++ ++.section .data._reset_handler ++.global runtime_wakeup_gpio_state ++.align 4 ++runtime_wakeup_gpio_state: ++.word 0x00000000 +\ No newline at end of file diff --git a/micropython/modules/micropython-badger2040w.cmake b/micropython/modules/micropython-badger2040w.cmake new file mode 100644 index 00000000..160ea378 --- /dev/null +++ b/micropython/modules/micropython-badger2040w.cmake @@ -0,0 +1,39 @@ +include_directories(${CMAKE_CURRENT_LIST_DIR}/../../) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../") + +include(pimoroni_i2c/micropython) +include(pimoroni_bus/micropython) + +include(breakout_dotmatrix/micropython) +include(breakout_encoder/micropython) +include(breakout_ioexpander/micropython) +include(breakout_ltr559/micropython) +include(breakout_as7262/micropython) +include(breakout_rgbmatrix5x5/micropython) +include(breakout_matrix11x7/micropython) +include(breakout_msa301/micropython) +include(breakout_pmw3901/micropython) +include(breakout_mics6814/micropython) +include(breakout_potentiometer/micropython) +include(breakout_rtc/micropython) +include(breakout_trackball/micropython) +include(breakout_sgp30/micropython) +include(breakout_bh1745/micropython) +include(breakout_bme68x/micropython) +include(breakout_bme280/micropython) +include(breakout_bmp280/micropython) +include(breakout_icp10125/micropython) +include(breakout_scd41/micropython) + +include(hershey_fonts/micropython) +include(bitmap_fonts/micropython) + +include(badger2040/micropython) +if(NOT DEFINED BADGER2040_NO_MODULES) +include(micropython/examples/badger2040/micropython-builtins) +endif() +include(plasma/micropython) +include(ulab/code/micropython) +include(qrcode/micropython/micropython)