ULP RISCV SPI Simulation Using Bit-banging
ULP RISCV SPI Simulation Using Bit-banging
Dear Espressif programmers,
I would like to use ULP RISCV for SPI Simulation Using Bit-banging with ESP32-S3.
Is it possible to increase the CLK frequency for reading data from an SPI slave device? The ULP runs at 17.5 MHz, but the maximum achieved CLK frequency using the GPIO Bit-banging using my code is 235 kHz (see the attached code).
Optimization of the code is already tested without impact (-Os, -O2, O0). Could implementing it in assembler help? Or is this the maximum speed that can be achieved? Alternatively, can ULP I2C be used for this purpose in any way?
Thank you,
Jan
I would like to use ULP RISCV for SPI Simulation Using Bit-banging with ESP32-S3.
Is it possible to increase the CLK frequency for reading data from an SPI slave device? The ULP runs at 17.5 MHz, but the maximum achieved CLK frequency using the GPIO Bit-banging using my code is 235 kHz (see the attached code).
Optimization of the code is already tested without impact (-Os, -O2, O0). Could implementing it in assembler help? Or is this the maximum speed that can be achieved? Alternatively, can ULP I2C be used for this purpose in any way?
Thank you,
Jan
- Attachments
-
- ulp_riscv_example_main.c
- (2.31 KiB) Downloaded 70 times
-
- main.c
- (5.29 KiB) Downloaded 68 times
-
- Posts: 2045
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ULP RISCV SPI Simulation Using Bit-banging
REG_WRITE(RTC_GPIO_OUT_W1TS_REG, ...) should be faster than REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG,...).
Note that most ULP instructions take several clock cycles to execute, so the 17.5MHz will hardly result in more than 3-5 MIPS of throughput.
Note that most ULP instructions take several clock cycles to execute, so the 17.5MHz will hardly result in more than 3-5 MIPS of throughput.
Re: ULP RISCV SPI Simulation Using Bit-banging
What is the correct setting by the REG_WRITE ? Commented code below doesn't work (it does probably nothing). The REG_SET_FIELD or ulp_riscv_gpio_output_level(PINx,level) works both with the same clock speed. I would like to improve to about 1 us (1 MHz) GPIO CLK.
// REG_WRITE(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS+0x02);
// REG_WRITE(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TS+0x02);
// WRITE_PERI_REG(RTC_GPIO_OUT_W1TS_REG,0x02);
// WRITE_PERI_REG(RTC_GPIO_OUT_W1TC_REG,0x02);
REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, 0x02);
REG_SET_FIELD(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TS, 0x02);
// REG_WRITE(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS+0x02);
// REG_WRITE(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TS+0x02);
// WRITE_PERI_REG(RTC_GPIO_OUT_W1TS_REG,0x02);
// WRITE_PERI_REG(RTC_GPIO_OUT_W1TC_REG,0x02);
REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, 0x02);
REG_SET_FIELD(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TS, 0x02);
-
- Posts: 2045
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ULP RISCV SPI Simulation Using Bit-banging
What is the correct setting by the REG_WRITE ?
Code: Select all
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));
(See also https://github.com/espressif/esp-idf/is ... 1439418487 - assuming an average of 7 clocks per instruction, i.e. ~2.5MIPS, there's no way you could get anywhere close to 1MHz.)
Re: ULP RISCV SPI Simulation Using Bit-banging
Ladies and gentlemen, this way you can generate 1.1 MHz!
350 kHz:
or:
How to get GPIO level by this fastest procedure? Something like REG_READ(...) ?
Code: Select all
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));
Code: Select all
REG_SET_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, 0x02);
REG_SET_FIELD(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TS, 0x02);
Code: Select all
ulp_riscv_gpio_output_level(CLK_PIN, 1);
ulp_riscv_gpio_output_level(CLK_PIN, 0);
- Attachments
-
- NewFile0.png (6.96 KiB) Viewed 5097 times
-
- Posts: 2045
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ULP RISCV SPI Simulation Using Bit-banging
You may save 1 instruction by replacing
Code: Select all
REG_GET_FIELD(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT)
Code: Select all
(REG_READ(RTC_GPIO_IN_REG) >> RTC_GPIO_IN_NEXT_S)
Re: ULP RISCV SPI Simulation Using Bit-banging
How can an array or a block of data be shared between the ULP and the main program? I am unable to share an array for the SPI buffer. All variables are automatically created as uint32_t. I cannot read the array in the main program either via a pointer or by directly accessing its elements. Thank you for any possible solution!
-
- Posts: 2045
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ULP RISCV SPI Simulation Using Bit-banging
This is the only way how to get the read_buffer elements ? It seems to be correct, it returns the right values. I tried other options to access the read_buffer, but it always returned an error except for this approach...
Code: Select all
for(int i = 0; i < 27; i++) {
printf("%lu ", *(uint32_t *) (&ulp_read_buffer + i) );
}
-
- Posts: 2045
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: ULP RISCV SPI Simulation Using Bit-banging
Yep, that's about the only way.
If you want you can try variations like
or
or
If you want you can try variations like
Code: Select all
volatile uint32_t* const buffer_array = &ulp_read_buffer;
uint32_t x = buffer_array[i];
Code: Select all
volatile uint8_t* const buffer_array_u8 = (volatile uint8_t*)&ulp_read_buffer;
uint8_t x = buffer_array_u8[i];
Code: Select all
typedef union {
volatile uint32_t first;
volatile uint32_t array_u32[27];
volatile uint8_t array_u8[27*4];
} ulp_buffer_t;
const ulp_buffer_t* const buffer = (ulp_buffer_t*)&ulp_read_buffer;
...
Who is online
Users browsing this forum: No registered users and 50 guests