Espressif SPI and GPIO expander

Hello, I am trying to interface ESP32S2 with a GPIO expander MCP23S18 using SPI in VScode (.c). However the spi.h that I got from the Espressif website is .cpp and therefore I cannot integrate it with my code. I tried sumtoy's library but looks like it does not support ESP32S2. My question is:

  1. Is there a spi library in C that can be used in my code? Or do I need to implement spi library for my interface?
  2. Can someone please check my below code and let me know If what I am doing is right since I am new to this?

Thank you

#include "SPI.h"
#include "gpio_expander.h"

#include "definitions.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "esp_log.h"
#include <stdbool.h>

#define GPA0 15
#define GPA1 16
#define GPA2 17
#define GPA3 18
#define GPA4 19

static bool blinkled = false;
static uint8_t state_led = 0;
static uint8_t state_low = 0;
static uint8_t state_high = 1;

static void periodic_timer(void* arg)
{
  blinkled = true;
}

void SPIWrite(byte address, byte data){
  gpio_reset_pin(CS);
  gpio_set_direction(CS, GPIO_MODE_OUTPUT);
  SPI.transfer(CHIP_WRITE);
  SPI.transfer(address);
  SPI.transfer(data);
  gpio_set_level(CS, state_high);
}

int initgpio(task_t *_this)
{
  if(_this->state > TASKSTATE_UNINITIALIZED) {
    return -1;
  }
  gpio_reset_pin(CS);
  gpio_set_direction(CS, GPIO_MODE_OUTPUT);
  gpio_set_level(CS, state_high);
  
  delay(100);
  
  SPI.begin();
  SPIWrite(GPA0,state_low);
  SPIWrite(GPA1,state_low);
  SPIWrite(GPA2,state_low);
  SPIWrite(GPA3,state_low);
  SPIWrite(GPA4,state_low);
  //SPIWrite(REG_GPIO,0x00);
 }

void execgpio(task_t *_this) {
  SPIWrite(GPA0,0x02);
  SPIWrite(GPA1,0x02);
  SPIWrite(GPA2,0x02);
  SPIWrite(GPA3,0x02);
  SPIWrite(GPA4,0x02);
  delay(500);
  SPIWrite(GPA0,0x00);
  SPIWrite(GPA1,0x00);
  SPIWrite(GPA2,0x00);
  SPIWrite(GPA3,0x00);
  SPIWrite(GPA4,0x00);
  delay(500);
}

doesn't the Wire library do what you want?

my interlock.ino uses it to access a similar chip

Thank you @gcjr

Wire library uses gpio expander with i2c interface where as I am looking for the same with spi interface. So I dont think wire library would work for me. Do you know similar examples that use spi?

believe wire supports both I2C and SPI

You sure if that?

@enthusiastsr what happens when you try and use the standard SPI library?

You do know that these are open collector port expanders, which means you will not see anything on an output unless you use a pull up resistor?

I am assuming you are powering it from 3V3.

Thank you @Grumpy_Mike

I am unable to build my code using standard SPI library. Since the standard SPI library is in C++ and my library is in C.

I keep getting error for type class, and other definition types that are not supported in C.

aren't you using the Arduino IDE to build your code?

you can certainly compile C code with gcc. name file .cpp

@gcjr, I am using Visual Studio Code to build my project.

Could you please tell me what is gcc. name file .cpp since I'm immature with this stuff.

Thank you.

You'll have to write one yourself. The ESP32's SPI API is easy to use.

Yes. I will have a look. Thank you very much:)

GNU C/C++ compiler used by Arduino and an industry standard. we used it at Qualcomms

a GNU legacy app wrote in the Arduino IDE and used on a ESP32 that runs the 2nd ESP32's CPU:

void ULP_BLINK_RUN(uint32_t us)
{
  size_t load_addr = 0;
  RTC_SLOW_MEM[12] = 0;
  ulp_set_wakeup_period(0, us);
  const ulp_insn_t  ulp_blink[] =
  {
    I_MOVI(R3, 12),                         // #12 -> R3
    I_LD(R0, R3, 0),                        // R0 = RTC_SLOW_MEM[R3(#12)]
    M_BL(1, 1),                             // GOTO M_LABEL(1) IF R0 < 1
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1),  // RTC_GPIO2 = 1
    I_SUBI(R0, R0, 1),                      // R0 = R0 - 1, R0 = 1, R0 = 0
    I_ST(R0, R3, 0),                        // RTC_SLOW_MEM[R3(#12)] = R0
    M_BX(2),                                // GOTO M_LABEL(2)
    M_LABEL(1),                             // M_LABEL(1)
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0),// RTC_GPIO2 = 0
    I_ADDI(R0, R0, 1),                    // R0 = R0 + 1, R0 = 0, R0 = 1
    I_ST(R0, R3, 0),                      // RTC_SLOW_MEM[R3(#12)] = R0
    M_LABEL(2),                             // M_LABEL(2)
    I_HALT()                                // HALT COPROCESSOR
  };
  const gpio_num_t led_gpios[] =
  {
    GPIO_NUM_2,
    // GPIO_NUM_0,
    // GPIO_NUM_4
  };
  for (size_t i = 0; i < sizeof(led_gpios) / sizeof(led_gpios[0]); ++i) {
    rtc_gpio_init(led_gpios[i]);
    rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
    rtc_gpio_set_level(led_gpios[i], 0);
  }
  size_t size = sizeof(ulp_blink) / sizeof(ulp_insn_t);
  ulp_process_macros_and_load( load_addr, ulp_blink, &size);
  ulp_run( load_addr );
} // void ULP_BLINK_RUN(uint32_t us)

Why can't you compile your existing code in C++? If necessary, you can use the directive:

extern "C" {

TOPIC LOCKED

Please do NOT cross post / duplicate as it wastes peoples time and efforts to have more than one post for a single topic.

Continued cross posting could result in a time out from the forum.

Could you also take a few moments to Learn How To Use The Forum.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.