1
0
Fork 0

[Core] Add Raspberry Pi RP2040 support (#14877)

* Disable RESET keycode because of naming conflicts

* Add Pico SDK as submodule

* Add RP2040 build support to QMK

* Adjust USB endpoint structs for RP2040

* Add RP2040 bootloader and double-tap reset routine

* Add generic and pro micro RP2040 boards

* Add RP2040 onekey keyboard

* Add WS2812 PIO DMA enabled driver and documentation

Supports regular and open-drain output configuration. RP2040 GPIOs are
sadly not 5V tolerant, so this is a bit use-less or needs extra hardware
or you take the risk to fry your hardware.

* Adjust SIO Driver for RP2040

* Adjust I2C Driver for RP2040

* Adjust SPI Driver for RP2040

* Add PIO serial driver and documentation

* Add general RP2040 documentation

* Apply suggestions from code review

Co-authored-by: Nick Brassel <nick@tzarc.org>

Co-authored-by: Nick Brassel <nick@tzarc.org>
This commit is contained in:
Stefan Kerkmann 2022-06-30 13:19:27 +02:00 committed by GitHub
parent d206c1791e
commit d717396708
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 2026 additions and 96 deletions

View file

@ -21,6 +21,11 @@
# include <hal.h>
#endif
/* Include the vendor specific pin defs */
#if __has_include_next("_pin_defs.h")
# include_next "_pin_defs.h"
#endif
#define A0 PAL_LINE(GPIOA, 0)
#define A1 PAL_LINE(GPIOA, 1)
#define A2 PAL_LINE(GPIOA, 2)

View file

@ -0,0 +1,9 @@
# List of all the board related files.
BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c
# Required include directories
BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040
# Shared variables
ALLCSRC += $(BOARDSRC)
ALLINC += $(BOARDINC)

View file

@ -0,0 +1,12 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include_next "board.h"
#undef BOARD_RP_PICO_RP2040
#define BOARD_GENERIC_PROMICRO_RP2040
#undef BOARD_NAME
#define BOARD_NAME "Pro Micro RP2040"

View file

@ -0,0 +1,13 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define CH_CFG_SMP_MODE TRUE
#define CH_CFG_ST_RESOLUTION 32
#define CH_CFG_ST_FREQUENCY 1000000
#define CH_CFG_INTERVALS_SIZE 32
#define CH_CFG_TIME_TYPES_SIZE 32
#define CH_CFG_ST_TIMEDELTA 20
#include_next <chconf.h>

View file

@ -0,0 +1,62 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
/**======================
** I2C Driver
*========================**/
#if !defined(I2C_DRIVER)
# define I2C_DRIVER I2CD2
#endif
#if !defined(I2C1_SDA_PIN)
# define I2C1_SDA_PIN GP2
#endif
#if !defined(I2C1_SCL_PIN)
# define I2C1_SCL_PIN GP3
#endif
/**======================
** SPI Driver
*========================**/
#if !defined(SPI_DRIVER)
# define SPI_DRIVER SPID0
#endif
#if !defined(SPI_SCK_PIN)
# define SPI_SCK_PIN GP18
#endif
#if !defined(SPI_MISO_PIN)
# define SPI_MISO_PIN GP20
#endif
#if !defined(SPI_MOSI_PIN)
# define SPI_MOSI_PIN GP19
#endif
/**======================
** SERIAL Driver
*========================**/
#if !defined(SERIAL_USART_DRIVER)
# define SERIAL_USART_DRIVER SIOD0
#endif
#if !defined(SERIAL_USART_TX_PIN) && !defined(SOFT_SERIAL_PIN)
# define SERIAL_USART_TX_PIN GP0
#endif
#if !defined(SERIAL_USART_RX_PIN)
# define SERIAL_USART_RX_PIN GP1
#endif
/**======================
** Double-tap
*========================**/
#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET

View file

@ -0,0 +1,98 @@
/*
ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef MCUCONF_H
#define MCUCONF_H
/*
* RP2040_MCUCONF drivers configuration.
*
* IRQ priorities:
* 3...0 Lowest...Highest.
*
* DMA priorities:
* 0...1 Lowest...Highest.
*/
#define RP2040_MCUCONF
/*
* HAL driver system settings.
*/
#define RP_NO_INIT FALSE
#define RP_CORE1_START FALSE
#define RP_CORE1_VECTORS_TABLE _vectors
#define RP_CORE1_ENTRY_POINT _crt0_c1_entry
#define RP_CORE1_STACK_END __c1_main_stack_end__
/*
* IRQ system settings.
*/
#define RP_IRQ_SYSTICK_PRIORITY 2
#define RP_IRQ_TIMER_ALARM0_PRIORITY 2
#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
#define RP_IRQ_UART0_PRIORITY 3
#define RP_IRQ_UART1_PRIORITY 3
#define RP_IRQ_SPI0_PRIORITY 2
#define RP_IRQ_SPI1_PRIORITY 2
#define RP_IRQ_USB0_PRIORITY 3
#define RP_IRQ_I2C0_PRIORITY 2
#define RP_IRQ_I2C1_PRIORITY 2
/*
* ADC driver system settings.
*/
#define RP_ADC_USE_ADC1 FALSE
/*
* SIO driver system settings.
*/
#define RP_SIO_USE_UART0 TRUE
#define RP_SIO_USE_UART1 FALSE
/*
* SPI driver system settings.
*/
#define RP_SPI_USE_SPI0 TRUE
#define RP_SPI_USE_SPI1 FALSE
#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI0_DMA_PRIORITY 1
#define RP_SPI_SPI1_DMA_PRIORITY 1
#define RP_SPI_DMA_ERROR_HOOK(spip)
/*
* I2C driver system settings.
*/
#define RP_I2C_USE_I2C0 FALSE
#define RP_I2C_USE_I2C1 TRUE
#define RP_I2C_BUSY_TIMEOUT 50
#define RP_I2C_ADDRESS_MODE_10BIT FALSE
/*
* USB driver system settings.
*/
#define RP_USB_USE_USBD0 TRUE
#define RP_USB_FORCE_VBUS_DETECT TRUE
#define RP_USE_EXTERNAL_VBUS_DETECT FALSE
#define RP_USB_USE_SOF_INTR TRUE
#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE
#endif /* MCUCONF_H */

View file

@ -0,0 +1,9 @@
# List of all the board related files.
BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c
# Required include directories
BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040
# Shared variables
ALLCSRC += $(BOARDSRC)
ALLINC += $(BOARDINC)

View file

@ -0,0 +1,12 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include_next "board.h"
#undef BOARD_RP_PICO_RP2040
#define BOARD_GENERIC_RP2040
#undef BOARD_NAME
#define BOARD_NAME "Generic Raspberry Pi RP2040"

View file

@ -0,0 +1,13 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define CH_CFG_SMP_MODE TRUE
#define CH_CFG_ST_RESOLUTION 32
#define CH_CFG_ST_FREQUENCY 1000000
#define CH_CFG_INTERVALS_SIZE 32
#define CH_CFG_TIME_TYPES_SIZE 32
#define CH_CFG_ST_TIMEDELTA 20
#include_next <chconf.h>

View file

@ -0,0 +1,98 @@
/*
ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef MCUCONF_H
#define MCUCONF_H
/*
* RP2040_MCUCONF drivers configuration.
*
* IRQ priorities:
* 3...0 Lowest...Highest.
*
* DMA priorities:
* 0...1 Lowest...Highest.
*/
#define RP2040_MCUCONF
/*
* HAL driver system settings.
*/
#define RP_NO_INIT FALSE
#define RP_CORE1_START FALSE
#define RP_CORE1_VECTORS_TABLE _vectors
#define RP_CORE1_ENTRY_POINT _crt0_c1_entry
#define RP_CORE1_STACK_END __c1_main_stack_end__
/*
* IRQ system settings.
*/
#define RP_IRQ_SYSTICK_PRIORITY 2
#define RP_IRQ_TIMER_ALARM0_PRIORITY 2
#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
#define RP_IRQ_UART0_PRIORITY 3
#define RP_IRQ_UART1_PRIORITY 3
#define RP_IRQ_SPI0_PRIORITY 2
#define RP_IRQ_SPI1_PRIORITY 2
#define RP_IRQ_USB0_PRIORITY 3
#define RP_IRQ_I2C0_PRIORITY 2
#define RP_IRQ_I2C1_PRIORITY 2
/*
* ADC driver system settings.
*/
#define RP_ADC_USE_ADC1 FALSE
/*
* SIO driver system settings.
*/
#define RP_SIO_USE_UART0 FALSE
#define RP_SIO_USE_UART1 FALSE
/*
* SPI driver system settings.
*/
#define RP_SPI_USE_SPI0 FALSE
#define RP_SPI_USE_SPI1 FALSE
#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY
#define RP_SPI_SPI0_DMA_PRIORITY 1
#define RP_SPI_SPI1_DMA_PRIORITY 1
#define RP_SPI_DMA_ERROR_HOOK(spip)
/*
* I2C driver system settings.
*/
#define RP_I2C_USE_I2C0 FALSE
#define RP_I2C_USE_I2C1 FALSE
#define RP_I2C_BUSY_TIMEOUT 50
#define RP_I2C_ADDRESS_MODE_10BIT FALSE
/*
* USB driver system settings.
*/
#define RP_USB_USE_USBD0 TRUE
#define RP_USB_FORCE_VBUS_DETECT TRUE
#define RP_USE_EXTERNAL_VBUS_DETECT FALSE
#define RP_USB_USE_SOF_INTR TRUE
#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE
#endif /* MCUCONF_H */

View file

@ -0,0 +1,57 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
#include "hal.h"
#include "bootloader.h"
#include "pico/bootrom.h"
#if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED)
# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U
#else
# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK (1U << RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED)
#endif
__attribute__((weak)) void mcu_reset(void) {
NVIC_SystemReset();
}
void bootloader_jump(void) {
reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U);
}
void enter_bootloader_mode_if_requested(void) {}
#if defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET)
# if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT)
# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U
# endif
// Needs to be located in a RAM section that is never initialized on boot to
// preserve its value on reset
static volatile uint32_t __attribute__((section(".ram0.bootloader_magic"))) magic_location;
const uint32_t magic_token = 0xCAFEB0BA;
// We can not use the __early_init / enter_bootloader_mode_if_requested hook as
// we depend on an already initialized system with usable memory regions and
// populated function pointer tables to the optimized math functions in the
// bootrom. This function is called just prior to main.
void __late_init(void) {
// All clocks have to be enabled before jumping to the bootloader function,
// otherwise the bootrom will be stuck infinitely.
clocks_init();
if (magic_location != magic_token) {
magic_location = magic_token;
// ChibiOS is not initialized at this point, so sleeping is only
// possible via busy waiting. The internal timer peripheral is running
// at this point with a precision of 1us.
chSysPolledDelayX(MS2RTC(1 * MHZ, RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT));
magic_location = 0;
return;
}
magic_location = 0;
reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U);
}
#endif

View file

@ -19,6 +19,27 @@
# define SPLIT_USB_DETECT // Force this on when dedicated pin is not used
#endif
#if defined(MCU_RP)
# define CPU_CLOCK RP_CORE_CLK
# define USE_GPIOV1
# define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible");
# define usb_lld_endpoint_fields
# define I2C1_SCL_PAL_MODE (PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_PUE | PAL_RP_PAD_DRIVE4)
# define I2C1_SDA_PAL_MODE I2C1_SCL_PAL_MODE
# define USE_I2CV1_CONTRIB
# if !defined(I2C1_CLOCK_SPEED)
# define I2C1_CLOCK_SPEED 400000
# endif
# define SPI_SCK_PAL_MODE (PAL_MODE_ALTERNATE_SPI | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_DRIVE4)
# define SPI_MOSI_PAL_MODE SPI_SCK_PAL_MODE
# define SPI_MISO_PAL_MODE SPI_SCK_PAL_MODE
#endif
// STM32 compatibility
#if defined(MCU_STM32)
# define CPU_CLOCK STM32_SYSCLK

View file

@ -8,12 +8,12 @@
#if defined(SERIAL_USART_CONFIG)
static QMKSerialConfig serial_config = SERIAL_USART_CONFIG;
#else
#elif defined(MCU_STM32) /* STM32 MCUs */
static QMKSerialConfig serial_config = {
# if HAL_USE_SERIAL
.speed = (SERIAL_USART_SPEED), /* baudrate - mandatory */
.speed = (SERIAL_USART_SPEED),
# else
.baud = (SERIAL_USART_SPEED), /* baudrate - mandatory */
.baud = (SERIAL_USART_SPEED),
# endif
.cr1 = (SERIAL_USART_CR1),
.cr2 = (SERIAL_USART_CR2),
@ -23,6 +23,19 @@ static QMKSerialConfig serial_config = {
.cr3 = (SERIAL_USART_CR3)
# endif
};
#elif defined(MCU_RP) /* Raspberry Pi MCUs */
/* USART in 8E2 config with RX and TX FIFOs enabled. */
// clang-format off
static QMKSerialConfig serial_config = {
.baud = (SERIAL_USART_SPEED),
.UARTLCR_H = UART_UARTLCR_H_WLEN_8BITS | UART_UARTLCR_H_PEN | UART_UARTLCR_H_STP2 | UART_UARTLCR_H_FEN,
.UARTCR = 0U,
.UARTIFLS = UART_UARTIFLS_RXIFLSEL_1_8F | UART_UARTIFLS_TXIFLSEL_1_8E,
.UARTDMACR = 0U
};
// clang-format on
#else
# error MCU Familiy not supported by default, supply your own serial_config by defining SERIAL_USART_CONFIG in your keyboard files.
#endif
static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER;
@ -156,7 +169,7 @@ inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t
* @brief Initiate pins for USART peripheral. Half-duplex configuration.
*/
__attribute__((weak)) void usart_init(void) {
# if defined(MCU_STM32)
# if defined(MCU_STM32) /* STM32 MCUs */
# if defined(USE_GPIOV1)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
# else
@ -166,6 +179,8 @@ __attribute__((weak)) void usart_init(void) {
# if defined(USART_REMAP)
USART_REMAP;
# endif
# elif defined(MCU_RP) /* Raspberry Pi MCUs */
# error Half-duplex with the SIO driver is not supported due to hardware limitations on the RP2040, switch to the PIO driver which has half-duplex support.
# else
# pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files."
# endif
@ -177,7 +192,7 @@ __attribute__((weak)) void usart_init(void) {
* @brief Initiate pins for USART peripheral. Full-duplex configuration.
*/
__attribute__((weak)) void usart_init(void) {
# if defined(MCU_STM32)
# if defined(MCU_STM32) /* STM32 MCUs */
# if defined(USE_GPIOV1)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
@ -189,6 +204,9 @@ __attribute__((weak)) void usart_init(void) {
# if defined(USART_REMAP)
USART_REMAP;
# endif
# elif defined(MCU_RP) /* Raspberry Pi MCUs */
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_UART);
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE_UART);
# else
# pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files."
# endif

View file

@ -20,7 +20,7 @@
static pin_t currentSlavePin = NO_PIN;
#if defined(K20x) || defined(KL2x)
#if defined(K20x) || defined(KL2x) || defined(RP2040)
static SPIConfig spiConfig = {NULL, 0, 0, 0};
#else
static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
@ -167,7 +167,36 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiConfig.SPI_CPOL = SPI_CPOL_High;
break;
}
#elif defined(MCU_RP)
if (lsbFirst) {
osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
}
// Motorola frame format and 8bit transfer data size.
spiConfig.SSPCR0 = SPI_SSPCR0_FRF_MOTOROLA | SPI_SSPCR0_DSS_8BIT;
// Serial output clock = (ck_sys or ck_peri) / (SSPCPSR->CPSDVSR * (1 +
// SSPCR0->SCR)). SCR is always set to zero, as QMK SPI API expects the
// passed divisor to be the only value to divide the input clock by.
spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
switch (mode) {
case 0:
spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
break;
case 1:
spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
break;
case 2:
spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
break;
case 3:
spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
break;
}
#else
spiConfig.cr1 = 0;

View file

@ -0,0 +1,457 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
#include "serial_usart.h"
#include "serial_protocol.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#if !defined(MCU_RP)
# error PIO Driver is only available for Raspberry Pi 2040 MCUs!
#endif
static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout);
static inline bool send_impl(const uint8_t* source, const size_t size);
static inline void pio_serve_interrupt(void);
#define MSG_PIO_ERROR ((msg_t)(-3))
#if defined(SERIAL_PIO_USE_PIO1)
static const PIO pio = pio1;
OSAL_IRQ_HANDLER(RP_PIO1_IRQ_0_HANDLER) {
OSAL_IRQ_PROLOGUE();
pio_serve_interrupt();
OSAL_IRQ_EPILOGUE();
}
#else
static const PIO pio = pio0;
OSAL_IRQ_HANDLER(RP_PIO0_IRQ_0_HANDLER) {
OSAL_IRQ_PROLOGUE();
pio_serve_interrupt();
OSAL_IRQ_EPILOGUE();
}
#endif
#define UART_TX_WRAP_TARGET 0
#define UART_TX_WRAP 3
// clang-format off
#if defined(SERIAL_USART_FULL_DUPLEX)
static const uint16_t uart_tx_program_instructions[] = {
// .wrap_target
0x9fa0, // 0: pull block side 1 [7]
0xf727, // 1: set x, 7 side 0 [7]
0x6001, // 2: out pins, 1
0x0642, // 3: jmp x--, 2 [6]
// .wrap
};
#else
static const uint16_t uart_tx_program_instructions[] = {
// .wrap_target
0x9fa0, // 0: pull block side 1 [7]
0xf727, // 1: set x, 7 side 0 [7]
0x6081, // 2: out pindirs, 1
0x0642, // 3: jmp x--, 2 [6]
// .wrap
};
#endif
// clang-format on
static const pio_program_t uart_tx_program = {
.instructions = uart_tx_program_instructions,
.length = 4,
.origin = -1,
};
#define UART_RX_WRAP_TARGET 0
#define UART_RX_WRAP 8
// clang-format off
static const uint16_t uart_rx_program_instructions[] = {
// .wrap_target
0x2020, // 0: wait 0 pin, 0
0xea27, // 1: set x, 7 [10]
0x4001, // 2: in pins, 1
0x0642, // 3: jmp x--, 2 [6]
0x00c8, // 4: jmp pin, 8
0xc020, // 5: irq wait 0
0x20a0, // 6: wait 1 pin, 0
0x0000, // 7: jmp 0
0x8020, // 8: push block
// .wrap
};
// clang-format on
static const pio_program_t uart_rx_program = {
.instructions = uart_rx_program_instructions,
.length = 9,
.origin = -1,
};
thread_reference_t rx_thread = NULL;
static int rx_state_machine = -1;
thread_reference_t tx_thread = NULL;
static int tx_state_machine = -1;
void pio_serve_interrupt(void) {
uint32_t irqs = pio->ints0;
// The RX FIFO is not empty any more, therefore wake any sleeping rx thread
if (irqs & (PIO_IRQ0_INTF_SM0_RXNEMPTY_BITS << rx_state_machine)) {
// Disable rx not empty interrupt
pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, false);
osalSysLockFromISR();
osalThreadResumeI(&rx_thread, MSG_OK);
osalSysUnlockFromISR();
}
// The TX FIFO is not full any more, therefore wake any sleeping tx thread
if (irqs & (PIO_IRQ0_INTF_SM0_TXNFULL_BITS << tx_state_machine)) {
// Disable tx not full interrupt
pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, false);
osalSysLockFromISR();
osalThreadResumeI(&tx_thread, MSG_OK);
osalSysUnlockFromISR();
}
// IRQ 0 is set on framing or break errors by the rx state machine
if (pio_interrupt_get(pio, 0UL)) {
pio_interrupt_clear(pio, 0UL);
osalSysLockFromISR();
osalThreadResumeI(&rx_thread, MSG_PIO_ERROR);
osalSysUnlockFromISR();
}
}
#if !defined(SERIAL_USART_FULL_DUPLEX)
// The internal pull-ups of the RP2040 are rather weakish with a range of 50k to
// 80k, which in turn do not provide enough current to guarantee fast signal rise
// times with a parasitic capacitance of greater than 100pf. In real world
// applications, like split keyboards which might have vias in the signal path
// or long PCB traces, this prevents a successful communication. The solution
// is to temporarily augment the weak pull ups from the receiving side by
// driving the tx pin high. On the receiving side the lowest possible drive
// strength is chosen because the transmitting side must still be able to drive
// the signal low. With this configuration the rise times are fast enough and
// the generated low level with 360mV will generate a logical zero.
static inline void enter_rx_state(void) {
osalSysLock();
// Wait for the transmitting state machines FIFO to run empty. At this point
// the last byte has been pulled from the transmitting state machines FIFO
// into the output shift register. We have to wait a tiny bit more until
// this byte is transmitted, before we can turn on the receiving state
// machine again.
while (!pio_sm_is_tx_fifo_empty(pio, tx_state_machine)) {
}
// Wait for ~11 bits, 1 start bit + 8 data bits + 1 stop bit + 1 bit
// headroom.
chSysPolledDelayX(US2RTC(1 * MHZ, (1000000U * 11 / SERIAL_USART_SPEED)));
// Disable tx state machine to not interfere with our tx pin manipulation
pio_sm_set_enabled(pio, tx_state_machine, false);
gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_2MA);
pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << SERIAL_USART_TX_PIN, 1U << SERIAL_USART_TX_PIN);
pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, false);
pio_sm_set_enabled(pio, rx_state_machine, true);
osalSysUnlock();
}
static inline void leave_rx_state(void) {
osalSysLock();
// In Half-duplex operation the tx pin dual-functions as sender and
// receiver. To not receive the data we will send, we disable the receiving
// state machine.
pio_sm_set_enabled(pio, rx_state_machine, false);
pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, true);
pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U, 1U << SERIAL_USART_TX_PIN);
gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_12MA);
pio_sm_restart(pio, tx_state_machine);
pio_sm_set_enabled(pio, tx_state_machine, true);
osalSysUnlock();
}
#else
// All this trickery is gladly not necessary for full-duplex.
static inline void enter_rx_state(void) {}
static inline void leave_rx_state(void) {}
#endif
/**
* @brief Clear the RX and TX hardware FIFOs of the state machines.
*/
inline void serial_transport_driver_clear(void) {
osalSysLock();
pio_sm_clear_fifos(pio, rx_state_machine);
pio_sm_clear_fifos(pio, tx_state_machine);
osalSysUnlock();
}
static inline msg_t sync_tx(sysinterval_t timeout) {
msg_t msg = MSG_OK;
osalSysLock();
while (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) {
pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true);
msg = osalThreadSuspendTimeoutS(&tx_thread, timeout);
if (msg < MSG_OK) {
break;
}
}
osalSysUnlock();
return msg;
}
static inline bool send_impl(const uint8_t* source, const size_t size) {
size_t send = 0;
msg_t msg;
while (send < size) {
msg = sync_tx(TIME_MS2I(SERIAL_USART_TIMEOUT));
if (msg < MSG_OK) {
return false;
}
osalSysLock();
while (send < size) {
if (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) {
break;
}
if (send >= size) {
break;
}
pio_sm_put(pio, tx_state_machine, (uint32_t)(*source));
source++;
send++;
}
osalSysUnlock();
}
return send == size;
}
/**
* @brief Blocking send of buffer with timeout.
*
* @return true Send success.
* @return false Send failed.
*/
inline bool serial_transport_send(const uint8_t* source, const size_t size) {
leave_rx_state();
bool result = send_impl(source, size);
enter_rx_state();
return result;
}
static inline msg_t sync_rx(sysinterval_t timeout) {
msg_t msg = MSG_OK;
osalSysLock();
while (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) {
pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true);
msg = osalThreadSuspendTimeoutS(&rx_thread, timeout);
if (msg < MSG_OK) {
break;
}
}
osalSysUnlock();
return msg;
}
static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout) {
size_t read = 0U;
while (read < size) {
msg_t msg = sync_rx(timeout);
if (msg < MSG_OK) {
return false;
}
osalSysLock();
while (true) {
if (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) {
break;
}
if (read >= size) {
break;
}
*destination++ = *((uint8_t*)&pio->rxf[rx_state_machine] + 3U);
read++;
}
osalSysUnlock();
}
return read == size;
}
/**
* @brief Blocking receive of size * bytes with timeout.
*
* @return true Receive success.
* @return false Receive failed, e.g. by timeout.
*/
inline bool serial_transport_receive(uint8_t* destination, const size_t size) {
return receive_impl(destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT));
}
/**
* @brief Blocking receive of size * bytes.
*
* @return true Receive success.
* @return false Receive failed.
*/
inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t size) {
return receive_impl(destination, size, TIME_INFINITE);
}
static inline void pio_tx_init(pin_t tx_pin) {
uint pio_idx = pio_get_index(pio);
uint offset = pio_add_program(pio, &uart_tx_program);
#if defined(SERIAL_USART_FULL_DUPLEX)
// clang-format off
iomode_t tx_pin_mode = PAL_RP_GPIO_OE |
PAL_RP_PAD_SLEWFAST |
PAL_RP_PAD_DRIVE4 |
(pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
// clang-format on
pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << tx_pin, 1U << tx_pin);
pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true);
#else
// clang-format off
iomode_t tx_pin_mode = PAL_RP_PAD_IE |
PAL_RP_GPIO_OE |
PAL_RP_PAD_SCHMITT |
PAL_RP_PAD_PUE |
PAL_RP_PAD_SLEWFAST |
PAL_RP_PAD_DRIVE12 |
PAL_RP_IOCTRL_OEOVER_DRVINVPERI |
(pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
// clang-format on
pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U << tx_pin, 1U << tx_pin);
pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true);
#endif
palSetLineMode(tx_pin, tx_pin_mode);
pio_sm_config config = pio_get_default_sm_config();
sm_config_set_wrap(&config, offset + UART_TX_WRAP_TARGET, offset + UART_TX_WRAP);
#if defined(SERIAL_USART_FULL_DUPLEX)
sm_config_set_sideset(&config, 2, true, false);
#else
sm_config_set_sideset(&config, 2, true, true);
#endif
// OUT shifts to right, no autopull
sm_config_set_out_shift(&config, true, false, 32);
// We are mapping both OUT and side-set to the same pin, because sometimes
// we need to assert user data onto the pin (with OUT) and sometimes
// assert constant values (start/stop bit)
sm_config_set_out_pins(&config, tx_pin, 1);
sm_config_set_sideset_pins(&config, tx_pin);
// We only need TX, so get an 8-deep FIFO!
sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED);
sm_config_set_clkdiv(&config, div);
pio_sm_init(pio, tx_state_machine, offset, &config);
pio_sm_set_enabled(pio, tx_state_machine, true);
}
static inline void pio_rx_init(pin_t rx_pin) {
uint offset = pio_add_program(pio, &uart_rx_program);
#if defined(SERIAL_USART_FULL_DUPLEX)
uint pio_idx = pio_get_index(pio);
pio_sm_set_consecutive_pindirs(pio, rx_state_machine, rx_pin, 1, false);
// clang-format off
iomode_t rx_pin_mode = PAL_RP_PAD_IE |
PAL_RP_PAD_SCHMITT |
PAL_RP_PAD_PUE |
(pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
// clang-format on
palSetLineMode(rx_pin, rx_pin_mode);
#endif
pio_sm_config config = pio_get_default_sm_config();
sm_config_set_wrap(&config, offset + UART_RX_WRAP_TARGET, offset + UART_RX_WRAP);
sm_config_set_in_pins(&config, rx_pin); // for WAIT, IN
sm_config_set_jmp_pin(&config, rx_pin); // for JMP
// Shift to right, autopush disabled
sm_config_set_in_shift(&config, true, false, 32);
// Deeper FIFO as we're not doing any TX
sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX);
// SM transmits 1 bit per 8 execution cycles.
float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED);
sm_config_set_clkdiv(&config, div);
pio_sm_init(pio, rx_state_machine, offset, &config);
pio_sm_set_enabled(pio, rx_state_machine, true);
}
static inline void pio_init(pin_t tx_pin, pin_t rx_pin) {
uint pio_idx = pio_get_index(pio);
/* Get PIOx peripheral out of reset state. */
hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1);
tx_state_machine = pio_claim_unused_sm(pio, true);
if (tx_state_machine < 0) {
dprintln("ERROR: Failed to acquire state machine for serial transmission!");
return;
}
pio_tx_init(tx_pin);
rx_state_machine = pio_claim_unused_sm(pio, true);
if (rx_state_machine < 0) {
dprintln("ERROR: Failed to acquire state machine for serial reception!");
return;
}
pio_rx_init(rx_pin);
// Enable error flag IRQ source for rx state machine
pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true);
pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true);
pio_set_irq0_source_enabled(pio, pis_interrupt0, true);
// Enable PIO specific interrupt vector
#if defined(SERIAL_PIO_USE_PIO1)
nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY);
#else
nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY);
#endif
enter_rx_state();
}
/**
* @brief PIO driver specific initialization function for the master side.
*/
void serial_transport_driver_master_init(void) {
#if defined(SERIAL_USART_FULL_DUPLEX)
pin_t tx_pin = SERIAL_USART_TX_PIN;
pin_t rx_pin = SERIAL_USART_RX_PIN;
#else
pin_t tx_pin = SERIAL_USART_TX_PIN;
pin_t rx_pin = SERIAL_USART_TX_PIN;
#endif
#if defined(SERIAL_USART_PIN_SWAP)
pio_init(rx_pin, tx_pin);
#else
pio_init(tx_pin, rx_pin);
#endif
}
/**
* @brief PIO driver specific initialization function for the slave side.
*/
void serial_transport_driver_slave_init(void) {
#if defined(SERIAL_USART_FULL_DUPLEX)
pin_t tx_pin = SERIAL_USART_TX_PIN;
pin_t rx_pin = SERIAL_USART_RX_PIN;
#else
pin_t tx_pin = SERIAL_USART_TX_PIN;
pin_t rx_pin = SERIAL_USART_TX_PIN;
#endif
pio_init(tx_pin, rx_pin);
}

View file

@ -0,0 +1,189 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
#include "ws2812.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#if !defined(MCU_RP)
# error PIO Driver is only available for Raspberry Pi 2040 MCUs!
#endif
#if defined(WS2812_PIO_USE_PIO1)
static const PIO pio = pio1;
#else
static const PIO pio = pio0;
#endif
#if !defined(RP_DMA_PRIORITY_WS2812)
# define RP_DMA_PRIORITY_WS2812 12
#endif
static int state_machine = -1;
#define WS2812_WRAP_TARGET 0
#define WS2812_WRAP 3
#define WS2812_T1 2
#define WS2812_T2 5
#define WS2812_T3 3
#if defined(WS2812_EXTERNAL_PULLUP)
# pragma message "The GPIOs of the RP2040 are NOT 5V tolerant! Make sure to NOT apply any voltage over 3.3V to the RGB data pin."
// clang-format off
static const uint16_t ws2812_program_instructions[] = {
// .wrap_target
0x7221, // 0: out x, 1 side 1 [2]
0x0123, // 1: jmp !x, 3 side 0 [1]
0x0400, // 2: jmp 0 side 0 [4]
0xb442, // 3: nop side 1 [4]
// .wrap
};
#else
static const uint16_t ws2812_program_instructions[] = {
// .wrap_target
0x6221, // 0: out x, 1 side 0 [2]
0x1123, // 1: jmp !x, 3 side 1 [1]
0x1400, // 2: jmp 0 side 1 [4]
0xa442, // 3: nop side 0 [4]
// .wrap
};
// clang-format on
#endif
static const pio_program_t ws2812_program = {
.instructions = ws2812_program_instructions,
.length = 4,
.origin = -1,
};
static uint32_t WS2812_BUFFER[RGBLED_NUM];
static const rp_dma_channel_t* WS2812_DMA_CHANNEL;
bool ws2812_init(void) {
uint pio_idx = pio_get_index(pio);
/* Get PIOx peripheral out of reset state. */
hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1);
// clang-format off
iomode_t rgb_pin_mode = PAL_RP_PAD_SLEWFAST |
PAL_RP_GPIO_OE |
(pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1);
// clang-format on
palSetLineMode(RGB_DI_PIN, rgb_pin_mode);
state_machine = pio_claim_unused_sm(pio, true);
if (state_machine < 0) {
dprintln("ERROR: Failed to acquire state machine for WS2812 output!");
return false;
}
uint offset = pio_add_program(pio, &ws2812_program);
pio_sm_set_consecutive_pindirs(pio, state_machine, RGB_DI_PIN, 1, true);
pio_sm_config config = pio_get_default_sm_config();
sm_config_set_wrap(&config, offset + WS2812_WRAP_TARGET, offset + WS2812_WRAP);
sm_config_set_sideset_pins(&config, RGB_DI_PIN);
sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX);
#if defined(WS2812_EXTERNAL_PULLUP)
/* Instruct side-set to change the pin-directions instead of outputting
* a logic level. We generate our levels the following way:
*
* 1: Set RGB data pin to high impedance input and let the pull-up drive the
* signal high.
*
* 0: Set RGB data pin to low impedance output and drive the pin low.
*/
sm_config_set_sideset(&config, 1, false, true);
#else
sm_config_set_sideset(&config, 1, false, false);
#endif
#if defined(RGBW)
sm_config_set_out_shift(&config, false, true, 32);
#else
sm_config_set_out_shift(&config, false, true, 24);
#endif
int cycles_per_bit = WS2812_T1 + WS2812_T2 + WS2812_T3;
float div = clock_get_hz(clk_sys) / (800.0f * KHZ * cycles_per_bit);
sm_config_set_clkdiv(&config, div);
pio_sm_init(pio, state_machine, offset, &config);
pio_sm_set_enabled(pio, state_machine, true);
WS2812_DMA_CHANNEL = dmaChannelAlloc(RP_DMA_CHANNEL_ID_ANY, RP_DMA_PRIORITY_WS2812, NULL, NULL);
// clang-format off
uint32_t mode = DMA_CTRL_TRIG_INCR_READ |
DMA_CTRL_TRIG_DATA_SIZE_WORD |
DMA_CTRL_TRIG_IRQ_QUIET |
DMA_CTRL_TRIG_TREQ_SEL(pio_idx == 0 ? state_machine : state_machine + 8);
// clang-format on
dmaChannelSetModeX(WS2812_DMA_CHANNEL, mode);
dmaChannelSetDestinationX(WS2812_DMA_CHANNEL, (uint32_t)&pio->txf[state_machine]);
return true;
}
/**
* @brief Convert RGBW value into WS2812 compatible 32-bit data word.
*/
__always_inline static uint32_t rgbw8888_to_u32(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
return ((uint32_t)green << 24) | ((uint32_t)red << 16) | ((uint32_t)blue << 8) | ((uint32_t)white);
#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
return ((uint32_t)red << 24) | ((uint32_t)green << 16) | ((uint32_t)blue << 8) | ((uint32_t)white);
#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
return ((uint32_t)blue << 24) | ((uint32_t)green << 16) | ((uint32_t)red << 8) | ((uint32_t)white);
#endif
}
static inline void sync_ws2812_transfer(void) {
if (unlikely(dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine))) {
fast_timer_t start = timer_read_fast();
do {
// Abort the synchronization if we have to wait longer than the total
// count of LEDs in millisecounds. This is safely much longer than it
// would take to push all the data out.
if (unlikely(timer_elapsed_fast(start) > RGBLED_NUM)) {
dprintln("ERROR: WS2812 DMA transfer has stalled, aborting!");
dmaChannelDisableX(WS2812_DMA_CHANNEL);
return;
}
} while (dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine));
// We wait for the WS2812 chain to reset after all data has been pushed
// out.
wait_us(WS2812_TRST_US);
}
}
void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
static bool is_initialized = false;
if (unlikely(!is_initialized)) {
is_initialized = ws2812_init();
}
sync_ws2812_transfer();
for (int i = 0; i < leds; i++) {
#if defined(RGBW)
WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w);
#else
WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, 0);
#endif
}
dmaChannelSetSourceX(WS2812_DMA_CHANNEL, (uint32_t)WS2812_BUFFER);
dmaChannelSetCounterX(WS2812_DMA_CHANNEL, leds);
dmaChannelEnableX(WS2812_DMA_CHANNEL);
}

View file

@ -108,6 +108,8 @@ else ifeq ($(strip $(BOOTLOADER)),kiibohd)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else ifeq ($(strip $(BOOTLOADER)),tinyuf2)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY)
else ifeq ($(strip $(BOOTLOADER)),rp2040)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY)
else ifeq ($(strip $(MCU_FAMILY)),KINETIS)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY)
else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062)

View file

@ -88,9 +88,9 @@ ifeq ("$(MCU_PORT_NAME)","")
endif
ifeq ("$(wildcard $(PLATFORM_MK))","")
PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
ifeq ("$(wildcard $(PLATFORM_MK))","")
PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
endif
endif
@ -287,6 +287,17 @@ EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \
$(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
$(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH)
#
# QMK specific MCU family support selection.
##############################################################################
ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk)","")
# Either by MCU series e.g. STM32/STM32F1xx.mk or...
include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk
else ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk)","")
# By MCU family e.g. STM32/STM32.mk
include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk
endif
#
# ChibiOS-Contrib
##############################################################################

285
platforms/chibios/vendors/RP/RP2040.mk vendored Normal file
View file

@ -0,0 +1,285 @@
#
# Raspberry Pi RP2040 specific drivers
##############################################################################
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/vendor/$(MCU_FAMILY)/$(MCU_SERIES)
ifeq ($(strip $(WS2812_DRIVER)), vendor)
OPT_DEFS += -DRP_DMA_REQUIRED=TRUE
endif
#
# Raspberry Pi Pico SDK Support
##############################################################################
ADEFS += -DCRT0_VTOR_INIT=1 \
-DCRT0_EXTRA_CORES_NUMBER=0
CFLAGS += -DPICO_NO_FPGA_CHECK \
-DNDEBUG
#
# Pico SDK source and header files needed by QMK and ChibiOS
##############################################################################
PICOSDKROOT := $(TOP_DIR)/lib/pico-sdk
PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \
$(PICOSDKROOT)/src/rp2_common/hardware_pll/pll.c \
$(PICOSDKROOT)/src/rp2_common/hardware_pio/pio.c \
$(PICOSDKROOT)/src/rp2_common/hardware_gpio/gpio.c \
$(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \
$(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \
$(PICOSDKROOT)/src/rp2_common/hardware_xosc/xosc.c \
$(PICOSDKROOT)/src/rp2_common/pico_bootrom/bootrom.c
PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \
$(PICOSDKROOT)/src/common/pico_base/include \
$(PICOSDKROOT)/src/rp2_common/pico_platform/include \
$(PICOSDKROOT)/src/rp2_common/hardware_base/include \
$(PICOSDKROOT)/src/rp2_common/hardware_clocks/include \
$(PICOSDKROOT)/src/rp2_common/hardware_claim/include \
$(PICOSDKROOT)/src/rp2_common/hardware_gpio/include \
$(PICOSDKROOT)/src/rp2_common/hardware_irq/include \
$(PICOSDKROOT)/src/rp2_common/hardware_pll/include \
$(PICOSDKROOT)/src/rp2_common/hardware_pio/include \
$(PICOSDKROOT)/src/rp2_common/hardware_sync/include \
$(PICOSDKROOT)/src/rp2_common/hardware_resets/include \
$(PICOSDKROOT)/src/rp2_common/hardware_watchdog/include \
$(PICOSDKROOT)/src/rp2_common/hardware_xosc/include \
$(PICOSDKROOT)/src/rp2040/hardware_regs/include \
$(PICOSDKROOT)/src/rp2040/hardware_structs/include \
$(PICOSDKROOT)/src/boards/include \
$(PICOSDKROOT)/src/rp2_common/pico_bootrom/include
PLATFORM_SRC += $(PICOSDKSRC)
EXTRAINCDIRS += $(PICOSDKINC)
PLATFORM_RP2040_PATH := $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)
PLATFORM_SRC += $(PLATFORM_RP2040_PATH)/stage2_bootloaders.c \
$(PLATFORM_RP2040_PATH)/pico_sdk_shims.c
EXTRAINCDIRS += $(PLATFORM_RP2040_PATH)
#
# RP2040 optimized compiler intrinsics
##############################################################################
# Enables optimized Compiler intrinsics which are located in the RP2040
# bootrom. This needs startup code and linker script support from ChibiOS,
# which is WIP. Therefore disabled by default for now.
RP2040_INTRINSICS_ENABLED ?= no
ifeq ($(strip $(RP2040_INTRINSICS_ENABLED)), yes)
PICOSDKINTRINSICSSRC = $(PICOSDKROOT)/src/rp2_common/pico_float/float_aeabi.S \
$(PICOSDKROOT)/src/rp2_common/pico_float/float_math.c \
$(PICOSDKROOT)/src/rp2_common/pico_float/float_init_rom.c \
$(PICOSDKROOT)/src/rp2_common/pico_float/float_v1_rom_shim.S \
$(PICOSDKROOT)/src/rp2_common/pico_double/double_aeabi.S \
$(PICOSDKROOT)/src/rp2_common/pico_double/double_math.c \
$(PICOSDKROOT)/src/rp2_common/pico_double/double_init_rom.c \
$(PICOSDKROOT)/src/rp2_common/pico_double/double_v1_rom_shim.S \
$(PICOSDKROOT)/src/rp2_common/pico_divider/divider.S \
$(PICOSDKROOT)/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \
$(PICOSDKROOT)/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \
$(PICOSDKROOT)/src/rp2_common/pico_malloc/pico_malloc.c \
$(PICOSDKROOT)/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
PICOSDKINTRINSICSINC = $(PICOSDKROOT)/src/common/pico_base/include \
$(PICOSDKROOT)/src/rp2_common/pico_platfrom/include \
$(PICOSDKROOT)/src/rp2_common/pico_bootrom/include \
$(PICOSDKROOT)/src/rp2_common/hardware_divider/include \
$(PICOSDKROOT)/src/rp2_common/pico_float/include \
$(PICOSDKROOT)/src/rp2_common/pico_double/include \
$(PICOSDKROOT)/src/rp2_common/pico_malloc/include
OPT_DEFS += -DPICO_FLOAT_SUPPORT_ROM_V1=0 -DPICO_DOUBLE_SUPPORT_ROM_V1=0
CFLAGS += -Wl,--defsym=__StackLimit=__heap_end__
CFLAGS += -Wl,--defsym=__unhandled_user_irq=_unhandled_exception
CFLAGS += -Wl,--build-id=none
# single precision floating point intrinsics
OPT_DEFS += -DPICO_FLOAT_IN_RAM=1
OPT_DEFS += -DPICO_FLOAT_PROPAGATE_NANS=0
CFLAGS += -Wl,--wrap=__aeabi_fdiv
CFLAGS += -Wl,--wrap=__aeabi_fmul
CFLAGS += -Wl,--wrap=__aeabi_frsub
CFLAGS += -Wl,--wrap=__aeabi_fsub
CFLAGS += -Wl,--wrap=__aeabi_cfcmpeq
CFLAGS += -Wl,--wrap=__aeabi_cfrcmple
CFLAGS += -Wl,--wrap=__aeabi_cfcmple
CFLAGS += -Wl,--wrap=__aeabi_fcmpeq
CFLAGS += -Wl,--wrap=__aeabi_fcmplt
CFLAGS += -Wl,--wrap=__aeabi_fcmple
CFLAGS += -Wl,--wrap=__aeabi_fcmpge
CFLAGS += -Wl,--wrap=__aeabi_fcmpgt
CFLAGS += -Wl,--wrap=__aeabi_fcmpun
CFLAGS += -Wl,--wrap=__aeabi_i2f
CFLAGS += -Wl,--wrap=__aeabi_l2f
CFLAGS += -Wl,--wrap=__aeabi_ui2f
CFLAGS += -Wl,--wrap=__aeabi_ul2f
CFLAGS += -Wl,--wrap=__aeabi_i2f
CFLAGS += -Wl,--wrap=__aeabi_f2iz
CFLAGS += -Wl,--wrap=__aeabi_f2lz
CFLAGS += -Wl,--wrap=__aeabi_f2uiz
CFLAGS += -Wl,--wrap=__aeabi_f2ulz
CFLAGS += -Wl,--wrap=__aeabi_f2d
CFLAGS += -Wl,--wrap=sqrtf
CFLAGS += -Wl,--wrap=cosf
CFLAGS += -Wl,--wrap=sinf
CFLAGS += -Wl,--wrap=tanf
CFLAGS += -Wl,--wrap=atan2f
CFLAGS += -Wl,--wrap=expf
CFLAGS += -Wl,--wrap=logf
CFLAGS += -Wl,--wrap=ldexpf
CFLAGS += -Wl,--wrap=copysignf
CFLAGS += -Wl,--wrap=truncf
CFLAGS += -Wl,--wrap=floorf
CFLAGS += -Wl,--wrap=ceilf
CFLAGS += -Wl,--wrap=roundf
CFLAGS += -Wl,--wrap=sincosf
CFLAGS += -Wl,--wrap=asinf
CFLAGS += -Wl,--wrap=acosf
CFLAGS += -Wl,--wrap=atanf
CFLAGS += -Wl,--wrap=sinhf
CFLAGS += -Wl,--wrap=coshf
CFLAGS += -Wl,--wrap=tanhf
CFLAGS += -Wl,--wrap=asinhf
CFLAGS += -Wl,--wrap=acoshf
CFLAGS += -Wl,--wrap=atanhf
CFLAGS += -Wl,--wrap=exp2f
CFLAGS += -Wl,--wrap=log2f
CFLAGS += -Wl,--wrap=exp10f
CFLAGS += -Wl,--wrap=log10f
CFLAGS += -Wl,--wrap=powf
CFLAGS += -Wl,--wrap=powintf
CFLAGS += -Wl,--wrap=hypotf
CFLAGS += -Wl,--wrap=cbrtf
CFLAGS += -Wl,--wrap=fmodf
CFLAGS += -Wl,--wrap=dremf
CFLAGS += -Wl,--wrap=remainderf
CFLAGS += -Wl,--wrap=remquof
CFLAGS += -Wl,--wrap=expm1f
CFLAGS += -Wl,--wrap=log1pf
CFLAGS += -Wl,--wrap=fmaf
# double precision floating point intrinsics
OPT_DEFS += -DPICO_DOUBLE_IN_RAM=1
OPT_DEFS += -DPICO_DOUBLE_PROPAGATE_NANS=0
CFLAGS += -Wl,--wrap=__aeabi_dadd
CFLAGS += -Wl,--wrap=__aeabi_ddiv
CFLAGS += -Wl,--wrap=__aeabi_dmul
CFLAGS += -Wl,--wrap=__aeabi_drsub
CFLAGS += -Wl,--wrap=__aeabi_dsub
CFLAGS += -Wl,--wrap=__aeabi_cdcmpeq
CFLAGS += -Wl,--wrap=__aeabi_cdrcmple
CFLAGS += -Wl,--wrap=__aeabi_cdcmple
CFLAGS += -Wl,--wrap=__aeabi_dcmpeq
CFLAGS += -Wl,--wrap=__aeabi_dcmplt
CFLAGS += -Wl,--wrap=__aeabi_dcmple
CFLAGS += -Wl,--wrap=__aeabi_dcmpge
CFLAGS += -Wl,--wrap=__aeabi_dcmpgt
CFLAGS += -Wl,--wrap=__aeabi_dcmpun
CFLAGS += -Wl,--wrap=__aeabi_i2d
CFLAGS += -Wl,--wrap=__aeabi_l2d
CFLAGS += -Wl,--wrap=__aeabi_ui2d
CFLAGS += -Wl,--wrap=__aeabi_ul2d
CFLAGS += -Wl,--wrap=__aeabi_d2iz
CFLAGS += -Wl,--wrap=__aeabi_d2lz
CFLAGS += -Wl,--wrap=__aeabi_d2uiz
CFLAGS += -Wl,--wrap=__aeabi_d2ulz
CFLAGS += -Wl,--wrap=__aeabi_d2f
CFLAGS += -Wl,--wrap=sqrt
CFLAGS += -Wl,--wrap=cos
CFLAGS += -Wl,--wrap=sin
CFLAGS += -Wl,--wrap=tan
CFLAGS += -Wl,--wrap=atan2
CFLAGS += -Wl,--wrap=exp
CFLAGS += -Wl,--wrap=log
CFLAGS += -Wl,--wrap=ldexp
CFLAGS += -Wl,--wrap=copysign
CFLAGS += -Wl,--wrap=trunc
CFLAGS += -Wl,--wrap=floor
CFLAGS += -Wl,--wrap=ceil
CFLAGS += -Wl,--wrap=round
CFLAGS += -Wl,--wrap=sincos
CFLAGS += -Wl,--wrap=asin
CFLAGS += -Wl,--wrap=acos
CFLAGS += -Wl,--wrap=atan
CFLAGS += -Wl,--wrap=sinh
CFLAGS += -Wl,--wrap=cosh
CFLAGS += -Wl,--wrap=tanh
CFLAGS += -Wl,--wrap=asinh
CFLAGS += -Wl,--wrap=acosh
CFLAGS += -Wl,--wrap=atanh
CFLAGS += -Wl,--wrap=exp2
CFLAGS += -Wl,--wrap=log2
CFLAGS += -Wl,--wrap=exp10
CFLAGS += -Wl,--wrap=log10
CFLAGS += -Wl,--wrap=pow
CFLAGS += -Wl,--wrap=powint
CFLAGS += -Wl,--wrap=hypot
CFLAGS += -Wl,--wrap=cbrt
CFLAGS += -Wl,--wrap=fmod
CFLAGS += -Wl,--wrap=drem
CFLAGS += -Wl,--wrap=remainder
CFLAGS += -Wl,--wrap=remquo
CFLAGS += -Wl,--wrap=expm1
CFLAGS += -Wl,--wrap=log1p
CFLAGS += -Wl,--wrap=fma
# bit operation intrinsics
OPT_DEFS += -DPICO_BITS_IN_RAM=1
CFLAGS += -Wl,--wrap=__clzsi2
CFLAGS += -Wl,--wrap=__clzsi2
CFLAGS += -Wl,--wrap=__clzdi2
CFLAGS += -Wl,--wrap=__ctzsi2
CFLAGS += -Wl,--wrap=__ctzdi2
CFLAGS += -Wl,--wrap=__popcountsi2
CFLAGS += -Wl,--wrap=__popcountdi2
CFLAGS += -Wl,--wrap=__clz
CFLAGS += -Wl,--wrap=__clzl
CFLAGS += -Wl,--wrap=__clzsi2
CFLAGS += -Wl,--wrap=__clzll
# integer division intrinsics
OPT_DEFS += -DPICO_DIVIDER_IN_RAM=1
OPT_DEFS += -DPICO_DIVIDER_DISABLE_INTERRUPTS=1
CFLAGS += -Wl,--wrap=__aeabi_idiv
CFLAGS += -Wl,--wrap=__aeabi_idivmod
CFLAGS += -Wl,--wrap=__aeabi_ldivmod
CFLAGS += -Wl,--wrap=__aeabi_uidiv
CFLAGS += -Wl,--wrap=__aeabi_uidivmod
CFLAGS += -Wl,--wrap=__aeabi_uldivmod
# 64bit integer intrinsics
OPT_DEFS += -DPICO_INT64_OPS_IN_RAM=1
CFLAGS += -Wl,--wrap=__aeabi_lmul
# malloc and friends functions
OPT_DEFS += -DPICO_USE_MALLOC_MUTEX=0
OPT_DEFS += -DPICO_DEBUG_MALLOC=0
OPT_DEFS ?= -DPICO_MALLOC_PANIC=0
CFLAGS += -Wl,--wrap=malloc
CFLAGS += -Wl,--wrap=calloc
CFLAGS += -Wl,--wrap=free
# memory operation intrinsics
OPT_DEFS += -DPICO_MEM_IN_RAM=1
CFLAGS += -Wl,--wrap=memcpy
CFLAGS += -Wl,--wrap=memset
CFLAGS += -Wl,--wrap=__aeabi_memcpy
CFLAGS += -Wl,--wrap=__aeabi_memset
CFLAGS += -Wl,--wrap=__aeabi_memcpy4
CFLAGS += -Wl,--wrap=__aeabi_memset4
CFLAGS += -Wl,--wrap=__aeabi_memcpy8
CFLAGS += -Wl,--wrap=__aeabi_memset8
PLATFORM_SRC += $(PICOSDKINTRINSICSSRC)
EXTRAINCDIRS += $(PICOSDKINTRINSICSINC)
endif

View file

@ -0,0 +1,37 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
/* RP2040 GPIO Numbering */
#define GP0 0U
#define GP1 1U
#define GP2 2U
#define GP3 3U
#define GP4 4U
#define GP5 5U
#define GP6 6U
#define GP7 7U
#define GP8 8U
#define GP9 9U
#define GP10 10U
#define GP11 11U
#define GP12 12U
#define GP13 13U
#define GP14 14U
#define GP15 15U
#define GP16 16U
#define GP17 17U
#define GP18 18U
#define GP19 19U
#define GP20 20U
#define GP21 21U
#define GP22 22U
#define GP23 23U
#define GP24 24U
#define GP25 25U
#define GP26 26U
#define GP27 27U
#define GP28 28U
#define GP29 29U
#define GP30 30U

View file

@ -0,0 +1,9 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdbool.h>
#include <ch.h>
void panic(const char *fmt, ...) {
chSysHalt(fmt);
}

View file

@ -0,0 +1,174 @@
// ----------------------------------------------------------------------------
// Pre-compiled second stage boot code for RP2040.
//
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
// ----------------------------------------------------------------------------
#include <stdint.h>
#define BOOTLOADER_SECTION __attribute__ ((used, section (".boot2")))
#if defined(RP2040_FLASH_AT25SF128A)
uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = {
0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b,
0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21,
0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66,
0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e,
0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1,
0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60,
0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21,
0x19, 0x66, 0x20, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21,
0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60,
0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49,
0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5,
0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42,
0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7,
0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00,
0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0x20,
0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xdd, 0xc0, 0xb5
};
#elif defined(RP2040_FLASH_GD25Q64CS)
uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = {
0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b,
0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21,
0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66,
0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e,
0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1,
0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60,
0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xe7, 0x21,
0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21,
0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60,
0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49,
0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5,
0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42,
0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7,
0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00,
0x21, 0x12, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x10, 0x00, 0xa0,
0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe2, 0xd9, 0xa2, 0xb5
};
#elif defined(RP2040_FLASH_W25X10CL)
uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = {
0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48,
0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21,
0x19, 0x66, 0x08, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd0, 0x00, 0x21,
0x99, 0x60, 0x0c, 0x49, 0x0a, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60,
0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x08, 0x48, 0x09, 0x49,
0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x3f, 0x00, 0x1d, 0x12, 0x00, 0x00,
0xf4, 0x00, 0x00, 0x18, 0x1e, 0x10, 0x00, 0x20, 0x00, 0x01, 0x00, 0x10,
0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7c, 0x81, 0x53, 0x9a
};
#elif defined(RP2040_FLASH_IS25LP080)
uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = {
0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0,
0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66,
0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20,
0x1a, 0x66, 0x00, 0xf0, 0x2b, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x1f, 0x48,
0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21,
0x99, 0x60, 0x1d, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x1c, 0x49,
0x1c, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66,
0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60,
0x17, 0x49, 0x16, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc,
0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x14, 0x48, 0x14, 0x49, 0x08, 0x60,
0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a,
0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1,
0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff,
0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18,
0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x33, 0x43, 0xb2
};
#elif defined(RP2040_FLASH_GENERIC_03H)
uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = {
0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61,
0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21,
0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0,
0x00, 0x47, 0x07, 0x48, 0x07, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3,
0x08, 0x88, 0x08, 0x47, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x1f, 0x00,
0x18, 0x02, 0x00, 0x03, 0xf4, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x10,
0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2c, 0xec, 0x21, 0x0d
};
#else
uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = {
0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21,
0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b,
0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22,
0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20,
0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21,
0x19, 0x66, 0x00, 0xf0, 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66,
0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e,
0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21,
0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60,
0x00, 0x21, 0x59, 0x60, 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21,
0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0,
0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60,
0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47,
0x12, 0x48, 0x13, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88,
0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0,
0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66,
0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd,
0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00,
0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18,
0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x0b, 0x8f, 0xd5
};
#endif