Close

SPI in an IRQ

A project log for ESP-32 BLDC Robot Actuator Controller

ESP-32 WROOM-32D has Three phase Centre Aligned MC-PWM, Dual SPI, I2C, 2MHz ADC, UART and CAN. Enough for a controller.

paul-gouldPaul Gould 02/27/2020 at 16:390 Comments

The standard SPI Transfer code does tot work well in an IRQ mainly becaise it is run out of FLASH. Uese the IRAM_ATTR to put it in RAM.

Other digitalWrte() is slow and should not be uses in the IRQ.

Use GPIO.out_w1ts = ((uint32_t)1 << IO_PIN_Number); to set the pin high

Use GPIO.out_w1ts = ((uint32_t)1 << IO_PIN_Number);  to set the pin low

This can only be used when the IO_PIN_Number is 0-31

There is other code for 32-39 pins. 

SPI Set-up

#include "driver/periph_ctrl.h"
#include "driver/spi_master.h"
#include "soc/gpio_sig_map.h"
#include "soc/spi_reg.h"
#include "soc/dport_reg.h"
#include "soc/spi_struct.h"

static const int spiClk = 4000000; // 1 MHz
SPIClass * hspi = NULL;

void IRAM_ATTR SPIInit(void)
{
  hspi = new SPIClass(HSPI);
  hspi->begin(); 
  pinMode(INT_ENC_nCS, OUTPUT);
  pinMode(EXT_ENC_nCS, OUTPUT);
  pinMode(DRV_nSCS, OUTPUT);
  GPIO.out_w1ts = ((uint32_t)1 << INT_ENC_nCS);
  GPIO.out_w1ts = ((uint32_t)1 << EXT_ENC_nCS);
  GPIO.out_w1ts = ((uint32_t)1 << DRV_nSCS);
  hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE1));
  SPI2.mosi_dlen.usr_mosi_dbitlen = (1 * 16) - 1;
  SPI2.miso_dlen.usr_miso_dbitlen = (1 * 16) - 1;
}


void IRAM_ATTR SPI_Read_Encoder(){ GPIO.out_w1tc = ((uint32_t)1 << INT_ENC_nCS); SPI2.data_buf[0] = 0xFFFF; SPI2.cmd.usr = 1; while(SPI2.cmd.usr); GPIO.out_w1ts = ((uint32_t)1 << INT_ENC_nCS); encoder_int = SPI2.data_buf[0] & 0xFFFF; if(!SPI2.ctrl.rd_bit_order){ encoder_int = (encoder_int >> 8) | (encoder_int << 8); } encoder_int = encoder_int & 0x3FFF ; }

Discussions