diff options
Diffstat (limited to 'platforms')
75 files changed, 3296 insertions, 731 deletions
| diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk index b49bf764d7..9462f517ae 100644 --- a/platforms/arm_atsam/platform.mk +++ b/platforms/arm_atsam/platform.mk @@ -24,13 +24,14 @@ COMPILEFLAGS += -fno-strict-aliasing  COMPILEFLAGS += -mfloat-abi=hard  COMPILEFLAGS += -mfpu=fpv4-sp-d16  COMPILEFLAGS += -mthumb +COMPILEFLAGS += -fno-builtin-printf  #ALLOW_WARNINGS = yes  CFLAGS += $(COMPILEFLAGS)  CXXFLAGS += $(COMPILEFLAGS) -CXXFLAGS += -fno-exceptions -std=c++11 +CXXFLAGS += -fno-exceptions $(CXXSTANDARD)  LDFLAGS +=-Wl,--gc-sections  LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map" diff --git a/platforms/avr/drivers/i2c_master.c b/platforms/avr/drivers/i2c_master.c index c1a7b5f72d..524494c99d 100644 --- a/platforms/avr/drivers/i2c_master.c +++ b/platforms/avr/drivers/i2c_master.c @@ -64,7 +64,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {      uint16_t timeout_timer = timer_read();      while (!(TWCR & (1 << TWINT))) { -        if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { +        if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) {              return I2C_STATUS_TIMEOUT;          }      } @@ -81,7 +81,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {      timeout_timer = timer_read();      while (!(TWCR & (1 << TWINT))) { -        if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { +        if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) {              return I2C_STATUS_TIMEOUT;          }      } @@ -102,7 +102,7 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {      i2c_status_t status;      do {          status = i2c_start_impl(address, time_slice); -    } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) < timeout))); +    } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) <= timeout)));      return status;  } @@ -114,7 +114,7 @@ i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {      uint16_t timeout_timer = timer_read();      while (!(TWCR & (1 << TWINT))) { -        if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { +        if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) {              return I2C_STATUS_TIMEOUT;          }      } @@ -132,7 +132,7 @@ int16_t i2c_read_ack(uint16_t timeout) {      uint16_t timeout_timer = timer_read();      while (!(TWCR & (1 << TWINT))) { -        if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { +        if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) {              return I2C_STATUS_TIMEOUT;          }      } @@ -147,7 +147,7 @@ int16_t i2c_read_nack(uint16_t timeout) {      uint16_t timeout_timer = timer_read();      while (!(TWCR & (1 << TWINT))) { -        if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { +        if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) {              return I2C_STATUS_TIMEOUT;          }      } diff --git a/platforms/avr/drivers/i2c_master.h b/platforms/avr/drivers/i2c_master.h index 2d95846db5..04ef126c80 100644 --- a/platforms/avr/drivers/i2c_master.h +++ b/platforms/avr/drivers/i2c_master.h @@ -19,6 +19,8 @@  #pragma once +#include <stdint.h> +  #define I2C_READ 0x01  #define I2C_WRITE 0x00 diff --git a/platforms/avr/drivers/ps2/ps2_usart.c b/platforms/avr/drivers/ps2/ps2_usart.c index 39ec930d4a..581badac64 100644 --- a/platforms/avr/drivers/ps2/ps2_usart.c +++ b/platforms/avr/drivers/ps2/ps2_usart.c @@ -72,8 +72,8 @@ uint8_t ps2_error = PS2_ERR_NONE;  static inline uint8_t pbuf_dequeue(void);  static inline void    pbuf_enqueue(uint8_t data); -static inline bool    pbuf_has_data(void);  static inline void    pbuf_clear(void); +bool                  pbuf_has_data(void);  void ps2_host_init(void) {      idle(); // without this many USART errors occur when cable is disconnected @@ -212,7 +212,7 @@ static inline uint8_t pbuf_dequeue(void) {      return val;  } -static inline bool pbuf_has_data(void) { +bool pbuf_has_data(void) {      uint8_t sreg = SREG;      cli();      bool has_data = (pbuf_head != pbuf_tail); diff --git a/platforms/avr/drivers/ssd1306.c b/platforms/avr/drivers/ssd1306.c deleted file mode 100644 index 7afbc09f00..0000000000 --- a/platforms/avr/drivers/ssd1306.c +++ /dev/null @@ -1,329 +0,0 @@ -#ifdef SSD1306OLED - -#    include "ssd1306.h" -#    include "i2c.h" -#    include <string.h> -#    include "print.h" -#    include "glcdfont.c" -#    ifdef PROTOCOL_LUFA -#        include "lufa.h" -#    endif -#    include "sendchar.h" -#    include "timer.h" - -struct CharacterMatrix display; - -// Set this to 1 to help diagnose early startup problems -// when testing power-on with ble.  Turn it off otherwise, -// as the latency of printing most of the debug info messes -// with the matrix scan, causing keys to drop. -#    define DEBUG_TO_SCREEN 0 - -// static uint16_t last_battery_update; -// static uint32_t vbat; -//#define BatteryUpdateInterval 10000 /* milliseconds */ -#    define ScreenOffInterval 300000 /* milliseconds */ -#    if DEBUG_TO_SCREEN -static uint8_t displaying; -#    endif -static uint16_t last_flush; - -// Write command sequence. -// Returns true on success. -static inline bool _send_cmd1(uint8_t cmd) { -    bool res = false; - -    if (i2c_start_write(SSD1306_ADDRESS)) { -        xprintf("failed to start write to %d\n", SSD1306_ADDRESS); -        goto done; -    } - -    if (i2c_master_write(0x0 /* command byte follows */)) { -        print("failed to write control byte\n"); - -        goto done; -    } - -    if (i2c_master_write(cmd)) { -        xprintf("failed to write command %d\n", cmd); -        goto done; -    } -    res = true; -done: -    i2c_master_stop(); -    return res; -} - -// Write 2-byte command sequence. -// Returns true on success -static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) { -    if (!_send_cmd1(cmd)) { -        return false; -    } -    return _send_cmd1(opr); -} - -// Write 3-byte command sequence. -// Returns true on success -static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) { -    if (!_send_cmd1(cmd)) { -        return false; -    } -    if (!_send_cmd1(opr1)) { -        return false; -    } -    return _send_cmd1(opr2); -} - -#    define send_cmd1(c)      \ -        if (!_send_cmd1(c)) { \ -            goto done;        \ -        } -#    define send_cmd2(c, o)      \ -        if (!_send_cmd2(c, o)) { \ -            goto done;           \ -        } -#    define send_cmd3(c, o1, o2)      \ -        if (!_send_cmd3(c, o1, o2)) { \ -            goto done;                \ -        } - -static void clear_display(void) { -    matrix_clear(&display); - -    // Clear all of the display bits (there can be random noise -    // in the RAM on startup) -    send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1); -    send_cmd3(ColumnAddr, 0, DisplayWidth - 1); - -    if (i2c_start_write(SSD1306_ADDRESS)) { -        goto done; -    } -    if (i2c_master_write(0x40)) { -        // Data mode -        goto done; -    } -    for (uint8_t row = 0; row < MatrixRows; ++row) { -        for (uint8_t col = 0; col < DisplayWidth; ++col) { -            i2c_master_write(0); -        } -    } - -    display.dirty = false; - -done: -    i2c_master_stop(); -} - -#    if DEBUG_TO_SCREEN -#        undef sendchar -static int8_t capture_sendchar(uint8_t c) { -    sendchar(c); -    iota_gfx_write_char(c); - -    if (!displaying) { -        iota_gfx_flush(); -    } -    return 0; -} -#    endif - -bool iota_gfx_init(void) { -    bool success = false; - -    send_cmd1(DisplayOff); -    send_cmd2(SetDisplayClockDiv, 0x80); -    send_cmd2(SetMultiPlex, DisplayHeight - 1); - -    send_cmd2(SetDisplayOffset, 0); - -    send_cmd1(SetStartLine | 0x0); -    send_cmd2(SetChargePump, 0x14 /* Enable */); -    send_cmd2(SetMemoryMode, 0 /* horizontal addressing */); - -#    ifdef OLED_ROTATE180 -    // the following Flip the display orientation 180 degrees -    send_cmd1(SegRemap); -    send_cmd1(ComScanInc); -#    endif -#    ifndef OLED_ROTATE180 -    // Flips the display orientation 0 degrees -    send_cmd1(SegRemap | 0x1); -    send_cmd1(ComScanDec); -#    endif - -    send_cmd2(SetComPins, 0x2); -    send_cmd2(SetContrast, 0x8f); -    send_cmd2(SetPreCharge, 0xf1); -    send_cmd2(SetVComDetect, 0x40); -    send_cmd1(DisplayAllOnResume); -    send_cmd1(NormalDisplay); -    send_cmd1(DeActivateScroll); -    send_cmd1(DisplayOn); - -    send_cmd2(SetContrast, 0); // Dim - -    clear_display(); - -    success = true; - -    iota_gfx_flush(); - -#    if DEBUG_TO_SCREEN -    print_set_sendchar(capture_sendchar); -#    endif - -done: -    return success; -} - -bool iota_gfx_off(void) { -    bool success = false; - -    send_cmd1(DisplayOff); -    success = true; - -done: -    return success; -} - -bool iota_gfx_on(void) { -    bool success = false; - -    send_cmd1(DisplayOn); -    success = true; - -done: -    return success; -} - -void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) { -    *matrix->cursor = c; -    ++matrix->cursor; - -    if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) { -        // We went off the end; scroll the display upwards by one line -        memmove(&matrix->display[0], &matrix->display[1], MatrixCols * (MatrixRows - 1)); -        matrix->cursor = &matrix->display[MatrixRows - 1][0]; -        memset(matrix->cursor, ' ', MatrixCols); -    } -} - -void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) { -    matrix->dirty = true; - -    if (c == '\n') { -        // Clear to end of line from the cursor and then move to the -        // start of the next line -        uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols; - -        while (cursor_col++ < MatrixCols) { -            matrix_write_char_inner(matrix, ' '); -        } -        return; -    } - -    matrix_write_char_inner(matrix, c); -} - -void iota_gfx_write_char(uint8_t c) { -    matrix_write_char(&display, c); -} - -void matrix_write(struct CharacterMatrix *matrix, const char *data) { -    const char *end = data + strlen(data); -    while (data < end) { -        matrix_write_char(matrix, *data); -        ++data; -    } -} - -void iota_gfx_write(const char *data) { -    matrix_write(&display, data); -} - -void matrix_write_P(struct CharacterMatrix *matrix, const char *data) { -    while (true) { -        uint8_t c = pgm_read_byte(data); -        if (c == 0) { -            return; -        } -        matrix_write_char(matrix, c); -        ++data; -    } -} - -void iota_gfx_write_P(const char *data) { -    matrix_write_P(&display, data); -} - -void matrix_clear(struct CharacterMatrix *matrix) { -    memset(matrix->display, ' ', sizeof(matrix->display)); -    matrix->cursor = &matrix->display[0][0]; -    matrix->dirty  = true; -} - -void iota_gfx_clear_screen(void) { -    matrix_clear(&display); -} - -void matrix_render(struct CharacterMatrix *matrix) { -    last_flush = timer_read(); -    iota_gfx_on(); -#    if DEBUG_TO_SCREEN -    ++displaying; -#    endif - -    // Move to the home position -    send_cmd3(PageAddr, 0, MatrixRows - 1); -    send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1); - -    if (i2c_start_write(SSD1306_ADDRESS)) { -        goto done; -    } -    if (i2c_master_write(0x40)) { -        // Data mode -        goto done; -    } - -    for (uint8_t row = 0; row < MatrixRows; ++row) { -        for (uint8_t col = 0; col < MatrixCols; ++col) { -            const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1)); - -            for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) { -                uint8_t colBits = pgm_read_byte(glyph + glyphCol); -                i2c_master_write(colBits); -            } - -            // 1 column of space between chars (it's not included in the glyph) -            i2c_master_write(0); -        } -    } - -    matrix->dirty = false; - -done: -    i2c_master_stop(); -#    if DEBUG_TO_SCREEN -    --displaying; -#    endif -} - -void iota_gfx_flush(void) { -    matrix_render(&display); -} - -__attribute__((weak)) void iota_gfx_task_user(void) {} - -void iota_gfx_task(void) { -    iota_gfx_task_user(); - -    if (display.dirty) { -        iota_gfx_flush(); -    } - -    if (timer_elapsed(last_flush) > ScreenOffInterval) { -        iota_gfx_off(); -    } -} -#endif diff --git a/platforms/avr/drivers/ssd1306.h b/platforms/avr/drivers/ssd1306.h deleted file mode 100644 index 6eecdcfaa4..0000000000 --- a/platforms/avr/drivers/ssd1306.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include <stdbool.h> -#include <stdio.h> -#include "config.h" - -enum ssd1306_cmds { -    DisplayOff = 0xAE, -    DisplayOn  = 0xAF, - -    SetContrast        = 0x81, -    DisplayAllOnResume = 0xA4, - -    DisplayAllOn       = 0xA5, -    NormalDisplay      = 0xA6, -    InvertDisplay      = 0xA7, -    SetDisplayOffset   = 0xD3, -    SetComPins         = 0xda, -    SetVComDetect      = 0xdb, -    SetDisplayClockDiv = 0xD5, -    SetPreCharge       = 0xd9, -    SetMultiPlex       = 0xa8, -    SetLowColumn       = 0x00, -    SetHighColumn      = 0x10, -    SetStartLine       = 0x40, - -    SetMemoryMode = 0x20, -    ColumnAddr    = 0x21, -    PageAddr      = 0x22, - -    ComScanInc    = 0xc0, -    ComScanDec    = 0xc8, -    SegRemap      = 0xa0, -    SetChargePump = 0x8d, -    ExternalVcc   = 0x01, -    SwitchCapVcc  = 0x02, - -    ActivateScroll                   = 0x2f, -    DeActivateScroll                 = 0x2e, -    SetVerticalScrollArea            = 0xa3, -    RightHorizontalScroll            = 0x26, -    LeftHorizontalScroll             = 0x27, -    VerticalAndRightHorizontalScroll = 0x29, -    VerticalAndLeftHorizontalScroll  = 0x2a, -}; - -// Controls the SSD1306 128x32 OLED display via i2c - -#ifndef SSD1306_ADDRESS -#    define SSD1306_ADDRESS 0x3C -#endif - -#define DisplayHeight 32 -#define DisplayWidth 128 - -#define FontHeight 8 -#define FontWidth 6 - -#define MatrixRows (DisplayHeight / FontHeight) -#define MatrixCols (DisplayWidth / FontWidth) - -struct CharacterMatrix { -    uint8_t  display[MatrixRows][MatrixCols]; -    uint8_t *cursor; -    bool     dirty; -}; - -extern struct CharacterMatrix display; - -bool iota_gfx_init(void); -void iota_gfx_task(void); -bool iota_gfx_off(void); -bool iota_gfx_on(void); -void iota_gfx_flush(void); -void iota_gfx_write_char(uint8_t c); -void iota_gfx_write(const char *data); -void iota_gfx_write_P(const char *data); -void iota_gfx_clear_screen(void); - -void iota_gfx_task_user(void); - -void matrix_clear(struct CharacterMatrix *matrix); -void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c); -void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c); -void matrix_write(struct CharacterMatrix *matrix, const char *data); -void matrix_write_P(struct CharacterMatrix *matrix, const char *data); -void matrix_render(struct CharacterMatrix *matrix); diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk index 978199b385..39a11b28e4 100644 --- a/platforms/avr/platform.mk +++ b/platforms/avr/platform.mk @@ -24,6 +24,7 @@ COMPILEFLAGS += -fdata-sections  COMPILEFLAGS += -fpack-struct  COMPILEFLAGS += -fshort-enums  COMPILEFLAGS += -mcall-prologues +COMPILEFLAGS += -fno-builtin-printf  # Linker relaxation is only possible if  # link time optimizations are not enabled. @@ -38,7 +39,7 @@ CFLAGS += -fno-inline-small-functions  CFLAGS += -fno-strict-aliasing  CXXFLAGS += $(COMPILEFLAGS) -CXXFLAGS += -fno-exceptions -std=c++11 +CXXFLAGS += -fno-exceptions $(CXXSTANDARD)  LDFLAGS += -Wl,--gc-sections diff --git a/platforms/chibios/_pin_defs.h b/platforms/chibios/_pin_defs.h index 0d96e2fc3b..414c9e3d11 100644 --- a/platforms/chibios/_pin_defs.h +++ b/platforms/chibios/_pin_defs.h @@ -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) diff --git a/platforms/chibios/_wait.h b/platforms/chibios/_wait.h index 2f36c64a2e..c0ccbc5569 100644 --- a/platforms/chibios/_wait.h +++ b/platforms/chibios/_wait.h @@ -17,6 +17,7 @@  #include <ch.h>  #include <hal.h> +#include "chibios_config.h"  /* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */  #define wait_ms(ms)                     \ @@ -30,6 +31,11 @@  #ifdef WAIT_US_TIMER  void wait_us(uint16_t duration); +#elif PORT_SUPPORTS_RT == TRUE +#    define wait_us(us)                                            \ +        do {                                                       \ +            chSysPolledDelayX(US2RTC(REALTIME_COUNTER_CLOCK, us)); \ +        } while (0)  #else  #    define wait_us(us)                     \          do {                                \ diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk @@ -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) diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h new file mode 100644 index 0000000000..b4363595d0 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h @@ -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" diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h @@ -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> diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h new file mode 100644 index 0000000000..7fe9b654e1 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h @@ -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  diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h new file mode 100644 index 0000000000..8348e5312f --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h @@ -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 */ diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk @@ -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) diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h new file mode 100644 index 0000000000..052050c944 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h @@ -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" diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h @@ -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> diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h new file mode 100644 index 0000000000..9d8dc61aac --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h @@ -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 */ diff --git a/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h b/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h index 9fdc825669..437a8e4df2 100644 --- a/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h +++ b/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h @@ -18,3 +18,5 @@  #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP  #    define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE  #endif + +#define USB_ENDPOINTS_ARE_REORDERABLE diff --git a/platforms/chibios/boards/QMK_PM2040/board/board.mk b/platforms/chibios/boards/QMK_PM2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/board/board.mk @@ -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) diff --git a/platforms/chibios/boards/QMK_PM2040/configs/board.h b/platforms/chibios/boards/QMK_PM2040/configs/board.h new file mode 100644 index 0000000000..433e1c527f --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/board.h @@ -0,0 +1,12 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef BOARD_RP_PICO_RP2040 +#define BOARD_PM2040 + +#undef BOARD_NAME +#define BOARD_NAME "Pro Micro RP2040" diff --git a/platforms/chibios/boards/QMK_PM2040/configs/chconf.h b/platforms/chibios/boards/QMK_PM2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/chconf.h @@ -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> diff --git a/platforms/chibios/boards/QMK_PM2040/configs/config.h b/platforms/chibios/boards/QMK_PM2040/configs/config.h new file mode 100644 index 0000000000..8c773f8b19 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/config.h @@ -0,0 +1,21 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifndef I2C_DRIVER +#    define I2C_DRIVER I2CD2 +#endif +#ifndef I2C1_SDA_PIN +#    define I2C1_SDA_PIN D1 +#endif +#ifndef I2C1_SCL_PIN +#    define I2C1_SCL_PIN D0 +#endif + +#ifndef RP2040_BOOTLOADER_DOUBLE_TAP_RESET +#    define RP2040_BOOTLOADER_DOUBLE_TAP_RESET +#endif +#ifndef RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT +#    define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U +#endif diff --git a/platforms/chibios/boards/QMK_PM2040/configs/halconf.h b/platforms/chibios/boards/QMK_PM2040/configs/halconf.h new file mode 100644 index 0000000000..d7a58f0ea6 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/halconf.h @@ -0,0 +1,9 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define HAL_USE_I2C TRUE +#define HAL_USE_SPI TRUE + +#include_next <halconf.h> diff --git a/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h b/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h new file mode 100644 index 0000000000..a737b36c1c --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h @@ -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                     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 */ diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c b/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c index cba977da77..e82e1d37ce 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c @@ -28,7 +28,9 @@ const PALConfig pal_default_config =    {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH},    {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH},    {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH}, +#    if STM32_HAS_GPIOE    {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH}, +#    endif  };  #endif diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld new file mode 100644 index 0000000000..18aaff2a23 --- /dev/null +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld @@ -0,0 +1,23 @@ +/* +    ChibiOS - Copyright (C) 2006..2016 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. +*/ + +/* + * STM32F103x6 memory setup for use with the STM32Duino bootloader. + */ +f103_flash_size = 32k; +f103_ram_size = 10k; + +INCLUDE stm32duino_bootloader_common.ld diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld index a4bd566b59..465af12cab 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld @@ -18,5 +18,6 @@   * STM32F103x8 memory setup for use with the STM32Duino bootloader.   */  f103_flash_size = 64k; +f103_ram_size = 20k;  INCLUDE stm32duino_bootloader_common.ld diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld index dc47400dc5..3a47a33156 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld @@ -18,5 +18,6 @@   * STM32F103xB memory setup for use with the STM32Duino bootloader.   */  f103_flash_size = 128k; +f103_ram_size = 20k;  INCLUDE stm32duino_bootloader_common.ld diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld index 76cd3153be..1466ae7ed2 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld @@ -27,7 +27,7 @@ MEMORY      flash5  : org = 0x00000000, len = 0      flash6  : org = 0x00000000, len = 0      flash7  : org = 0x00000000, len = 0 -    ram0    : org = 0x20000000, len = 20k +    ram0    : org = 0x20000000, len = f103_ram_size      ram1    : org = 0x00000000, len = 0      ram2    : org = 0x00000000, len = 0      ram3    : org = 0x00000000, len = 0 diff --git a/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld b/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld new file mode 100644 index 0000000000..66ed4ce086 --- /dev/null +++ b/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld @@ -0,0 +1,117 @@ +/* +    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. +*/ + +/* + * RP2040 memory setup. + */ +MEMORY +{ +    flash0 (rx) : org = 0x00000000, len = 16k   /* ROM                  */ +    flash1 (rx) : org = 0x10000000, len = DEFINED(FLASH_LEN) ? FLASH_LEN : 2048k /* XIP */ +    flash2 (rx) : org = 0x00000000, len = 0 +    flash3 (rx) : org = 0x00000000, len = 0 +    flash4 (rx) : org = 0x00000000, len = 0 +    flash5 (rx) : org = 0x00000000, len = 0 +    flash6 (rx) : org = 0x00000000, len = 0 +    flash7 (rx) : org = 0x00000000, len = 0 +    ram0   (wx) : org = 0x20000000, len = 256k  /* SRAM0 striped        */ +    ram1   (wx) : org = 0x00000000, len = 256k  /* SRAM0 non striped    */ +    ram2   (wx) : org = 0x00000000, len = 0 +    ram3   (wx) : org = 0x00000000, len = 0 +    ram4   (wx) : org = 0x20040000, len = 4k    /* SRAM4                */ +    ram5   (wx) : org = 0x20041000, len = 4k    /* SRAM5                */ +    ram6   (wx) : org = 0x00000000, len = 0 +    ram7   (wx) : org = 0x20041f00, len = 256   /* SRAM5 boot           */ +} + +/* For each data/text section two region are defined, a virtual region +   and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing +   of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by +   the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* RAM region to be used for Main stack. This stack accommodates the processing +   of all exceptions and interrupts.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); + +/* RAM region to be used for the process stack. This is the stack used by +   the main() function.*/ +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +SECTIONS +{ +   .flash_begin : { +      __flash_binary_start = .; +   } > flash1 + +   .boot2 : { +      __boot2_start__ = .; +      KEEP (*(.boot2)) +      __boot2_end__ = .; +   } > flash1 +} + +/* Generic rules inclusion.*/ +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE RP2040_rules_code_with_boot2.ld +INCLUDE RP2040_rules_data_with_timecrit.ld +INCLUDE rules_memory.ld + +SECTIONS +{ +   .flash_end : { +      __flash_binary_end = .; +   } > flash1 +} diff --git a/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld b/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld new file mode 100644 index 0000000000..a9a47be983 --- /dev/null +++ b/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld @@ -0,0 +1,46 @@ +/* +    ChibiOS - Copyright (C) 2006..2018 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. +*/ + +SECTIONS +{ +    .data : ALIGN(4) +    { +        PROVIDE(_textdata = LOADADDR(.data)); +        PROVIDE(_data = .); +        __textdata_base__ = LOADADDR(.data); +        __data_base__ = .; +        *(vtable) +        *(.time_critical*) +        . = ALIGN(4); +        *(.data) +        *(.data.*) +        *(.ramtext) +        . = ALIGN(4); +        PROVIDE(_edata = .); +        __data_end__ = .; +    } > DATA_RAM AT > DATA_RAM_LMA + +    .bss (NOLOAD) : ALIGN(4) +    { +        __bss_base__ = .; +        *(.bss) +        *(.bss.*) +        *(COMMON) +        . = ALIGN(4); +        __bss_end__ = .; +        PROVIDE(end = .); +    } > BSS_RAM +} diff --git a/platforms/chibios/bootloaders/rp2040.c b/platforms/chibios/bootloaders/rp2040.c new file mode 100644 index 0000000000..bedc00f32e --- /dev/null +++ b/platforms/chibios/bootloaders/rp2040.c @@ -0,0 +1,56 @@ +// 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. +        wait_us(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT * 1000U); +        magic_location = 0; +        return; +    } + +    magic_location = 0; +    reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U); +} + +#endif diff --git a/platforms/chibios/bootloaders/stm32_dfu.c b/platforms/chibios/bootloaders/stm32_dfu.c index ff866bd2bc..7b4ab86033 100644 --- a/platforms/chibios/bootloaders/stm32_dfu.c +++ b/platforms/chibios/bootloaders/stm32_dfu.c @@ -38,7 +38,7 @@ extern uint32_t __ram0_end__;  #    endif  #    ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY -#        define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000 +#        define STM32_BOOTLOADER_DUAL_BANK_DELAY 100  #    endif  __attribute__((weak)) void bootloader_jump(void) { @@ -55,7 +55,7 @@ __attribute__((weak)) void bootloader_jump(void) {  #    endif      // Wait for a while for the capacitor to charge -    wait_ms(100); +    wait_ms(STM32_BOOTLOADER_DUAL_BANK_DELAY);      // Issue a system reset to get the ROM bootloader to execute, with BOOT0 high      NVIC_SystemReset(); diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index a7098f2713..8dcc23727f 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -19,6 +19,30 @@  #    define SPLIT_USB_DETECT // Force this on when dedicated pin is not used  #endif +#if defined(MCU_RP) +#    define CPU_CLOCK RP_CORE_CLK +// ChibiOS uses the RP2040 timer peripheral as its real time counter, this timer +// is monotonic and running at 1MHz. +#    define REALTIME_COUNTER_CLOCK 1000000 + +#    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 @@ -60,6 +84,8 @@  #        define PAL_OUTPUT_TYPE_PUSHPULL PAL_WB32_OTYPE_PUSHPULL  #        define PAL_OUTPUT_SPEED_HIGHEST PAL_WB32_OSPEED_HIGH  #        define PAL_PUPDR_FLOATING PAL_WB32_PUPDR_FLOATING + +#        define SPI_SCK_FLAGS PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST | PAL_WB32_CURRENT_LEVEL3  #    endif  #endif @@ -74,13 +100,18 @@  #if defined(MCU_KINETIS)  #    define CPU_CLOCK KINETIS_SYSCLK_FREQUENCY -#    if defined(K20x) || defined(KL2x) +#    if defined(K20x) || defined(K60x) || defined(KL2x)  #        define USE_I2CV1  #        define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed  #        define USE_GPIOV1  #    endif  #endif +#if defined(MCU_MIMXRT1062) +#    include "clock_config.h" +#    define CPU_CLOCK BOARD_BOOTCLOCKRUN_CORE_CLOCK +#endif +  #if defined(HT32)  #    define CPU_CLOCK HT32_CK_SYS_FREQUENCY  #    define PAL_MODE_ALTERNATE PAL_HT32_MODE_AF @@ -88,3 +119,20 @@  #    define PAL_OUTPUT_TYPE_PUSHPULL PAL_HT32_MODE_DIR  #    define PAL_OUTPUT_SPEED_HIGHEST 0  #endif + +#if !defined(REALTIME_COUNTER_CLOCK) +#    define REALTIME_COUNTER_CLOCK CPU_CLOCK +#endif + +// SPI Fallbacks +#ifndef SPI_SCK_FLAGS +#    define SPI_SCK_FLAGS PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST +#endif + +#ifndef SPI_MOSI_FLAGS +#    define SPI_MOSI_FLAGS PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST +#endif + +#ifndef SPI_MISO_FLAGS +#    define SPI_MISO_FLAGS PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST +#endif diff --git a/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h b/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h new file mode 100644 index 0000000000..92e8fbfa1a --- /dev/null +++ b/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h @@ -0,0 +1,39 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +//      GND +//      GND +#define D1 2U +#define D0 3U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +//      RAW +//      GND +//      RESET +//      VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 22U +#define B3 20U +#define B2 23U +#define B6 21U + +// LEDs (Mapped to R and G channel of the Bit-C PRO's RGB led) +#define D5 16U +#define B0 17U + +// Bit-C LED (mapped to B channel of the Bit-C PRO's RGB led) +#define F0 18U diff --git a/platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk b/platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk new file mode 100644 index 0000000000..c0eaee8593 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk @@ -0,0 +1,12 @@ +# nullbits Bit-C PRO MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software + +# Tell QMK to use the correct 2nd stage bootloader +OPT_DEFS += -DRP2040_FLASH_W25X10CL diff --git a/platforms/chibios/converters/promicro_to_blok/_pin_defs.h b/platforms/chibios/converters/promicro_to_blok/_pin_defs.h new file mode 100644 index 0000000000..957b84e1a6 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_blok/_pin_defs.h @@ -0,0 +1,36 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +//      GND +//      GND +#define D1 16U +#define D0 17U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +//      RAW +//      GND +//      RESET +//      VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 22U +#define B3 20U +#define B2 23U +#define B6 21U + +// LEDs (Mapped to unused pins to avoid collisions) +#define D5 12U +#define B0 13U diff --git a/platforms/chibios/converters/promicro_to_blok/converter.mk b/platforms/chibios/converters/promicro_to_blok/converter.mk new file mode 100644 index 0000000000..5106e411f4 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_blok/converter.mk @@ -0,0 +1,9 @@ +# Boardsource Blok MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software diff --git a/platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h b/platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h new file mode 100644 index 0000000000..0a3110890b --- /dev/null +++ b/platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h @@ -0,0 +1,36 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +//      GND +//      GND +#define D1 2U +#define D0 3U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +//      RAW +//      GND +//      RESET +//      VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 18U +#define B3 20U +#define B2 19U +#define B6 10U + +// LEDs (Mapped to QT connector to avoid collisions with button/neopixel) +#define D5 12U +#define B0 13U diff --git a/platforms/chibios/converters/promicro_to_kb2040/converter.mk b/platforms/chibios/converters/promicro_to_kb2040/converter.mk new file mode 100644 index 0000000000..6ffee357b3 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_kb2040/converter.mk @@ -0,0 +1,9 @@ +# Adafruit KB2040 MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software diff --git a/platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h b/platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h new file mode 100644 index 0000000000..0a1f4112a3 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h @@ -0,0 +1,36 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +//      GND +//      GND +#define D1 2U +#define D0 3U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +//      RAW +//      GND +//      RESET +//      VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 22U +#define B3 20U +#define B2 23U +#define B6 21U + +// LEDs (Mapped to QT connector to avoid collisions with button/neopixel) +#define D5 17U +#define B0 16U diff --git a/platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk b/platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk new file mode 100644 index 0000000000..03863eeb02 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk @@ -0,0 +1,9 @@ +# Sparkfun Pro Micro RP2040 MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software diff --git a/platforms/chibios/eeprom_stm32.c b/platforms/chibios/drivers/eeprom/eeprom_stm32.c index a15bfe09ed..1a354dc213 100644 --- a/platforms/chibios/eeprom_stm32.c +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32.c @@ -250,7 +250,7 @@ uint16_t EEPROM_Init(void) {                  }                  wvalue = ~*log_addr;                  if (!wvalue) { -                    eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr); +                    eeprom_printf("Incomplete write at log_addr: 0x%04lx;\n", (uint32_t)log_addr);                      /* Possibly incomplete write.  Ignore and continue */                      continue;                  } @@ -261,7 +261,7 @@ uint16_t EEPROM_Init(void) {              } else {                  /* Reserved for future use */                  if (address & FEE_VALUE_RESERVED) { -                    eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr); +                    eeprom_printf("Reserved encoded value at log_addr: 0x%04lx;\n", (uint32_t)log_addr);                      continue;                  }                  /* Optimization for 0 or 1 values. */ @@ -293,14 +293,14 @@ static void eeprom_clear(void) {      FLASH_Unlock();      for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) { -        eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE))); +        eeprom_printf("FLASH_ErasePage(0x%04lx)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)));          FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE));      }      FLASH_Lock();      empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; -    eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot); +    eeprom_printf("eeprom_clear empty_slot: 0x%08lx\n", (uint32_t)empty_slot);  }  /* Erase emulated eeprom */ @@ -328,7 +328,7 @@ static uint8_t eeprom_compact(void) {      for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 2) {          value = *src;          if (value) { -            eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value); +            eeprom_printf("FLASH_ProgramHalfWord(0x%04lx, 0x%04x)\n", (uint32_t)dest, ~value);              FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value);              if (status != FLASH_COMPLETE) final_status = status;          } @@ -355,7 +355,7 @@ static uint8_t eeprom_write_direct_entry(uint16_t Address) {          FLASH_Unlock(); -        eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value); +        eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value);          FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value);          FLASH_Lock(); @@ -397,12 +397,12 @@ static uint8_t eeprom_write_log_word_entry(uint16_t Address) {      FLASH_Unlock();      /* address */ -    eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address); +    eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x)\n", (uint32_t)empty_slot, Address);      final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address);      /* value */      if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) { -        eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value); +        eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x)\n", (uint32_t)empty_slot, ~value);          FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value);          if (status != FLASH_COMPLETE) final_status = status;      } @@ -428,7 +428,7 @@ static uint8_t eeprom_write_log_byte_entry(uint16_t Address) {      uint16_t value = (Address << 8) | DataBuf[Address];      /* write to flash */ -    eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value); +    eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x)\n", (uint32_t)empty_slot, value);      FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value);      FLASH_Lock(); diff --git a/platforms/chibios/eeprom_stm32.h b/platforms/chibios/drivers/eeprom/eeprom_stm32.h index 8fcfb556b8..8fcfb556b8 100644 --- a/platforms/chibios/eeprom_stm32.h +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32.h diff --git a/platforms/chibios/eeprom_stm32_defs.h b/platforms/chibios/drivers/eeprom/eeprom_stm32_defs.h index 57d0440330..57d0440330 100644 --- a/platforms/chibios/eeprom_stm32_defs.h +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32_defs.h diff --git a/platforms/chibios/eeprom_teensy.c b/platforms/chibios/drivers/eeprom/eeprom_teensy.c index c8777febde..c8777febde 100644 --- a/platforms/chibios/eeprom_teensy.c +++ b/platforms/chibios/drivers/eeprom/eeprom_teensy.c diff --git a/platforms/chibios/eeprom_teensy.h b/platforms/chibios/drivers/eeprom/eeprom_teensy.h index 9a14a1fa79..9a14a1fa79 100755 --- a/platforms/chibios/eeprom_teensy.h +++ b/platforms/chibios/drivers/eeprom/eeprom_teensy.h diff --git a/platforms/chibios/flash_stm32.c b/platforms/chibios/drivers/flash/flash_stm32.c index 72c41b8b78..72c41b8b78 100644 --- a/platforms/chibios/flash_stm32.c +++ b/platforms/chibios/drivers/flash/flash_stm32.c diff --git a/platforms/chibios/flash_stm32.h b/platforms/chibios/drivers/flash/flash_stm32.h index 6c66642ec5..6c66642ec5 100644 --- a/platforms/chibios/flash_stm32.h +++ b/platforms/chibios/drivers/flash/flash_stm32.h diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 21e064b1dc..4c7a5daa17 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -107,16 +107,25 @@ static const I2CConfig i2cconfig = {  #endif  }; -static i2c_status_t chibios_to_qmk(const msg_t* status) { -    switch (*status) { -        case I2C_NO_ERROR: -            return I2C_STATUS_SUCCESS; -        case I2C_TIMEOUT: -            return I2C_STATUS_TIMEOUT; -        // I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT -        default: -            return I2C_STATUS_ERROR; +/** + * @brief Handles any I2C error condition by stopping the I2C peripheral and + * aborting any ongoing transactions. Furthermore ChibiOS status codes are + * converted into QMK codes. + * + * @param status ChibiOS specific I2C status code + * @return i2c_status_t QMK specific I2C status code + */ +static i2c_status_t i2c_epilogue(const msg_t status) { +    if (status == MSG_OK) { +        return I2C_STATUS_SUCCESS;      } + +    // From ChibiOS HAL: "After a timeout the driver must be stopped and +    // restarted because the bus is in an uncertain state." We also issue that +    // hard stop in case of any error. +    i2c_stop(); + +    return status == MSG_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR;  }  __attribute__((weak)) void i2c_init(void) { @@ -149,14 +158,14 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length,      i2c_address = address;      i2cStart(&I2C_DRIVER, &i2cconfig);      msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout)); -    return chibios_to_qmk(&status); +    return i2c_epilogue(status);  }  i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {      i2c_address = address;      i2cStart(&I2C_DRIVER, &i2cconfig);      msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, TIME_MS2I(timeout)); -    return chibios_to_qmk(&status); +    return i2c_epilogue(status);  }  i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { @@ -170,7 +179,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,      complete_packet[0] = regaddr;      msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout)); -    return chibios_to_qmk(&status); +    return i2c_epilogue(status);  }  i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { @@ -185,14 +194,14 @@ i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* da      complete_packet[1] = regaddr & 0xFF;      msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout)); -    return chibios_to_qmk(&status); +    return i2c_epilogue(status);  }  i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {      i2c_address = devaddr;      i2cStart(&I2C_DRIVER, &i2cconfig);      msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), ®addr, 1, data, length, TIME_MS2I(timeout)); -    return chibios_to_qmk(&status); +    return i2c_epilogue(status);  }  i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { @@ -200,7 +209,7 @@ i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uin      i2cStart(&I2C_DRIVER, &i2cconfig);      uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF};      msg_t   status             = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout)); -    return chibios_to_qmk(&status); +    return i2c_epilogue(status);  }  void i2c_stop(void) { diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index 0cff057d1d..0dd8e71ae8 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c @@ -20,7 +20,8 @@  #    error "chSysPolledDelayX method not supported on this platform"  #else  #    undef wait_us -#    define wait_us(x) chSysPolledDelayX(US2RTC(CPU_CLOCK, x)) +// Force usage of polled waiting - in case WAIT_US_TIMER is activated +#    define wait_us(us) chSysPolledDelayX(US2RTC(REALTIME_COUNTER_CLOCK, us))  #endif  #ifndef SELECT_SOFT_SERIAL_SPEED @@ -87,10 +88,7 @@ static THD_FUNCTION(Thread1, arg) {      chRegSetThreadName("blinker");      while (true) {          palWaitLineTimeout(SOFT_SERIAL_PIN, TIME_INFINITE); - -        split_shared_memory_lock();          interrupt_handler(NULL); -        split_shared_memory_unlock();      }  } @@ -155,6 +153,7 @@ static void __attribute__((noinline)) serial_write_byte(uint8_t data) {  // interrupt handle to be used by the slave device  void interrupt_handler(void *arg) { +    split_shared_memory_lock_autounlock();      chSysLockFromISR();      sync_send(); @@ -212,6 +211,8 @@ void interrupt_handler(void *arg) {  static inline bool initiate_transaction(uint8_t sstd_index) {      if (sstd_index > NUM_TOTAL_TRANSACTIONS) return false; +    split_shared_memory_lock_autounlock(); +      split_transaction_desc_t *trans = &split_transaction_table[sstd_index];      // TODO: remove extra delay between transactions @@ -233,7 +234,7 @@ static inline bool initiate_transaction(uint8_t sstd_index) {      // check if the slave is present      if (serial_read_pin()) {          // slave failed to pull the line low, assume not present -        dprintf("serial::NO_RESPONSE\n"); +        serial_dprintf("serial::NO_RESPONSE\n");          chSysUnlock();          return false;      } @@ -269,7 +270,7 @@ static inline bool initiate_transaction(uint8_t sstd_index) {      serial_delay();      if ((checksum_computed) != (checksum_received)) { -        dprintf("serial::FAIL[%u,%u,%u]\n", checksum_computed, checksum_received, sstd_index); +        serial_dprintf("serial::FAIL[%u,%u,%u]\n", checksum_computed, checksum_received, sstd_index);          serial_output();          serial_high(); @@ -292,8 +293,5 @@ static inline bool initiate_transaction(uint8_t sstd_index) {  //  // this code is very time dependent, so we need to disable interrupts  bool soft_serial_transaction(int sstd_index) { -    split_shared_memory_lock(); -    bool result = initiate_transaction((uint8_t)sstd_index); -    split_shared_memory_unlock(); -    return result; +    return initiate_transaction((uint8_t)sstd_index);  } diff --git a/platforms/chibios/drivers/serial_protocol.c b/platforms/chibios/drivers/serial_protocol.c new file mode 100644 index 0000000000..c95aed9885 --- /dev/null +++ b/platforms/chibios/drivers/serial_protocol.c @@ -0,0 +1,164 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <ch.h> + +#include "quantum.h" +#include "serial.h" +#include "serial_protocol.h" +#include "printf.h" +#include "synchronization_util.h" + +static inline bool initiate_transaction(uint8_t transaction_id); +static inline bool react_to_transaction(void); + +/** + * @brief This thread runs on the slave and responds to transactions initiated + * by the master. + */ +static THD_WORKING_AREA(waSlaveThread, 1024); +static THD_FUNCTION(SlaveThread, arg) { +    (void)arg; +    chRegSetThreadName("split_protocol_tx_rx"); + +    while (true) { +        if (unlikely(!react_to_transaction())) { +            /* Clear the receive queue, to start with a clean slate. +             * Parts of failed transactions or spurious bytes could still be in it. */ +            serial_transport_driver_clear(); +        } +    } +} + +/** + * @brief Slave specific initializations. + */ +void soft_serial_target_init(void) { +    serial_transport_driver_slave_init(); + +    /* Start transport thread. */ +    chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL); +} + +/** + * @brief Master specific initializations. + */ +void soft_serial_initiator_init(void) { +    serial_transport_driver_master_init(); +} + +/** + * @brief React to transactions started by the master. + */ +static inline bool react_to_transaction(void) { +    uint8_t transaction_id = 0; +    /* Wait until there is a transaction for us. */ +    if (unlikely(!serial_transport_receive_blocking(&transaction_id, sizeof(transaction_id)))) { +        return false; +    } + +    /* Sanity check that we are actually responding to a valid transaction. */ +    if (unlikely(transaction_id >= NUM_TOTAL_TRANSACTIONS)) { +        return false; +    } + +    split_shared_memory_lock_autounlock(); + +    split_transaction_desc_t* transaction = &split_transaction_table[transaction_id]; + +    /* Send back the handshake which is XORed as a simple checksum, +     to signal that the slave is ready to receive possible transaction buffers  */ +    transaction_id ^= NUM_TOTAL_TRANSACTIONS; +    if (unlikely(!serial_transport_send(&transaction_id, sizeof(transaction_id)))) { +        return false; +    } + +    /* Receive transaction buffer from the master. If this transaction requires it.*/ +    if (transaction->initiator2target_buffer_size) { +        if (unlikely(!serial_transport_receive(split_trans_initiator2target_buffer(transaction), transaction->initiator2target_buffer_size))) { +            return false; +        } +    } + +    /* Allow any slave processing to occur. */ +    if (transaction->slave_callback) { +        transaction->slave_callback(transaction->initiator2target_buffer_size, split_trans_initiator2target_buffer(transaction), transaction->initiator2target_buffer_size, split_trans_target2initiator_buffer(transaction)); +    } + +    /* Send transaction buffer to the master. If this transaction requires it. */ +    if (transaction->target2initiator_buffer_size) { +        if (unlikely(!serial_transport_send(split_trans_target2initiator_buffer(transaction), transaction->target2initiator_buffer_size))) { +            return false; +        } +    } + +    return true; +} + +/** + * @brief Start transaction from the master half to the slave half. + * + * @param index Transaction Table index of the transaction to start. + * @return bool Indicates success of transaction. + */ +bool soft_serial_transaction(int index) { +    bool result = initiate_transaction((uint8_t)index); + +    if (unlikely(!result)) { +        /* Clear the receive queue, to start with a clean slate. +         * Parts of failed transactions or spurious bytes could still be in it. */ +        serial_transport_driver_clear(); +    } + +    return result; +} + +/** + * @brief Initiate transaction to slave half. + */ +static inline bool initiate_transaction(uint8_t transaction_id) { +    /* Sanity check that we are actually starting a valid transaction. */ +    if (unlikely(transaction_id >= NUM_TOTAL_TRANSACTIONS)) { +        serial_dprintf("SPLIT: illegal transaction id\n"); +        return false; +    } + +    split_shared_memory_lock_autounlock(); + +    split_transaction_desc_t* transaction = &split_transaction_table[transaction_id]; + +    /* Send transaction table index to the slave, which doubles as basic handshake token. */ +    if (unlikely(!serial_transport_send(&transaction_id, sizeof(transaction_id)))) { +        serial_dprintf("SPLIT: sending handshake failed\n"); +        return false; +    } + +    uint8_t transaction_id_shake = 0xFF; + +    /* Which we always read back first so that we can error out correctly. +     *   - due to the half duplex limitations on return codes, we always have to read *something*. +     *   - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready. +     */ +    if (unlikely(!serial_transport_receive(&transaction_id_shake, sizeof(transaction_id_shake)) || (transaction_id_shake != (transaction_id ^ NUM_TOTAL_TRANSACTIONS)))) { +        serial_dprintf("SPLIT: receiving handshake failed\n"); +        return false; +    } + +    /* Send transaction buffer to the slave. If this transaction requires it. */ +    if (transaction->initiator2target_buffer_size) { +        if (unlikely(!serial_transport_send(split_trans_initiator2target_buffer(transaction), transaction->initiator2target_buffer_size))) { +            serial_dprintf("SPLIT: sending buffer failed\n"); +            return false; +        } +    } + +    /* Receive transaction buffer from the slave. If this transaction requires it. */ +    if (transaction->target2initiator_buffer_size) { +        if (unlikely(!serial_transport_receive(split_trans_target2initiator_buffer(transaction), transaction->target2initiator_buffer_size))) { +            serial_dprintf("SPLIT: receiving buffer failed\n"); +            return false; +        } +    } + +    return true; +} diff --git a/platforms/chibios/drivers/serial_protocol.h b/platforms/chibios/drivers/serial_protocol.h new file mode 100644 index 0000000000..4275a7f8d8 --- /dev/null +++ b/platforms/chibios/drivers/serial_protocol.h @@ -0,0 +1,49 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#pragma once + +/** + * @brief Clears any intermediate sending or receiving state of the driver to a known good + * state. This happens after errors in the middle of transactions, to start with + * a clean slate. + */ +void serial_transport_driver_clear(void); + +/** + * @brief Driver specific initialization on the slave half. + */ +void serial_transport_driver_slave_init(void); + +/** + * @brief Driver specific specific initialization on the master half. + */ +void serial_transport_driver_master_init(void); + +/** + * @brief  Blocking receive of size * bytes. + * + * @return true Receive success. + * @return false Receive failed, e.g. by bit errors. + */ +bool __attribute__((nonnull, hot)) serial_transport_receive(uint8_t* destination, const size_t size); + +/** + * @brief Blocking receive of size * bytes with an implicitly defined timeout. + * + * @return true Receive success. + * @return false Receive failed, e.g. by timeout or bit errors. + */ +bool __attribute__((nonnull, hot)) serial_transport_receive_blocking(uint8_t* destination, const size_t size); + +/** + * @brief Blocking send of buffer with timeout. + * + * @return true Send success. + * @return false Send failed, e.g. by timeout or bit errors. + */ +bool __attribute__((nonnull, hot)) serial_transport_send(const uint8_t* source, const size_t size); diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index e9fa4af7a3..6581a5b6e9 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c @@ -1,49 +1,55 @@ -/* Copyright 2021 QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ +// Copyright 2021 QMK +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later  #include "serial_usart.h" +#include "serial_protocol.h"  #include "synchronization_util.h"  #if defined(SERIAL_USART_CONFIG) -static SerialConfig serial_config = SERIAL_USART_CONFIG; -#else -static SerialConfig serial_config = { -    .speed = (SERIAL_USART_SPEED), /* speed - mandatory */ +static QMKSerialConfig serial_config = SERIAL_USART_CONFIG; +#elif defined(MCU_STM32) /* STM32 MCUs */ +static QMKSerialConfig serial_config = { +#    if HAL_USE_SERIAL +    .speed = (SERIAL_USART_SPEED), +#    else +    .baud = (SERIAL_USART_SPEED), +#    endif      .cr1   = (SERIAL_USART_CR1),      .cr2   = (SERIAL_USART_CR2),  #    if !defined(SERIAL_USART_FULL_DUPLEX)      .cr3   = ((SERIAL_USART_CR3) | USART_CR3_HDSEL) /* activate half-duplex mode */  #    else -    .cr3 = (SERIAL_USART_CR3) +    .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 SerialDriver* serial_driver = &SERIAL_USART_DRIVER; +static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER; -static inline bool react_to_transactions(void); -static inline bool __attribute__((nonnull)) receive(uint8_t* destination, const size_t size); -static inline bool __attribute__((nonnull)) send(const uint8_t* source, const size_t size); -static inline bool initiate_transaction(uint8_t sstd_index); -static inline void usart_clear(void); +#if HAL_USE_SERIAL  /** - * @brief Clear the receive input queue. + * @brief SERIAL Driver startup routine.   */ -static inline void usart_clear(void) { +static inline void usart_driver_start(void) { +    sdStart(serial_driver, &serial_config); +} + +inline void serial_transport_driver_clear(void) {      osalSysLock();      bool volatile queue_not_empty = !iqIsEmptyI(&serial_driver->iqueue);      osalSysUnlock(); @@ -64,36 +70,96 @@ static inline void usart_clear(void) {      }  } +#elif HAL_USE_SIO + +void clear_rx_evt_cb(SIODriver* siop) { +    osalSysLockFromISR(); +    /* If errors occured during transactions this callback is invoked. We just +     * clear the error sources and move on. We rely on the fact that we check +     * for the success of the transaction by comparing the received/send bytes +     * with the actual received/send bytes in the send/receive functions. */ +    sioGetAndClearEventsI(serial_driver); +    osalSysUnlockFromISR(); +} + +static const SIOOperation serial_usart_operation = {.rx_cb = NULL, .rx_idle_cb = NULL, .tx_cb = NULL, .tx_end_cb = NULL, .rx_evt_cb = &clear_rx_evt_cb}; +  /** - * @brief Blocking send of buffer with timeout. - * - * @return true Send success. - * @return false Send failed. + * @brief SIO Driver startup routine.   */ -static inline bool send(const uint8_t* source, const size_t size) { -    bool success = (size_t)sdWriteTimeout(serial_driver, source, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; +static inline void usart_driver_start(void) { +    sioStart(serial_driver, &serial_config); +    sioStartOperation(serial_driver, &serial_usart_operation); +} + +inline void serial_transport_driver_clear(void) { +    osalSysLock(); +    while (!sioIsRXEmptyX(serial_driver)) { +        (void)sioGetX(serial_driver); +    } +    osalSysUnlock(); +} + +#else + +#    error Either the SERIAL or SIO driver has to be activated to use the usart driver for split keyboards. + +#endif + +inline bool serial_transport_send(const uint8_t* source, const size_t size) { +    bool success = (size_t)chnWriteTimeout(serial_driver, source, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size;  #if !defined(SERIAL_USART_FULL_DUPLEX) -    if (success) { -        /* Half duplex fills the input queue with the data we wrote - just throw it away. -           Under the right circumstances (e.g. bad cables paired with high baud rates) -           less bytes can be present in the input queue, therefore a timeout is needed. */ -        uint8_t dump[size]; -        return receive(dump, size); +    /* Half duplex fills the input queue with the data we wrote - just throw it away. */ +    if (likely(success)) { +        size_t bytes_left = size; +#    if HAL_USE_SERIAL +        /* The SERIAL driver uses large soft FIFOs that are filled from an IRQ +         * context, so there is a delay between receiving the data and it +         * becoming actually available, therefore we have to apply a timeout +         * mechanism. Under the right circumstances (e.g. bad cables paired with +         * high baud rates) less bytes can be present in the input queue as +         * well. */ +        uint8_t dump[64]; + +        while (unlikely(bytes_left >= 64)) { +            if (unlikely(!serial_transport_receive(dump, 64))) { +                return false; +            } +            bytes_left -= 64; +        } + +        return serial_transport_receive(dump, bytes_left); +#    else +        /* The SIO driver directly accesses the hardware FIFOs of the USART +         * peripheral. As these are limited in depth, the RX FIFO might have been +         * overflowed by a large that we just send. Therefore we attempt to read +         * back all the data we send or until the FIFO runs empty in case it +         * overflowed and data was truncated. */ +        if (unlikely(sioSynchronizeTXEnd(serial_driver, TIME_MS2I(SERIAL_USART_TIMEOUT)) < MSG_OK)) { +            return false; +        } + +        osalSysLock(); +        while (bytes_left > 0 && !sioIsRXEmptyX(serial_driver)) { +            (void)sioGetX(serial_driver); +            bytes_left--; +        } +        osalSysUnlock(); +#    endif      }  #endif      return success;  } -/** - * @brief  Blocking receive of size * bytes with timeout. - * - * @return true Receive success. - * @return false Receive failed. - */ -static inline bool receive(uint8_t* destination, const size_t size) { -    bool success = (size_t)sdReadTimeout(serial_driver, destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; +inline bool serial_transport_receive(uint8_t* destination, const size_t size) { +    bool success = (size_t)chnReadTimeout(serial_driver, destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; +    return success; +} + +inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t size) { +    bool success = (size_t)chnRead(serial_driver, destination, size) == size;      return success;  } @@ -103,7 +169,7 @@ static inline bool receive(uint8_t* destination, const size_t size) {   * @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 @@ -113,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 @@ -124,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); @@ -136,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 @@ -146,7 +217,7 @@ __attribute__((weak)) void usart_init(void) {  /**   * @brief Overridable master specific initializations.   */ -__attribute__((weak, nonnull)) void usart_master_init(SerialDriver** driver) { +__attribute__((weak, nonnull)) void usart_master_init(QMKSerialDriver** driver) {      (void)driver;      usart_init();  } @@ -154,161 +225,22 @@ __attribute__((weak, nonnull)) void usart_master_init(SerialDriver** driver) {  /**   * @brief Overridable slave specific initializations.   */ -__attribute__((weak, nonnull)) void usart_slave_init(SerialDriver** driver) { +__attribute__((weak, nonnull)) void usart_slave_init(QMKSerialDriver** driver) {      (void)driver;      usart_init();  } -/** - * @brief This thread runs on the slave and responds to transactions initiated - * by the master. - */ -static THD_WORKING_AREA(waSlaveThread, 1024); -static THD_FUNCTION(SlaveThread, arg) { -    (void)arg; -    chRegSetThreadName("usart_tx_rx"); - -    while (true) { -        if (!react_to_transactions()) { -            /* Clear the receive queue, to start with a clean slate. -             * Parts of failed transactions or spurious bytes could still be in it. */ -            usart_clear(); -        } -        split_shared_memory_unlock(); -    } -} - -/** - * @brief Slave specific initializations. - */ -void soft_serial_target_init(void) { +void serial_transport_driver_slave_init(void) {      usart_slave_init(&serial_driver); - -    sdStart(serial_driver, &serial_config); - -    /* Start transport thread. */ -    chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL); +    usart_driver_start();  } -/** - * @brief React to transactions started by the master. - */ -static inline bool react_to_transactions(void) { -    /* Wait until there is a transaction for us. */ -    uint8_t sstd_index = (uint8_t)sdGet(serial_driver); - -    /* Sanity check that we are actually responding to a valid transaction. */ -    if (sstd_index >= NUM_TOTAL_TRANSACTIONS) { -        return false; -    } - -    split_shared_memory_lock(); -    split_transaction_desc_t* trans = &split_transaction_table[sstd_index]; - -    /* Send back the handshake which is XORed as a simple checksum, -     to signal that the slave is ready to receive possible transaction buffers  */ -    sstd_index ^= HANDSHAKE_MAGIC; -    if (!send(&sstd_index, sizeof(sstd_index))) { -        return false; -    } - -    /* Receive transaction buffer from the master. If this transaction requires it.*/ -    if (trans->initiator2target_buffer_size) { -        if (!receive(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) { -            return false; -        } -    } - -    /* Allow any slave processing to occur. */ -    if (trans->slave_callback) { -        trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, split_trans_target2initiator_buffer(trans)); -    } - -    /* Send transaction buffer to the master. If this transaction requires it. */ -    if (trans->target2initiator_buffer_size) { -        if (!send(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) { -            return false; -        } -    } - -    return true; -} - -/** - * @brief Master specific initializations. - */ -void soft_serial_initiator_init(void) { +void serial_transport_driver_master_init(void) {      usart_master_init(&serial_driver);  #if defined(MCU_STM32) && defined(SERIAL_USART_PIN_SWAP)      serial_config.cr2 |= USART_CR2_SWAP; // master has swapped TX/RX pins  #endif -    sdStart(serial_driver, &serial_config); -} - -/** - * @brief Start transaction from the master half to the slave half. - * - * @param index Transaction Table index of the transaction to start. - * @return bool Indicates success of transaction. - */ -bool soft_serial_transaction(int index) { -    /* Clear the receive queue, to start with a clean slate. -     * Parts of failed transactions or spurious bytes could still be in it. */ -    usart_clear(); - -    split_shared_memory_lock(); -    bool result = initiate_transaction((uint8_t)index); -    split_shared_memory_unlock(); - -    return result; -} - -/** - * @brief Initiate transaction to slave half. - */ -static inline bool initiate_transaction(uint8_t sstd_index) { -    /* Sanity check that we are actually starting a valid transaction. */ -    if (sstd_index >= NUM_TOTAL_TRANSACTIONS) { -        dprintln("USART: Illegal transaction Id."); -        return false; -    } - -    split_transaction_desc_t* trans = &split_transaction_table[sstd_index]; - -    /* Send transaction table index to the slave, which doubles as basic handshake token. */ -    if (!send(&sstd_index, sizeof(sstd_index))) { -        dprintln("USART: Send Handshake failed."); -        return false; -    } - -    uint8_t sstd_index_shake = 0xFF; - -    /* Which we always read back first so that we can error out correctly. -     *   - due to the half duplex limitations on return codes, we always have to read *something*. -     *   - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready. -     */ -    if (!receive(&sstd_index_shake, sizeof(sstd_index_shake)) || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) { -        dprintln("USART: Handshake failed."); -        return false; -    } - -    /* Send transaction buffer to the slave. If this transaction requires it. */ -    if (trans->initiator2target_buffer_size) { -        if (!send(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) { -            dprintln("USART: Send failed."); -            return false; -        } -    } - -    /* Receive transaction buffer from the slave. If this transaction requires it. */ -    if (trans->target2initiator_buffer_size) { -        if (!receive(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) { -            dprintln("USART: Receive failed."); -            return false; -        } -    } - -    return true; +    usart_driver_start();  } diff --git a/platforms/chibios/drivers/serial_usart.h b/platforms/chibios/drivers/serial_usart.h index 81fe9e0113..fa062cd736 100644 --- a/platforms/chibios/drivers/serial_usart.h +++ b/platforms/chibios/drivers/serial_usart.h @@ -1,42 +1,12 @@ -/* Copyright 2021 QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ +// Copyright 2021 QMK +// SPDX-License-Identifier: GPL-2.0-or-later  #pragma once  #include "quantum.h"  #include "serial.h" -#include "printf.h" - -#include <ch.h>  #include <hal.h> -#if !defined(SERIAL_USART_DRIVER) -#    define SERIAL_USART_DRIVER SD1 -#endif - -#if !defined(USE_GPIOV1) -/* The default PAL alternate modes are used to signal that the pins are used for USART. */ -#    if !defined(SERIAL_USART_TX_PAL_MODE) -#        define SERIAL_USART_TX_PAL_MODE 7 -#    endif -#    if !defined(SERIAL_USART_RX_PAL_MODE) -#        define SERIAL_USART_RX_PAL_MODE 7 -#    endif -#endif -  #if defined(SOFT_SERIAL_PIN)  #    define SERIAL_USART_TX_PIN SOFT_SERIAL_PIN  #endif @@ -49,6 +19,62 @@  #    define SERIAL_USART_RX_PIN A10  #endif +#if !defined(SELECT_SOFT_SERIAL_SPEED) +#    define SELECT_SOFT_SERIAL_SPEED 1 +#endif + +#if defined(SERIAL_USART_SPEED) +// Allow advanced users to directly set SERIAL_USART_SPEED +#elif SELECT_SOFT_SERIAL_SPEED == 0 +#    define SERIAL_USART_SPEED 460800 +#elif SELECT_SOFT_SERIAL_SPEED == 1 +#    define SERIAL_USART_SPEED 230400 +#elif SELECT_SOFT_SERIAL_SPEED == 2 +#    define SERIAL_USART_SPEED 115200 +#elif SELECT_SOFT_SERIAL_SPEED == 3 +#    define SERIAL_USART_SPEED 57600 +#elif SELECT_SOFT_SERIAL_SPEED == 4 +#    define SERIAL_USART_SPEED 38400 +#elif SELECT_SOFT_SERIAL_SPEED == 5 +#    define SERIAL_USART_SPEED 19200 +#else +#    error invalid SELECT_SOFT_SERIAL_SPEED value +#endif + +#if !defined(SERIAL_USART_TIMEOUT) +#    define SERIAL_USART_TIMEOUT 20 +#endif + +#if HAL_USE_SERIAL + +typedef SerialDriver QMKSerialDriver; +typedef SerialConfig QMKSerialConfig; + +#    if !defined(SERIAL_USART_DRIVER) +#        define SERIAL_USART_DRIVER SD1 +#    endif + +#elif HAL_USE_SIO + +typedef SIODriver QMKSerialDriver; +typedef SIOConfig QMKSerialConfig; + +#    if !defined(SERIAL_USART_DRIVER) +#        define SERIAL_USART_DRIVER SIOD1 +#    endif + +#endif + +#if !defined(USE_GPIOV1) +/* The default PAL alternate modes are used to signal that the pins are used for USART. */ +#    if !defined(SERIAL_USART_TX_PAL_MODE) +#        define SERIAL_USART_TX_PAL_MODE 7 +#    endif +#    if !defined(SERIAL_USART_RX_PAL_MODE) +#        define SERIAL_USART_RX_PAL_MODE 7 +#    endif +#endif +  #if !defined(USART_CR1_M0)  #    define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so  #endif @@ -86,31 +112,3 @@              (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \          } while (0)  #endif - -#if !defined(SELECT_SOFT_SERIAL_SPEED) -#    define SELECT_SOFT_SERIAL_SPEED 1 -#endif - -#if defined(SERIAL_USART_SPEED) -// Allow advanced users to directly set SERIAL_USART_SPEED -#elif SELECT_SOFT_SERIAL_SPEED == 0 -#    define SERIAL_USART_SPEED 460800 -#elif SELECT_SOFT_SERIAL_SPEED == 1 -#    define SERIAL_USART_SPEED 230400 -#elif SELECT_SOFT_SERIAL_SPEED == 2 -#    define SERIAL_USART_SPEED 115200 -#elif SELECT_SOFT_SERIAL_SPEED == 3 -#    define SERIAL_USART_SPEED 57600 -#elif SELECT_SOFT_SERIAL_SPEED == 4 -#    define SERIAL_USART_SPEED 38400 -#elif SELECT_SOFT_SERIAL_SPEED == 5 -#    define SERIAL_USART_SPEED 19200 -#else -#    error invalid SELECT_SOFT_SERIAL_SPEED value -#endif - -#if !defined(SERIAL_USART_TIMEOUT) -#    define SERIAL_USART_TIMEOUT 20 -#endif - -#define HANDSHAKE_MAGIC 7 diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index ce69e7f0ac..c3ab0623f0 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c @@ -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}; @@ -42,10 +42,12 @@ __attribute__((weak)) void spi_init(void) {          palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);          palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);  #else -        palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); -        palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); -        palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); +        palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_FLAGS); +        palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_FLAGS); +        palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_FLAGS);  #endif +        spiStop(&SPI_DRIVER); +        currentSlavePin = NO_PIN;      }  } @@ -167,7 +169,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; diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c new file mode 100644 index 0000000000..764764b3f9 --- /dev/null +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -0,0 +1,473 @@ +// 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(); +    nvicEnableVector(RP_USBCTRL_IRQ_NUMBER, RP_IRQ_USB0_PRIORITY); +    // 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. +    wait_us(1000000U * 11U / 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(); +    // We don't want to be interrupted by frequent (1KHz) USB interrupts while +    // doing our timing critical sending operation. +    nvicDisableVector(RP_USBCTRL_IRQ_NUMBER); +    // 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)) { +#if !defined(SERIAL_USART_FULL_DUPLEX) +        // Enable USB interrupts again, because we might sleep for a long time +        // here and don't want to be disconnected from the host. +        nvicEnableVector(RP_USBCTRL_IRQ_NUMBER, RP_IRQ_USB0_PRIORITY); +#endif +        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) { +            pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, false); +            break; +        } +    } +#if !defined(SERIAL_USART_FULL_DUPLEX) +    // Entering timing critical territory again. +    nvicDisableVector(RP_USBCTRL_IRQ_NUMBER); +#endif +    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) { +            pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, false); +            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, as the pio implementation is timing +    // critical we use the highest possible priority. +#if defined(SERIAL_PIO_USE_PIO1) +    nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, CORTEX_MAX_KERNEL_PRIORITY); +#else +    nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, CORTEX_MAX_KERNEL_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); +} diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c new file mode 100644 index 0000000000..bc34eded14 --- /dev/null +++ b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c @@ -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); +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c new file mode 100644 index 0000000000..cdd1e26a7d --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c @@ -0,0 +1,143 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include <stdbool.h> +#include <hal.h> +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +static flash_offset_t base_offset = UINT32_MAX; + +#if defined(WEAR_LEVELING_EFL_FIRST_SECTOR) +static flash_sector_t first_sector = WEAR_LEVELING_EFL_FIRST_SECTOR; +#else  // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) +static flash_sector_t first_sector = UINT16_MAX; +#endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + +static flash_sector_t sector_count = UINT16_MAX; +static BaseFlash *    flash; + +#ifndef WEAR_LEVELING_EFL_FIRST_SECTOR +// "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't. +static inline uint32_t detect_flash_size(void) { +#    if defined(WEAR_LEVELING_EFL_FLASH_SIZE) +    return WEAR_LEVELING_EFL_FLASH_SIZE; +#    elif defined(FLASH_BANK_SIZE) +    return FLASH_BANK_SIZE; +#    elif defined(FLASH_SIZE) +    return FLASH_SIZE; +#    elif defined(FLASHSIZE_BASE) +#        if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_GD32VF103) +    return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes +#        elif defined(QMK_MCU_SERIES_STM32L1XX) +#            error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead? +#        endif +#    else +#        error Unknown flash size definition. +    return 0; +#    endif +} +#endif // WEAR_LEVELING_EFL_FIRST_SECTOR + +bool backing_store_init(void) { +    bs_dprintf("Init\n"); +    flash = (BaseFlash *)&EFLD1; + +    // Need to re-lock the EFL, as if we've just had the bootloader executing it'll already be unlocked. +    backing_store_lock(); + +    const flash_descriptor_t *desc    = flashGetDescriptor(flash); +    uint32_t                  counter = 0; + +#if defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + +    // Work out how many sectors we want to use, working forwards from the first sector specified +    for (flash_sector_t i = 0; i < desc->sectors_count - first_sector; ++i) { +        counter += flashGetSectorSize(flash, first_sector + i); +        if (counter >= (WEAR_LEVELING_BACKING_SIZE)) { +            sector_count = i + 1; +            base_offset  = flashGetSectorOffset(flash, first_sector); +            break; +        } +    } +    if (sector_count == UINT16_MAX || base_offset >= flash_size) { +        // We didn't get the required number of sectors. Can't do anything here. Fault. +        chSysHalt("Invalid sector count intended to be used with wear_leveling"); +    } + +#else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + +    // Work out how many sectors we want to use, working backwards from the end of the flash +    uint32_t       flash_size  = detect_flash_size(); +    flash_sector_t last_sector = desc->sectors_count; +    for (flash_sector_t i = 0; i < desc->sectors_count; ++i) { +        first_sector = desc->sectors_count - i - 1; +        if (flashGetSectorOffset(flash, first_sector) >= flash_size) { +            last_sector = first_sector; +            continue; +        } +        counter += flashGetSectorSize(flash, first_sector); +        if (counter >= (WEAR_LEVELING_BACKING_SIZE)) { +            sector_count = last_sector - first_sector; +            base_offset  = flashGetSectorOffset(flash, first_sector); +            break; +        } +    } + +#endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + +    return true; +} + +bool backing_store_unlock(void) { +    bs_dprintf("Unlock\n"); +    return eflStart(&EFLD1, NULL) == HAL_RET_SUCCESS; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT +    uint32_t start = timer_read32(); +#endif + +    bool          ret = true; +    flash_error_t status; +    for (int i = 0; i < sector_count; ++i) { +        // Kick off the sector erase +        status = flashStartEraseSector(flash, first_sector + i); +        if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) { +            ret = false; +        } + +        // Wait for the erase to complete +        status = flashWaitErase(flash); +        if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) { +            ret = false; +        } +    } + +    bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); +    return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { +    uint32_t offset = (base_offset + address); +    bs_dprintf("Write "); +    wl_dump(offset, &value, sizeof(value)); +    value = ~value; +    return flashProgram(flash, offset, sizeof(value), (const uint8_t *)&value) == FLASH_NO_ERROR; +} + +bool backing_store_lock(void) { +    bs_dprintf("Lock  \n"); +    eflStop(&EFLD1); +    return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { +    uint32_t             offset = (base_offset + address); +    backing_store_int_t *loc    = (backing_store_int_t *)flashGetOffsetAddress(flash, offset); +    *value                      = ~(*loc); +    bs_dprintf("Read  "); +    wl_dump(offset, value, sizeof(backing_store_int_t)); +    return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h new file mode 100644 index 0000000000..244c87cb7f --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h @@ -0,0 +1,52 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +#    include <hal.h> +#endif + +// Work out how many bytes per write to internal flash +#ifndef BACKING_STORE_WRITE_SIZE +// These need to match EFL's XXXXXX_FLASH_LINE_SIZE, see associated code in `lib/chibios/os/hal/ports/**/hal_efl_lld.c`, +// or associated `stm32_registry.h` for the MCU in question (or equivalent for the family). +#    if defined(QMK_MCU_SERIES_GD32VF103) +#        define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +#    elif defined(QMK_MCU_FAMILY_NUC123) +#        define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c +#    elif defined(QMK_MCU_FAMILY_WB32) +#        define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +#    elif defined(QMK_MCU_FAMILY_STM32) +#        if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file +#            define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE) +#        else +#            if defined(QMK_MCU_SERIES_STM32F1XX) +#                define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +#            elif defined(QMK_MCU_SERIES_STM32F3XX) +#                define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +#            elif defined(QMK_MCU_SERIES_STM32F4XX) +#                define BACKING_STORE_WRITE_SIZE (1 << STM32_FLASH_PSIZE) // from hal_efl_lld.c +#            elif defined(QMK_MCU_SERIES_STM32L4XX) +#                define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +#            elif defined(QMK_MCU_SERIES_STM32G0XX) +#                define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +#            elif defined(QMK_MCU_SERIES_STM32G4XX) +#                define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +#            else +#                error "ChibiOS hasn't defined STM32_FLASH_LINE_SIZE, and could not automatically determine BACKING_STORE_WRITE_SIZE" // normally defined in stm32_registry.h, should be set by STM32_FLASH_LINE_SIZE +#            endif +#        endif +#    else +#        error "Could not automatically determine BACKING_STORE_WRITE_SIZE" +#    endif +#endif + +// 2kB backing space allocated +#ifndef WEAR_LEVELING_BACKING_SIZE +#    define WEAR_LEVELING_BACKING_SIZE 2048 +#endif // WEAR_LEVELING_BACKING_SIZE + +// 1kB logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +#    define WEAR_LEVELING_LOGICAL_SIZE 1024 +#endif // WEAR_LEVELING_LOGICAL_SIZE diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c new file mode 100644 index 0000000000..87126c4467 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c @@ -0,0 +1,59 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include <stdbool.h> +#include <hal.h> +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" +#include "flash_stm32.h" + +bool backing_store_init(void) { +    bs_dprintf("Init\n"); +    return true; +} + +bool backing_store_unlock(void) { +    bs_dprintf("Unlock\n"); +    FLASH_Unlock(); +    return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT +    uint32_t start = timer_read32(); +#endif + +    bool         ret = true; +    FLASH_Status status; +    for (int i = 0; i < (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT); ++i) { +        status = FLASH_ErasePage(WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS + (i * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))); +        if (status != FLASH_COMPLETE) { +            ret = false; +        } +    } + +    bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); +    return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { +    uint32_t offset = ((WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS) + address); +    bs_dprintf("Write "); +    wl_dump(offset, &value, sizeof(backing_store_int_t)); +    return FLASH_ProgramHalfWord(offset, ~value) == FLASH_COMPLETE; +} + +bool backing_store_lock(void) { +    bs_dprintf("Lock  \n"); +    FLASH_Lock(); +    return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t* value) { +    uint32_t             offset = ((WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS) + address); +    backing_store_int_t* loc    = (backing_store_int_t*)offset; +    *value                      = ~(*loc); +    bs_dprintf("Read  "); +    wl_dump(offset, loc, sizeof(backing_store_int_t)); +    return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h new file mode 100644 index 0000000000..1e4691a6c0 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h @@ -0,0 +1,67 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +// Work out the page size to use +#ifndef WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE +#    if defined(QMK_MCU_STM32F042) +#        define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 1024 +#    elif defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +#        define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 2048 +#    elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +#        define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 16384 +#    endif +#endif + +// Work out how much flash space we have +#ifndef WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE +#    define WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) // in kB +#endif + +// The base location of program memory +#ifndef WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE +#    define WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE 0x08000000 +#endif + +// The number of pages to use +#ifndef WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT +#    if defined(QMK_MCU_STM32F042) +#        define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 2 +#    elif defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +#        define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 1 +#    elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +#        define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 1 +#    endif +#endif + +// The origin of the emulated eeprom +#ifndef WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS +#    if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +#        define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS ((uintptr_t)(WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE) + WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE * 1024 - (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT * WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE)) +#    elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +#        if defined(BOOTLOADER_STM32) +#            define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (1 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +16k +#        elif defined(BOOTLOADER_TINYUF2) +#            define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (3 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +48k +#        endif +#    endif +#endif + +// 2-byte writes +#ifndef BACKING_STORE_WRITE_SIZE +#    define BACKING_STORE_WRITE_SIZE 2 +#endif + +// The amount of space to use for the entire set of emulation +#ifndef WEAR_LEVELING_BACKING_SIZE +#    if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +#        define WEAR_LEVELING_BACKING_SIZE 2048 +#    elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +#        define WEAR_LEVELING_BACKING_SIZE 16384 +#    endif +#endif + +// The logical amount of eeprom available +#ifndef WEAR_LEVELING_LOGICAL_SIZE +#    define WEAR_LEVELING_LOGICAL_SIZE 1024 +#endif diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c new file mode 100644 index 0000000000..640628e1e9 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2022 Nick Brassel (@tzarc) + * Copyright (c) 2022 Stefan Kerkmann (@KarlK90) + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/bootrom.h" +#include "hardware/flash.h" +#include "hardware/sync.h" +#include "hardware/structs/ssi.h" +#include "hardware/structs/ioqspi.h" + +#include <stdbool.h> +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +#ifndef WEAR_LEVELING_RP2040_FLASH_BULK_COUNT +#    define WEAR_LEVELING_RP2040_FLASH_BULK_COUNT 64 +#endif // WEAR_LEVELING_RP2040_FLASH_BULK_COUNT + +#define FLASHCMD_PAGE_PROGRAM 0x02 +#define FLASHCMD_READ_STATUS 0x05 +#define FLASHCMD_WRITE_ENABLE 0x06 + +extern uint8_t  BOOT2_ROM[256]; +static uint32_t BOOT2_ROM_RAM[64]; + +static ssi_hw_t *const ssi = (ssi_hw_t *)XIP_SSI_BASE; + +// Sanity check +check_hw_layout(ssi_hw_t, ssienr, SSI_SSIENR_OFFSET); +check_hw_layout(ssi_hw_t, spi_ctrlr0, SSI_SPI_CTRLR0_OFFSET); + +static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) { +    ((void (*)(void))BOOT2_ROM_RAM + 1)(); +} + +// Bitbanging the chip select using IO overrides, in case RAM-resident IRQs +// are still running, and the FIFO bottoms out. (the bootrom does the same) +static void __no_inline_not_in_flash_func(flash_cs_force)(bool high) { +    uint32_t field_val = high ? IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; +    hw_write_masked(&ioqspi_hw->io[1].ctrl, field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB, IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS); +} + +// Also allow any unbounded loops to check whether the above abort condition +// was asserted, and terminate early +static int __no_inline_not_in_flash_func(flash_was_aborted)(void) { +    return *(io_rw_32 *)(IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET) & IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS; +} + +// Put bytes from one buffer, and get bytes into another buffer. +// These can be the same buffer. +// If tx is NULL then send zeroes. +// If rx is NULL then all read data will be dropped. +// +// If rx_skip is nonzero, this many bytes will first be consumed from the FIFO, +// before reading a further count bytes into *rx. +// E.g. if you have written a command+address just before calling this function. +static void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count, size_t rx_skip) { +    // Make sure there is never more data in flight than the depth of the RX +    // FIFO. Otherwise, when we are interrupted for long periods, hardware +    // will overflow the RX FIFO. +    const uint max_in_flight = 16 - 2; // account for data internal to SSI +    size_t     tx_count      = count; +    size_t     rx_count      = count; +    while (tx_count || rx_skip || rx_count) { +        // NB order of reads, for pessimism rather than optimism +        uint32_t tx_level      = ssi_hw->txflr; +        uint32_t rx_level      = ssi_hw->rxflr; +        bool     did_something = false; // Expect this to be folded into control flow, not register +        if (tx_count && tx_level + rx_level < max_in_flight) { +            ssi->dr0 = (uint32_t)(tx ? *tx++ : 0); +            --tx_count; +            did_something = true; +        } +        if (rx_level) { +            uint8_t rxbyte = ssi->dr0; +            did_something  = true; +            if (rx_skip) { +                --rx_skip; +            } else { +                if (rx) *rx++ = rxbyte; +                --rx_count; +            } +        } +        // APB load costs 4 cycles, so only do it on idle loops (our budget is +        // 48 cyc/byte) +        if (!did_something && __builtin_expect(flash_was_aborted(), 0)) break; +    } +    flash_cs_force(1); +} + +// Convenience wrapper for above +// (And it's hard for the debug host to get the tight timing between +// cmd DR0 write and the remaining data) +static void __no_inline_not_in_flash_func(_flash_do_cmd)(uint8_t cmd, const uint8_t *tx, uint8_t *rx, size_t count) { +    flash_cs_force(0); +    ssi->dr0 = cmd; +    flash_put_get(tx, rx, count, 1); +} + +// Timing of this one is critical, so do not expose the symbol to debugger etc +static void __no_inline_not_in_flash_func(flash_put_cmd_addr)(uint8_t cmd, uint32_t addr) { +    flash_cs_force(0); +    addr |= cmd << 24; +    for (int i = 0; i < 4; ++i) { +        ssi->dr0 = addr >> 24; +        addr <<= 8; +    } +} + +// Poll the flash status register until the busy bit (LSB) clears +static void __no_inline_not_in_flash_func(flash_wait_ready)(void) { +    uint8_t stat; +    do { +        _flash_do_cmd(FLASHCMD_READ_STATUS, NULL, &stat, 1); +    } while (stat & 0x1 && !flash_was_aborted()); +} + +// Set the WEL bit (needed before any program/erase operation) +static void __no_inline_not_in_flash_func(flash_enable_write)(void) { +    _flash_do_cmd(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0); +} + +static void __no_inline_not_in_flash_func(pico_program_bulk)(uint32_t flash_address, backing_store_int_t *values, size_t item_count) { +    rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); +    rom_flash_exit_xip_fn         flash_exit_xip         = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); +    rom_flash_flush_cache_fn      flash_flush_cache      = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); +    assert(connect_internal_flash && flash_exit_xip && flash_flush_cache); + +    static backing_store_int_t bulk_write_buffer[WEAR_LEVELING_RP2040_FLASH_BULK_COUNT]; + +    while (item_count) { +        size_t batch_size = MIN(item_count, WEAR_LEVELING_RP2040_FLASH_BULK_COUNT); +        for (size_t i = 0; i < batch_size; i++, values++, item_count--) { +            bulk_write_buffer[i] = ~(*values); +        } +        __compiler_memory_barrier(); + +        connect_internal_flash(); +        flash_exit_xip(); +        flash_enable_write(); + +        flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_address); +        flash_put_get((uint8_t *)bulk_write_buffer, NULL, batch_size * sizeof(backing_store_int_t), 4); +        flash_wait_ready(); +        flash_address += batch_size * sizeof(backing_store_int_t); + +        flash_flush_cache(); +        flash_enable_xip_via_boot2(); +    } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// QMK Wear-Leveling Backing Store implementation + +static int interrupts; + +bool backing_store_init(void) { +    bs_dprintf("Init\n"); +    memcpy(BOOT2_ROM_RAM, BOOT2_ROM, sizeof(BOOT2_ROM)); +    __compiler_memory_barrier(); +    return true; +} + +bool backing_store_unlock(void) { +    bs_dprintf("Unlock\n"); +    return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT +    uint32_t start = timer_read32(); +#endif + +    // Ensure the backing size can be cleanly subtracted from the flash size without alignment issues. +    _Static_assert((WEAR_LEVELING_BACKING_SIZE) % (FLASH_SECTOR_SIZE) == 0, "Backing size must be a multiple of FLASH_SECTOR_SIZE"); + +    interrupts = save_and_disable_interrupts(); +    flash_range_erase((WEAR_LEVELING_RP2040_FLASH_BASE), (WEAR_LEVELING_BACKING_SIZE)); +    restore_interrupts(interrupts); + +    bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); +    return true; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { +    return backing_store_write_bulk(address, &value, 1); +} + +bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { +    uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address; +    bs_dprintf("Write "); +    wl_dump(offset, values, sizeof(backing_store_int_t) * item_count); +    interrupts = save_and_disable_interrupts(); +    pico_program_bulk(offset, values, item_count); +    restore_interrupts(interrupts); +    return true; +} + +bool backing_store_lock(void) { +    return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { +    return backing_store_read_bulk(address, value, 1); +} + +bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { +    uint32_t             offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address; +    backing_store_int_t *loc    = (backing_store_int_t *)((XIP_BASE) + offset); +    for (size_t i = 0; i < item_count; ++i) { +        values[i] = ~loc[i]; +    } +    bs_dprintf("Read  "); +    wl_dump(offset, values, item_count * sizeof(backing_store_int_t)); +    return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h new file mode 100644 index 0000000000..93a9aa0372 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h @@ -0,0 +1,32 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +#    include "hardware/flash.h" +#endif + +// 2-byte writes +#ifndef BACKING_STORE_WRITE_SIZE +#    define BACKING_STORE_WRITE_SIZE 2 +#endif + +// 64kB backing space allocated +#ifndef WEAR_LEVELING_BACKING_SIZE +#    define WEAR_LEVELING_BACKING_SIZE 8192 +#endif // WEAR_LEVELING_BACKING_SIZE + +// 32kB logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +#    define WEAR_LEVELING_LOGICAL_SIZE 4096 +#endif // WEAR_LEVELING_LOGICAL_SIZE + +// Define how much flash space we have (defaults to lib/pico-sdk/src/boards/include/boards/***) +#ifndef WEAR_LEVELING_RP2040_FLASH_SIZE +#    define WEAR_LEVELING_RP2040_FLASH_SIZE (PICO_FLASH_SIZE_BYTES) +#endif + +// Define the location of emulated EEPROM +#ifndef WEAR_LEVELING_RP2040_FLASH_BASE +#    define WEAR_LEVELING_RP2040_FLASH_BASE ((WEAR_LEVELING_RP2040_FLASH_SIZE) - (WEAR_LEVELING_BACKING_SIZE)) +#endif diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk index a91ef2cf35..790c4f3316 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk @@ -54,11 +54,11 @@ endef  # TODO: Remove once ARM has a way to configure EECONFIG_HANDEDNESS  #       within the emulated eeprom via dfu-util or another tool -ifneq (,$(filter $(MAKECMDGOALS),dfu-util-split-left)) +ifneq (,$(filter $(MAKECMDGOALS), dfu-util-split-left uf2-split-left))      OPT_DEFS += -DINIT_EE_HANDS_LEFT  endif -ifneq (,$(filter $(MAKECMDGOALS),dfu-util-split-right)) +ifneq (,$(filter $(MAKECMDGOALS), dfu-util-split-right uf2-split-right))      OPT_DEFS += -DINIT_EE_HANDS_RIGHT  endif @@ -66,6 +66,10 @@ dfu-util-split-left: dfu-util  dfu-util-split-right: dfu-util +uf2-split-left: flash + +uf2-split-right: flash +  ST_LINK_CLI ?= st-link_cli  ST_LINK_ARGS ?= @@ -104,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) diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 21751f23fd..b2a8ec89e1 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -36,6 +36,7 @@ ifeq ($(strip $(MCU)), risc-v)      # RISC-V Support      # As of 7.4.2021 there is only one supported RISC-V platform in Chibios-Contrib,      # therefore all required settings are hard-coded +    USE_CHIBIOS_CONTRIB = yes      STARTUP_MK = $(CHIBIOS_CONTRIB)/os/common/startup/RISCV-ECLIC/compilers/GCC/mk/startup_$(MCU_STARTUP).mk      PORT_V = $(CHIBIOS_CONTRIB)/os/common/ports/RISCV-ECLIC/compilers/GCC/mk/port.mk      RULESPATH = $(CHIBIOS_CONTRIB)/os/common/startup/RISCV-ECLIC/compilers/GCC @@ -87,12 +88,17 @@ 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 +# If no MCU architecture specified, use the MCU instead (allows for mcu_selection.mk to swap to cortex-m0 etc.) +ifeq ("$(MCU_ARCH)","") +    MCU_ARCH = $(MCU) +endif +  include $(STARTUP_MK)  include $(PORT_V)  include $(PLATFORM_MK) @@ -282,6 +288,17 @@ EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \           $(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  ############################################################################## @@ -332,10 +349,14 @@ SHARED_CFLAGS = -fomit-frame-pointer \                  -ffunction-sections \                  -fdata-sections \                  -fno-common \ -                -fshort-wchar +                -fshort-wchar \ +                -fno-builtin-printf + +LDSCRIPT_PATH := $(shell dirname "$(LDSCRIPT)")  # Shared Linker flags for all toolchains  SHARED_LDFLAGS = -T $(LDSCRIPT) \ +                 -L $(LDSCRIPT_PATH) \                   -Wl,--gc-sections \                   -nostartfiles diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk new file mode 100644 index 0000000000..de426c9c40 --- /dev/null +++ b/platforms/chibios/vendors/RP/RP2040.mk @@ -0,0 +1,287 @@ +# +# 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_flash/flash.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_flash/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 diff --git a/platforms/chibios/vendors/RP/_pin_defs.h b/platforms/chibios/vendors/RP/_pin_defs.h new file mode 100644 index 0000000000..4241845369 --- /dev/null +++ b/platforms/chibios/vendors/RP/_pin_defs.h @@ -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 diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c new file mode 100644 index 0000000000..239155c086 --- /dev/null +++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c @@ -0,0 +1,13 @@ +// 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); +} + +void hard_assertion_failure(void) { +    panic("hard assert"); +} diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c new file mode 100644 index 0000000000..e65b0a5802 --- /dev/null +++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c @@ -0,0 +1,178 @@ +// ---------------------------------------------------------------------------- +// 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"))) + +// clang-format off + +#if defined(RP2040_FLASH_AT25SF128A) + +uint8_t BOOTLOADER_SECTION BOOT2_ROM[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_ROM[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_ROM[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_ROM[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_ROM[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_ROM[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 + +// clang-format on diff --git a/platforms/eeprom.h b/platforms/eeprom.h index 091e6e4400..8cb7e342dc 100644 --- a/platforms/eeprom.h +++ b/platforms/eeprom.h @@ -27,6 +27,8 @@ void     eeprom_update_block(const void *__src, void *__dst, size_t __n);  #        error EEPROM_SIZE has not been defined for custom driver.  #    endif  #    define TOTAL_EEPROM_BYTE_COUNT (EEPROM_SIZE) +#elif defined(EEPROM_WEAR_LEVELING) +#    define TOTAL_EEPROM_BYTE_COUNT (WEAR_LEVELING_LOGICAL_SIZE)  #elif defined(EEPROM_TRANSIENT)  #    include "eeprom_transient.h"  #    define TOTAL_EEPROM_BYTE_COUNT (TRANSIENT_EEPROM_SIZE) diff --git a/platforms/synchronization_util.h b/platforms/synchronization_util.h index 3730f271db..59933945c3 100644 --- a/platforms/synchronization_util.h +++ b/platforms/synchronization_util.h @@ -9,6 +9,40 @@ void split_shared_memory_lock(void);  void split_shared_memory_unlock(void);  #    endif  #else +#    if defined(SPLIT_KEYBOARD)  inline void split_shared_memory_lock(void){};  inline void split_shared_memory_unlock(void){}; +#    endif +#endif + +/* GCCs cleanup attribute expects a function with one parameter, which is a + * pointer to a type compatible with the variable. As we don't want to expose + * the platforms internal mutex type this workaround with auto generated adapter + * function is defined */ +#define QMK_DECLARE_AUTOUNLOCK_HELPERS(prefix)                              \ +    inline unsigned prefix##_autounlock_lock_helper(void) {                 \ +        prefix##_lock();                                                    \ +        return 0;                                                           \ +    }                                                                       \ +                                                                            \ +    inline void prefix##_autounlock_unlock_helper(unsigned* unused_guard) { \ +        prefix##_unlock();                                                  \ +    } + +/* Convinience macro the automatically generate the correct RAII-style + * lock_autounlock function macro */ +#define QMK_DECLARE_AUTOUNLOCK_CALL(prefix) unsigned prefix##_guard __attribute__((unused, cleanup(prefix##_autounlock_unlock_helper))) = prefix##_autounlock_lock_helper + +#if defined(SPLIT_KEYBOARD) +QMK_DECLARE_AUTOUNLOCK_HELPERS(split_shared_memory) + +/** + * @brief Acquire exclusive access to the split keyboard shared memory, by + * calling the platforms `split_shared_memory_lock()` function. The lock is + * automatically released by calling the platforms `split_shared_memory_unlock()` + * function. This happens when the block where + * `split_shared_memory_lock_autounlock()` is called in goes out of scope i.e. + * when the enclosing function returns. + */ +#    define split_shared_memory_lock_autounlock QMK_DECLARE_AUTOUNLOCK_CALL(split_shared_memory)  #endif diff --git a/platforms/test/platform.mk b/platforms/test/platform.mk index eb2424ec5c..f07c863e69 100644 --- a/platforms/test/platform.mk +++ b/platforms/test/platform.mk @@ -31,4 +31,4 @@ CFLAGS += -fno-strict-aliasing  CXXFLAGS += $(COMPILEFLAGS)  CXXFLAGS += -fno-exceptions -CXXFLAGS += -std=gnu++11 +CXXFLAGS += $(CXXSTANDARD) diff --git a/platforms/test/rules.mk b/platforms/test/rules.mk index 55512c7392..a2baa283d0 100644 --- a/platforms/test/rules.mk +++ b/platforms/test/rules.mk @@ -11,7 +11,8 @@ eeprom_stm32_large_DEFS := $(eeprom_stm32_DEFS) \  	-DFEE_PAGE_COUNT=16  eeprom_stm32_INC := \ -	$(PLATFORM_PATH)/chibios/ +	$(PLATFORM_PATH)/chibios/drivers/eeprom/ \ +	$(PLATFORM_PATH)/chibios/drivers/flash/  eeprom_stm32_tiny_INC := $(eeprom_stm32_INC)  eeprom_stm32_large_INC := $(eeprom_stm32_INC) @@ -19,6 +20,6 @@ eeprom_stm32_SRC := \  	$(TOP_DIR)/drivers/eeprom/eeprom_driver.c \  	$(PLATFORM_PATH)/$(PLATFORM_KEY)/eeprom_stm32_tests.cpp \  	$(PLATFORM_PATH)/$(PLATFORM_KEY)/flash_stm32_mock.c \ -	$(PLATFORM_PATH)/chibios/eeprom_stm32.c +	$(PLATFORM_PATH)/chibios/drivers/eeprom/eeprom_stm32.c  eeprom_stm32_tiny_SRC := $(eeprom_stm32_SRC)  eeprom_stm32_large_SRC := $(eeprom_stm32_SRC) | 
