Port ESP32 Code to ESP32-C3 – Notes

The new tiny and low power RISC-V MCU from Espressif – ESP32-C3 – has been around for a while now. While the ESP-IDF has grown to have good support for all core features, there are items that need your attention when you are trying to port ESP32 code to ESP32-C3.

This article with notes is a result of changes I had to make when trying to port ESP-ADF Lyra audio kit driver from ESP32 to ESP32-C3. ESP32-C3 examples do not use an ES8388 codec within the ESP-ADF, which means you need to port the code to make audio applications with ESP32-C3 and ES8388. In this case, we are using our ES8388 codec module.

Most generic, everyday code can simply work with an ESP32-C3. There are some major limitations that you need to work around. Here is a list of the common ones that you will have to deal with:

1. ESP32-C3 is single core

The ESP32-C3 should be treated like an ESP8266.
It only has a single core that runs at 160 MHz. While that is a lot of processing power in the embedded world, you must take care that your RTOS code is capable of running on the same core that also handles all real-time networking tasks.

In case of audio and GUI applications, this means that you must offload all large data transfers to the DMA and also ensure that your tasks do not completely block the core or starve the idle process.

Converting all polling based code segments to interrupt, RTOS event or flag based processes is a good idea to start with.

2. Lower GPIO count

ESP32 had more GPIOs to work with. When you port ESP32 code to the ESP32-C3, you need to make sure your application can run with constrained GPIOs.

The number of GPIOs alone should not be considered. There are other factors that matter too:

  • Strapping pin states must be respected
  • RTC domain and analog GPIOs vs digital, regular GPIOs
  • Default pull-up or pull-down state of the GPIO (in ultra low power applications)
  • If external flash is used in DIO mode, 2 GPIOs can be used for other functions

Here is a good list of ESP32-C3 GPIOs and capabilities.

port esp32 esp32-c3 pinout and gpios
ESP32-C3 Pinout and GPIOs

If you leave unavailable GPIO numbers in the source code, you will encounter errors like
error: ‘GPIO_NUM_23’ undeclared (first use in this function); did you mean ‘GPIO_NUM_21’?

3. Lower peripheral count

Peripheral count is low on the ESP32-C3. You do not get 3 I2C blocks or multiple SPI and I2S hosts with parallel interface options for cameras and displays like you had on the ESP32. Therefore, you need to remove references from the code to peripheral indices that do not exist on the ESP32-C3.

While peripherals may appear similar, there are subtle differences:

  •  I2S peripheral does not have parallel data option
  • There is no APLL on ESP32-C3, the I2S needs to be clocked from PLL_D2_CLK instead
  • many other similar differences that are noted in the technical reference manual

If you mention a peripheral that does not exist, you will see errors like the following:
error: ‘I2C_NUM_1’ undeclared (first use in this function); did you mean ‘I2C_NUM_0’?


4. Although similar, ESP-IDF functions may differ

You can do certain things with the ESP32-C3 that are not possible in the regular ESP32 series. For example, the ESP32-C3 MCLK output for the audio MCLK can be routed through the GPIO matrix to any GPIO. With the ESP32, you could not do that.

So with the ESP32-C3, you can initialize the I2S structure and route MCLK to any GPIO without the need to explicitly enable clock output using additional code. The same function call will fail for an ESP32.

This is in no way a complete list of items that you need to pay attention to – but these are the very first edits you will need to make to port ESP32 code. I will keep updating the list as and when I come across important points.
Note that this is relevant to ESP32-C3 silicon version 3 and ESP-IDF 5.0. Things may change with future versions of the IDF.

Change Log

  • 28 January 2023
    – Initial Release

You may also like

Leave a Comment

three × 5 =


Gerry July 20, 2023 - 5:00 pm

I’m about to use an ES7134 DAC with the ESP32-c3. I see you’re saying that MCLK is mappable to any pin. Is this also true of the serial data, left-right clock, and bit clock lines? Right now I am using PWM output from the ADF libraries which I modified to get 10-bit sound instead of 8-bit, then doing low pass filters feeding NS4150 3watt audio amps.

Pratik (A PCBArtist) July 21, 2023 - 8:57 am

You can route other I2S pins to any GPIO. MCLK was not flexible on the regular old ESP32 chips and was only available on GPIO0 and 2 other pins.
That being said, you should consult the datasheet of the chip to make sure there are no conflicting properties like strapping inputs.

Gerry August 4, 2023 - 2:01 am

Thanks – yes the strapping pins are needed to program, but I seem to have got around it (even though pin 8 and pin 9 used – I have isolating resistors). I have it actually working however the sound has a weird and very annoying distortion that is consistent

Gerry August 4, 2023 - 3:35 am

All working well now. I had the sample rate at 44100 which was wrong and switched it to 48000 in the I2S_stream.h file. All good

Pratik (A PCBArtist) August 4, 2023 - 10:21 am

Glad you could get it all working!
If you notice white noise like audio, it is usually a byte format issue – LSB and MSB of audio data interchanged or in reverse order. For incorrect sampling rates, behavior will vary across codecs. We make sure to check the error flag registers on codecs when available to make sure we are not violating something.