Merge remote-tracking branch 'qmk/master' into merge-2022-09-10
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define I2C_READ 0x01
|
||||
#define I2C_WRITE 0x00
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 { \
|
||||
|
||||
@@ -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)
|
||||
@@ -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"
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
12
platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h
Normal file
12
platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h
Normal 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"
|
||||
13
platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h
Normal file
13
platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h
Normal 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>
|
||||
98
platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h
Normal file
98
platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h
Normal 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 */
|
||||
@@ -18,3 +18,5 @@
|
||||
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
|
||||
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
|
||||
#endif
|
||||
|
||||
#define USB_ENDPOINTS_ARE_REORDERABLE
|
||||
|
||||
9
platforms/chibios/boards/QMK_PM2040/board/board.mk
Normal file
9
platforms/chibios/boards/QMK_PM2040/board/board.mk
Normal 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)
|
||||
12
platforms/chibios/boards/QMK_PM2040/configs/board.h
Normal file
12
platforms/chibios/boards/QMK_PM2040/configs/board.h
Normal 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"
|
||||
13
platforms/chibios/boards/QMK_PM2040/configs/chconf.h
Normal file
13
platforms/chibios/boards/QMK_PM2040/configs/chconf.h
Normal 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>
|
||||
21
platforms/chibios/boards/QMK_PM2040/configs/config.h
Normal file
21
platforms/chibios/boards/QMK_PM2040/configs/config.h
Normal 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
|
||||
9
platforms/chibios/boards/QMK_PM2040/configs/halconf.h
Normal file
9
platforms/chibios/boards/QMK_PM2040/configs/halconf.h
Normal 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>
|
||||
98
platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h
Normal file
98
platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h
Normal 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 */
|
||||
15
platforms/chibios/boards/STEMCELL/board/board.mk
Normal file
15
platforms/chibios/boards/STEMCELL/board/board.mk
Normal 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)
|
||||
8
platforms/chibios/boards/STEMCELL/configs/board.h
Normal file
8
platforms/chibios/boards/STEMCELL/configs/board.h
Normal 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
|
||||
9
platforms/chibios/boards/STEMCELL/configs/chconf.h
Normal file
9
platforms/chibios/boards/STEMCELL/configs/chconf.h
Normal 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>
|
||||
29
platforms/chibios/boards/STEMCELL/configs/config.h
Normal file
29
platforms/chibios/boards/STEMCELL/configs/config.h
Normal 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
|
||||
|
||||
11
platforms/chibios/boards/STEMCELL/configs/halconf.h
Normal file
11
platforms/chibios/boards/STEMCELL/configs/halconf.h
Normal 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>
|
||||
231
platforms/chibios/boards/STEMCELL/configs/mcuconf.h
Normal file
231
platforms/chibios/boards/STEMCELL/configs/mcuconf.h
Normal 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 */
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
117
platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld
Normal file
117
platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
56
platforms/chibios/bootloaders/rp2040.c
Normal file
56
platforms/chibios/bootloaders/rp2040.c
Normal 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
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
36
platforms/chibios/converters/promicro_to_blok/_pin_defs.h
Normal file
36
platforms/chibios/converters/promicro_to_blok/_pin_defs.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -0,0 +1,4 @@
|
||||
# Proton C MCU settings for converting AVR projects
|
||||
MCU := STM32F411
|
||||
BOARD := GENERIC_STM32_F411XE
|
||||
BOOTLOADER := stm32-dfu
|
||||
36
platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h
Normal file
36
platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
@@ -107,16 +107,25 @@ static const I2CConfig i2cconfig = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static i2c_status_t chibios_to_qmk(const msg_t* status) {
|
||||
switch (*status) {
|
||||
case I2C_NO_ERROR:
|
||||
return I2C_STATUS_SUCCESS;
|
||||
case I2C_TIMEOUT:
|
||||
return I2C_STATUS_TIMEOUT;
|
||||
// I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
|
||||
default:
|
||||
return I2C_STATUS_ERROR;
|
||||
/**
|
||||
* @brief Handles any I2C error condition by stopping the I2C peripheral and
|
||||
* aborting any ongoing transactions. Furthermore ChibiOS status codes are
|
||||
* converted into QMK codes.
|
||||
*
|
||||
* @param status ChibiOS specific I2C status code
|
||||
* @return i2c_status_t QMK specific I2C status code
|
||||
*/
|
||||
static i2c_status_t i2c_epilogue(const msg_t status) {
|
||||
if (status == MSG_OK) {
|
||||
return I2C_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// From ChibiOS HAL: "After a timeout the driver must be stopped and
|
||||
// restarted because the bus is in an uncertain state." We also issue that
|
||||
// hard stop in case of any error.
|
||||
i2c_stop();
|
||||
|
||||
return status == MSG_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void i2c_init(void) {
|
||||
@@ -149,14 +158,14 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length,
|
||||
i2c_address = address;
|
||||
i2cStart(&I2C_DRIVER, &i2cconfig);
|
||||
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout));
|
||||
return chibios_to_qmk(&status);
|
||||
return i2c_epilogue(status);
|
||||
}
|
||||
|
||||
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
|
||||
i2c_address = address;
|
||||
i2cStart(&I2C_DRIVER, &i2cconfig);
|
||||
msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, TIME_MS2I(timeout));
|
||||
return chibios_to_qmk(&status);
|
||||
return i2c_epilogue(status);
|
||||
}
|
||||
|
||||
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
|
||||
@@ -170,7 +179,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
|
||||
complete_packet[0] = regaddr;
|
||||
|
||||
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout));
|
||||
return chibios_to_qmk(&status);
|
||||
return i2c_epilogue(status);
|
||||
}
|
||||
|
||||
i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
|
||||
@@ -185,14 +194,14 @@ i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* da
|
||||
complete_packet[1] = regaddr & 0xFF;
|
||||
|
||||
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout));
|
||||
return chibios_to_qmk(&status);
|
||||
return i2c_epilogue(status);
|
||||
}
|
||||
|
||||
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
|
||||
i2c_address = devaddr;
|
||||
i2cStart(&I2C_DRIVER, &i2cconfig);
|
||||
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), ®addr, 1, data, length, TIME_MS2I(timeout));
|
||||
return chibios_to_qmk(&status);
|
||||
return i2c_epilogue(status);
|
||||
}
|
||||
|
||||
i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
|
||||
@@ -200,7 +209,7 @@ i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uin
|
||||
i2cStart(&I2C_DRIVER, &i2cconfig);
|
||||
uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF};
|
||||
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout));
|
||||
return chibios_to_qmk(&status);
|
||||
return i2c_epilogue(status);
|
||||
}
|
||||
|
||||
void i2c_stop(void) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
164
platforms/chibios/drivers/serial_protocol.c
Normal file
164
platforms/chibios/drivers/serial_protocol.c
Normal 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;
|
||||
}
|
||||
49
platforms/chibios/drivers/serial_protocol.h
Normal file
49
platforms/chibios/drivers/serial_protocol.h
Normal 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);
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
473
platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c
vendored
Normal file
473
platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c
vendored
Normal 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);
|
||||
}
|
||||
189
platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c
vendored
Normal file
189
platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c
vendored
Normal 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);
|
||||
}
|
||||
143
platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
Normal file
143
platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
287
platforms/chibios/vendors/RP/RP2040.mk
vendored
Normal 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
|
||||
37
platforms/chibios/vendors/RP/_pin_defs.h
vendored
Normal file
37
platforms/chibios/vendors/RP/_pin_defs.h
vendored
Normal 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
|
||||
13
platforms/chibios/vendors/RP/pico_sdk_shims.c
vendored
Normal file
13
platforms/chibios/vendors/RP/pico_sdk_shims.c
vendored
Normal 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");
|
||||
}
|
||||
178
platforms/chibios/vendors/RP/stage2_bootloaders.c
vendored
Normal file
178
platforms/chibios/vendors/RP/stage2_bootloaders.c
vendored
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -31,4 +31,4 @@ CFLAGS += -fno-strict-aliasing
|
||||
|
||||
CXXFLAGS += $(COMPILEFLAGS)
|
||||
CXXFLAGS += -fno-exceptions
|
||||
CXXFLAGS += -std=gnu++11
|
||||
CXXFLAGS += $(CXXSTANDARD)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user