feat: SPI flash driver (#4012)

Co-authored-by: Richard Li <richard.li@ces.hk>
This commit is contained in:
Raphael Coeffic
2023-10-13 19:51:11 +10:00
committed by GitHub
co-authored by Richard Li
parent 7400a598a1
commit cb16786a74
17 changed files with 1977 additions and 31 deletions
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) EdgeTX
*
* Authors:
* Dr. Richard Li <richard.li@ces.hk>
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
/*
* FrFTL - Flash Resident Flash Translation Layer
*
* This is a FTL designed for NOR flash, logical to physical mapping uses 2 layers
* of translation tables all resident in flash. It comes with mechanisms to ensure
* the integrity of the data in previous state when power out occurs in the middle
* of flash programming.
*
* It can be used to back the FatFS library by ChaN and included the support of
* CTRL_SYNC and CTRL_TRIM functions for best performance.
*
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
bool (*flashRead)(uint32_t addr, uint8_t* buf, uint32_t len);
bool (*flashProgram)(uint32_t addr, const uint8_t* buf, uint32_t len);
bool (*flashErase)(uint32_t addr);
bool (*isFlashErased)(uint32_t addr);
} FrFTLOps;
typedef struct {
const FrFTLOps* callbacks;
uint32_t mttPhysicalPageNo;
uint16_t physicalPageCount;
uint8_t ttPageCount;
uint32_t usableSectorCount;
uint16_t writeFrontier;
uint32_t* physicalPageState;
bool physicalPageStateResolved;
uint16_t pageBufferSize;
void *pageBuffer;
void* bufferHead; // LRU most used
void* bufferTail; // LRU least used
void* hashTable; // Fast cache lookup
uint32_t memoryUsed;
} FrFTL;
bool ftlInit(FrFTL* ftl, const FrFTLOps* cb, uint16_t flashSizeInMB);
void ftlDeInit(FrFTL* ftl);
bool ftlWrite(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors, const uint8_t* buf);
bool ftlRead(FrFTL* ftl, uint32_t sectorNo, uint8_t* buffer);
bool ftlTrim(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors);
bool ftlSync(FrFTL* ftl);
#ifdef __cplusplus
}
#endif
+15
View File
@@ -58,6 +58,21 @@ int fatfsRegisterDriver(const diskio_driver_t* drv, uint8_t lun)
return 1;
}
void fatfsUnregisterDrivers()
{
for (uint8_t i = 0; i < _fatfs_n_drives; i++) {
auto& drive = _fatfs_drives[i];
if (drive.initialized) {
disk_ioctl(i, CTRL_SYNC, 0);
if (drive.drv->deinit) {
drive.drv->deinit(drive.lun);
}
drive.initialized = false;
}
}
_fatfs_n_drives = 0;
}
const diskio_driver_t* fatfsGetDriver(uint8_t pdrv)
{
if (pdrv >= _fatfs_n_drives) {
+5
View File
@@ -28,6 +28,8 @@ struct diskio_driver_t
{
DSTATUS (*initialize)(BYTE pdrv);
DSTATUS (*deinit)(BYTE pdrv);
DSTATUS (*status)(BYTE pdrv);
DRESULT (*read)(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
@@ -40,6 +42,9 @@ struct diskio_driver_t
// returns 1 if successful, 0 otherwise
int fatfsRegisterDriver(const diskio_driver_t* drv, uint8_t lun);
// gracefully tear down all drivers
void fatfsUnregisterDrivers();
// returns a pyhsical disk driver or NULL
const diskio_driver_t* fatfsGetDriver(uint8_t pdrv);
+8
View File
@@ -30,6 +30,9 @@
#elif defined(STORAGE_USE_SDCARD_SPI)
#include "diskio_spi.h"
#define _STORAGE_DRIVER sdcard_spi_driver
#elif defined(STORAGE_USE_SPI_FLASH)
#include "diskio_spi_flash.h"
#define _STORAGE_DRIVER spi_flash_diskio_driver
#else
#error "No supported storage driver configured"
#endif
@@ -62,6 +65,11 @@ void storageInit()
}
}
void storageDeInit()
{
fatfsUnregisterDrivers();
}
void storagePreMountHook()
{
#if defined(DISK_CACHE)
+1
View File
@@ -26,6 +26,7 @@
// Note: can be used to attach the pyhsical volume driver
// to the generic FatFs driver
void storageInit();
void storageDeInit();
// Called before the storage is mounted
void storagePreMountHook();
@@ -78,6 +78,11 @@ if(PCB STREQUAL X10 OR PCB STREQUAL X12S OR PCB STREQUAL NV14)
../../../../../thirdparty/libopenui/thirdparty/lz4/lz4.c
../../../../../targets/common/arm/stm32/diskio_sdio.cpp
../../../../../targets/common/arm/stm32/rtc_driver.cpp
../../../../../targets/common/arm/stm32/diskio_spi_flash.cpp
../../../../../targets/common/arm/stm32/spi_flash.cpp
../../../../../targets/common/arm/stm32/stm32_spi.cpp
../../../../../drivers/frftl.cpp
../../../../../crc.cpp
../../../../../targets/${TARGET_DIR}/sdram_driver.c
../../../../../targets/${TARGET_DIR}/haptic_driver.cpp
)
@@ -41,15 +41,21 @@ UINT BlockCount;
void sdInit(void)
{
static FATFS fatFS __DMA;
storageInit();
static FATFS fatFS __DMA;
if (f_mount(&fatFS, "", 1) == FR_OK) {
f_chdir("/");
}
}
void sdDone()
{
// unmount
f_mount(0, "", 0);
storageDeInit();
}
FRESULT openBinDir(MemoryType mt)
{
FRESULT fr = f_chdir(getBinaryPath(mt));
@@ -550,11 +550,13 @@ int bootloaderMain()
if (state != ST_FLASHING && state != ST_USB) {
if (pwrOffPressed()) {
sdDone();
boardOff();
}
}
if (state == ST_REBOOT) {
sdDone();
#if !defined(SIMU)
#if defined(RTC_BACKUP_RAM)
rtcInit();
@@ -0,0 +1,195 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include "diskio_spi_flash.h"
#include "spi_flash.h"
#if !defined(DISABLE_FLASH_FTL)
#define USE_FLASH_FTL
#endif
#if defined(USE_FLASH_FTL)
#include "drivers/frftl.h"
static FrFTL _frftl;
static bool flashRead(uint32_t addr, uint8_t* buf, uint32_t len)
{
flashSpiRead(addr, buf, len);
return true;
}
static bool flashWrite(uint32_t addr, const uint8_t *buf, uint32_t len)
{
uint32_t pageSize = flashSpiGetPageSize();
if(len % pageSize != 0)
return false;
while(len > 0) {
flashSpiWrite(addr, buf, pageSize);
len -= pageSize;
buf += pageSize;
addr += pageSize;
}
if(len != 0) {
return false;
}
return true;
}
static bool flashErase(uint32_t addr)
{
flashSpiErase(addr);
return true;
}
static bool isFlashErased(uint32_t addr)
{
return flashSpiIsErased(addr);
}
static const FrFTLOps _frftl_cb = {
.flashRead = flashRead,
.flashProgram = flashWrite,
.flashErase = flashErase,
.isFlashErased = isFlashErased,
};
#endif
static DSTATUS spi_flash_initialize(BYTE lun)
{
if (!flashSpiInit()) {
return STA_NOINIT;
}
#if defined(USE_FLASH_FTL)
int flashSize = flashSpiGetSize();
int flashSizeMB = flashSize / 1024 / 1024;
if (!ftlInit(&_frftl, &_frftl_cb, flashSizeMB)) {
return STA_NOINIT;
}
#endif
return 0;
}
static DSTATUS spi_flash_status (BYTE lun)
{
return 0;
}
static DRESULT spi_flash_read(BYTE lun, BYTE * buff, DWORD sector, UINT count)
{
#if defined(USE_FLASH_FTL)
while(count) {
if(!ftlRead(&_frftl, sector, (uint8_t*)buff)) {
return RES_ERROR;
}
buff += 512;
sector++;
count --;
}
#else
flashSpiRead((uint32_t)sector * 512, buff, count * 512);
#endif
return RES_OK;
}
static DRESULT spi_flash_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
#if defined(USE_FLASH_FTL)
if (!ftlWrite(&_frftl, sector, count, (uint8_t*)buff)) {
return RES_ERROR;
}
#else
// write in page size
uint32_t address = (uint32_t)sector * 512;
count <<= 1;
while(count) {
if (!flashSpiWrite(address, buff, 256)) {
return RES_ERROR;
}
buff += 256;
address += 256;
count -= 1;
}
#endif
return RES_OK;
}
static DRESULT spi_flash_ioctl(BYTE lun, BYTE ctrl, void *buff)
{
DRESULT res = RES_OK;
switch (ctrl) {
case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
#if defined(USE_FLASH_FTL)
*(DWORD*)buff = _frftl.usableSectorCount;
#else
*(DWORD*)buff = flashSpiGetSize() / 512;
#endif
break;
case GET_SECTOR_SIZE: /* Get R/W sector size (WORD) */
*(WORD*)buff = 512;
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
*(DWORD*)buff = 4096 / 512;
break;
case CTRL_SYNC:
#if defined(USE_FLASH_FTL)
if (!ftlSync(&_frftl)) {
res = RES_ERROR;
}
#else
flashSpiSync();
#endif
break;
case CTRL_TRIM:
#if defined(USE_FLASH_FTL)
if (!ftlTrim(&_frftl, *(DWORD*)buff, 1 + *((DWORD*)buff + 1) - *(DWORD*)buff)) {
res = RES_ERROR;
}
#endif
break;
}
return res;
}
const diskio_driver_t spi_flash_diskio_driver = {
.initialize = spi_flash_initialize,
.status = spi_flash_status,
.read = spi_flash_read,
.write = spi_flash_write,
.ioctl = spi_flash_ioctl,
};
@@ -0,0 +1,26 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#pragma once
#include "hal/fatfs_diskio.h"
extern const diskio_driver_t spi_flash_diskio_driver;
@@ -0,0 +1,378 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include "stm32_spi.h"
#include "delays_driver.h"
#include "hal.h"
#define CS_HIGH() stm32_spi_unselect(&_flash_spi)
#define CS_LOW() stm32_spi_select(&_flash_spi)
#define MIN(a,b) (a < b ? a : b)
#define FLASH_SECTOR_SIZE 4096
#define FLASH_SECTOR_MASK (FLASH_SECTOR_SIZE - 1)
#define FLASH_BLOCK_SIZE 32768
#define FLASH_BLOCK_MASK (FLASH_BLOCK_SIZE - 1)
#define FLASH_PAGE_SIZE 256
#define FLASH_PAGE_MASK (FLASH_PAGE_SIZE - 1)
#define FLASH_CMD_READ_ID 0x90
#define FLASH_CMD_READ_JEDEC_ID 0x9f
#define FLASH_CMD_READ_SFDP 0x5a
#define FLASH_CMD_WRITE 0x02
#define FLASH_CMD_READ 0x03
#define FLASH_CMD_STATUS 0x05
#define FLASH_CMD_WRITE_ENABLE 0x06
#define FLASH_CMD_SECTOR_ERASE 0x20
#define FLASH_CMD_BLOCK_ERASE 0x52
#define FLASH_CMD_CHIP_ERASE 0xc7
#define FLASH_CMD_EN4B 0xb7
struct SpiFlashDescriptor {
uint16_t id;
uint8_t log2Size;
bool use4BytesAddress;
};
// * RadioMaster/Eachine TX16S, RadioKing TX18S and Jumper T18 use GD25Q127C (16 MByte)
// * FlySky PL18, Paladin EV and NV14 use WinBond W25Q64JV (8 MByte)
// TODO:
// - fallback for flash size discovery (no JEDEC SFDP; see 'pico-bootrom')
const stm32_spi_t _flash_spi = {
.SPIx = FLASH_SPI,
.SPI_GPIOx = FLASH_SPI_GPIO,
.SPI_Pins = FLASH_SPI_SCK_GPIO_PIN | FLASH_SPI_MISO_GPIO_PIN | FLASH_SPI_MOSI_GPIO_PIN,
.CS_GPIOx = FLASH_SPI_CS_GPIO,
.CS_Pin = FLASH_SPI_CS_GPIO_PIN,
.DMA = nullptr,
.DMA_Channel = 0,
.txDMA_Stream = 0,
.rxDMA_Stream = 0,
};
static SpiFlashDescriptor _flashDescriptor;
static inline void flash_select() { stm32_spi_select(&_flash_spi); }
static inline void flash_unselect() { stm32_spi_unselect(&_flash_spi); }
static inline uint8_t flash_rw_byte(uint8_t value)
{
return stm32_spi_transfer_byte(&_flash_spi, value);
}
static inline uint8_t flash_read_byte()
{
return flash_rw_byte(0xFF);
}
static void flash_rw_bytes(const uint8_t* tx, uint8_t* rx, uint16_t count)
{
stm32_spi_transfer_bytes(&_flash_spi, tx, rx, count);
}
static inline void flash_put_cmd_addr(uint8_t cmd, uint32_t addr)
{
addr |= cmd << 24;
for (int i = 0; i < 4; i++) {
flash_rw_byte(addr >> 24);
addr <<= 8;
}
}
static inline void flash_put_cmd_4b_addr(uint8_t cmd, uint32_t addr)
{
flash_rw_byte(cmd);
for (int i = 0; i < 4; i++) {
flash_rw_byte(addr >> 24);
addr <<= 8;
}
}
static inline void flash_do_cmd(uint8_t cmd, const uint8_t* tx, uint8_t* rx, uint16_t count)
{
flash_select();
flash_rw_byte(cmd);
flash_rw_bytes(tx, rx, count);
flash_unselect();
}
static void flash_wait_for_not_busy()
{
uint8_t status;
do {
flash_do_cmd(FLASH_CMD_STATUS, 0, &status, 1);
} while (status & 0x01);
}
static void flash_enable_write()
{
flash_do_cmd(FLASH_CMD_WRITE_ENABLE, 0, 0, 0);
}
static void flash_read_sfdp(uint32_t addr, uint8_t *rx, uint16_t count)
{
flash_select();
flash_put_cmd_addr(FLASH_CMD_READ_SFDP, addr);
flash_read_byte(); // dummy byte
flash_rw_bytes(0, rx, count);
flash_unselect();
}
static inline uint32_t bytes_to_u32le(const uint8_t *b) {
return b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
}
static bool flash_read_id(SpiFlashDescriptor* desc)
{
uint8_t rxbuf[2];
flash_select();
flash_put_cmd_addr(FLASH_CMD_READ_ID, 0);
flash_rw_bytes(0, rxbuf, 2);
flash_unselect();
uint16_t id = (rxbuf[0] << 8) | rxbuf[1];
if (id == 0xFFFF) {
return false;
}
desc->id = id;
return true;
}
static bool flash_read_sfdp(SpiFlashDescriptor* desc)
{
uint8_t rxbuf[16];
// check magic signature
flash_read_sfdp(0, rxbuf, 16);
if (rxbuf[0] != 'S' || rxbuf[1] != 'F' || rxbuf[2] != 'D' || rxbuf[3] != 'P') {
return false;
}
// check JEDEC ID is 0
if (rxbuf[8] != 0) {
return false;
}
// read param table
uint32_t param_table_ptr = bytes_to_u32le(rxbuf + 12) & 0xffffffu;
flash_read_sfdp(param_table_ptr, rxbuf, 8);
// 1st DWORD
uint32_t param_table_dword = bytes_to_u32le(rxbuf);
if ((param_table_dword & 3) != 1) {
// 4 kilobyte erase is unavailable
return false;
}
if (((param_table_dword >> 17) & 3) != 0) {
// 4-byte addressing supported
desc->use4BytesAddress = true;
flash_do_cmd(FLASH_CMD_EN4B, 0, 0, 0);
}
// 2nd DWORD: flash memory density
// - MSB set: array >= 2 Gbit, encoded as log2 of number of bits
// - MSB clear: array < 2 Gbit, encoded as direct bit count
param_table_dword = bytes_to_u32le(rxbuf + 4);
if (param_table_dword & (1u << 31)) {
param_table_dword &= ~(1u << 31);
} else {
uint32_t ctr = 0;
param_table_dword += 1;
while (param_table_dword >>= 1)
++ctr;
param_table_dword = ctr;
}
desc->log2Size = param_table_dword - 3;
return true;
}
bool flashSpiInit(void)
{
stm32_spi_init(&_flash_spi);
delay_ms(1);
if (!flash_read_id(&_flashDescriptor)) {
return false;
}
if (!flash_read_sfdp(&_flashDescriptor)) {
return false;
}
return true;
}
void flashSpiSync()
{
uint8_t status;
do {
flash_do_cmd(FLASH_CMD_STATUS, 0, &status, 1);
} while (status & 0x01);
}
uint32_t flashSpiGetSize()
{
return (1UL << _flashDescriptor.log2Size);
}
bool flashSpiIsErased(uint32_t address)
{
// verify sector alignment
if((address & FLASH_SECTOR_MASK) != 0)
return false;
flash_wait_for_not_busy();
flash_select();
if (_flashDescriptor.use4BytesAddress) {
flash_put_cmd_4b_addr(FLASH_CMD_READ, address);
} else {
flash_put_cmd_addr(FLASH_CMD_READ, address);
}
bool ret = true;
for(uint32_t i = 0; i < FLASH_SECTOR_SIZE; i++) {
uint8_t byte = flash_rw_byte(0xFF);
if (byte != 0xff) {
ret = false;
break;
}
}
flash_unselect();
return ret;
}
uint32_t flashSpiRead(uint32_t address, uint8_t* data, uint32_t size)
{
size = MIN(size, (uint32_t)(flashSpiGetSize() - address));
flash_wait_for_not_busy();
flash_select();
if (_flashDescriptor.use4BytesAddress) {
flash_put_cmd_4b_addr(FLASH_CMD_READ, address);
} else {
flash_put_cmd_addr(FLASH_CMD_READ, address);
}
flash_rw_bytes(0, data, size);
flash_unselect();
return size;
}
uint32_t flashSpiWrite(uint32_t address, const uint8_t* data, uint32_t size)
{
size = MIN(size, (uint32_t)(flashSpiGetSize() - address));
// verify page alignment and size
if (size != FLASH_PAGE_SIZE || (address & FLASH_PAGE_MASK) != 0) {
return 0;
}
flash_wait_for_not_busy();
flash_enable_write();
flash_select();
if (_flashDescriptor.use4BytesAddress) {
flash_put_cmd_4b_addr(FLASH_CMD_WRITE, address);
} else {
flash_put_cmd_addr(FLASH_CMD_WRITE, address);
}
flash_rw_bytes(data, 0, size);
flash_unselect();
flash_wait_for_not_busy();
return size;
}
int flashSpiErase(uint32_t address)
{
if((address & FLASH_SECTOR_MASK) != 0)
return -1;
flash_wait_for_not_busy();
flash_enable_write();
flash_select();
if (_flashDescriptor.use4BytesAddress) {
flash_put_cmd_4b_addr(FLASH_CMD_SECTOR_ERASE, address);
} else {
flash_put_cmd_addr(FLASH_CMD_SECTOR_ERASE, address);
}
flash_unselect();
flash_wait_for_not_busy();
return 0;
}
int flashSpiBlockErase(uint32_t address)
{
// verify block alignment
if((address & FLASH_BLOCK_MASK) != 0)
return -1;
flash_wait_for_not_busy();
flash_enable_write();
flash_select();
if (_flashDescriptor.use4BytesAddress) {
flash_put_cmd_4b_addr(FLASH_CMD_BLOCK_ERASE, address);
} else {
flash_put_cmd_addr(FLASH_CMD_BLOCK_ERASE, address);
}
flash_unselect();
flash_wait_for_not_busy();
return 0;
}
void flashSpiEraseAll()
{
flash_wait_for_not_busy();
flash_enable_write();
flash_do_cmd(FLASH_CMD_CHIP_ERASE, 0, 0, 0);
flash_wait_for_not_busy();
}
uint16_t flashSpiGetPageSize()
{
return FLASH_PAGE_SIZE;
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include <stdint.h>
#include <stdbool.h>
bool flashSpiInit();
uint32_t flashSpiRead(uint32_t address, uint8_t* data, uint32_t size);
uint32_t flashSpiWrite(uint32_t address, const uint8_t* data, uint32_t size);
uint32_t flashSpiGetSize();
uint16_t flashSpiGetPageSize();
int flashSpiErase(uint32_t address);
bool flashSpiIsErased(uint32_t address);
int flashSpiBlockErase(uint32_t address);
void flashSpiEraseAll();
void flashSpiSync();
+3
View File
@@ -272,6 +272,9 @@ set(FIRMWARE_SRC
targets/common/arm/stm32/trainer_driver.cpp
targets/common/arm/stm32/ads79xx.cpp
targets/common/arm/stm32/diskio_sdio.cpp
targets/common/arm/stm32/spi_flash.cpp
targets/common/arm/stm32/diskio_spi_flash.cpp
drivers/frftl.cpp
)
if(BOOTLOADER)
+44 -29
View File
@@ -281,6 +281,7 @@
#define ADC_EXT_CHANNELS { ADC_CHANNEL_RTC_BATT }
#define ADC_DMA DMA2
#define ADC_DMA_CHANNEL LL_DMA_CHANNEL_2
// TODO: use for SPI1_RX instead?
#define ADC_DMA_STREAM LL_DMA_STREAM_0
#define ADC_DMA_STREAM_IRQ DMA2_Stream0_IRQn
#define ADC_DMA_STREAM_IRQHandler DMA2_Stream0_IRQHandler
@@ -624,7 +625,7 @@
#define SD_PRESENT_GPIO_PIN GPIO_Pin_5 // PC.05
#define SD_PRESENT_LL_GPIO_PIN LL_GPIO_PIN_5 // PC.05
#define SD_SDIO_DMA DMA2
#define SD_SDIO_DMA_STREAM DMA2_Stream3
#define SD_SDIO_DMA_STREAM DMA2_Stream3 // or Stream6
#define SD_SDIO_DMA_CHANNEL LL_DMA_CHANNEL_4
#define SD_SDIO_DMA_IRQn DMA2_Stream3_IRQn
#define SD_SDIO_DMA_IRQHANDLER DMA2_Stream3_IRQHandler
@@ -633,35 +634,49 @@
#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000)
#define STORAGE_USE_SDIO
// EEPROM
// SPI NOR Flash
#if defined(PCBX12S) && PCBREV >= 13
#define EEPROM_RCC_AHB1Periph RCC_AHB1Periph_GPIOA
#define EEPROM_RCC_APB1Periph RCC_APB1Periph_SPI1
#define EEPROM_SPI_CS_GPIO GPIOA
#define EEPROM_SPI_CS_GPIO_PIN GPIO_Pin_15 // PA.15
#define EEPROM_SPI_SCK_GPIO GPIOA
#define EEPROM_SPI_SCK_GPIO_PIN GPIO_Pin_5 // PA.05
#define EEPROM_SPI_SCK_GPIO_PinSource GPIO_PinSource5
#define EEPROM_SPI_MISO_GPIO GPIOA
#define EEPROM_SPI_MISO_GPIO_PIN GPIO_Pin_6 // PA.06
#define EEPROM_SPI_MISO_GPIO_PinSource GPIO_PinSource6
#define EEPROM_SPI_MOSI_GPIO GPIOA
#define EEPROM_SPI_MOSI_GPIO_PIN GPIO_Pin_7 // PA.07
#define EEPROM_SPI_MOSI_GPIO_PinSource GPIO_PinSource7
#define FLASH_SPI SPI1
#define FLASH_SPI_CS_GPIO GPIOA
#define FLASH_SPI_CS_GPIO_PIN LL_GPIO_PIN_15 // PA.15
#define FLASH_SPI_GPIO GPIOA
#define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_5 // PA.05
#define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_6 // PA.06
#define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_7 // PA.07
// SPI1_TX: DMA2 Stream 3 (SDIO) / Stream 5 (Ext. module timer)
// #define FLASH_SPI_TX_DMA_CHANNEL DMA_Channel_3
// #define FLASH_SPI_TX_DMA_STREAM DMA2_Stream3
// #define FLASH_SPI_TX_DMA_IRQn DMA2_Stream3_IRQn
// #define FLASH_SPI_TX_DMA_IRQHandler DMA2_Stream3_IRQHandler
// #define FLASH_SPI_TX_DMA_FLAG_TC DMA_IT_TCIF3
// #define FLASH_SPI_TX_DMA_STATUS_REG HISR
// SPI1_RX: DMA2 Stream 0 / Stream 2
// #define FLASH_SPI_RX_DMA_CHANNEL DMA_Channel_3
// #define FLASH_SPI_RX_DMA_STREAM DMA2_Stream5
// #define FLASH_SPI_RX_DMA_IRQn DMA2_Stream5_IRQn
// #define FLASH_SPI_RX_DMA_IRQHandler DMA2_Stream5_IRQHandler
// #define FLASH_SPI_RX_DMA_STATUS_REG HISR
// #define FLASH_SPI_RX_DMA_FLAG_TC DMA_IT_TCIF5
#elif defined(PCBX10)
#define EEPROM_RCC_AHB1Periph RCC_AHB1Periph_GPIOI
#define EEPROM_RCC_APB1Periph RCC_APB1Periph_SPI2
#define EEPROM_SPI_CS_GPIO GPIOI
#define EEPROM_SPI_CS_GPIO_PIN GPIO_Pin_0 // PI.00
#define EEPROM_SPI_SCK_GPIO GPIOI
#define EEPROM_SPI_SCK_GPIO_PIN GPIO_Pin_1 // PI.01
#define EEPROM_SPI_SCK_GPIO_PinSource GPIO_PinSource1
#define EEPROM_SPI_MISO_GPIO GPIOI
#define EEPROM_SPI_MISO_GPIO_PIN GPIO_Pin_2 // PI.02
#define EEPROM_SPI_MISO_GPIO_PinSource GPIO_PinSource2
#define EEPROM_SPI_MOSI_GPIO GPIOI
#define EEPROM_SPI_MOSI_GPIO_PIN GPIO_Pin_3 // PI.03
#define EEPROM_SPI_MOSI_GPIO_PinSource GPIO_PinSource3
#define FLASH_SPI SPI2
#define FLASH_SPI_CS_GPIO GPIOI
#define FLASH_SPI_CS_GPIO_PIN LL_GPIO_PIN_0 // PI.00
#define FLASH_SPI_GPIO GPIOI
#define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_1 // PI.01
#define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_2 // PI.02
#define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_3 // PI.03
// #define FLASH_SPI_TX_DMA_CHANNEL DMA_Channel_0
// #define FLASH_SPI_TX_DMA_STREAM DMA1_Stream4
// #define FLASH_SPI_TX_DMA_IRQn DMA1_Stream4_IRQn
// #define FLASH_SPI_TX_DMA_IRQHandler DMA1_Stream4_IRQHandler
// #define FLASH_SPI_TX_DMA_FLAG_TC DMA_IT_TCIF4
// #define FLASH_SPI_TX_DMA_STATUS_REG HISR
// #define FLASH_SPI_RX_DMA_CHANNEL DMA_Channel_0
// #define FLASH_SPI_RX_DMA_STREAM DMA1_Stream3
// #define FLASH_SPI_RX_DMA_IRQn DMA1_Stream3_IRQn
// #define FLASH_SPI_RX_DMA_IRQHandler DMA1_Stream3_IRQHandler
// #define FLASH_SPI_RX_DMA_STATUS_REG LISR
// #define FLASH_SPI_RX_DMA_FLAG_TC DMA_IT_TCIF3
#endif
// Audio
@@ -819,7 +834,7 @@
#define FLYSKY_HALL_SERIAL_USART_IRQn UART4_IRQn
#define FLYSKY_HALL_SERIAL_DMA DMA1
#define FLYSKY_HALL_DMA_Stream_RX LL_DMA_STREAM_2
#define FLYSKY_HALL_DMA_Stream_TX LL_DMA_STREAM_4
// #define FLYSKY_HALL_DMA_Stream_TX LL_DMA_STREAM_4
#endif
+3
View File
@@ -153,6 +153,9 @@ set(FIRMWARE_SRC
targets/common/arm/stm32/trainer_driver.cpp
targets/common/arm/stm32/pwr_driver.cpp
targets/common/arm/stm32/diskio_sdio.cpp
targets/common/arm/stm32/spi_flash.cpp
targets/common/arm/stm32/diskio_spi_flash.cpp
drivers/frftl.cpp
targets/common/arm/stm32/vs1053b.cpp
)
+9
View File
@@ -307,6 +307,15 @@
#define SD_SDIO_TRANSFER_CLK_DIV SD_SDIO_CLK_DIV(24000000)
#define STORAGE_USE_SDIO
// SPI NOR Flash
#define FLASH_SPI SPI6
#define FLASH_SPI_CS_GPIO GPIOG
#define FLASH_SPI_CS_GPIO_PIN LL_GPIO_PIN_6 // PG.06
#define FLASH_SPI_GPIO GPIOG
#define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_13 // PG.13
#define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_12 // PG.12
#define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_14 // PG.14
// SDRAM
#define SDRAM_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH)
#define SDRAM_RCC_AHB3Periph RCC_AHB3Periph_FMC