SPI slave speed problem

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

SPI slave speed problem

Postby Atalaya » Sun Feb 13, 2022 8:07 pm

Hello group
I'm hoping to solve this SPI slave problem. I've tried with esp-idf coding and Arduino coding.
Scenario: To simplify, I have a SPI "black-box" master that sends me 2 blocks of 5 bytes (Trace 1).
I read the first block but never the second.

As I see it, I think the ~ 3nS pulse on the slave CS line (Trace 4 on the scope), in the middle of the two "5-Byte" blocks, is the problem.
I thought my best bet would be to have the slave.queue/slave.yield commands in their own task for speed but it hasn't solved the problem.
The replies are all the first block, never the second.
Thanks in advance for your suggestions.
Slave.png
Slave.png (19.76 KiB) Viewed 5495 times
Test Code:
#include <Arduino.h>
#include <sys/types.h>
#include <SPI.h>
#include "ESP32DMASPISlave.h"

#define HSPI_MISO -1
#define HSPI_MOSI 11
#define HSPI_SCLK 12
#define HSPI_SS 10
#define MSG5_SIZE 5U

ESP32DMASPI::Slave slave;

uint16_t ResultsHex[80] = {0};

uint8_t *slave_buffer1;
uint8_t *slave_buffer2;

constexpr uint8_t CORE_TASK_SPI_SLAVE {0};
constexpr uint8_t CORE_TASK_PROCESS_BUFFER {0};

static TaskHandle_t task_handle_wait_spi = 0;
static TaskHandle_t task_handle_process_buffer = 0;

void dump_buf(const char* title, uint8_t* buf, uint8_t len) {
printf("%4s[%2d]: ", title, len);
for (uint8_t i = 0; i < len; i++)
printf("%02X ", buf);
}

void task_wait_spi(void* pvParameters) {
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
slave.yield();
if (slave.remained() == 0) {
slave.queue(slave_buffer1, NULL, MSG5_SIZE);
slave.yield();
}
// delayMicroseconds(11);
xTaskNotifyGive(task_handle_process_buffer);
}
}

// int i;
void task_process_buffer(void* pvParameters) {
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// printf("Avail %u, size %u\n", slave.available(), slave.size());

slave.queue(slave_buffer2, NULL, MSG5_SIZE);

xTaskNotifyGive(task_handle_wait_spi);
}
}

void setup() {
Serial.begin(115200); while (!Serial) {} ;

printf("\n* * * * * * * * * * * * * * * * * * * *\n");
printf("%s - SLAVE ", __FILE__);
printf("* * * * * * * * * * * * * * * * * * * *\n");
// pinMode(INT_PIN, INPUT_PULLUP);
pinMode(HSPI_SCLK, INPUT_PULLUP);
pinMode(HSPI_MOSI, INPUT_PULLUP);
pinMode(HSPI_SS, INPUT_PULLUP);
delay(2000);
// attachInterrupt(digitalPinToInterrupt(INT_PIN), blink, RISING);

slave_buffer1 = (uint8_t*)heap_caps_calloc(MSG5_SIZE, 1, MALLOC_CAP_DMA);
slave_buffer2 = (uint8_t*)heap_caps_calloc(MSG5_SIZE, 1, MALLOC_CAP_DMA);
memset(slave_buffer1, 0x0, MSG5_SIZE);
delay(1);

slave.setDataMode(SPI_MODE1);
slave.setMaxTransferSize(1024);
slave.setDMAChannel(2); // Auto
slave.setQueueSize(80); // transaction queue size
slave.begin(HSPI, HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SCLK, MISO, MOSI, SS

xTaskCreatePinnedToCore(task_wait_spi, "task_wait_spi", 10000, NULL, 2, &task_handle_wait_spi, CORE_TASK_SPI_SLAVE);
delay(1);
xTaskCreatePinnedToCore(task_process_buffer, "task_process_buffer", 10000, NULL, 2, &task_handle_process_buffer, CORE_TASK_PROCESS_BUFFER);
delay(1);
xTaskNotifyGive(task_handle_wait_spi);
delay(1);
}

void loop() {
dump_buf("Rx1: ", slave_buffer1, MSG5_SIZE);
dump_buf("Rx2: ", slave_buffer2, MSG5_SIZE);
printf("\n");
delay(1);
}

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: SPI slave speed problem

Postby ESP_Sprite » Mon Feb 14, 2022 1:48 am

Likely the CS pulse in the middle is the issue, indeed: it makes the SPI hardware think the transaction stopped which makes the software process the result. Because the CS pulse high time is only a few uS, software can't set up a new transaction in time to capture the 2nd transaction, and it gets lost.

You could try solving this by making the middle CS pulse 'disappear' somehow, but given the timings involved, it may be tricky to do in software, and it depends on other behaviour of the black box if it could be done succesfully.

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

Re: SPI slave speed problem

Postby Atalaya » Mon Feb 14, 2022 6:44 pm

Thank your for your reply. I was wondering if there is a way to use interrupts on the CS line?
I have investigated the esp-idf code looking for possible solutions, but so far I haven't had any luck

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: SPI slave speed problem

Postby ESP_Sprite » Tue Feb 15, 2022 1:51 am

Yes, you should be able to put a GPIO interrupt on any pin regardless of its function. (Probably best to initialize the GPIO interrupt before initializing SPI, by the way.)

Another option: You can also control the CS SPI input signal by manually using the GPIO matrix to the always-high or always-low signal... so you could at the start, force the CS SPI input signal low, put a rising-edge interrupt on your physical CS pin (which now doesn't directly control the SPI slave CS anymore as that is under software control), and as soon as that triggers, delay a bit for the 2nd bit of data to come in and manually make the SPI slave CS high again.

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

Re: SPI slave speed problem

Postby Atalaya » Wed Feb 16, 2022 9:42 am

Thank you again. I shall make another incursion into this possibility, probably tomorrow or so.

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

Re: SPI slave speed problem

Postby Atalaya » Sat Feb 19, 2022 11:24 am

Good news
thank you. it was what I needed to unblock this problem. I moved my test code to esp-idf to have more control on the SPI's and took control of the incoming CS line to the SPI slave on the ESP, having modified the CS line logic on my "black box".
The annoying pulse in the middle of trace-4 is no longer. :D
Slave2.png
Slave2.png (18.02 KiB) Viewed 5321 times
Only took an extra line and a bit of delay to get it working.

static void cs_high()
{
gpio_set_level(MASTER_SS, 1);
ets_delay_us(30);
gpio_set_level(SLAVE_SS, 1);
}

static void cs_low()
{
gpio_set_level(MASTER_SS, 0);
ets_delay_us(2);
gpio_set_level(SLAVE_SS, 0);
}

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

Re: SPI slave speed problem

Postby Atalaya » Sat Feb 19, 2022 10:52 pm

Hello again
trying to make a single ESP run what I need, I assume I need to unite "a GPIO pin" with the "spics_in" signal of the SPI slave.

Investigating I thought that this would do it ...
esp_rom_gpio_connect_in_signal( someGPIOpin, spi_periph_signal[SPI3_HOST].spics_in , false );
However a high/low signal sent to "someGPIOpin", doesn't appear on the slave CS pin.
What am I missing, please?

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: SPI slave speed problem

Postby ESP_Sprite » Sun Feb 20, 2022 6:53 am

Fancy trick that does not need any GPIO: (note: this particular snipped is untested but should work)

Code: Select all

#include "rom/gpio.h"

//make CS of the SPI peripheral high
esp_rom_gpio_connect_in_signal( GPIO_FUNC_IN_HIGH, spi_periph_signal[SPI3_HOST].spics_in , false );

//make CS low
esp_rom_gpio_connect_in_signal( GPIO_FUNC_IN_LOW, spi_periph_signal[SPI3_HOST].spics_in , false );

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

Re: SPI slave speed problem

Postby Atalaya » Sun Feb 20, 2022 8:37 pm

Evening
I liked your last reply, but I didn't spend too much time on it as "it didn't work". Maybe because the code wants to tell an "input pin" to modify it's level, which isn't done.
So, I've used 2 pins to get past this problem and I'm advancing again with the next 1000 lines of code
Many thanks

Atalaya
Posts: 11
Joined: Mon Jan 10, 2022 7:56 am

Re: SPI slave speed problem

Postby Atalaya » Sun Feb 20, 2022 11:49 pm

Next problem....
I'm using esp-idf v4.4 and It seems the limitation of using DMA with SPI still exists...
The master SPI only ever sends 5 bytes so I have DMA switched off, no problem, except 5 is not a multiple of 8.
There is however one master command that expects to receive 1280 bits, which is not possible with slave DMA switched on.
(maximum of 64 bytes, 512 bits)
I had hoped that the 64 bytes of dedicated SPI memory was goingto be enough.
I've only just discovered this because the code I'm working on is over 20k lines.

If I switch on DMA for the slave SPI, I only ever see 4 bytes returned.
Any workarounds? Before I start rewriting code?
By the way, we are using a ESP32 WROOM (8MB) and at our stage of development, for example, should a different ESP solve this, thats a valid possibility for us.
Thank you

Who is online

Users browsing this forum: Google [Bot] and 65 guests