External flash component

lllucius
Posts: 13
Joined: Sun Feb 11, 2018 9:02 am

External flash component

Postby lllucius » Sun Feb 11, 2018 9:18 am

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.

hgptamn
Posts: 26
Joined: Mon Oct 16, 2017 4:47 pm

Re: External flash component

Postby hgptamn » Fri Mar 02, 2018 10:46 am

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

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 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):

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
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):

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));
Result:

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...

lllucius
Posts: 13
Joined: Sun Feb 11, 2018 9:02 am

Re: External flash component

Postby lllucius » Fri Mar 02, 2018 4:55 pm

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.

User avatar
Vader_Mester
Posts: 300
Joined: Tue Dec 05, 2017 8:28 pm
Location: Hungary
Contact:

Re: External flash component

Postby Vader_Mester » Sat Mar 03, 2018 1:57 pm

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.

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);
}

hgptamn
Posts: 26
Joined: Mon Oct 16, 2017 4:47 pm

Re: External flash component

Postby hgptamn » Mon Mar 05, 2018 10:24 am

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.

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...

Later edit:
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);
}
The S25FL164K datasheet states:
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.
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?

lllucius
Posts: 13
Joined: Sun Feb 11, 2018 9:02 am

Re: External flash component

Postby lllucius » Mon Mar 05, 2018 3:34 pm

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

hgptamn
Posts: 26
Joined: Mon Oct 16, 2017 4:47 pm

Re: External flash component

Postby hgptamn » Mon Mar 05, 2018 5:58 pm

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
So i was on:

Code: Select all

ESP-IDF v3.1-dev-380-gca3faa61 2nd stage bootloader
Now, I've updated to the latest version:

Code: Select all

ESP-IDF v3.1-dev-443-g17e8d49f 2nd stage bootloader
The results are the same as in the previous posts :(
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

lllucius
Posts: 13
Joined: Sun Feb 11, 2018 9:02 am

Re: External flash component

Postby lllucius » Mon Mar 05, 2018 7:38 pm

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".

hgptamn
Posts: 26
Joined: Mon Oct 16, 2017 4:47 pm

Re: External flash component

Postby hgptamn » Tue Mar 06, 2018 9:38 am

I've added the 1s delay as suggested and also switched to std test and the results are the same:

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 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.
Attachments
esp32_extflash-master.zip
(13.19 MiB) Downloaded 735 times

lllucius
Posts: 13
Joined: Sun Feb 11, 2018 9:02 am

Re: External flash component

Postby lllucius » Tue Mar 06, 2018 3:56 pm

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). :-)

Who is online

Users browsing this forum: No registered users and 42 guests