Skip to content

Commit

Permalink
RP2040 emulated EEPROM. (qmk#17519)
Browse files Browse the repository at this point in the history
  • Loading branch information
tzarc authored and nolanseaton committed Jan 23, 2023
1 parent 8ae86a6 commit b1ff223
Show file tree
Hide file tree
Showing 13 changed files with 470 additions and 22 deletions.
10 changes: 9 additions & 1 deletion builddefs/common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ else
# True EEPROM on STM32L0xx, L1xx
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_STM32_L0_L1
SRC += eeprom_driver.c eeprom_stm32_L0_L1.c
else ifneq ($(filter $(MCU_SERIES),RP2040),)
# Wear-leveling EEPROM implementation, backed by RP2040 flash
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
SRC += eeprom_driver.c eeprom_wear_leveling.c
WEAR_LEVELING_DRIVER = rp2040_flash
else ifneq ($(filter $(MCU_SERIES),KL2x K20x),)
# Teensy EEPROM implementations
OPT_DEFS += -DEEPROM_TEENSY
Expand All @@ -241,7 +246,7 @@ else
endif
endif

VALID_WEAR_LEVELING_DRIVER_TYPES := custom embedded_flash spi_flash legacy
VALID_WEAR_LEVELING_DRIVER_TYPES := custom embedded_flash spi_flash rp2040_flash legacy
WEAR_LEVELING_DRIVER ?= none
ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none)
ifeq ($(filter $(WEAR_LEVELING_DRIVER),$(VALID_WEAR_LEVELING_DRIVER_TYPES)),)
Expand All @@ -262,6 +267,9 @@ ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none)
FLASH_DRIVER := spi
SRC += wear_leveling_flash_spi.c
POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_flash_spi_config.h
else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), rp2040_flash)
SRC += wear_leveling_rp2040_flash.c
POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_rp2040_flash_config.h
else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), legacy)
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
SRC += flash_stm32.c wear_leveling_legacy.c
Expand Down
2 changes: 1 addition & 1 deletion builddefs/mcu_selection.mk
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ ifneq ($(findstring RP2040, $(MCU)),)
# - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
# or <keyboard_dir>/ld/
STARTUPLD_CONTRIB = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/ld
MCU_LDSCRIPT ?= RP2040_FLASH
MCU_LDSCRIPT ?= RP2040_FLASH_TIMECRIT
LDFLAGS += -L $(STARTUPLD_CONTRIB)

# Startup code to use
Expand Down
17 changes: 16 additions & 1 deletion docs/eeprom_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Driver | Description
----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
`WEAR_LEVELING_DRIVER = embedded_flash` | This driver is used for emulating EEPROM by writing to embedded flash on the MCU.
`WEAR_LEVELING_DRIVER = spi_flash` | This driver is used to address external SPI NOR Flash peripherals.
`WEAR_LEVELING_DRIVER = rp2040_flash` | This driver is used to write to the same storage the RP2040 executes code from.
`WEAR_LEVELING_DRIVER = legacy` | This driver is the "legacy" emulated EEPROM provided in historical revisions of QMK. Currently used for STM32F0xx and STM32F4x1, but slated for deprecation and removal once `embedded_flash` support for those MCU families is complete.

!> All wear-leveling drivers require an amount of RAM equivalent to the selected logical EEPROM size. Increasing the size to 32kB of EEPROM requires 32kB of RAM, which a significant number of MCUs simply do not have.
Expand Down Expand Up @@ -128,6 +129,20 @@ Configurable options in your keyboard's `config.h`:

!> There is currently a limit of 64kB for the EEPROM subsystem within QMK, so using a larger flash is not going to be beneficial as the logical size cannot be increased beyond 65536. The backing size may be increased to a larger value, but erase timing may suffer as a result.

## Wear-leveling RP2040 Driver Configuration :id=wear_leveling-rp2040-driver-configuration

This driver performs writes to the same underlying storage that the RP2040 executes its code.

Configurable options in your keyboard's `config.h`:

`config.h` override | Default | Description
------------------------------------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------
`#define WEAR_LEVELING_RP2040_FLASH_SIZE` | `PICO_FLASH_SIZE_BYTES` | Number of bytes of flash on the board.
`#define WEAR_LEVELING_RP2040_FLASH_BASE` | `(flash_size-sector_size)` | The byte-wise location that the backing storage should be located.
`#define WEAR_LEVELING_LOGICAL_SIZE` | `4096` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM.
`#define WEAR_LEVELING_BACKING_SIZE` | `8192` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size as well as the sector size.
`#define BACKING_STORE_WRITE_SIZE` | `2` | The write width used whenever a write is performed on the external flash peripheral.

## Wear-leveling Legacy EEPROM Emulation Driver Configuration :id=wear_leveling-legacy-driver-configuration

This driver performs writes to the embedded flash storage embedded in the MCU much like the normal Embedded Flash Driver, and is only for use with STM32F0xx and STM32F4x1 devices. This flash implementation is still currently provided as the EFL driver is currently non-functional for the previously mentioned families.
Expand All @@ -142,4 +157,4 @@ STM32F072 | `1024` bytes | `2048` bytes
STM32F401 | `1024` bytes | `16384` bytes
STM32F411 | `1024` bytes | `16384` bytes

Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code.
Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code.
22 changes: 11 additions & 11 deletions docs/platformdev_rp2040.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

The following table shows the current driver status for peripherals on RP2040 MCUs:

| System | Support |
| ------------------------------------ | ---------------------------------------------- |
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
| [Audio](audio_driver.md) | Support planned (no ETA) |
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
| [SPI driver](spi_driver.md) | :heavy_check_mark: |
| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver |
| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver |
| [EEPROM emulation](eeprom_driver.md) | Support planned (no ETA) |
| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver |
| [UART driver](uart_driver.md) | Support planned (no ETA) |
| System | Support |
| ---------------------------------------------------------------- | ---------------------------------------------- |
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
| [Audio](audio_driver.md) | Support planned (no ETA) |
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
| [SPI driver](spi_driver.md) | :heavy_check_mark: |
| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver |
| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver |
| [EEPROM emulation](eeprom_driver.md#wear_leveling-configuration) | :heavy_check_mark: |
| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver |
| [UART driver](uart_driver.md) | Support planned (no ETA) |

## GPIO

Expand Down
117 changes: 117 additions & 0 deletions platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit b1ff223

Please sign in to comment.