External flash component
External flash component
Not a big project, but it might come in handy for somebody:
https://github.com/lllucius/esp32_extflash
It should work with most flash chips that uses 24-bit addressing and there's additional support for Winbond w25q series of chips.
Standard, Dual, DIO, Quad, QIO, and QPI protocols are all supported.
https://github.com/lllucius/esp32_extflash
It should work with most flash chips that uses 24-bit addressing and there's additional support for Winbond w25q series of chips.
Standard, Dual, DIO, Quad, QIO, and QPI protocols are all supported.
Re: External flash component
Hi, first of all congrats on the great work! I've tested your libraries using reading tests and the results were very good.
However, do you have any idea why the write test wouldn't work on a Cypress S25FL164K ?
The setup that I'm using is:
- ESP32D0WDQ6 chip
- S25FL164K 8MB external flash hooked-up on SPI via GPIO MUX
I've tried doing some debugging, but without any success.
I've made sure that I properly mapped the commands lists to my chip by analogy with Winbond's chip (the majority of them were the same):
I'm only running the wb_w25q_dual test, but all of them fail.
While debugging I've printed the error messages to the console and they all return ESP_OK (this being 0):
Result:
However, do you have any idea why the write test wouldn't work on a Cypress S25FL164K ?
The setup that I'm using is:
- ESP32D0WDQ6 chip
- S25FL164K 8MB external flash hooked-up on SPI via GPIO MUX
Code: Select all
#define PIN_SPI_MOSI GPIO_NUM_25 // PIN 5 - IO0 - DI
#define PIN_SPI_MISO GPIO_NUM_26 // PIN 2 - IO1 - DO
#define PIN_SPI_WP GPIO_NUM_13 // PIN 3 - IO2 - /WP
#define PIN_SPI_HD GPIO_NUM_14 // PIN 7 - IO3 - /HOLD - /RESET
#define PIN_SPI_SCK GPIO_NUM_27 // PIN 6 - CLK - CLK
#define PIN_SPI_SS GPIO_NUM_15 // PIN 1 - /CS - /CS
I've made sure that I properly mapped the commands lists to my chip by analogy with Winbond's chip (the majority of them were the same):
Code: Select all
//in extflash.h
#define CMD_WRITE_STATUS_REG1 0x01
#define CMD_PAGE_PROGRAM 0x02
#define CMD_READ_DATA 0x03
#define CMD_READ_STATUS_REG1 0x05
#define CMD_WRITE_ENABLE 0x06
#define CMD_FAST_READ 0x0b
#define CMD_SECTOR_ERASE 0x20
#define CMD_READ_SFDP 0x5a
#define CMD_ENABLE_RESET 0x66
#define CMD_RESET_DEVICE 0x99
#define CMD_READ_JEDEC_ID 0x9f
#define CMD_CHIP_ERASE 0xc7
Code: Select all
//in wb_w25q_base.h
#define CMD_WRITE_STATUS_REG2 0x01
#define CMD_READ_STATUS_REG2 0x35
#define CMD_ENTER_QPI_MODE 0x38
#define CMD_FAST_READ_DUAL_OUTPUT 0x3b
#define CMD_SR_WRITE_ENABLE 0x50
#define CMD_BLOCK_ERASE_32K 0x52
#define CMD_FAST_READ_QUAD_OUTPUT 0x6b
#define CMD_FAST_READ_DUAL_IO 0xbb
#define CMD_SET_READ_PARAMETERS 0xc0
#define CMD_BLOCK_ERASE_64K 0xd8
#define CMD_OCTAL_WORD_READ_QUAD_IO 0xe3
#define CMD_WORD_READ_QUAD_IO 0xe7
#define CMD_FAST_READ_QUAD_IO 0xeb
#define CMD_EXIT_QPI_MODE 0xff
While debugging I've printed the error messages to the console and they all return ESP_OK (this being 0):
Code: Select all
printf("Erase error code: %d \n",flash.erase_sector(addr / sector_sz));
printf("Write error code: %d \n",flash.write(addr, wbuf, sector_sz));
printf("Read error code: %d \n",flash.read(addr, rbuf, sector_sz));
Code: Select all
ERRASE/WRITE/VERIFY Test...
Bus
Proto Cycles
dual 1-1-2
Flash size 83388608
Sector size 4096
Erase error code: 0
Write error code: 0
Read error code: 0
addr = 0
erase/write/verify failed at block 0 offset 0
Done...
Re: External flash component
The chips do look very similar, so I'm as confused as you. But, some things to try:
In the write_enable() method, add a call to read_status_register1() and print the result. What you're looking for is that bit 1 is on (you should probably get back a value of 0x02).
You might want to also display the value of status register 2 by printing it value in read_status_register2().
Just want to verify that the chip is in an expected mode and that stuff like block protection isn't enabled.
You could also try adding a chip_erase() call. It should take many seconds to return.
In the write_enable() method, add a call to read_status_register1() and print the result. What you're looking for is that bit 1 is on (you should probably get back a value of 0x02).
You might want to also display the value of status register 2 by printing it value in read_status_register2().
Just want to verify that the chip is in an expected mode and that stuff like block protection isn't enabled.
You could also try adding a chip_erase() call. It should take many seconds to return.
- Vader_Mester
- Posts: 300
- Joined: Tue Dec 05, 2017 8:28 pm
- Location: Hungary
- Contact:
Re: External flash component
Illuscius: Does your driver sends a Write enable command to the Flash?
hgptamn: If you can read, you should read out the registers and check for write enable and write protection bits, so you can make sure the flash can be written.
hgptamn: If you can read, you should read out the registers and check for write enable and write protection bits, so you can make sure the flash can be written.
Code: Select all
task_t coffeeTask()
{
while(atWork){
if(!xStreamBufferIsEmpty(mug)){
coffeeDrink(mug);
} else {
xTaskCreate(sBrew, "brew", 9000, &mug, 1, NULL);
xSemaphoreTake(sCoffeeRdy, portMAX_DELAY);
}
}
vTaskDelete(NULL);
}
Re: External flash component
Thanks for the tip!
I think that I might have found out what's the problem: register 1 and 2 seem to not be set up properly.
But why? I will take a closer look into this and come up with an update when I figure it out.
Later edit:
Ok, so the write_enable method looks like this:
The S25FL164K datasheet states:
I think that I might have found out what's the problem: register 1 and 2 seem to not be set up properly.
But why? I will take a closer look into this and come up with an update when I figure it out.
Code: Select all
ERASE/WRITE/VERIFY Test...
Bus
dual 1-1-2
Flash size 8388608
Sector size 4096
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Erase error code: 0
Register 1 result binary = 00000000
Registeer 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 000001100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result deciaml = 4
WWrite enabled!
Write error code: 0
Read error code: 0
addr = 0
erase/write/verify failed at block 0 offset 0
Done...
Ok, so the write_enable method looks like this:
Code: Select all
void ExtFlash::write_enable()
{
uint8_t reg1_result, reg2_result;
cmd(CMD_WRITE_ENABLE);
reg1_result = read_status_register1();
reg2_result = read_status_register2();
printf("Register 1 result binary = "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(reg1_result));
printf("\n Register 1 result decimal = %d \n",reg1_result);
printf("Register 2 result binary = "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(reg2_result));
printf("\n Register 2 result decimal = %d \n",reg2_result);
}
I doubt void ExtFlash::cmd(uint8_t cmd) methond is the one causing the problem. Instead, I would assume there's something wrong with either spi_transaction_ext_t *ExtFlash::cmd_prolog() or void ExtFlash::cmd_epilog(spi_transaction_ext_t *t), but these methods seem to work fine when it comes to reading. Any idea on the problem?8.1.2 Write Enable (06h)
The Write Enable command (Figure 35) sets the Write Enable Latch (WEL) bit in the Status Register to a 1. The WEL bit must be set
prior to every Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Registers and Erase / Program Security
Registers command. The Write Enable command is entered by driving CS# low, shifting the instruction code “06h” into the Data
Input (SI) pin on the rising edge of SCK, and then driving CS# high.
Re: External flash component
Grasping at straws here, but when was the last time you updated your esp-idf SDK? There was a bug I'd reported that "may" be relevant here and it was fixed on December 12th:
https://github.com/espressif/esp-idf/issues/1549
https://github.com/espressif/esp-idf/issues/1549
Re: External flash component
So i was on:lllucius wrote:Grasping at straws here, but when was the last time you updated your esp-idf SDK? There was a bug I'd reported that "may" be relevant here and it was fixed on December 12th:
https://github.com/espressif/esp-idf/issues/1549
Code: Select all
ESP-IDF v3.1-dev-380-gca3faa61 2nd stage bootloader
Code: Select all
ESP-IDF v3.1-dev-443-g17e8d49f 2nd stage bootloader
I've noticed a difference while mapping the commands for the particular Cypress flash that I'm using: status register 1 and status register 2 are both written using the same command 0x01h, while the Winbonds flash that you've designed the library for use 0x01h for the first status register and 0x31h for the 2'nd. I don't see why, but could this be the problem?
I've mapped them in the following way (as posted in the first post):
Code: Select all
#define CMD_WRITE_STATUS_REG2 0x01
#define CMD_WRITE_STATUS_REG1 0x01
Re: External flash component
Good eyeballs! I totally missed that.
And yes, it would matter in the bigger picture. The is an example of why I made nearly all of the methods virtual. There "seems" to be a general flash "standard", but there seems to be slight differences here an there that must be handled by chip specific code.
But in your case, I don't think it matters at this point since the only thing you'd be using reg2 for is the QE bit and you're working with dual. And write_status_register1 isn't being called from anywhere.
That still doesn't explain why the "write enable" command isn't setting the WEL bit in SR1.
For the heck of it, can you add a call to "vTaskDelay(1000);" after the cmd() call in write_enable(). Just trying to see if there's some sort of timing issue.
Also, have you tried just plain old non-dual mode? I really don't think it'd matter, but it "might" tell us "something".
And yes, it would matter in the bigger picture. The is an example of why I made nearly all of the methods virtual. There "seems" to be a general flash "standard", but there seems to be slight differences here an there that must be handled by chip specific code.
But in your case, I don't think it matters at this point since the only thing you'd be using reg2 for is the QE bit and you're working with dual. And write_status_register1 isn't being called from anywhere.
That still doesn't explain why the "write enable" command isn't setting the WEL bit in SR1.
For the heck of it, can you add a call to "vTaskDelay(1000);" after the cmd() call in write_enable(). Just trying to see if there's some sort of timing issue.
Also, have you tried just plain old non-dual mode? I really don't think it'd matter, but it "might" tell us "something".
Re: External flash component
I've added the 1s delay as suggested and also switched to std test and the results are the same:
I also don't see why the write_enable() method doesn't set the WEL bit in SR1.
I've attached the modified library that I'm using if you want to take a look into this. I think I've spent more than 24hrs total looking for the problem; still haven't found it. As mentioned earlier reading tests work like a charm, the writing is the culprit.
Code: Select all
ERASE/WRITE/VERIFY Test...
Bus
std 1-1-1
Flash size 8388608
Sector size 4096
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result decimal = 4
Erase error code: 0
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result decimal = 4
Write enabled!
Register 1 result binary = 00000000
Register 1 result decimal = 0
Register 2 result binary = 00000100
Register 2 result decimal = 4
Write enabled!
.......
I've attached the modified library that I'm using if you want to take a look into this. I think I've spent more than 24hrs total looking for the problem; still haven't found it. As mentioned earlier reading tests work like a charm, the writing is the culprit.
- Attachments
-
- esp32_extflash-master.zip
- (13.19 MiB) Downloaded 995 times
Re: External flash component
It all "looks" good. I'm really starting to wonder if reading is actually working. Even though the esp32 SPI transactions complete normally, that's not a guarantee that they really did work since there's no success/failure response from the chip.
The only thing I can think to check is the wiring and pin assignments, though I'm sure they're okay since the CMD_READ_SFDP or CMD_READ_JEDEC_ID must have worked to determine the sector size and chip capacity.
I would buy a chip from mouser to help debug, but I don't have access to my soldering stuff right now (I solder in the garage and it's about 30F out there).
The only thing I can think to check is the wiring and pin assignments, though I'm sure they're okay since the CMD_READ_SFDP or CMD_READ_JEDEC_ID must have worked to determine the sector size and chip capacity.
I would buy a chip from mouser to help debug, but I don't have access to my soldering stuff right now (I solder in the garage and it's about 30F out there).
Who is online
Users browsing this forum: No registered users and 9 guests