Skip to content

Instantly share code, notes, and snippets.

@igrr
Created January 13, 2020 05:06
Show Gist options
  • 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!

@ulao
Copy link

ulao commented Jun 20, 2024

thx for this exmaple, I was trying to use the bundle trick here
https://esp32.com/viewtopic.php?t=27963
with no luck

I saw your example but this line didnt work.

   gpio_matrix_out(gpio_num, PRO_ALONEGPIO_OUT0_IDX + i, false, false);

I think it changed to

  gpio_iomux_out(gpio_num, PRO_ALONEGPIO_OUT0_IDX + i, false);

dropping the last parm. but I'm ony able to make my GPIO go high, it will not go low.

#define HIGH(dedic_io_num) asm volatile ("ee.set_bit_gpio_out %0" : : "I"(dedic_io_num) : );
#define LOW(dedic_io_num) asm volatile ("ee.clr_bit_gpio_out %0" : : "I"(dedic_io_num) : );

Also could not use any of the enable the peripheral as those are undefined.

@ulao
Copy link

ulao commented Jun 20, 2024

using the new way that also failed I tried this

#define HIGH(dedic_io_num)  __asm__ __volatile__ ("ee.set_bit_gpio_out %0" : : "I"(dedic_io_num) : );
#define LOW(dedic_io_num)  __asm__ __volatile__ ("ee.clr_bit_gpio_out %0" : : "I"(dedic_io_num) : );
  
 

// configure GPIO
const int bundleA_gpios[] = {0, 1, 2};
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
};
for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
// io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
// io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
//io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&io_conf);
}
// Create bundleA, output only
dedic_gpio_bundle_handle_t bundleA = NULL;
dedic_gpio_bundle_config_t bundleA_config = {
.gpio_array = bundleA_gpios,
.array_size = sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]),
.flags = {
.out_en = 1,
},
};

  while ( 1) 
  {
  
  HIGH(2);
 // _delay_us(10);
  LOW(2);
}

@JanPoppeliers
Copy link

You need to logical OR each bundleA_gpios[i] in io_conf.bit_mask:
io_conf.pin_bit_mask |= 1ULL << bundleA_gpios[i];

And after defining the bundleA_config you need to call:
ESP_ERROR_CHECK( dedic_gpio_new_bundle(&bundleA_config, &bundleA));

Then it should work.

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