Merge remote-tracking branch 'qmk/master' into merge-2022-09-10

This commit is contained in:
Ilya Zhuravlev
2022-09-10 04:10:44 -06:00
9866 changed files with 143396 additions and 44465 deletions

View File

@@ -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"

View File

@@ -17,6 +17,26 @@
#include <util/delay.h>
// http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf
// page 22: Table 4-2.Arithmetic and Logic Instructions
/*
for (uint16_t i = times; i > 0; i--) {
__builtin_avr_delay_cycles(1);
}
.L3: sbiw r24,0 // loop step 1
brne .L4 // loop step 2
ret
.L4: nop // __builtin_avr_delay_cycles(1);
sbiw r24,1 // loop step 3
rjmp .L3 // loop step 4
*/
#define AVR_sbiw_clocks 2
#define AVR_rjmp_clocks 2
#define AVR_brne_clocks 2
#define AVR_WAIT_LOOP_OVERHEAD (AVR_sbiw_clocks + AVR_brne_clocks + AVR_sbiw_clocks + AVR_rjmp_clocks)
#define wait_ms(ms) \
do { \
if (__builtin_constant_p(ms)) { \
@@ -27,15 +47,15 @@
} \
} \
} while (0)
#define wait_us(us) \
do { \
if (__builtin_constant_p(us)) { \
_delay_us(us); \
} else { \
for (uint16_t i = us; i > 0; i--) { \
_delay_us(1); \
} \
} \
#define wait_us(us) \
do { \
if (__builtin_constant_p(us)) { \
_delay_us(us); \
} else { \
for (uint16_t i = us; i > 0; i--) { \
__builtin_avr_delay_cycles((F_CPU / 1000000) - AVR_WAIT_LOOP_OVERHEAD); \
} \
} \
} while (0)
#define wait_cpuclock(n) __builtin_avr_delay_cycles(n)
#define CPU_CLOCK F_CPU

View File

@@ -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;
}
}

View File

@@ -19,6 +19,8 @@
#pragma once
#include <stdint.h>
#define I2C_READ 0x01
#define I2C_WRITE 0x00

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

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

View File

@@ -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 { \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,3 +18,5 @@
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
#endif
#define USB_ENDPOINTS_ARE_REORDERABLE

View File

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

View File

@@ -0,0 +1,12 @@
// Copyright 2022 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"

View File

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

View File

@@ -0,0 +1,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

View File

@@ -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>

View File

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

View File

@@ -0,0 +1,15 @@
# Copyright 2022 Mega Mind (@megamind4089)
# SPDX-License-Identifier: GPL-2.0-or-later
# Default pin config of nucleo64_411re has most pins in input pull up mode
# List of all the board related files.
BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO64_F411RE/board.c
# Required include directories
BOARDINC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO64_F411RE
# Shared variables
ALLCSRC += $(BOARDSRC)
ALLINC += $(BOARDINC)

View File

@@ -0,0 +1,8 @@
// Copyright 2022 Mega Mind (@megamind4089)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include_next "board.h"
#undef STM32_HSE_BYPASS

View File

@@ -0,0 +1,9 @@
// Copyright 2022 Mega Mind (@megamind4089)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define CH_CFG_ST_RESOLUTION 16
#define CH_CFG_ST_FREQUENCY 10000
#include_next <chconf.h>

View File

@@ -0,0 +1,29 @@
// Copyright 2022 Mega Mind(@megamind4089)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
#endif
/**======================
** I2C Driver
*========================**/
#if !defined(I2C1_SDA_PIN)
# define I2C1_SDA_PIN D0
#endif
#if !defined(I2C1_SCL_PIN)
# define I2C1_SCL_PIN D1
#endif
/**======================
** SERIAL Driver
*========================**/
#if !defined(SERIAL_USART_DRIVER)
# define SERIAL_USART_DRIVER SD2
#endif

View File

@@ -0,0 +1,11 @@
// Copyright 2022 Mega Mind (@megamind4089)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define PAL_USE_WAIT TRUE
#define PAL_USE_CALLBACKS TRUE
#define HAL_USE_I2C TRUE
#define HAL_USE_SERIAL TRUE
#include_next <halconf.h>

View File

@@ -0,0 +1,231 @@
// Copyright 2022 Mega Mind (@megamind4089)
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef MCUCONF_H
#define MCUCONF_H
/*
* STM32F4xx drivers configuration.
* The following settings override the default settings present in
* the various device driver implementation headers.
* Note that the settings for each driver only have effect if the whole
* driver is enabled in halconf.h.
*
* IRQ priorities:
* 15...0 Lowest...Highest.
*
* DMA priorities:
* 0...3 Lowest...Highest.
*/
#define STM32F4xx_MCUCONF
#define STM32F411_MCUCONF
/*
* HAL driver system settings.
*/
#define STM32_NO_INIT FALSE
#define STM32_PVD_ENABLE FALSE
#define STM32_PLS STM32_PLS_LEV0
#define STM32_BKPRAM_ENABLE FALSE
#define STM32_HSI_ENABLED TRUE
#define STM32_LSI_ENABLED TRUE
#define STM32_HSE_ENABLED TRUE
#define STM32_LSE_ENABLED FALSE
#define STM32_CLOCK48_REQUIRED TRUE
#define STM32_SW STM32_SW_PLL
#define STM32_PLLSRC STM32_PLLSRC_HSE
#define STM32_PLLM_VALUE 8
#define STM32_PLLN_VALUE 336
#define STM32_PLLP_VALUE 4
#define STM32_PLLQ_VALUE 7
#define STM32_HPRE STM32_HPRE_DIV1
#define STM32_PPRE1 STM32_PPRE1_DIV2
#define STM32_PPRE2 STM32_PPRE2_DIV1
#define STM32_RTCSEL STM32_RTCSEL_LSI
#define STM32_RTCPRE_VALUE 8
#define STM32_MCO1SEL STM32_MCO1SEL_HSI
#define STM32_MCO1PRE STM32_MCO1PRE_DIV1
#define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK
#define STM32_MCO2PRE STM32_MCO2PRE_DIV5
#define STM32_I2SSRC STM32_I2SSRC_CKIN
#define STM32_PLLI2SN_VALUE 192
#define STM32_PLLI2SR_VALUE 5
/*
* IRQ system settings.
*/
#define STM32_IRQ_EXTI0_PRIORITY 6
#define STM32_IRQ_EXTI1_PRIORITY 6
#define STM32_IRQ_EXTI2_PRIORITY 6
#define STM32_IRQ_EXTI3_PRIORITY 6
#define STM32_IRQ_EXTI4_PRIORITY 6
#define STM32_IRQ_EXTI5_9_PRIORITY 6
#define STM32_IRQ_EXTI10_15_PRIORITY 6
#define STM32_IRQ_EXTI16_PRIORITY 6
#define STM32_IRQ_EXTI17_PRIORITY 15
#define STM32_IRQ_EXTI18_PRIORITY 6
#define STM32_IRQ_EXTI19_PRIORITY 6
#define STM32_IRQ_EXTI20_PRIORITY 6
#define STM32_IRQ_EXTI21_PRIORITY 15
#define STM32_IRQ_EXTI22_PRIORITY 15
#define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7
#define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7
#define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7
#define STM32_IRQ_TIM1_CC_PRIORITY 7
#define STM32_IRQ_TIM2_PRIORITY 7
#define STM32_IRQ_TIM3_PRIORITY 7
#define STM32_IRQ_TIM4_PRIORITY 7
#define STM32_IRQ_TIM5_PRIORITY 7
#define STM32_IRQ_USART1_PRIORITY 12
#define STM32_IRQ_USART2_PRIORITY 12
#define STM32_IRQ_USART6_PRIORITY 12
/*
* ADC driver system settings.
*/
#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4
#define STM32_ADC_USE_ADC1 FALSE
#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#define STM32_ADC_IRQ_PRIORITY 6
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6
/*
* GPT driver system settings.
*/
#define STM32_GPT_USE_TIM1 FALSE
#define STM32_GPT_USE_TIM2 FALSE
#define STM32_GPT_USE_TIM3 FALSE
#define STM32_GPT_USE_TIM4 FALSE
#define STM32_GPT_USE_TIM5 FALSE
#define STM32_GPT_USE_TIM9 FALSE
#define STM32_GPT_USE_TIM10 FALSE
#define STM32_GPT_USE_TIM11 FALSE
/*
* I2C driver system settings.
*/
#define STM32_I2C_USE_I2C1 TRUE
#define STM32_I2C_USE_I2C2 FALSE
#define STM32_I2C_USE_I2C3 FALSE
#define STM32_I2C_BUSY_TIMEOUT 50
#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_I2C_I2C1_IRQ_PRIORITY 5
#define STM32_I2C_I2C2_IRQ_PRIORITY 5
#define STM32_I2C_I2C3_IRQ_PRIORITY 5
#define STM32_I2C_I2C1_DMA_PRIORITY 3
#define STM32_I2C_I2C2_DMA_PRIORITY 3
#define STM32_I2C_I2C3_DMA_PRIORITY 3
#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
/*
* I2S driver system settings.
*/
#define STM32_I2S_USE_SPI2 FALSE
#define STM32_I2S_USE_SPI3 FALSE
#define STM32_I2S_SPI2_IRQ_PRIORITY 10
#define STM32_I2S_SPI3_IRQ_PRIORITY 10
#define STM32_I2S_SPI2_DMA_PRIORITY 1
#define STM32_I2S_SPI3_DMA_PRIORITY 1
#define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
#define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure")
/*
* ICU driver system settings.
*/
#define STM32_ICU_USE_TIM1 FALSE
#define STM32_ICU_USE_TIM2 FALSE
#define STM32_ICU_USE_TIM3 FALSE
#define STM32_ICU_USE_TIM4 FALSE
#define STM32_ICU_USE_TIM5 FALSE
#define STM32_ICU_USE_TIM9 FALSE
#define STM32_ICU_USE_TIM10 FALSE
#define STM32_ICU_USE_TIM11 FALSE
/*
* PWM driver system settings.
*/
#define STM32_PWM_USE_TIM1 FALSE
#define STM32_PWM_USE_TIM2 FALSE
#define STM32_PWM_USE_TIM3 FALSE
#define STM32_PWM_USE_TIM4 FALSE
#define STM32_PWM_USE_TIM5 FALSE
#define STM32_PWM_USE_TIM9 FALSE
#define STM32_PWM_USE_TIM10 FALSE
#define STM32_PWM_USE_TIM11 FALSE
/*
* SERIAL driver system settings.
*/
#define STM32_SERIAL_USE_USART1 TRUE
#define STM32_SERIAL_USE_USART2 TRUE
#define STM32_SERIAL_USE_USART6 FALSE
/*
* SPI driver system settings.
*/
#define STM32_SPI_USE_SPI1 FALSE
#define STM32_SPI_USE_SPI2 FALSE
#define STM32_SPI_USE_SPI3 FALSE
#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_SPI_SPI1_DMA_PRIORITY 1
#define STM32_SPI_SPI2_DMA_PRIORITY 1
#define STM32_SPI_SPI3_DMA_PRIORITY 1
#define STM32_SPI_SPI1_IRQ_PRIORITY 10
#define STM32_SPI_SPI2_IRQ_PRIORITY 10
#define STM32_SPI_SPI3_IRQ_PRIORITY 10
#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
/*
* ST driver system settings.
*/
#define STM32_ST_IRQ_PRIORITY 8
#define STM32_ST_USE_TIMER 2
/*
* UART driver system settings.
*/
#define STM32_UART_USE_USART1 FALSE
#define STM32_UART_USE_USART2 FALSE
#define STM32_UART_USE_USART6 FALSE
#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_UART_USART1_DMA_PRIORITY 0
#define STM32_UART_USART2_DMA_PRIORITY 0
#define STM32_UART_USART6_DMA_PRIORITY 0
#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
/*
* USB driver system settings.
*/
#define STM32_USB_USE_OTG1 TRUE
#define STM32_USB_OTG1_IRQ_PRIORITY 14
#define STM32_USB_OTG1_RX_FIFO_SIZE 512
#define STM32_USB_HOST_WAKEUP_DURATION 2
/*
* WDG driver system settings.
*/
#define STM32_WDG_USE_IWDG FALSE
#endif /* MCUCONF_H */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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 R and G channel of the Bit-C PRO's RGB led)
#define D5 16U
#define B0 17U

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,40 @@
// Copyright 2022 customMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// Left side (front)
#define D3 PAL_LINE(GPIOB, 7)
#define D2 PAL_LINE(GPIOA, 15)
// GND
// GND
#define D1 PAL_LINE(GPIOB, 9)
#define D0 PAL_LINE(GPIOB, 6)
#define D4 PAL_LINE(GPIOA, 4)
#define C6 PAL_LINE(GPIOB, 8)
#define D7 PAL_LINE(GPIOA, 3)
#define E6 PAL_LINE(GPIOB, 10)
#define B4 PAL_LINE(GPIOA, 8)
#define B5 PAL_LINE(GPIOB, 0)
// Right side (front)
// RAW
// GND
// RESET
// VCC
#define F4 PAL_LINE(GPIOA, 7)
#define F5 PAL_LINE(GPIOA, 6)
#define F6 PAL_LINE(GPIOA, 5)
#define F7 PAL_LINE(GPIOA, 1)
#define B1 PAL_LINE(GPIOB, 13)
#define B3 PAL_LINE(GPIOB, 14)
#define B2 PAL_LINE(GPIOB, 15)
#define B6 PAL_LINE(GPIOB, 1)
// LEDs (only D5/B2 uses an actual LED)
// Setting both RX and TX LEDs to the same pin as there
// is only one LED availble
// If this is undesirable, either B0 or B5 can be redefined by
// using #undef and #define to change its assignment
#define B0 PAL_LINE(GPIOB, 2)
#define D5 PAL_LINE(GPIOB, 2)

View File

@@ -0,0 +1,4 @@
# Proton C MCU settings for converting AVR projects
MCU := STM32F411
BOARD := GENERIC_STM32_F411XE
BOOTLOADER := stm32-dfu

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,51 @@
// Copyright 2022 Mega Mind (@megamind4089)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// Pindefs for v2.0.0
// https://megamind4089.github.io/STeMCell/pinout/
// Left side (front)
#ifdef STEMCELL_UART_SWAP
# define D3 PAL_LINE(GPIOA, 3)
# define D2 PAL_LINE(GPIOA, 2)
#else
# define D3 PAL_LINE(GPIOA, 2)
# define D2 PAL_LINE(GPIOA, 3)
#endif
// GND
// GND
#ifdef STEMCELL_I2C_SWAP
# define D1 PAL_LINE(GPIOB, 6)
# define D0 PAL_LINE(GPIOB, 7)
#else
# define D1 PAL_LINE(GPIOB, 7)
# define D0 PAL_LINE(GPIOB, 6)
#endif
#define D4 PAL_LINE(GPIOA, 15)
#define C6 PAL_LINE(GPIOB, 3)
#define D7 PAL_LINE(GPIOB, 4)
#define E6 PAL_LINE(GPIOB, 5)
#define B4 PAL_LINE(GPIOB, 8)
#define B5 PAL_LINE(GPIOB, 9)
// Right side (front)
// RAW
// GND
// RESET
// VCC
#define F4 PAL_LINE(GPIOB, 10)
#define F5 PAL_LINE(GPIOB, 2)
#define F6 PAL_LINE(GPIOB, 1)
#define F7 PAL_LINE(GPIOB, 0)
#define B1 PAL_LINE(GPIOA, 5)
#define B3 PAL_LINE(GPIOA, 6)
#define B2 PAL_LINE(GPIOA, 7)
#define B6 PAL_LINE(GPIOA, 4)
// LEDs
#define D5 PAL_LINE(GPIOA, 8) // User LED
#define B0 PAL_LINE(GPIOA, 9) // unconnected pin

View File

@@ -0,0 +1,18 @@
# Copyright 2022 Mega Mind (@megamind4089)
# SPDX-License-Identifier: GPL-2.0-or-later
MCU := STM32F411
BOARD := STEMCELL
BOOTLOADER := tinyuf2
SERIAL_DRIVER ?= usart
WS2812_DRIVER ?= bitbang
ifeq ($(strip $(STMC_US)), yes)
OPT_DEFS += -DSTEMCELL_UART_SWAP
endif
ifeq ($(strip $(STMC_IS)), yes)
OPT_DEFS += -DSTEMCELL_I2C_SWAP
endif

View File

@@ -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();

View File

@@ -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), &regaddr, 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) {

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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

View File

@@ -20,7 +20,7 @@
static pin_t currentSlavePin = NO_PIN;
#if defined(K20x) || defined(KL2x)
#if defined(K20x) || defined(KL2x) || defined(RP2040)
static SPIConfig spiConfig = {NULL, 0, 0, 0};
#else
static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
@@ -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;

View File

@@ -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);
}

View File

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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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_DFU)
# 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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -6,7 +6,7 @@
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
#ifndef NOP_FUDGE
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX)
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
# define NOP_FUDGE 0.4
# else
# error("NOP_FUDGE configuration required")

View File

@@ -29,6 +29,22 @@
# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM?_UP"
#endif
/* Summarize https://www.st.com/resource/en/application_note/an4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf to
* figure out if we are using a 32bit timer. This is needed to setup the DMA controller correctly.
* Ignore STM32H7XX and STM32U5XX as they are not supported by ChibiOS.
*/
#if !defined(STM32F1XX) && !defined(STM32L0XX) && !defined(STM32L1XX)
# define WS2812_PWM_TIMER_32BIT_PWMD2 1
#endif
#if !defined(STM32F1XX)
# define WS2812_PWM_TIMER_32BIT_PWMD5 1
#endif
#define WS2812_CONCAT1(a, b) a##b
#define WS2812_CONCAT(a, b) WS2812_CONCAT1(a, b)
#if WS2812_CONCAT(WS2812_PWM_TIMER_32BIT_, WS2812_PWM_DRIVER)
# define WS2812_PWM_TIMER_32BIT
#endif
#ifndef WS2812_PWM_COMPLEMENTARY_OUTPUT
# define WS2812_PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_HIGH
#else
@@ -89,6 +105,9 @@
* The duty cycle is calculated for a high period of 350 nS.
*/
#define WS2812_DUTYCYCLE_0 (WS2812_PWM_FREQUENCY / (1000000000 / 350))
#if (WS2812_DUTYCYCLE_0 > 255)
# error WS2812 PWM driver: High period for a 0 is more than a byte
#endif
/**
* @brief High period for a one, in ticks
@@ -105,6 +124,9 @@
* This is in the middle of the specifications of the WS2812 and WS2812B.
*/
#define WS2812_DUTYCYCLE_1 (WS2812_PWM_FREQUENCY / (1000000000 / 800))
#if (WS2812_DUTYCYCLE_1 > 255)
# error WS2812 PWM driver: High period for a 1 is more than a byte
#endif
/* --- PRIVATE MACROS ------------------------------------------------------- */
@@ -247,13 +269,35 @@
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */
// STM32F2XX, STM32F4XX and STM32F7XX do NOT zero pad DMA transfers of unequal data width. Buffer width must match TIMx CCR.
// For all other STM32 DMA transfer will automatically zero pad. We only need to set the right peripheral width.
#if defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX)
# if defined(WS2812_PWM_TIMER_32BIT)
# define WS2812_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_WORD
# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_WORD
typedef uint32_t ws2812_buffer_t;
# else
# define WS2812_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_HWORD
# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD
typedef uint16_t ws2812_buffer_t;
# endif
#else
# define WS2812_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_BYTE
# if defined(WS2812_PWM_TIMER_32BIT)
# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_WORD
# else
# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD
# endif
typedef uint8_t ws2812_buffer_t;
#endif
static ws2812_buffer_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */
/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
/*
* Gedanke: Double-buffer type transactions: double buffer transfers using two memory pointers for
the memory (while the DMA is reading/writing from/to a buffer, the application can
write/read to/from the other buffer).
* the memory (while the DMA is reading/writing from/to a buffer, the application can
* write/read to/from the other buffer).
*/
void ws2812_init(void) {
@@ -284,11 +328,18 @@ void ws2812_init(void) {
// Configure DMA
// dmaInit(); // Joe added this
#if defined(WB32F3G71xx) || defined(WB32FQ95xx)
dmaStreamAlloc(WS2812_DMA_STREAM - WB32_DMA_STREAM(0), 10, NULL, NULL);
dmaStreamSetSource(WS2812_DMA_STREAM, ws2812_frame_buffer);
dmaStreamSetDestination(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
dmaStreamSetMode(WS2812_DMA_STREAM, WB32_DMA_CHCFG_HWHIF(WS2812_DMA_CHANNEL) | WB32_DMA_CHCFG_DIR_M2P | WB32_DMA_CHCFG_PSIZE_WORD | WB32_DMA_CHCFG_MSIZE_WORD | WB32_DMA_CHCFG_MINC | WB32_DMA_CHCFG_CIRC | WB32_DMA_CHCFG_TCIE | WB32_DMA_CHCFG_PL(3));
#else
dmaStreamAlloc(WS2812_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL);
dmaStreamSetPeripheral(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
dmaStreamSetMemory0(WS2812_DMA_STREAM, ws2812_frame_buffer);
dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | WS2812_DMA_PERIPHERAL_WIDTH | WS2812_DMA_MEMORY_WIDTH | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3));
#endif
dmaStreamSetTransactionSize(WS2812_DMA_STREAM, WS2812_BIT_N);
dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3));
// M2P: Memory 2 Periph; PL: Priority Level
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE)

View File

@@ -16,6 +16,10 @@
# define WS2812_SPI_SCK_PAL_MODE 5
#endif
#ifndef WS2812_SPI_DIVISOR
# define WS2812_SPI_DIVISOR 16
#endif
// Push Pull or Open Drain Configuration
// Default Push Pull
#ifndef WS2812_EXTERNAL_PULLUP
@@ -42,7 +46,7 @@
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0)
#elif WS2812_SPI_DIVISOR == 8
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1)
#elif WS2812_SPI_DIVISOR == 16 // same as default
#elif WS2812_SPI_DIVISOR == 16 // default
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)
#elif WS2812_SPI_DIVISOR == 32
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2)
@@ -53,7 +57,7 @@
#elif WS2812_SPI_DIVISOR == 256
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
#else
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0) // default
# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
#endif
// Use SPI circular buffer
@@ -148,8 +152,14 @@ void ws2812_init(void) {
NULL, // end_cb
PAL_PORT(RGB_DI_PIN),
PAL_PAD(RGB_DI_PIN),
# if defined(WB32F3G71xx) || defined(WB32FQ95xx)
0,
0,
WS2812_SPI_DIVISOR
# else
WS2812_SPI_DIVISOR_CR1_BR_X,
0
# endif
#else
// HAL_SPI_V2
# if SPI_SUPPORTS_CIRCULAR == TRUE

View File

@@ -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)

View File

@@ -35,7 +35,9 @@
#define STM32_DMA_STREAM_ID(peripheral, channel) GD32_DMA_STREAM_ID(peripheral - 1, channel - 1)
#define STM32_DMA_CR_DIR_M2P GD32_DMA_CTL_DIR_M2P
#define STM32_DMA_CR_PSIZE_WORD GD32_DMA_CTL_PWIDTH_WORD
#define STM32_DMA_CR_PSIZE_HWORD GD32_DMA_CTL_PWIDTH_HWORD
#define STM32_DMA_CR_MSIZE_WORD GD32_DMA_CTL_MWIDTH_WORD
#define STM32_DMA_CR_MSIZE_BYTE GD32_DMA_CTL_MWIDTH_BYTE
#define STM32_DMA_CR_MINC GD32_DMA_CTL_MNAGA
#define STM32_DMA_CR_CIRC GD32_DMA_CTL_CMEN
#define STM32_DMA_CR_PL GD32_DMA_CTL_PRIO

View File

@@ -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)
@@ -281,6 +287,17 @@ EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \
$(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
$(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH)
#
# QMK specific MCU family support selection.
##############################################################################
ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk)","")
# Either by MCU series e.g. STM32/STM32F1xx.mk or...
include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk
else ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk)","")
# By MCU family e.g. STM32/STM32.mk
include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk
endif
#
# ChibiOS-Contrib
##############################################################################
@@ -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

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

@@ -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

View File

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

View File

@@ -0,0 +1,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");
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -31,4 +31,4 @@ CFLAGS += -fno-strict-aliasing
CXXFLAGS += $(COMPILEFLAGS)
CXXFLAGS += -fno-exceptions
CXXFLAGS += -std=gnu++11
CXXFLAGS += $(CXXSTANDARD)

View File

@@ -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)