Skip to content

Commit 37debb1

Browse files
committed
Merge remote-tracking branch 'origin/master' into path-args/fix9100
2 parents 9980d2c + c2f1365 commit 37debb1

5 files changed

+96
-15
lines changed

cores/esp8266/core_esp8266_flash_quirks.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,13 @@ void initFlashQuirks() {
6666
newSR3=SR3;
6767
if (get_flash_mhz()>26) { // >26Mhz?
6868
// Set the output drive to 100%
69+
// These definitions are for the XM25QH32B part. On a XM25QH32C
70+
// part, the XM25QH32B's 100% is C's 25% driver strength.
6971
newSR3 &= ~(SPI_FLASH_SR3_XMC_DRV_MASK << SPI_FLASH_SR3_XMC_DRV_S);
7072
newSR3 |= (SPI_FLASH_SR3_XMC_DRV_100 << SPI_FLASH_SR3_XMC_DRV_S);
7173
}
7274
if (newSR3 != SR3) { // only write if changed
73-
if (SPI0Command(SPI_FLASH_CMD_WEVSR,NULL,0,0)==SPI_RESULT_OK) // write enable volatile SR
74-
SPI0Command(SPI_FLASH_CMD_WSR3,&newSR3,8,0); // write to SR3
75+
SPI0Command(SPI_FLASH_CMD_WSR3,&newSR3,8,0,SPI_FLASH_CMD_WEVSR); // write to SR3, use write enable volatile prefix
7576
SPI0Command(SPI_FLASH_CMD_WRDI,NULL,0,0); // write disable - probably not needed
7677
}
7778
}

cores/esp8266/core_esp8266_main.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
//#define CONT_STACKSIZE 4096
2525

2626
#include <numeric>
27+
#include <exception>
2728

2829
#include <Arduino.h>
2930
#include "Schedule.h"

cores/esp8266/core_esp8266_spi_utils.cpp

+80-12
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

@@ -51,12 +52,12 @@ namespace experimental {
5152
static SpiOpResult PRECACHE_ATTR
5253
_SPICommand(volatile uint32_t spiIfNum,
5354
uint32_t spic,uint32_t spiu,uint32_t spiu1,uint32_t spiu2,
54-
uint32_t *data,uint32_t writeWords,uint32_t readWords)
55+
uint32_t *data,uint32_t writeWords,uint32_t readWords, uint32_t pre_cmd)
5556
{
5657
if (spiIfNum>1)
5758
return SPI_RESULT_ERR;
5859

59-
// force SPI register access via base+offset.
60+
// force SPI register access via base+offset.
6061
// Prevents loading individual address constants from flash.
6162
uint32_t *spibase = (uint32_t*)(spiIfNum ? &(SPI1CMD) : &(SPI0CMD));
6263
#define SPIREG(reg) (*((volatile uint32_t *)(spibase+(&(reg) - &(SPI0CMD)))))
@@ -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;
@@ -77,15 +79,30 @@ _SPICommand(volatile uint32_t spiIfNum,
7779
PRECACHE_START();
7880
Wait_SPI_Idlep((SpiFlashChip *)fchip);
7981
}
80-
82+
8183
// preserve essential controller state such as incoming/outgoing
8284
// data lengths and IO mode.
8385
uint32_t oldSPI0U = SPIREG(SPI0U);
8486
uint32_t oldSPI0U2= SPIREG(SPI0U2);
8587
uint32_t oldSPI0C = SPIREG(SPI0C);
8688

87-
//SPI0S &= ~(SPISE|SPISBE|SPISSE|SPISCD);
8889
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
95+
if (pre_cmd) {
96+
// Send prefix cmd w/o data - sends 8 bits. eg. Volatile SR Write Enable, 0x50
97+
SPIREG(SPI0U) = (spiu & ~(SPIUMOSI|SPIUMISO));
98+
SPIREG(SPI0U1) = 0;
99+
SPIREG(SPI0U2) = (spiu2 & ~0xFFFFu) | pre_cmd;
100+
101+
SPIREG(SPI0CMD) = spicmdusr; //Send cmd
102+
while ((SPIREG(SPI0CMD) & spicmdusr));
103+
}
104+
105+
//SPI0S &= ~(SPISE|SPISBE|SPISSE|SPISCD);
89106
SPIREG(SPI0U) = spiu;
90107
SPIREG(SPI0U1)= spiu1;
91108
SPIREG(SPI0U2)= spiu2;
@@ -117,11 +134,22 @@ _SPICommand(volatile uint32_t spiIfNum,
117134
SPIREG(SPI0U) = oldSPI0U;
118135
SPIREG(SPI0U2)= oldSPI0U2;
119136
SPIREG(SPI0C) = oldSPI0C;
120-
121-
PRECACHE_END();
137+
122138
if (!spiIfNum) {
139+
// w/o a call to Wait_SPI_Idlep, 'Exception 0' or other exceptions (saw
140+
// 28) may occur later after returning to iCache code. This issue was
141+
// observed with non-volatile status register writes.
142+
//
143+
// My guess is: Returning too soon to uncached iCache executable space. An
144+
// iCache read may not complete properly because the Flash or SPI
145+
// interface is still busy with the last write operation. In such a case,
146+
// I expect new reads from iROM to result in zeros. This would explain
147+
// the Exception 0 for code, and Exception 20, 28, and 29 where a literal
148+
// was misread as 0 and then used as a pointer.
149+
Wait_SPI_Idlep((SpiFlashChip *)fchip);
123150
xt_wsr_ps(saved_ps);
124151
}
152+
PRECACHE_END();
125153
return (timeout>0 ? SPI_RESULT_OK : SPI_RESULT_TIMEOUT);
126154
}
127155

@@ -139,12 +167,37 @@ _SPICommand(volatile uint32_t spiIfNum,
139167
* miso_bits
140168
* Number of bits to read from the SPI bus after the outgoing
141169
* data has been sent.
170+
* pre_cmd
171+
* A few SPI Flash commands require enable commands to immediately preceed
172+
* them. Since two calls to SPI0Command from ICACHE memory most likely would
173+
* be separated by SPI Flash read request for iCache, use this option to
174+
* supply a prefix command, 8-bits w/o read or write data.
175+
*
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."
142179
*
143180
* Note: This code has only been tested with SPI bus 0, but should work
144181
* equally well with other buses. The ESP8266 has bus 0 and 1,
145182
* newer chips may have more one day.
183+
*
184+
* Supplemental Notes:
185+
*
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.
191+
*
192+
* When presenting a 3 or 4-byte address, the byte order will need to be
193+
* reversed. Don't overthink it. For a 3-byte address, view *data as a byte
194+
* array and set the first 3-bytes to the address. eg. byteData[0] MSB,
195+
* byteData[1] middle, and byteData[2] LSB.
196+
*
197+
* When sending a fractional byte, fill in the most significant bit positions
198+
* of the byte first.
146199
*/
147-
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits) {
200+
SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits, uint32_t pre_cmd) {
148201
if (mosi_bits>(64*8))
149202
return SPI_RESULT_ERR;
150203
if (miso_bits>(64*8))
@@ -159,8 +212,16 @@ SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_
159212
if (miso_bits % 32 != 0)
160213
miso_words++;
161214

215+
// Use SPI_CS_SETUP to add time for #CS to settle (ringing) before SPI CLK
216+
// begins. The BootROM does not do this; however, RTOS SDK and NONOS SDK do
217+
// as part of flash init/configuration.
218+
//
219+
// One SPI bus clock cycle time inserted between #CS active and the 1st SPI
220+
// bus clock cycle. The number of clock cycles is in SPI_CNTRL2
221+
// SPI_SETUP_TIME, which defaults to 1.
222+
//
162223
// Select user defined command mode in the controller
163-
uint32_t spiu=SPIUCOMMAND; //SPI_USR_COMMAND
224+
uint32_t spiu=SPIUCOMMAND | SPIUCSSETUP; //SPI_USR_COMMAND | SPI_CS_SETUP
164225

165226
// Set the command byte to send
166227
uint32_t spiu2 = ((7 & SPIMCOMMAND)<<SPILCOMMAND) | cmd;
@@ -183,12 +244,19 @@ SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_
183244
spic &= ~(SPICQIO | SPICDIO | SPICQOUT | SPICDOUT | SPICAHB | SPICFASTRD);
184245
spic |= (SPICRESANDRES | SPICSHARE | SPICWPR | SPIC2BSE);
185246

186-
SpiOpResult rc =_SPICommand(0,spic,spiu,spiu1,spiu2,data,mosi_words,miso_words);
247+
SpiOpResult rc =_SPICommand(0,spic,spiu,spiu1,spiu2,data,mosi_words,miso_words,pre_cmd);
187248

188249
if (rc==SPI_RESULT_OK) {
189-
// clear any bits we did not read in the last word.
190-
if (miso_bits % 32) {
191-
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;
192260
}
193261
}
194262
return rc;

cores/esp8266/esp8266_undocumented.h

+11
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

+1-1
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);
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)