Skip to content

Commit 5045f29

Browse files
committed
When sending instruction Write Enable 0x06, use BootROM API
SPI_write_enable for the special handling of the WEL bit. Corrected zero mask for fractional byte returns where the partial byte bits are positioned at the most significant bit position in the byte.
1 parent ad60987 commit 5045f29

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

cores/esp8266/core_esp8266_spi_utils.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "core_esp8266_features.h"
3333

3434
#include "spi_utils.h"
35+
#include "spi_flash_defs.h"
3536

3637
extern "C" uint32_t Wait_SPI_Idle(SpiFlashChip *fc);
3738

@@ -65,6 +66,7 @@ _SPICommand(volatile uint32_t spiIfNum,
6566
// Everything defined here must be volatile or the optimizer can
6667
// treat them as constants, resulting in the flash reads we're
6768
// trying to avoid
69+
SpiFlashOpResult (* volatile SPI_write_enablep)(SpiFlashChip *) = SPI_write_enable;
6870
uint32_t (* volatile Wait_SPI_Idlep)(SpiFlashChip *) = Wait_SPI_Idle;
6971
volatile SpiFlashChip *fchip=flashchip;
7072
volatile uint32_t spicmdusr=SPICMDUSR;
@@ -85,8 +87,13 @@ _SPICommand(volatile uint32_t spiIfNum,
8587
uint32_t oldSPI0C = SPIREG(SPI0C);
8688

8789
SPIREG(SPI0C) = spic;
90+
91+
if (SPI_FLASH_CMD_WREN == pre_cmd) {
92+
// See SPI_write_enable comments in esp8266_undocumented.h
93+
SPI_write_enablep((SpiFlashChip *)fchip);
94+
} else
8895
if (pre_cmd) {
89-
// Send prefix cmd w/o data - sends 8 bits - usually a Write Enable cmd
96+
// Send prefix cmd w/o data - sends 8 bits. eg. Volatile SR Write Enable, 0x50
9097
SPIREG(SPI0U) = (spiu & ~(SPIUMOSI|SPIUMISO));
9198
SPIREG(SPI0U1) = 0;
9299
SPIREG(SPI0U2) = (spiu2 & ~0xFFFFu) | pre_cmd;
@@ -166,25 +173,29 @@ _SPICommand(volatile uint32_t spiIfNum,
166173
* be separated by SPI Flash read request for iCache, use this option to
167174
* supply a prefix command, 8-bits w/o read or write data.
168175
*
176+
* Case in point from the GD25Q32E datasheet: "The Write Enable for Volatile
177+
* Status Register command must be issued prior to a Write Status Register
178+
* command and any other commands can’t be inserted between them."
179+
*
169180
* Note: This code has only been tested with SPI bus 0, but should work
170181
* equally well with other buses. The ESP8266 has bus 0 and 1,
171182
* newer chips may have more one day.
172183
*
173184
* Supplemental Notes:
174185
*
175-
* SPI Bus view: For *data as an array of bytes, byte[0] goes out first wit
176-
* the most significant bit shifted out first and so on. When thinking of th
177-
* data as an array of 32bit-words, the least significant byte of the first
178-
* 32bit-word goes out first on the SPI bus with the most significant bit of
179-
* that byte shifted out first onto the wire.
186+
* SPI Bus wire view: Think of *data as an array of bytes, byte[0] goes out
187+
* first with the most significant bit shifted out first and so on. When
188+
* thinking of the data as an array of 32bit-words, the least significant byte
189+
* of the first 32bit-word goes out first on the SPI bus with the most
190+
* significant bit of that byte shifted out first onto the wire.
180191
*
181192
* When presenting a 3 or 4-byte address, the byte order will need to be
182193
* reversed. Don't overthink it. For a 3-byte address, view *data as a byte
183194
* array and set the first 3-bytes to the address. eg. byteData[0] MSB,
184195
* byteData[1] middle, and byteData[2] LSB.
185196
*
186197
* When sending a fractional byte, fill in the most significant bit positions
187-
* first.
198+
* of the byte first.
188199
*/
189200
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits, uint32_t pre_cmd) {
190201
if (mosi_bits>(64*8))
@@ -236,9 +247,16 @@ SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_
236247
SpiOpResult rc =_SPICommand(0,spic,spiu,spiu1,spiu2,data,mosi_words,miso_words,pre_cmd);
237248

238249
if (rc==SPI_RESULT_OK) {
239-
// clear any bits we did not read in the last word.
240-
if (miso_bits % 32) {
241-
data[miso_bits/32] &= ~(0xFFFFFFFF << (miso_bits % 32));
250+
// Clear any bits we did not read in the last word. Bits in a fractional
251+
// bytes will be stored in the most significant part of the byte first.
252+
if (miso_bits % 32u) {
253+
uint32_t whole_byte_bits = (miso_bits % 32u) & ~7u;
254+
uint32_t mask = ~(0xFFFFFFFFu << whole_byte_bits);
255+
if (miso_bits % 8u) {
256+
// Select fractional byte bits.
257+
mask |= (~(0xFFu >> (miso_bits % 8u)) & 0xFFu) << whole_byte_bits;
258+
}
259+
data[miso_bits/32u] &= mask;
242260
}
243261
}
244262
return rc;

cores/esp8266/esp8266_undocumented.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,17 @@ extern fn_c_exception_handler_t _xtos_c_handler_table[XCHAL_EXCCAUSE_NUM];
241241
extern fn_c_exception_handler_t _xtos_set_exception_handler(int cause, fn_c_exception_handler_t fn);
242242
#endif
243243

244+
/*
245+
BootROM function that sends the SPI Flash "Write Enable" command, 0x06.
246+
The function internally calls Wait_SPI_Idle before enabling.
247+
Polls status register forever waiting for WEL bit to set.
248+
This function always returns 0; however, most examples test for 0.
249+
250+
Every function I find that needs WEL set, call this function. I suspect the
251+
waiting for the WEL bit to set is a Flash chip anomaly workaround.
252+
*/
253+
extern SpiFlashOpResult SPI_write_enable(SpiFlashChip *fc);
254+
244255
extern uint32_t Wait_SPI_Idle(SpiFlashChip *fc);
245256
extern void Cache_Read_Disable();
246257
extern int32_t system_func1(uint32_t);

cores/esp8266/spi_utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ typedef enum {
3535
SPI_RESULT_TIMEOUT
3636
} SpiOpResult;
3737

38-
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits, uint32_t prefix=0);
38+
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits, uint32_t pre_cmd=0);
3939
}
4040

4141
#ifdef __cplusplus

0 commit comments

Comments
 (0)