Skip to content

Instantly share code, notes, and snippets.

@igrr
Created January 13, 2020 05:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save igrr/1515d369310479bbaf9239afeed4aac5 to your computer and use it in GitHub Desktop.
Save igrr/1515d369310479bbaf9239afeed4aac5 to your computer and use it in GitHub Desktop.
ESP32-S2 (beta) dedicated GPIO example
/* ESP32-S2 (beta) "dedicated GPIO" peripheral example */
#include <stdio.h>
#include "sdkconfig.h"
#include "soc/system_reg.h"
#include "esp32s2beta/rom/gpio.h"
#include "soc/gpio_sig_map.h"
#include "driver/gpio.h"
/* The header file is not yet in IDF; however this is the only register we need. */
#define DEDICATED_GPIO_OUT_CPU_EN_REG (DR_REG_DEDICATED_GPIO_BASE + 0x10)
void IRAM_ATTR app_main(void)
{
/* enable the peripheral */
REG_SET_BIT(DPORT_CPU_PERI_CLK_EN_REG, DPORT_CLK_EN_DEDICATED_GPIO);
REG_CLR_BIT(DPORT_CPU_PERI_RST_EN_REG, DPORT_RST_EN_DEDICATED_GPIO);
/* get the values of dedicated GPIO from the CPU, not peripheral registers */
REG_WRITE(DEDICATED_GPIO_OUT_CPU_EN_REG, 0xff);
/* configure GPIOs as outputs and route "dedicated GPIO" signals to them */
const int gpio_nums[] = {0, 1, 2, 3, 4, 5, 6, 7};
int n_gpios = sizeof(gpio_nums)/sizeof(gpio_nums[0]);
for (int i = 0; i < n_gpios; ++i) {
int gpio_num = gpio_nums[i];
gpio_config_t io_conf={
.mode=GPIO_MODE_OUTPUT,
.pin_bit_mask=(1ULL<<gpio_num)
};
ESP_ERROR_CHECK(gpio_config(&io_conf));
gpio_matrix_out(gpio_num, PRO_ALONEGPIO_OUT0_IDX + i, false, false);
}
uint32_t val = 0;
const uint32_t mask = 0xff;
const uint32_t zero = 0;
while(true) {
/* Set individual bits */
__asm__ __volatile__ ("set_bit_gpio_out 0x1");
__asm__ __volatile__ ("set_bit_gpio_out 0x2");
__asm__ __volatile__ ("set_bit_gpio_out 0x4");
__asm__ __volatile__ ("set_bit_gpio_out 0x8");
__asm__ __volatile__ ("clr_bit_gpio_out 0x1");
__asm__ __volatile__ ("clr_bit_gpio_out 0x2");
__asm__ __volatile__ ("clr_bit_gpio_out 0x4");
__asm__ __volatile__ ("clr_bit_gpio_out 0x8");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
/* write from a register with mask */
__asm__ __volatile__ ("wr_mask_gpio_out %0, %1" : : "r"(val), "r"(mask));
__asm__ __volatile__ ("wr_mask_gpio_out %0, %1" : : "r"(zero), "r"(mask));
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
/* can also set all the 8 bits (without masking) */
__asm__ __volatile__ ("wur.gpio_out %0" : : "r"(val));
__asm__ __volatile__ ("wur.gpio_out %0" : : "r"(zero));
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
__asm__ __volatile__ ("nop");
val++;
}
}
@JanPoppeliers
Copy link

What is the maximum GPIO toggle speed you can achieve this way? I need 20 MHz and the ESP32 can only achieve 10 MHz. Considering switching to an ESP32-S2 if this one can do it.

@igrr
Copy link
Author

igrr commented Feb 24, 2023

I found this screenshot of a logic analyzer trace produced by this example:
image

the pictured delay of 12.5 ns (1/80 MHz) corresponds to lines 43 and 44 of this code.

For the latest docs about this feature (on ESP32-S2), please check https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/dedic_gpio.html#manipulate-gpios-by-writing-assembly-code.

@JanPoppeliers
Copy link

Thanks, that is good news!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment