Skip to content

SPI - Allow detaching of some SPI pins without stopping SPI #9117

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 7 commits into from
Jan 19, 2024
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
2 changes: 1 addition & 1 deletion cores/esp32/esp32-hal-periman.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const char* perimanGetTypeName(peripheral_bus_type_t type) {
case ESP32_BUS_TYPE_SPI_MASTER_SCK: return "SPI_MASTER_SCK";
case ESP32_BUS_TYPE_SPI_MASTER_MISO: return "SPI_MASTER_MISO";
case ESP32_BUS_TYPE_SPI_MASTER_MOSI: return "SPI_MASTER_MOSI";
case ESP32_BUS_TYPE_SPI_MASTER_CS: return "SPI_MASTER_CS";
case ESP32_BUS_TYPE_SPI_MASTER_SS: return "SPI_MASTER_SS";
#endif
#if SOC_SDMMC_HOST_SUPPORTED
case ESP32_BUS_TYPE_SDMMC_CLK: return "SDMMC_CLK";
Expand Down
2 changes: 1 addition & 1 deletion cores/esp32/esp32-hal-periman.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ typedef enum {
ESP32_BUS_TYPE_SPI_MASTER_SCK, // IO is used as SPI master SCK pin
ESP32_BUS_TYPE_SPI_MASTER_MISO, // IO is used as SPI master MISO pin
ESP32_BUS_TYPE_SPI_MASTER_MOSI, // IO is used as SPI master MOSI pin
ESP32_BUS_TYPE_SPI_MASTER_CS, // IO is used as SPI master CS pin
ESP32_BUS_TYPE_SPI_MASTER_SS, // IO is used as SPI master SS pin
#endif
#if SOC_SDMMC_HOST_SUPPORTED
ESP32_BUS_TYPE_SDMMC_CLK, // IO is used as SDMMC CLK pin
Expand Down
159 changes: 99 additions & 60 deletions cores/esp32/esp32-hal-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,36 +177,65 @@ static spi_t _spi_bus_array[] = {
static bool spiDetachBus(void * bus){
uint8_t spi_num = (int)bus - 1;
spi_t * spi = &_spi_bus_array[spi_num];
if(spi->dev->clock.val != 0){
log_d("Stopping SPI BUS");

if(spi->dev->clock.val == 0){
log_d("SPI bus already stopped");
return true;
}
else if(spi->sck == -1 || (spi->miso == -1 && spi->mosi == -1)){
log_d("Stopping SPI bus");
spiStopBus(spi);

spiDetachSCK(spi);
spiDetachMISO(spi);
spiDetachMOSI(spi);
spiDetachSS(spi);
spi = NULL;
return true;
}
return true;
}

static bool spiDetachBus_SCK(void * bus){
uint8_t spi_num = (int)bus - 1;
spi_t * spi = &_spi_bus_array[spi_num];
if(spi->sck != -1){
log_d("SPI detach SCK pin %d",spi->sck);
spiDetachSCK(spi,spi->sck);
spiDetachSCK(spi);
spiDetachBus(bus);
}
return true;
}

static bool spiDetachBus_MISO(void * bus){
uint8_t spi_num = (int)bus - 1;
spi_t * spi = &_spi_bus_array[spi_num];
if(spi->miso != -1){
log_d("SPI detach MISO pin %d",spi->miso);
spiDetachMISO(spi,spi->miso);
spiDetachMISO(spi);
spiDetachBus(bus);
}
return true;
}

static bool spiDetachBus_MOSI(void * bus){
uint8_t spi_num = (int)bus - 1;
spi_t * spi = &_spi_bus_array[spi_num];
if(spi->mosi != -1){
log_d("SPI detach MOSI pin %d",spi->mosi);
spiDetachMOSI(spi,spi->mosi);
spiDetachMOSI(spi);
spiDetachBus(bus);
}
return true;
}

static bool spiDetachBus_SS(void * bus){
uint8_t spi_num = (int)bus - 1;
spi_t * spi = &_spi_bus_array[spi_num];
if(spi->ss != -1){
log_d("SPI detach SS pin %d",spi->ss);
spiDetachSS(spi,spi->ss);
spiDetachSS(spi);
spiDetachBus(bus);
}
//set SPI to NULL, as all pins are already detached
if(spi->sck == -1 && spi->miso == -1 && spi->mosi == -1 && spi->ss == -1){
log_d("Set spi handle to NULL");
spi = NULL;
return true;
}
return false;
return true;
}


bool spiAttachSCK(spi_t * spi, int8_t sck)
{
if(!spi || sck < 0) {
Expand All @@ -220,7 +249,7 @@ bool spiAttachSCK(spi_t * spi, int8_t sck)
pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false);
spi->sck = sck;
if(!perimanSetPinBus(sck, ESP32_BUS_TYPE_SPI_MASTER_SCK, (void *)(spi->num+1), spi->num, -1)){
spiDetachBus((void *)(spi->num+1));
spiDetachBus_SCK((void *)(spi->num+1));
log_e("Failed to set pin bus to SPI for pin %d", sck);
return false;
}
Expand All @@ -236,13 +265,11 @@ bool spiAttachMISO(spi_t * spi, int8_t miso)
if(bus != NULL && !perimanClearPinBus(miso)){
return false;
}
SPI_MUTEX_LOCK();
pinMode(miso, INPUT);
pinMatrixInAttach(miso, SPI_MISO_IDX(spi->num), false);
spi->miso = miso;
SPI_MUTEX_UNLOCK();
if(!perimanSetPinBus(miso, ESP32_BUS_TYPE_SPI_MASTER_MISO, (void *)(spi->num+1), spi->num, -1)){
spiDetachBus((void *)(spi->num+1));
spiDetachBus_MISO((void *)(spi->num+1));
log_e("Failed to set pin bus to SPI for pin %d", miso);
return false;
}
Expand All @@ -262,102 +289,114 @@ bool spiAttachMOSI(spi_t * spi, int8_t mosi)
pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false);
spi->mosi = mosi;
if(!perimanSetPinBus(mosi, ESP32_BUS_TYPE_SPI_MASTER_MOSI, (void *)(spi->num+1), spi->num, -1)){
spiDetachBus((void *)(spi->num+1));
spiDetachBus_MOSI((void *)(spi->num+1));
log_e("Failed to set pin bus to SPI for pin %d", mosi);
return false;
}
return true;
}

bool spiDetachSCK(spi_t * spi, int8_t sck)
bool spiDetachSCK(spi_t * spi)
{
if(!spi || sck < 0) {
if(!spi) {
return false;
}
pinMatrixOutDetach(sck, false, false);
spi->sck = -1;
perimanClearPinBus(sck);
int8_t sck = spi->sck;
if(sck != -1) {
pinMatrixOutDetach(sck, false, false);
spi->sck = -1;
perimanClearPinBus(sck);
}
return true;
}

bool spiDetachMISO(spi_t * spi, int8_t miso)
bool spiDetachMISO(spi_t * spi)
{
if(!spi || miso < 0) {
if(!spi) {
return false;
}
pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false);
spi->miso = -1;
perimanClearPinBus(miso);
int8_t miso = spi->miso;
if(miso != -1) {
pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false);
spi->miso = -1;
perimanClearPinBus(miso);
}
return true;
}

bool spiDetachMOSI(spi_t * spi, int8_t mosi)
bool spiDetachMOSI(spi_t * spi)
{
if(!spi || mosi < 0) {
if(!spi) {
return false;
}
pinMatrixOutDetach(mosi, false, false);
spi->mosi = -1;
perimanClearPinBus(mosi);
int8_t mosi = spi->mosi;
if(mosi != -1) {
pinMatrixOutDetach(mosi, false, false);
spi->mosi = -1;
perimanClearPinBus(mosi);
}
return true;
}

bool spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
bool spiAttachSS(spi_t * spi, uint8_t ss_num, int8_t ss)
{
if(!spi || ss < 0 || cs_num > 2) {
if(!spi || ss < 0 || ss_num > 2) {
return false;
}
void * bus = perimanGetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_CS);
void * bus = perimanGetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_SS);
if(bus != NULL && !perimanClearPinBus(ss)){
return false;
}
pinMode(ss, OUTPUT);
pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false);
spiEnableSSPins(spi, (1 << cs_num));
pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, ss_num), false, false);
spiEnableSSPins(spi, (1 << ss_num));
spi->ss = ss;
if(!perimanSetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_CS, (void *)(spi->num+1), spi->num, -1)){
spiDetachBus((void *)(spi->num+1));
if(!perimanSetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER_SS, (void *)(spi->num+1), spi->num, -1)){
spiDetachBus_SS((void *)(spi->num+1));
log_e("Failed to set pin bus to SPI for pin %d", ss);
return false;
}
return true;
}

bool spiDetachSS(spi_t * spi, int8_t ss)
bool spiDetachSS(spi_t * spi)
{
if(!spi || ss < 0) {
if(!spi) {
return false;
}
pinMatrixOutDetach(ss, false, false);
spi->ss = -1;
perimanClearPinBus(ss);
int8_t ss = spi->ss;
if(ss != -1) {
pinMatrixOutDetach(ss, false, false);
spi->ss = -1;
perimanClearPinBus(ss);
}
return true;
}

void spiEnableSSPins(spi_t * spi, uint8_t cs_mask)
void spiEnableSSPins(spi_t * spi, uint8_t ss_mask)
{
if(!spi) {
return;
}
SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL);
spi->dev->misc.val &= ~(ss_mask & SPI_SS_MASK_ALL);
#else
spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL);
spi->dev->pin.val &= ~(ss_mask & SPI_SS_MASK_ALL);
#endif
SPI_MUTEX_UNLOCK();
}

void spiDisableSSPins(spi_t * spi, uint8_t cs_mask)
void spiDisableSSPins(spi_t * spi, uint8_t ss_mask)
{
if(!spi) {
return;
}
SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL);
spi->dev->misc.val |= (ss_mask & SPI_SS_MASK_ALL);
#else
spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL);
spi->dev->pin.val |= (ss_mask & SPI_SS_MASK_ALL);
#endif
SPI_MUTEX_UNLOCK();
}
Expand Down Expand Up @@ -578,10 +617,10 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
return NULL;
}

perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_SCK, spiDetachBus);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_MISO, spiDetachBus);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_MOSI, spiDetachBus);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_CS, spiDetachBus);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_SCK, spiDetachBus_SCK);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_MISO, spiDetachBus_MISO);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_MOSI, spiDetachBus_MOSI);
perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER_SS, spiDetachBus_SS);

spi_t * spi = &_spi_bus_array[spi_num];

Expand Down
32 changes: 16 additions & 16 deletions cores/esp32/esp32-hal-spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ extern "C" {
#define SPI_MODE2 2
#define SPI_MODE3 3

#define SPI_CS0 0
#define SPI_CS1 1
#define SPI_CS2 2
#define SPI_CS_MASK_ALL 0x7
#define SPI_SS0 0
#define SPI_SS1 1
#define SPI_SS2 2
#define SPI_SS_MASK_ALL 0x7

#define SPI_LSBFIRST 0
#define SPI_MSBFIRST 1
Expand All @@ -72,25 +72,25 @@ void spiStopBus(spi_t * spi);
bool spiAttachSCK(spi_t * spi, int8_t sck);
bool spiAttachMISO(spi_t * spi, int8_t miso);
bool spiAttachMOSI(spi_t * spi, int8_t mosi);
bool spiDetachSCK(spi_t * spi, int8_t sck);
bool spiDetachMISO(spi_t * spi, int8_t miso);
bool spiDetachMOSI(spi_t * spi, int8_t mosi);
bool spiDetachSCK(spi_t * spi);
bool spiDetachMISO(spi_t * spi);
bool spiDetachMOSI(spi_t * spi);

//Attach/Detach SS pin to SPI_CSx signal
bool spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss);
bool spiDetachSS(spi_t * spi, int8_t ss);
//Attach/Detach SS pin to SPI_SSx signal
bool spiAttachSS(spi_t * spi, uint8_t ss_num, int8_t ss);
bool spiDetachSS(spi_t * spi);

//Enable/Disable SPI_CSx pins
void spiEnableSSPins(spi_t * spi, uint8_t cs_mask);
void spiDisableSSPins(spi_t * spi, uint8_t cs_mask);
//Enable/Disable SPI_SSx pins
void spiEnableSSPins(spi_t * spi, uint8_t ss_mask);
void spiDisableSSPins(spi_t * spi, uint8_t ss_mask);

//Enable/Disable hardware control of SPI_CSx pins
//Enable/Disable hardware control of SPI_SSx pins
void spiSSEnable(spi_t * spi);
void spiSSDisable(spi_t * spi);

//Activate enabled SPI_CSx pins
//Activate enabled SPI_SSx pins
void spiSSSet(spi_t * spi);
//Deactivate enabled SPI_CSx pins
//Deactivate enabled SPI_SSx pins
void spiSSClear(spi_t * spi);

void spiWaitReady(spi_t * spi);
Expand Down
16 changes: 7 additions & 9 deletions libraries/SPI/src/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,13 @@ void SPIClass::end()
if(!_spi) {
return;
}
spiDetachSCK(_spi, _sck);
if(_miso >= 0){
spiDetachMISO(_spi, _miso);
}
if(_mosi >= 0){
spiDetachMOSI(_spi, _mosi);
}
spiDetachSCK(_spi);
spiDetachMISO(_spi);
spiDetachMOSI(_spi);
setHwCs(false);
spiStopBus(_spi);
if(spiGetClockDiv(_spi) != 0) {
spiStopBus(_spi);
}
_spi = NULL;
}

Expand All @@ -146,7 +144,7 @@ void SPIClass::setHwCs(bool use)
spiSSEnable(_spi);
} else if(!use && _use_hw_ss) {
spiSSDisable(_spi);
spiDetachSS(_spi, _ss);
spiDetachSS(_spi);
}
_use_hw_ss = use;
}
Expand Down