mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
esp_flash: support override default chip driver list
This commit is contained in:
parent
1d0e1409c7
commit
f2a86c4205
@ -35,7 +35,7 @@ endif()
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
PRIV_REQUIRES "${priv_requires}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
PRIV_INCLUDE_DIRS include/spi_flash
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
# Avoid cache miss by unexpected inlineing when built by -Os
|
||||
|
@ -114,7 +114,18 @@ menu "SPI Flash driver"
|
||||
help
|
||||
Defines how many ticks will be before returning to continue a erasing.
|
||||
|
||||
config SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST
|
||||
bool "Override default chip driver list"
|
||||
depends on !SPI_FLASH_USE_LEGACY_IMPL
|
||||
default n
|
||||
help
|
||||
This option allows customize the chip driver list, instead of using the default one provided by IDF.
|
||||
When this option is enabled, the default list is no longer compiled or linked. `default_registered_chips` structure should be provided by the user.
|
||||
|
||||
See example: custom_chip_driver under examples/storage for more details.
|
||||
|
||||
menu "Auto-detect flash chips"
|
||||
visible if !SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST
|
||||
|
||||
config SPI_FLASH_SUPPORT_ISSI_CHIP
|
||||
bool "ISSI"
|
||||
|
@ -1,5 +1,5 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := private_include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include/spi_flash
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "spi_flash_chip_gd.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if !CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST
|
||||
/*
|
||||
* Default registered chip drivers. Note these are tested in order and first
|
||||
* match is taken, so generic/catchall entries should go last. Note that the
|
||||
@ -40,5 +41,9 @@ static const spi_flash_chip_t *default_registered_chips[] = {
|
||||
&esp_flash_chip_generic,
|
||||
NULL,
|
||||
};
|
||||
#else
|
||||
//When the config option is enabled, user should provide this struct themselves.
|
||||
extern const spi_flash_chip_t *default_registered_chips[];
|
||||
#endif //!CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST
|
||||
|
||||
const spi_flash_chip_t **esp_flash_registered_chips = default_registered_chips;
|
||||
|
@ -1,4 +1,11 @@
|
||||
.. include:: ../../../../components/spi_flash/README.rst
|
||||
As an expert feature, you can also try to customize your own flash chip driver, see :doc:`spi_flash_override_driver`.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
Custom Flash Driver <spi_flash_override_driver>
|
||||
|
||||
|
||||
See also
|
||||
--------
|
||||
|
37
docs/en/api-reference/storage/spi_flash_override_driver.rst
Normal file
37
docs/en/api-reference/storage/spi_flash_override_driver.rst
Normal file
@ -0,0 +1,37 @@
|
||||
Override Default Chip Drivers
|
||||
=============================
|
||||
|
||||
The flash driver has a chip detection step, during which the driver go through the default chip driver list and see which driver can properly fit the current flash chip. The default chip driver is provided by the IDF, and will update together with IDF version. However IDF also allows user customizing their own chip drivers.
|
||||
|
||||
.. note::
|
||||
Customize the flash driver is an expert feature, please use it on your own risk:
|
||||
|
||||
1. You may have to rely on some non-public IDF functions, which have slightly possibility to change among versions. On one hand, these changes may be useful bug fixes for your driver, on the other hand, they may also break your code.
|
||||
2. Some IDF bug fixes to other chip drivers will not be automatically applied to your own custom chip drivers.
|
||||
3. If the protection of flash is not handled properly, there may be some random reliability issue.
|
||||
|
||||
Steps of Making Custom Chip Driver and Override the IDF Default Driver
|
||||
----------------------------------------------------------------------
|
||||
|
||||
1. Enables the SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST config option. The default chip driver list (`default_registered_chips`) provided by IDF will no longer be compiled or linked. Instead, the linker will search for the structure, which is supposed to be provided by the user.
|
||||
2. Add a new component in your project, e.g. 'custom_chip_driver'.
|
||||
3. Add dependency from `spi_flash` component to the new `custom_chip_driver` component, by a CMake file `project_include.cmake` under the component folder, with the following code:
|
||||
```
|
||||
idf_build_set_property(___COMPONENT_REQUIRES_COMMON idf::custom_chip_driver APPEND)
|
||||
```
|
||||
4. Copy the necessary chip driver files from IDF spi_flash component. It may includes:
|
||||
|
||||
- spi_flash_chip_drivers.c (to provide the `default_registered_chips` structure)
|
||||
- any of the `spi_flash_chip_*.c` files that matches your own flash model best
|
||||
- CMakeLists.txt and linker.lf file
|
||||
|
||||
Modify the files above properly.
|
||||
|
||||
5. The linker.lf is used to put every you are going to use, when the cache is disabled, into internal RAM. Make sure this file covers all the source files you add.
|
||||
|
||||
6. Build your project, and you will see the new flash driver is used.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
See also :example:`storage/custom_flash_driver`.
|
@ -1 +1,28 @@
|
||||
.. include:: ../../../en/api-reference/storage/spi_flash.rst
|
||||
.. include:: ../../../en/api-reference/storage/spi_flash.rst
|
||||
|
||||
|
||||
Flash 特性支持情况
|
||||
-----------------------------------
|
||||
|
||||
不同厂家的 Flash 特性通过不同的方式来操作,因此需要特殊的驱动支持。当前驱动支持大多数厂家 Flash 24 位地址范围内的快速/慢速读,以及二线模式( DIO / DOUT ),因为他们不需要任何厂家自定义的命令。
|
||||
|
||||
当前驱动支持以下厂家/型号的 Flash 的四线模式( QIO / QOUT ):
|
||||
|
||||
1. ISSI
|
||||
2. GD
|
||||
3. MXIC
|
||||
4. FM
|
||||
5. Winbond
|
||||
6. XMC
|
||||
7. BOYA
|
||||
|
||||
当前驱动支持以下厂家/型号的 Flash 的 32 位地址范围的访问:
|
||||
|
||||
1. W25Q256
|
||||
|
||||
如果有需要,也可以自定义 Flash 芯片驱动,参见 :doc:`spi_flash_override_driver` 。但此功能仅供专业用户使用。
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
自定义 Flash 芯片驱动 <spi_flash_override_driver>
|
@ -0,0 +1 @@
|
||||
.. include:: ../../../en/api-reference/storage/spi_flash_override_driver.rst
|
6
examples/storage/custom_flash_driver/CMakeLists.txt
Normal file
6
examples/storage/custom_flash_driver/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(custom-flash-driver)
|
8
examples/storage/custom_flash_driver/Makefile
Normal file
8
examples/storage/custom_flash_driver/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := custom-flash-driver
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
64
examples/storage/custom_flash_driver/README.md
Normal file
64
examples/storage/custom_flash_driver/README.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Custom Flash Driver Example
|
||||
|
||||
This example shows how to override the default chip driver list provided by IDF. Please make sure the SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST config option is enabled when you build the project (though it is supposed be default with the sdkconfig.defaults). See [programming guide](https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/storage/spi_flash_override_driver.html) for more details of this feature.
|
||||
|
||||
CAUTION: this is only an example on how to extend your own flash chip driver. Espressif doesn't guarantee the chip driver in the example is reliable for mass production, nor the reliabilities of the flash models appear in this example. Please refer to the specification of the flash chips, or contact the flash vendors if you have any problems on the flash.
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
## How to use example
|
||||
|
||||
Follow detailed instructions provided specifically for this example.
|
||||
|
||||
Select the instructions depending on Espressif chip installed on your development board:
|
||||
|
||||
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
|
||||
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
||||
|
||||
|
||||
## Example folder contents
|
||||
|
||||
The project **custom_flash_driver** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
|
||||
|
||||
The component **custom_chip_driver** placed under **components** folder, provides
|
||||
|
||||
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
||||
|
||||
Below is short explanation of remaining files in the project folder.
|
||||
|
||||
```
|
||||
├── CMakeLists.txt
|
||||
├── sdkconfig.defaults Default options to add into sdkconfig file (mainly to enable the SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST option)
|
||||
├── example_test.py Python script used for automated example testing
|
||||
├── main
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── component.mk Component make file
|
||||
│ └── main.c
|
||||
├── components/custom_chip_driver
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── component.mk Component make file
|
||||
│ ├── linker.lf Linker script to put the customized chip driver into internal RAM
|
||||
│ ├── project_include.cmake Global cmake file to add dependency to spi_flash
|
||||
│ ├── chip_drivers.c
|
||||
│ └── spi_flash_chip_eon.c
|
||||
├── Makefile Makefile used by legacy GNU Make
|
||||
└── README.md This is the file you are currently reading
|
||||
```
|
||||
|
||||
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* Program upload failure
|
||||
|
||||
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
||||
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
||||
|
||||
## Technical support and feedback
|
||||
|
||||
Please use the following feedback channels:
|
||||
|
||||
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
|
||||
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
|
||||
|
||||
We will get back to you as soon as possible.
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "chip_drivers.c" "spi_flash_chip_eon.c"
|
||||
PRIV_REQUIRES spi_flash
|
||||
LDFRAGMENTS linker.lf
|
||||
INCLUDE_DIRS "")
|
@ -0,0 +1,27 @@
|
||||
/* Custom flash driver example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "spi_flash_chip_driver.h"
|
||||
#include "spi_flash_chip_generic.h"
|
||||
#include "spi_flash_chip_issi.h"
|
||||
#include "spi_flash_chip_gd.h"
|
||||
|
||||
extern const spi_flash_chip_t esp_flash_chip_eon;
|
||||
|
||||
//Override the default chip driver provided by the IDF, CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST should be set
|
||||
const spi_flash_chip_t *default_registered_chips[] = {
|
||||
&esp_flash_chip_eon,
|
||||
&esp_flash_chip_issi,
|
||||
&esp_flash_chip_gd,
|
||||
// Default chip drivers that will accept all chip ID.
|
||||
// FM, Winbond and XMC chips are supposed to be supported by this chip driver.
|
||||
&esp_flash_chip_generic,
|
||||
NULL,
|
||||
};
|
||||
|
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -0,0 +1,5 @@
|
||||
[mapping:custom_chip_driver]
|
||||
archive: libcustom_chip_driver.a
|
||||
entries:
|
||||
chip_drivers (noflash)
|
||||
spi_flash_chip_eon (noflash)
|
@ -0,0 +1,3 @@
|
||||
# Add custom dependency to the spi_flash component.
|
||||
# This is a workaround, which will also add the dependency to all other components.
|
||||
idf_build_set_property(___COMPONENT_REQUIRES_COMMON idf::custom_chip_driver APPEND)
|
@ -0,0 +1,143 @@
|
||||
/* Custom chip driver example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h> // For MIN/MAX
|
||||
#include "esp_log.h"
|
||||
#include "spi_flash_chip_generic.h"
|
||||
#include "spi_flash/spi_flash_defs.h"
|
||||
|
||||
|
||||
#define REGION_32BIT(start, len) ((start) + (len) > (1<<24))
|
||||
#define ADDR_32BIT(addr) (addr >= (1<<24))
|
||||
|
||||
// Not for all the vendors
|
||||
#define CMD_ENTER_OTP 0x3A
|
||||
|
||||
static const char chip_name[] = "eon";
|
||||
|
||||
/* Driver for Winbond flash chip */
|
||||
|
||||
esp_err_t spi_flash_chip_eon_probe(esp_flash_t *chip, uint32_t flash_id)
|
||||
{
|
||||
/* Check manufacturer and product IDs match our desired masks */
|
||||
const uint8_t MFG_ID = 0x1C;
|
||||
const uint16_t DEV_ID = 0x7000;
|
||||
if (flash_id >> 16 != MFG_ID || (flash_id & 0xFF00) != DEV_ID) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t spi_flash_chip_eon_enter_otp_mode(esp_flash_t* chip)
|
||||
{
|
||||
spi_flash_trans_t trans = {
|
||||
.command = CMD_ENTER_OTP,
|
||||
};
|
||||
return chip->host->common_command(chip->host, &trans);
|
||||
}
|
||||
|
||||
static esp_err_t spi_flash_chip_eon_exit_otp_mode(esp_flash_t* chip)
|
||||
{
|
||||
spi_flash_trans_t trans = {
|
||||
.command = CMD_WRDI,
|
||||
};
|
||||
return chip->host->common_command(chip->host, &trans);
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_eon_get_io_mode(esp_flash_t *chip, esp_flash_io_mode_t* out_io_mode)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = spi_flash_chip_eon_enter_otp_mode(chip);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// On "eon" chips, this involves checking
|
||||
// bit 1 (QE) of RDSR (05h) result
|
||||
// (it works this way on GigaDevice & Fudan Micro chips, probably others...)
|
||||
const uint8_t BIT_QE = 1 << 6;
|
||||
uint32_t sr;
|
||||
ret = spi_flash_common_read_status_8b_rdsr(chip, &sr);
|
||||
if (ret == ESP_OK) {
|
||||
*out_io_mode = ((sr & BIT_QE)? SPI_FLASH_QOUT: 0);
|
||||
}
|
||||
|
||||
//unconditionally exit OTP mode
|
||||
esp_err_t ret_exit = spi_flash_chip_eon_exit_otp_mode(chip);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
return ret_exit;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_eon_set_io_mode(esp_flash_t *chip)
|
||||
{
|
||||
if (!esp_flash_is_quad_mode(chip)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ret;
|
||||
ret = spi_flash_chip_eon_enter_otp_mode(chip);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// On "eon" chips, this involves checking
|
||||
// bit 1 (QE) of RDSR (05h) result
|
||||
const uint32_t BIT_QE = 1 << 6;
|
||||
ret = spi_flash_common_set_io_mode(chip,
|
||||
spi_flash_common_write_status_8b_wrsr,
|
||||
spi_flash_common_read_status_8b_rdsr,
|
||||
BIT_QE);
|
||||
|
||||
//unconditionally exit OTP mode
|
||||
esp_err_t ret_exit = spi_flash_chip_eon_exit_otp_mode(chip);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
return ret_exit;
|
||||
}
|
||||
|
||||
esp_err_t spi_flash_chip_eon_suspend_cmd_conf(esp_flash_t *chip)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const spi_flash_chip_t esp_flash_chip_eon = {
|
||||
.name = chip_name,
|
||||
.probe = spi_flash_chip_eon_probe,
|
||||
.reset = spi_flash_chip_generic_reset,
|
||||
.detect_size = spi_flash_chip_generic_detect_size,
|
||||
.erase_chip = spi_flash_chip_generic_erase_chip,
|
||||
.erase_sector = spi_flash_chip_generic_erase_sector,
|
||||
.erase_block = spi_flash_chip_generic_erase_block,
|
||||
.sector_size = 4 * 1024,
|
||||
.block_erase_size = 64 * 1024,
|
||||
|
||||
.get_chip_write_protect = spi_flash_chip_generic_get_write_protect,
|
||||
.set_chip_write_protect = spi_flash_chip_generic_set_write_protect,
|
||||
|
||||
.num_protectable_regions = 0,
|
||||
.protectable_regions = NULL,
|
||||
.get_protected_regions = NULL,
|
||||
.set_protected_regions = NULL,
|
||||
|
||||
.read = spi_flash_chip_generic_read,
|
||||
.write = spi_flash_chip_generic_write,
|
||||
.program_page = spi_flash_chip_generic_page_program,
|
||||
.page_size = 256,
|
||||
.write_encrypted = spi_flash_chip_generic_write_encrypted,
|
||||
|
||||
.wait_idle = spi_flash_chip_generic_wait_idle,
|
||||
.set_io_mode = spi_flash_chip_eon_set_io_mode,
|
||||
.get_io_mode = spi_flash_chip_eon_get_io_mode,
|
||||
};
|
||||
|
3
examples/storage/custom_flash_driver/main/CMakeLists.txt
Normal file
3
examples/storage/custom_flash_driver/main/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
PRIV_REQUIRES custom_chip_driver
|
||||
INCLUDE_DIRS "")
|
4
examples/storage/custom_flash_driver/main/component.mk
Normal file
4
examples/storage/custom_flash_driver/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
26
examples/storage/custom_flash_driver/main/main.c
Normal file
26
examples/storage/custom_flash_driver/main/main.c
Normal file
@ -0,0 +1,26 @@
|
||||
/* Hello World Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
// Extra check to ensure our custom chip driver file is correctly linked
|
||||
#if !CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST
|
||||
#error Custom flash chip driver not used!
|
||||
#endif
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Hello world!\n");
|
||||
|
||||
while(1) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
2
examples/storage/custom_flash_driver/sdkconfig.defaults
Normal file
2
examples/storage/custom_flash_driver/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_SPI_FLASH_USE_LEGACY_IMPL=n
|
||||
CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST=y
|
Loading…
Reference in New Issue
Block a user