SOLVED - How to use HSPI in ‘MCP23S08’ library?

gjgsmithvr
Posts: 5
Joined: Fri Jun 17, 2022 4:41 am

SOLVED - How to use HSPI in ‘MCP23S08’ library?

Postby gjgsmithvr » Sat Jun 18, 2022 1:04 am

I have a project which uses a standard TFT Touch Display, SD Card and an MCP23S08 expander chip. All communicating via SPI. The ESP32 is a standard 38 pin devkit module.

The TFT Touch Display and SD Card uses VSPI with three CS pins using TFT_eSPI library and the SD library. As VSPI is the default SPI config, these devices are are all working as expected.

The MCP23S08 using https://github.com/julianschuler/MCP23S08 library is simple to use with default VSPI but I need help getting it to work with HSPI.

I have looked at https://github.com/espressif/arduino-es ... iple_Buses but I do not know if or how this can be implemented in the MCP23S08 library so that the HSPI is used instead of VSPI.

I am familiar with Arduino IDE and VSCode/PlatformIO.
Any code or guidance would be appreciated.

PIN Allocations.

VSPI
Display_SCK 18
Display_MOSI 23
Display_MISO 19
Display_CS 5
Touch_CS 17
SD_CS 16

HSPI
MCP23S08_SCK 14
MCP23S08_MOSI 13
MCP23S08_MISO 12
MCP23S08_CS 15
Last edited by gjgsmithvr on Fri Jun 24, 2022 11:31 pm, edited 1 time in total.

gjgsmithvr
Posts: 5
Joined: Fri Jun 17, 2022 4:41 am

Re: How to Change SPI in ‘MCP23S08’ library to use HSPI?

Postby gjgsmithvr » Sun Jun 19, 2022 4:51 am

This is what I have tried so far but getting this compile error:

MCP23S08.cpp:25:2: error: 'hspi' was not declared in this scope.


Modified Arduino MCP23S08 example...

Code: Select all

[Codebox=cpp file=Untitled.cpp]
/**************************************************************************
 *
 * File: SimultanPinAccess.ino
 * Author: Julian Schuler (https://github.com/julianschuler)
 * License: MIT License, see LICENSE.txt
 * Description: This file is an example from the MCP23S08 library.
 *              It shows advanced usage of the MCP23S08 port expander
 *              by controlling 8 LEDs simultaniously.
 *
 * Circuit: - MCP23S08 pin 1 to SCK (D13 on Arduino Uno)
 *          - MCP23S08 pin 2 to MOSI (D11 on Arduino Uno)
 *          - MCP23S08 pin 3 to MISO (D12 on Arduino Uno)
 *          - MCP23S08 pin 4, 5, 9 to GND
 *          - MCP23S08 pin 6, 18 to 5V
 *          - MCP23S08 pin 7 to D10
 *          - MCP23S08 pin 10 - 17 over an 220 Ohm resistor to the anode
 *              of a LED, LED kathode to GND
 *              
 * MODIFIED by G Smith for two expanders.
 * 
 **************************************************************************/
 
#include <Arduino.h>
#include <MCP23S08.h>
#include <SPI.h>

//uninitalised pointer to SPI object
SPIClass* hspi = nullptr;

MCP23S08 expander1(15, 0x20);     // CS_pin, '0x20' - hardware device address.
MCP23S08 expander2(15, 0x21);


void setup() {
  
//initialise two instances of the SPIClass attached to VSPI and HSPI respectively
//  vspi = new SPIClass(VSPI);

  hspi = new SPIClass(HSPI);
  
  hspi->begin();

//SPI.begin(14,12,13,15);                // start hardware_SPI bus
  
  expander1.begin();                     // begin communication with the I/O expander
  expander1.setPinModes(B11111111);      // set all pins to output
  expander1.setOutputStates(B11111111);  // turn all pins on.
  
  expander2.begin();                     // begin communication with the I/O expander
  expander2.setPinModes(B11111111);      // set all pins to output
  expander2.setOutputStates(B11111111);  // turn all pins on.
}


void loop() {
  uint8_t outputStates1 = expander1.getOutputStates();  // get output states of all pins
  expander1.setOutputStates(~(outputStates1));          // set output states to am inverse of the previous states
  
  delay(1500); 
  
  uint8_t outputStates2 = expander2.getOutputStates();  // get output states of all pins
  expander2.setOutputStates(~(outputStates2));          // set output states to am inverse of the previous states
  
  delay(1500);                                         // wait
}
[/Codebox]

MCP23S08 Modified Library
- MCP23S08.cpp

Code: Select all

[Codebox=cpp file=Untitled.cpp]
/**********************************************************************
 * 
 * This is the C++ part of the MCP23S08 library.
 * See MCP23S08.h and the example files for a full documentation.
 * 
 *********************************************************************/


#include <Arduino.h>
#include <MCP23S08.h>
#include <SPI.h>


/*##################################### PUBLIC FUNCTIONS #####################################*/

MCP23S08::MCP23S08(uint8_t csPin) : csPin(csPin) {}


MCP23S08::MCP23S08(uint8_t csPin, uint8_t deviceAddr) : csPin(csPin) {
	deviceOpcode |= ((deviceAddr & 0x03) << 1);
}


void MCP23S08::begin() {
	hspi->beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
	pinMode(csPin, OUTPUT);
	digitalWrite(csPin, LOW);
	// reset all registers to default:
	hspi->transfer(MCP23S08_IODIR);	//set address pointer to first register
	hspi->transfer(0xFF);				// reset first register
	for (uint8_t i = 0; i < MCP23S08_OLAT; i++) {
		hspi->transfer(0x00);			// reset other 10 registers
	}
	digitalWrite(csPin, HIGH);
	hspi->endTransaction();
}


bool MCP23S08::digitalReadIO(uint8_t pin) {
	if (pin > 7) {
		return 0;
	}
	return (getInputStates() >> pin) & 1;
}


void MCP23S08::digitalWriteIO(uint8_t pin, bool state) {
	if (pin > 7) {
		return;
	}
	
	setOutputStates((getOutputStates() & ~(1 << pin)) | (state << pin));
}


void MCP23S08::pinModeIO(uint8_t pin, uint8_t mode) {
	if (pin > 7) {
		return;
	}
	
	switch (mode) {
		case INPUT:
			setPinModes(getPinModes() & ~(1 << pin));			// set pin to input
			enablePullups(getEnabledPullups() & ~(1 << pin));	// disable pullup for pin
			break;
		case OUTPUT:
			setPinModes(getPinModes() | (1 << pin));				// set pin to output
			enablePullups(getEnabledPullups() & ~(1 << pin));	// disable pullup for pin
			break;
		case INPUT_PULLUP:
			setPinModes(getPinModes() & ~(1 << pin));			// set pin to input
			enablePullups(getEnabledPullups() | (1 << pin));	// enable pullup for pin
			break;
	}
}


void MCP23S08::setOutputStates(uint8_t states) {
	writeRegister(MCP23S08_OLAT, states);
}


void MCP23S08::setPinModes(uint8_t modes) {
	writeRegister(MCP23S08_IODIR, ~(modes));	// inverted to match IDE defaults
}


void MCP23S08::enablePullups(uint8_t enables) {
	writeRegister(MCP23S08_GPPU, enables);
}


uint8_t MCP23S08::getInputStates() {
	return readRegister(MCP23S08_GPIO);
}


uint8_t MCP23S08::getOutputStates() {
	return readRegister(MCP23S08_OLAT);
}


uint8_t MCP23S08::getPinModes() {
	return ~(readRegister(MCP23S08_IODIR));		// inverted to match IDE defaults
}


uint8_t MCP23S08::getEnabledPullups() {
	return readRegister(MCP23S08_GPPU);
}


/*##################################### PRIVATE FUNCTIONS #####################################*/

void MCP23S08::writeRegister(uint8_t address, uint8_t data) {
	hspi->beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
	digitalWrite(csPin, LOW);
	hspi->transfer(deviceOpcode);		// initialize transfer with opcode and R/W-flag cleared
	hspi->transfer(address);
	hspi->transfer(data);
	digitalWrite(csPin, HIGH);
	hspi->endTransaction();
}


uint8_t MCP23S08::readRegister(uint8_t address) {
	uint8_t data;
	hspi->beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
	digitalWrite(csPin, LOW);
	hspi->transfer(deviceOpcode | 1);		// initialize transfer with opcode and R/W-flag set
	hspi->transfer(address);
	data = hspi->transfer(0);
	digitalWrite(csPin, HIGH);
	hspi->endTransaction();
	return data;
}
[/Codebox]

gjgsmithvr
Posts: 5
Joined: Fri Jun 17, 2022 4:41 am

Re: SOLVED - How to use HSPI in ‘MCP23S08’ library?

Postby gjgsmithvr » Fri Jun 24, 2022 11:27 pm

SOLUTION

Using the monoidk/MCP23S08 library fork code I have test code running successfully using two MCP23S08's and two SPI's. I don't need two SPI's to run two expanders, they just demonstrate that the VSPI and HSPI are working at MAX speed of 80Mhz.
Thanks to monoidk for their input and MCP23S08 library fork which adds SPIClass and speed to the constructor.

I have successfully run this code at 79Mhz which seems to be about max speed with this setup.

This is consistent with the ESP32 API reference manual which states 80Mhz VHSPI and HSPI buses and 26Mhz for GPIO pins. Which means that if were to use with alternate pins...
SPI.begin(SCLK, MISO, MOSI, SS); with alternate pins, then the max SPI bus speed would be 26Mhz.

Code: Select all

/**************************************************************************
 *
 * File: SimultanPinAccess.ino
 * Author: Julian Schuler (https://github.com/julianschuler)
 * License: MIT License, see LICENSE.txt
 * monoidk/MCP23S08 fork code.
 * MODIFIED by G Smith for two expanders.
 * 
 **************************************************************************/
 
#include <Arduino.h>
#include <MCP23S08.h>
#include <SPI.h>

SPIClass SPIexp(HSPI);


MCP23S08 expander1(SPIexp, 15, 0x20, 79000000);     // (SPIClass, CS_pin, '0x20' - hardware device address, speed)
MCP23S08 expander2(SPI, 15, 0x21, 79000000);


void setup() {

  SPI.begin();                            // VSPI bus - (18, 19, 18, 5) - (SCLK, MISO, MOSI, SS)
  SPIexp.begin();                       // HSPI bus - (14, 12, 13, 15) - (SCLK, MISO, MOSI, SS)
  
  expander1.begin();                     // begin communication with the I/O expander
  expander1.setPinModes(B11111111);      // set all pins to output
  expander1.setOutputStates(B11111111);  // turn all pins on.
  
  expander2.begin();                     // begin communication with the I/O expander
  expander2.setPinModes(B11111111);      // set all pins to output
  expander2.setOutputStates(B11111111);  // turn all pins on.
}


void loop() {
  uint8_t outputStates1 = expander1.getOutputStates();  // get output states of all pins
  expander1.setOutputStates(~(outputStates1));          // set output states to am inverse of the previous states
  
  delay(1500); 
  
  uint8_t outputStates2 = expander2.getOutputStates();  // get output states of all pins
  expander2.setOutputStates(~(outputStates2));          // set output states to am inverse of the previous states
  
  delay(1500);                                         // wait
}

Who is online

Users browsing this forum: No registered users and 114 guests