Skip to content

Commit e011d38

Browse files
committed
Extend SPI to use SPI0 pins and add Dual and Quad modes
1 parent b39146d commit e011d38

File tree

3 files changed

+190
-24
lines changed

3 files changed

+190
-24
lines changed

cores/esp8266/esp8266_peri.h

+1
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ extern uint8_t esp8266_gpioToFn[16];
489489
#define SPIUCSSETUP (1 << 5) //SPI_CS_SETUP
490490
#define SPIUCSHOLD (1 << 4) //SPI_CS_HOLD
491491
#define SPIUAHBUCMD (1 << 3) //SPI_AHB_USR_COMMAND
492+
#define SPIUFLASHMODE (1 << 2) //SPI_FLASH_MODE
492493
#define SPIUAHBUCMD4B (1 << 1) //SPI_AHB_USR_COMMAND_4BYTE
493494
#define SPIUDUPLEX (1 << 0) //SPI_DOUTDIN
494495

libraries/SPI/SPI.cpp

+174-21
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "SPI.h"
2323
#include "HardwareSerial.h"
2424

25+
#define SPI_FLASH_READ_MODE_MASK 0x196000
26+
2527
typedef union {
2628
uint32_t regValue;
2729
struct {
@@ -37,49 +39,200 @@ SPIClass SPI;
3739

3840
SPIClass::SPIClass() {
3941
useHwCs = false;
42+
LastUsedDev = HSPI_IDLE;
43+
}
44+
45+
void SPIClass::RegBackup(uint32 backup_mem[7])
46+
{
47+
uint8_t ptr = 0;
48+
49+
backup_mem[ptr++] = SPI1CMD;
50+
backup_mem[ptr++] = SPI1C;
51+
backup_mem[ptr++] = SPI1CLK;
52+
backup_mem[ptr++] = SPI1U;
53+
backup_mem[ptr++] = SPI1U1;
54+
backup_mem[ptr++] = SPI1U2;
55+
backup_mem[ptr] = SPI1P;
56+
}
57+
58+
void SPIClass::RegRestore(uint32 backup_mem[7])
59+
{
60+
uint8_t ptr = 0;
61+
62+
SPI1CMD = backup_mem[ptr++];
63+
SPI1C = backup_mem[ptr++];
64+
SPI1CLK = backup_mem[ptr++];
65+
SPI1U = backup_mem[ptr++];
66+
SPI1U1 = backup_mem[ptr++];
67+
SPI1U2 = backup_mem[ptr++];
68+
SPI1P = backup_mem[ptr];
69+
}
70+
71+
void SPIClass::OverlapInit(void)
72+
{
73+
// Enable HSPI overlap to SPI, Two SPI Masters on CSPI
74+
IOSWAP |= IOSWAP2CS;
75+
76+
// Set higher priority for SPI than HSPI and enable HwCs
77+
SPI0E3 |= 0x1;
78+
SPI1E3 |= 0x3;
79+
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD);
4080
}
4181

42-
void SPIClass::begin() {
43-
pinMode(SCK, SPECIAL); ///< GPIO14
44-
pinMode(MISO, SPECIAL); ///< GPIO12
45-
pinMode(MOSI, SPECIAL); ///< GPIO13
82+
void SPIClass::OverlapDeinit(void)
83+
{
84+
// Disable HSPI overlap to SPI, Two SPI Masters on CSPI
85+
IOSWAP &= ~IOSWAP2CS;
4686

47-
SPI1C = 0;
48-
setFrequency(1000000); ///< 1MHz
49-
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
50-
SPI1U1 = (7 << SPILMOSI) | (7 << SPILMISO);
51-
SPI1C1 = 0;
87+
// Set higher priority for HSPI than SPI and disable HwCs
88+
SPI0E3 &= ~0x1;
89+
SPI1E3 &= ~0x3;
90+
SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD);
5291
}
5392

54-
void SPIClass::end() {
55-
pinMode(SCK, INPUT);
56-
pinMode(MISO, INPUT);
57-
pinMode(MOSI, INPUT);
58-
if(useHwCs) {
59-
pinMode(SS, INPUT);
93+
void SPIClass::begin(spi_devno dev_no) {
94+
while(SPI1CMD & SPIBUSY) {}
95+
96+
SPISettings settings = {ESP8266_CLOCK, LSBFIRST, SPI_MODE0};
97+
switch(dev_no){
98+
case HSPI_CS_DEV :
99+
pinMode(SCK, SPECIAL); ///< GPIO14
100+
pinMode(MISO, SPECIAL); ///< GPIO12
101+
pinMode(MOSI, SPECIAL); ///< GPIO13
102+
103+
SPI1C = 0;
104+
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
105+
SPI1U1 = (7 << SPILMOSI) | (7 << SPILMISO);
106+
SPI1C1 = 0;
107+
settings._clock = 1000000; // Use default 1MHz Frequency
108+
break;
109+
case SPI_CS0_FLASH :
110+
OverlapInit();
111+
break;
112+
case SPI_CS1_DEV :
113+
OverlapInit();
114+
pinMode(1, FUNCTION_1); // GPIO1
115+
break;
116+
case SPI_CS2_DEV :
117+
OverlapInit();
118+
pinMode(0, FUNCTION_1); // GPIO0
119+
break;
120+
default: return;
121+
}
122+
123+
if ( LastUsedDev == HSPI_IDLE ) { // First begin()
124+
SPI1C &= ~(SPI_FLASH_READ_MODE_MASK);
125+
SPI1C |= (SPI0C & SPI_FLASH_READ_MODE_MASK);
126+
RegBackup(hspi_flash_reg_backup);
127+
bitClear(SPI1U, SPIUFLASHMODE);
128+
HSPIdevSel( {1000000, LSBFIRST, SPI_MODE0}, HSPI_CS_DEV);
129+
RegBackup(hspi_dev_reg_backup);
130+
}
131+
132+
HSPIdevSel(settings, dev_no);
133+
}
134+
135+
void SPIClass::end(spi_devno dev_no) {
136+
while(SPI1CMD & SPIBUSY) {}
137+
138+
switch(dev_no){
139+
case HSPI_CS_DEV :
140+
pinMode(SCK, INPUT);
141+
pinMode(MISO, INPUT);
142+
pinMode(MOSI, INPUT);
143+
if(useHwCs) {
144+
pinMode(SS, INPUT);
145+
}
146+
break;
147+
case SPI_CS0_FLASH :
148+
break;
149+
case SPI_CS1_DEV :
150+
pinMode(1, INPUT);
151+
break;
152+
case SPI_CS2_DEV :
153+
pinMode(0, INPUT);
154+
break;
155+
default: return;
60156
}
61157
}
62158

63159
void SPIClass::setHwCs(bool use) {
64-
if(use) {
160+
while(SPI1CMD & SPIBUSY) {}
161+
162+
if (LastUsedDev != HSPI_CS_DEV) return; // Only HSPI allows the use of soft CS
163+
164+
if (use) {
65165
pinMode(SS, SPECIAL); ///< GPIO15
66166
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD);
67167
} else {
68-
if(useHwCs) {
168+
if (useHwCs) {
69169
pinMode(SS, INPUT);
70170
SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD);
71171
}
72172
}
73173
useHwCs = use;
74174
}
75175

76-
void SPIClass::beginTransaction(SPISettings settings) {
176+
void SPIClass::HSPIdevSel(SPISettings settings, spi_devno dev_no)
177+
{
77178
while(SPI1CMD & SPIBUSY) {}
179+
180+
if ( LastUsedDev == SPI_CS0_FLASH && LastUsedDev != dev_no ) RegRestore(hspi_dev_reg_backup);
181+
else if ( dev_no == SPI_CS0_FLASH && LastUsedDev != dev_no ) RegRestore(hspi_flash_reg_backup);
182+
183+
LastUsedDev = dev_no;
184+
185+
switch(dev_no){
186+
case HSPI_CS_DEV :
187+
bitClear(SPI1P, 0);
188+
bitSet(SPI1P, 1);
189+
bitSet(SPI1P, 2);
190+
setHwCs(useHwCs);
191+
break;
192+
case SPI_CS0_FLASH :
193+
bitClear(SPI1P, 0);
194+
bitSet(SPI1P, 1);
195+
bitSet(SPI1P, 2);
196+
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); // HwCs
197+
break;
198+
case SPI_CS1_DEV :
199+
bitClear(SPI1P, 1);
200+
bitSet(SPI1P, 0);
201+
bitSet(SPI1P, 2);
202+
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); // HwCs
203+
break;
204+
case SPI_CS2_DEV :
205+
bitClear(SPI1P, 2);
206+
bitSet(SPI1P, 0);
207+
bitSet(SPI1P, 1);
208+
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); // HwCs
209+
break;
210+
default: break;
211+
}
212+
78213
setFrequency(settings._clock);
79214
setBitOrder(settings._bitOrder);
80215
setDataMode(settings._dataMode);
81216
}
82217

218+
void SPIClass::beginTransaction(SPISettings settings, spi_devno dev_no, spi_modes spi_mode) {
219+
HSPIdevSel(settings, dev_no);
220+
221+
SPI1C &= ~(SPICQIO | SPICDIO | SPICFASTRD); // Reset to defaults (SIO)
222+
SPI1U &= ~(SPIUFWQIO | SPIUFWDIO);
223+
switch (spi_mode) {
224+
case SPI_QIO :
225+
SPI1C |= (SPICQIO | SPICFASTRD);
226+
SPI1U |= SPIUFWQIO;
227+
break;
228+
case SPI_DIO :
229+
SPI1C |= (SPICDIO | SPICFASTRD);
230+
SPI1U |= SPIUFWDIO;
231+
break;
232+
default: break;
233+
}
234+
}
235+
83236
void SPIClass::endTransaction() {
84237
}
85238

@@ -102,7 +255,7 @@ void SPIClass::setDataMode(uint8_t dataMode) {
102255
}
103256

104257
if(CPOL) {
105-
//todo How set CPOL???
258+
//todo How set CPOL??? SPIC2CKO(H/L)M ???
106259
}
107260

108261
}
@@ -209,9 +362,9 @@ void SPIClass::setFrequency(uint32_t freq) {
209362

210363
void SPIClass::setClockDivider(uint32_t clockDiv) {
211364
if(clockDiv == 0x80000000) {
212-
GPMUX |= (1 << 9); // Set bit 9 if sysclock required
365+
bitSet(GPMUX, 9); // Set bit 9 if sysclock required
213366
} else {
214-
GPMUX &= ~(1 << 9);
367+
bitClear(GPMUX, 9);
215368
}
216369
SPI1CLK = clockDiv;
217370
}

libraries/SPI/SPI.h

+15-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
#define SPI_CLOCK_DIV64 0x027c1001 //250 KHz
3737
#define SPI_CLOCK_DIV128 0x04fc1001 //125 KHz
3838

39+
enum spi_devno { HSPI_CS_DEV = 0, SPI_CS1_DEV, SPI_CS2_DEV, SPI_CS0_FLASH, HSPI_IDLE };
40+
enum spi_modes { SPI_SIO = 0, SPI_DIO, SPI_QIO };
41+
3942
const uint8_t SPI_MODE0 = 0x00; ///< CPOL: 0 CPHA: 0
4043
const uint8_t SPI_MODE1 = 0x01; ///< CPOL: 0 CPHA: 1
4144
const uint8_t SPI_MODE2 = 0x10; ///< CPOL: 1 CPHA: 0
@@ -53,14 +56,16 @@ class SPISettings {
5356
class SPIClass {
5457
public:
5558
SPIClass();
56-
void begin();
57-
void end();
59+
void begin(spi_devno dev_no = HSPI_CS_DEV);
60+
void end(spi_devno dev_no = HSPI_CS_DEV);
61+
void OverlapInit(void);
62+
void OverlapDeinit(void);
5863
void setHwCs(bool use);
5964
void setBitOrder(uint8_t bitOrder);
6065
void setDataMode(uint8_t dataMode);
6166
void setFrequency(uint32_t freq);
6267
void setClockDivider(uint32_t clockDiv);
63-
void beginTransaction(SPISettings settings);
68+
void beginTransaction(SPISettings settings, spi_devno dev_no = HSPI_CS_DEV, spi_modes spi_mode = SPI_SIO);
6469
uint8_t transfer(uint8_t data);
6570
uint16_t transfer16(uint16_t data);
6671
void write(uint8_t data);
@@ -73,6 +78,13 @@ class SPIClass {
7378
void transferBytes(uint8_t * out, uint8_t * in, uint32_t size);
7479
void endTransaction(void);
7580
private:
81+
spi_devno LastUsedDev;
82+
uint32 hspi_flash_reg_backup[7];
83+
uint32 hspi_dev_reg_backup[7];
84+
void RegBackup(uint32 backup_mem[7]);
85+
void RegRestore(uint32 backup_mem[7]);
86+
void HSPIdevSel(SPISettings settings, spi_devno dev_no);
87+
7688
bool useHwCs;
7789
void writeBytes_(uint8_t * data, uint8_t size);
7890
void writePattern_(uint8_t * data, uint8_t size, uint8_t repeat);

0 commit comments

Comments
 (0)