Skip to content

Implement support for HSPI overlap mode #3189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cores/esp8266/esp8266_peri.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,10 @@ extern uint8_t esp8266_gpioToFn[16];
#define SPIE2IHEN 0x3 //SPI_INT_HOLD_ENA
#define SPIE2IHEN_S 0 //SPI_INT_HOLD_ENA_S

//SPI PIN (SPIxP)
#define SPIPCS2DIS (1 << 2)
#define SPIPCS1DIS (1 << 1)
#define SPIPCS0DIS (1 << 0)

//SLC (DMA) Registers
#define SLCC0 ESP8266_REG(0xB00) //SLC_CONF0
Expand Down
22 changes: 22 additions & 0 deletions doc/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ else they default to pins 4(SDA) and 5(SCL).

SPI library supports the entire Arduino SPI API including transactions, including setting phase (CPHA).
Setting the Clock polarity (CPOL) is not supported, yet (SPI_MODE2 and SPI_MODE3 not working).
The usual SPI pins are:

- `MOSI` = GPIO13
- `MISO` = GPIO12
- `SCLK` = GPIO14

There's an extended mode where you can swap the normal pins to the pin0 hardware pins.
This is enabled by calling `SPI.pins(6, 7, 8, 0)` before the call to `SPI.begin()`. The pins would
change to:

- `MOSI` = SD1
- `MISO` = SD0
- `SCLK` = CLK
- `HWCS` = GPIO0

This mode shares the SPI pins with the controller that reads the program code from flash and is
controlled by a hardware arbiter (the flash has always higher priority). For this mode the CS
will be controlled by hardware as you can't handle the CS line with a GPIO, you never actually
know when the arbiter is going to grant you access to the bus so you must let it handle CS
automatically.



## SoftwareSerial

Expand Down
96 changes: 82 additions & 14 deletions libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
#include "SPI.h"
#include "HardwareSerial.h"

#define SPI_PINS_HSPI 0 // Normal HSPI mode (MISO = GPIO12, MOSI = GPIO13, SCLK = GPIO14);
#define SPI_PINS_HSPI_OVERLAP 1 // HSPI Overllaped in spi0 pins (MISO = SD0, MOSI = SDD1, SCLK = CLK);

#define SPI_OVERLAP_SS 0


typedef union {
uint32_t regValue;
struct {
Expand All @@ -35,12 +41,43 @@ typedef union {

SPIClass::SPIClass() {
useHwCs = false;
pinSet = SPI_PINS_HSPI;
}

bool SPIClass::pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
if (sck == 6 &&
miso == 7 &&
mosi == 8 &&
ss == 0) {
pinSet = SPI_PINS_HSPI_OVERLAP;
} else if (sck == 14 &&
miso == 12 &&
mosi == 13) {
pinSet = SPI_PINS_HSPI;
} else {
return false;
}

return true;
}

void SPIClass::begin() {
pinMode(SCK, SPECIAL); ///< GPIO14
pinMode(MISO, SPECIAL); ///< GPIO12
pinMode(MOSI, SPECIAL); ///< GPIO13
switch (pinSet) {
case SPI_PINS_HSPI_OVERLAP:
IOSWAP |= (1 << IOSWAP2CS);
//SPI0E3 |= 0x1; This is in the MP3_DECODER example, but makes the WD kick in here.
SPI1E3 |= 0x3;

setHwCs(true);
break;
case SPI_PINS_HSPI:
default:
pinMode(SCK, SPECIAL); ///< GPIO14
pinMode(MISO, SPECIAL); ///< GPIO12
pinMode(MOSI, SPECIAL); ///< GPIO13
break;
}

SPI1C = 0;
setFrequency(1000000); ///< 1MHz
Expand All @@ -50,24 +87,55 @@ void SPIClass::begin() {
}

void SPIClass::end() {
pinMode(SCK, INPUT);
pinMode(MISO, INPUT);
pinMode(MOSI, INPUT);
if(useHwCs) {
pinMode(SS, INPUT);
switch (pinSet) {
case SPI_PINS_HSPI:
pinMode(SCK, INPUT);
pinMode(MISO, INPUT);
pinMode(MOSI, INPUT);
if (useHwCs) {
pinMode(SS, INPUT);
}
break;
case SPI_PINS_HSPI_OVERLAP:
IOSWAP &= ~(1 << IOSWAP2CS);
if (useHwCs) {
SPI1P |= SPIPCS1DIS | SPIPCS0DIS | SPIPCS2DIS;
pinMode(SPI_OVERLAP_SS, INPUT);
}
break;
}
}

void SPIClass::setHwCs(bool use) {
if(use) {
pinMode(SS, SPECIAL); ///< GPIO15
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD);
switch (pinSet) {
case SPI_PINS_HSPI:
if (use) {
pinMode(SS, SPECIAL); ///< GPIO15
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD);
} else {
if(useHwCs) {
pinMode(SS, INPUT);
if (useHwCs) {
pinMode(SS, INPUT);
SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD);
}
}
break;
case SPI_PINS_HSPI_OVERLAP:
if (use) {
pinMode(SPI_OVERLAP_SS, FUNCTION_1); // GPI0 to SPICS2 mode
SPI1P &= ~SPIPCS2DIS;
SPI1P |= SPIPCS1DIS | SPIPCS0DIS;
SPI1U |= (SPIUCSSETUP | SPIUCSHOLD);
}
else {
if (useHwCs) {
pinMode(SPI_OVERLAP_SS, INPUT);
SPI1P |= SPIPCS1DIS | SPIPCS0DIS | SPIPCS2DIS;
SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD);
}
}
break;
}

useHwCs = use;
}

Expand Down Expand Up @@ -306,7 +374,7 @@ void SPIClass::write32(uint32_t data, bool msb) {
SPI1W0 = data;
SPI1CMD |= SPIBUSY;
}
while(SPI1CMD & SPIBUSY) {}
while(SPI1CMD & SPIBUSY) {}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions libraries/SPI/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class SPISettings {
class SPIClass {
public:
SPIClass();
bool pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss);
void begin();
void end();
void setHwCs(bool use);
Expand All @@ -74,6 +75,7 @@ class SPIClass {
void endTransaction(void);
private:
bool useHwCs;
uint8_t pinSet;
void writeBytes_(uint8_t * data, uint8_t size);
void transferBytes_(uint8_t * out, uint8_t * in, uint8_t size);
inline void setDataBits(uint16_t bits);
Expand Down