3232#include " core_esp8266_features.h"
3333
3434#include " spi_utils.h"
35+ #include " spi_flash_defs.h"
3536
3637extern " C" uint32_t Wait_SPI_Idle (SpiFlashChip *fc);
3738
@@ -51,12 +52,12 @@ namespace experimental {
5152static 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;
0 commit comments