Compare commits

...

10 Commits

Author SHA1 Message Date
Michael (XIAO Xufeng) b24a5e78f2 Merge branch 'bugfix/spi_flash_cs_setup_xiaomi_v4.0' into customer/maintain_v4.0_xiaomi_tsf_issue
See merge request espressif/esp-idf!13893
2021-06-15 12:35:03 +08:00
Cao Sen Miao a212d866f4 spi_flash: fix cs line setup to make the flash driver more stable 2021-06-08 00:59:41 +08:00
Michael (XIAO Xufeng) b7c8288056 Merge branch 'bugfix/xmc_overerase_xiaomi_v4.0' into customer/maintain_v4.0_xiaomi_tsf_issue
See merge request espressif/esp-idf!13892
2021-06-08 00:21:56 +08:00
chenjianqiang e3f975b5a8 spi_flash: fix xm25qh32c flash overerase 2021-06-07 23:19:03 +08:00
Michael (XIAO Xufeng) 937ce5dfd5 Merge branch 'feature/support_eon_flash_qaud_mode_esp_flash_xiaomi' into 'customer/maintain_v4.0_xiaomi_tsf_issue'
esp_flash: support override default chip driver list (backport xm)

See merge request espressif/esp-idf!12568
2021-03-03 20:02:43 +08:00
Michael (XIAO Xufeng) f2a86c4205 esp_flash: support override default chip driver list 2021-03-03 12:37:21 +08:00
Michael (XIAO Xufeng) 1d0e1409c7 Merge branch 'bugfix/support_eon_flash_qaud_mode_for_xiaomi' into 'customer/maintain_v4.0_xiaomi_tsf_issue'
flash: support EON flash qaud mode

See merge request espressif/esp-idf!12523
2021-02-26 16:35:06 +08:00
chenjianqiang acd3c945d2 flash: support EON flash qaud mode 2021-02-26 11:36:23 +08:00
wangcheng 8c9f5876be components/bt: fixed tx_prog insert error. 2021-01-27 20:41:51 +08:00
zhangyanjiao 60b0e9749f don't disconnect AP when timestamp decrease abnormally 2020-12-29 12:22:32 +08:00
32 changed files with 582 additions and 26 deletions
+16
View File
@@ -219,6 +219,22 @@ menu "Bootloader config"
It allow to test anti-rollback implemention without permanent write eFuse bits.
In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`.
choice BOOTLOADER_FLASH_XMC_OVERERASE_PATCH
bool "Patch strategy for XMC over-erase issue"
default BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
help
Specify the patch strategy for XMC chips. The over-erase issue may exist on
XM25QH16C, XM25QH32C and XM25QH128C.
config BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_ALL
bool "Run the patch for all XMC chips. This can completely avoid over-erase issue. But may cost some time."
config BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
bool "Run the patch on XMC chips when there are clues indicating the flash is running incorrectly."
config BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_BYPASS
bool "Not using the patch"
endchoice # BOOTLOADER_FLASH_XMC_OVERERASE_PATCH
endmenu # Bootloader
@@ -17,6 +17,8 @@
extern "C" {
#endif
#include "esp_err.h"
/** @brief Enable Quad I/O mode in bootloader (if configured)
*
* Queries attached SPI flash ID and sends correct SPI flash
@@ -32,6 +34,8 @@ void bootloader_enable_qio_mode(void);
*/
uint32_t bootloader_read_flash_id();
esp_err_t bootloader_xmc_flash_overerase_fix();
#ifdef __cplusplus
}
#endif
@@ -120,8 +120,16 @@ esp_err_t bootloader_init()
static esp_err_t bootloader_main()
{
bootloader_common_vddsdio_configure();
/* Read and keep flash ID, for further use. */
g_rom_flashchip.device_id = bootloader_read_flash_id();
#if CONFIG_BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_ALL || CONFIG_BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
if (bootloader_xmc_flash_overerase_fix() != ESP_OK) {
ESP_LOGE(TAG, "failed to fix XMC flash overerase, reboot!");
return ESP_FAIL;
}
#endif
esp_image_header_t fhdr;
if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) {
ESP_LOGE(TAG, "failed to load bootloader header!");
@@ -66,10 +66,10 @@ static void write_status_8b_wrsr2(unsigned new_status);
/* Write 16 bit status using WRSR */
static void write_status_16b_wrsr(unsigned new_status);
/* Read 8 bit status of XM25QU64A */
static unsigned read_status_8b_xmc25qu64a();
/* Write 8 bit status of XM25QU64A */
static void write_status_8b_xmc25qu64a(unsigned new_status);
/* Read 8 bit status using RDSR command in otp mode */
static unsigned read_status_8b_rdsr_otp(void);
/* Write 8 bit status using WRSR command in otp mode */
static void write_status_8b_wrsr_otp(unsigned new_status);
#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */
@@ -95,7 +95,8 @@ const static qio_info_t chip_data[] = {
{ "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
{ "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
{ "GD", 0xC8, 0x6000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
{ "XM25QU64A", 0x20, 0x3817, 0xFFFF, read_status_8b_xmc25qu64a, write_status_8b_xmc25qu64a, 6 },
{ "XM25QU64A", 0x20, 0x3817, 0xFFFF, read_status_8b_rdsr_otp, write_status_8b_wrsr_otp, 6 },
{ "EON", 0x1C, 0x7000, 0xFF00, read_status_8b_rdsr_otp, write_status_8b_wrsr_otp, 6 }, /* EN25QH sereils: IDs 0x70xx */
/* Final entry is default entry, if no other IDs have matched.
@@ -253,7 +254,7 @@ static void write_status_16b_wrsr(unsigned new_status)
execute_flash_command(CMD_WRSR, new_status, 16, 0);
}
static unsigned read_status_8b_xmc25qu64a()
static unsigned read_status_8b_rdsr_otp(void)
{
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
@@ -262,7 +263,7 @@ static unsigned read_status_8b_xmc25qu64a()
return read_status;
}
static void write_status_8b_xmc25qu64a(unsigned new_status)
static void write_status_8b_wrsr_otp(unsigned new_status)
{
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
@@ -305,3 +306,111 @@ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8
SPIFLASH.ctrl.val = old_ctrl_reg;
return SPIFLASH.data_buf[0];
}
// cmd(0x5A) + 24bit address + 8 cycles dummy
static uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
{
assert(miso_byte_num <= 4);
uint8_t command = 0x5A;
uint8_t miso_len = miso_byte_num * 8;
uint8_t mosi_len = 0;
uint32_t mosi_data = 0;
uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
SPIFLASH.user.usr_dummy = 1;
SPIFLASH.user1.usr_dummy_cyclelen = 7 + g_rom_spiflash_dummy_len_plus[1];
SPIFLASH.user.usr_addr = 1;
SPIFLASH.addr = (sfdp_addr<<8);
SPIFLASH.user1.usr_addr_bitlen = 23;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = command;
SPIFLASH.user.usr_miso = miso_len > 0;
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
SPIFLASH.user.usr_mosi = mosi_len > 0;
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
SPIFLASH.data_buf[0] = mosi_data;
SPIFLASH.cmd.usr = 1;
while(SPIFLASH.cmd.usr != 0)
{ }
SPIFLASH.ctrl.val = old_ctrl_reg;
uint32_t ret = SPIFLASH.data_buf[0];
if (miso_len < 32) {
//set unused bits to 0
ret &= ~(UINT32_MAX << miso_len);
}
return ret;
}
#define XMC_VENDOR_ID 0x20
//use strict model checking for over-erase issue
static bool is_xmc_chip_strict(uint32_t rdid)
{
uint32_t vendor_id = (rdid >> 16) & 0xFF;
uint32_t mfid = (rdid >> 8) & 0xFF;
uint32_t cpid = rdid & 0xFF;
if (vendor_id != XMC_VENDOR_ID) {
return false;
}
bool matched = false;
if (mfid == 0x40) {
if (cpid >= 0x13 && cpid <= 0x20) {
matched = true;
}
} else if (mfid == 0x41) {
if (cpid >= 0x17 && cpid <= 0x20) {
matched = true;
}
} else if (mfid == 0x50) {
if (cpid >= 0x15 && cpid <= 0x16) {
matched = true;
}
}
return matched;
}
esp_err_t bootloader_xmc_flash_overerase_fix()
{
#if CONFIG_BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
//correct RDID value means the issue doesn't occur
if (is_xmc_chip_strict(g_rom_flashchip.device_id)) {
return ESP_OK;
}
#endif
// Check vendor ID in SFDP registers. If not XMC chip, no need to run the patch
uint8_t mf_id = (bootloader_flash_read_sfdp(0x10, 1) & 0xff);
if (mf_id != XMC_VENDOR_ID) {
return ESP_OK;
}
ESP_LOGI(TAG, "XM25QHxxC flash overerase fix");
// Enter DPD
execute_flash_command(0xB9, 0, 0, 0);
// Enter UDPD
execute_flash_command(0x79, 0, 0, 0);
// Exit UDPD
execute_flash_command(0xFF, 0, 0, 0);
// Delay tXUDPD
ets_delay_us(2000);
// Release Power-down
execute_flash_command(0xAB, 0, 0, 0);
ets_delay_us(20);
// Read flash ID and check
g_rom_flashchip.device_id = bootloader_read_flash_id();
if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
// fail
ESP_LOGE(TAG, "XM25QH32C flash overerase fix fail");
return ESP_FAIL;
}
return ESP_OK;
}
@@ -121,6 +121,7 @@ extern "C" {
#define ESP_ROM_SPIFLASH_BP2 BIT4
#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2)
#define ESP_ROM_SPIFLASH_QE BIT9
#define ESP_ROM_SPIFLASH_BP_MASK_EON (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2)
//Extra dummy for flash read
#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0
@@ -340,3 +340,9 @@ static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
dev->user.usr_dummy = dummy_n ? 1 : 0;
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
}
static inline void spi_flash_ll_set_cs_setup(spi_dev_t *dev, uint32_t cs_setup_time)
{
dev->user.cs_setup = (cs_setup_time > 0 ? 1 : 0);
dev->ctrl2.setup_time = cs_setup_time - 1;
}
@@ -38,6 +38,7 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *host)
spi_flash_ll_reset(dev);
spi_flash_ll_set_cs_pin(dev, drv_data->cs_num);
spi_flash_ll_set_clock(dev, &drv_data->clock_conf);
spi_flash_ll_set_cs_setup(dev, 1);
/*
* workaround for the ROM: the ROM, as well as the OpenOCD, don't know the
+1 -1
View File
@@ -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
+11
View File
@@ -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 -1
View File
@@ -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;
+38 -14
View File
@@ -24,6 +24,11 @@
extern esp_rom_spiflash_chip_t g_rom_spiflash_chip;
static inline bool is_eon_chip(const esp_rom_spiflash_chip_t* chip)
{
return ((((chip->device_id >> 16)&0xff)) == 0x1C && (((chip->device_id >> 8)&0xff) == 0x70));
}
esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi)
{
uint32_t status;
@@ -53,33 +58,52 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp
about interrupts, CPU coordination, flash mapping. However some of
the functions in esp_spi_flash.c call it.
*/
esp_rom_spiflash_result_t esp_rom_spiflash_unlock()
esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void)
{
uint32_t status;
uint32_t new_status;
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}
if (is_eon_chip(&g_rom_spiflash_chip)) {
// Eon chips have different QE position
/* Clear all bits except QIE, if it is set.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
status &= ESP_ROM_SPIFLASH_QE;
if (esp_rom_spiflash_read_status(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}
/* Clear all bits in the mask.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
new_status = status & (~ESP_ROM_SPIFLASH_BP_MASK_EON);
// Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing.
if (new_status == status) return ESP_ROM_SPIFLASH_RESULT_OK;
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
} else {
if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
}
/* Clear all bits except QE, if it is set.
(This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.)
*/
new_status = status & ESP_ROM_SPIFLASH_QE;
SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
}
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN);
while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) {
}
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B);
if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, status) != ESP_ROM_SPIFLASH_RESULT_OK) {
return ESP_ROM_SPIFLASH_RESULT_ERR;
esp_rom_spiflash_result_t ret = esp_rom_spiflash_write_status(&g_rom_spiflash_chip, new_status);
// WEL bit should be cleared after operations regardless of writing succeed or not.
esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip);
REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WRDI);
while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) {
}
return ESP_ROM_SPIFLASH_RESULT_OK;
return ret;
}
@@ -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
--------
@@ -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`.
+28 -1
View File
@@ -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
@@ -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)
@@ -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
@@ -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,
};
@@ -0,0 +1,3 @@
idf_component_register(SRCS "main.c"
PRIV_REQUIRES custom_chip_driver
INCLUDE_DIRS "")
@@ -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,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);
}
}
@@ -0,0 +1,2 @@
CONFIG_SPI_FLASH_USE_LEGACY_IMPL=n
CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST=y