Sorry for the late reply. At the moment, the achieved SPI transfer speed using bit-banging is sufficient for reading data from two SPI slave devices every 2 ms (500 samples per second). My original goal was 1 kSPS, but this will probably not be achievable.
Below, I am sending the complete code for the ULP coprocessor (created from the example project ULP => interrupts). I shifts the bits immediately when reading a byte and the DATA (MISO) is on pin 0, as this solution gave me the best results. It also didn’t matter whether I used a pointer or assigned data to an array using an index. Optimization didn't matter; `0s` or `02` gives the same result. The result is reading from two SPI slave devices into two ping-pong buffers of 1350 bytes each, allowing one buffer to be processed while the other is being filled with data.
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* ULP RISC-V interrupts example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
This code runs on ULP RISC-V coprocessor
*/
Code: Select all
#include "ulp_riscv_utils.h"
#include "ulp_riscv_gpio.h"
#define DRDY_PIN 6
#define CLK_PIN 2
#define DATA_PIN 0
#define CS1_PIN 3
#define CS2_PIN 4
uint8_t read_buffer1[1350] = {0};
uint8_t read_buffer2[1350] = {0};
// uint8_t *p_buffer = read_buffer1;
// uint16_t buf_i = 0;
volatile bool buffer_ready = false;
volatile uint8_t *p_buffer_global = NULL;
/* SW Interrupt Handler */
//void sw_int_handler(void *arg)
//{
// sw_int_cnt++;
//}
/* GPIO Interrupt Handler */
void gpio_int_handler(void *arg)
{
// static uint8_t read_buffer1[1350] = {0};
// static uint8_t read_buffer2[1350] = {0};
static uint8_t *p_buffer = read_buffer1;
static uint16_t buf_i = 0;
/* * * * * * * * * * * * * * * * * * * * * * DEVICE ONE * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Activate Device 1
REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CS1_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
for(uint8_t i = 0; i < 27; i++) {
uint8_t byte1 = 0;
byte1 = 0;
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 7);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 6);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 5);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 4);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 3);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 2);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 1);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 0);
p_buffer[buf_i++] = byte1;
}
// Deactivate Device 1
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CS1_PIN) << RTC_GPIO_OUT_DATA_W1TS_S));
/* * * * * * * * * * * * * * * * * * * * * * DEVICE TWO * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Activate Device 2
REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CS2_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
for(uint8_t i = 0; i < 27; i++) {
uint8_t byte1 = 0;
byte1 = 0;
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 7);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 6);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 5);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 4);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 3);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 2);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 1);
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TS_S)); REG_WRITE(RTC_GPIO_OUT_W1TC_REG, (BIT(CLK_PIN) << RTC_GPIO_OUT_DATA_W1TC_S));
byte1 |= (((uint8_t)((REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S) & BIT(DATA_PIN)) ) << 0);
p_buffer[buf_i++] = byte1;
}
// Deactivate Device 2
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, (BIT(CS2_PIN) << RTC_GPIO_OUT_DATA_W1TS_S));
// Přepnutí bufferu, pokud je plný
if (buf_i >= 1350) {
buf_i = 0;
p_buffer_global = p_buffer;
p_buffer = (p_buffer == read_buffer1) ? read_buffer2 : read_buffer1;
buffer_ready = true;
ulp_riscv_wakeup_main_processor();
}
}
int main(void) {
/* Register SW interrupt handler */
// ulp_riscv_enable_sw_intr(sw_int_handler, NULL);
/* Configure GPIO in input mode for interrupt */
ulp_riscv_gpio_init(DRDY_PIN);
ulp_riscv_gpio_input_enable(DRDY_PIN);
ulp_riscv_gpio_init(DATA_PIN);
ulp_riscv_gpio_input_enable(DATA_PIN);
ulp_riscv_gpio_init(CLK_PIN);
ulp_riscv_gpio_output_enable(CLK_PIN);
ulp_riscv_gpio_init(CS1_PIN);
ulp_riscv_gpio_output_enable(CS1_PIN);
ulp_riscv_gpio_output_level(CS1_PIN, 1);
ulp_riscv_gpio_init(CS2_PIN);
ulp_riscv_gpio_output_enable(CS2_PIN);
ulp_riscv_gpio_output_level(CS1_PIN, 1);
/* Register GPIO interrupt handler */
ulp_riscv_gpio_isr_register(DRDY_PIN, ULP_RISCV_GPIO_INTR_NEGEDGE, gpio_int_handler, NULL);
while (1) {
// if(sw_int_cnt > 20000L) {
// wake_by_gpio = 0;
// wake_by_sw = 1;
// ulp_riscv_wakeup_main_processor();
// sw_int_cnt = 0;
// }
ulp_riscv_delay_cycles(1000 * ULP_RISCV_CYCLES_PER_MS);
}
return 0;
}