RTEMS support for ESP32 (Xtensa) / existing BSP work?

Hello everyone,

I am exploring the possibility of running RTEMS on an old ESP32 Wrover-E module, which uses the Xtensa® 32-bit LX6 microprocessor.

After reviewing the list of officially supported RTEMS BSPs, I noticed that Xtensa does not appear to be among them. Interestingly, I also came across this Reddit thread from 2019 which suggests there may have been some prior work in this area that is not available right now.

I have two questions:

  1. Has there been any prior or experimental BSP development for ESP32 or other Xtensa-based targets within the RTEMS community?
  2. If such work existed and was later abandoned, is there any reason behind that?

Any pointers to past discussions, patches, or repositories would be greatly appreciated.

Thank you

There is already work by @opticron to support ESP32-C3 and possibly C6 after. That leaves the C5 and P4

The Xtensa chips will never be supported as it requires too much custom tooling.

I plan on adding some GSoC projects around the new ESP32 BSPs not limited to:

  • Adding support for C3,C5,C6 depending on which ones are done
  • Wifi support loading the binary blob from expressif
  • GPIO support.

These would be 3 separate projects.

1 Like

Hi @opticron,

I would like to review your current work related to the RISC-V-based ESP32 to align my learning.

Could you please share some links to the specific branches or the repository where your ESP32-C3 and C6 work is hosted? I tried to find out, but didn’t have any luck. I’m particularly interested in the core initialisation and any basic peripheral drivers already in place.
Thank you very much.

The existing support for C3 is detailed here: ESP-32 C5 and C6 (#5527) · Issues · RTEMS / RTOS / RTEMS · GitLab

This does not yet include support for C5/C6.

This includes support for the RISC-V core, the interrupt matrix, SYSTIMER, and basic console on both UART0 and the USB-Serial connection. The watchdog is also quiesced during boot. SYSTIMER, UART0, USB-Serial, and watchdog support are likely directly reusable for the S-series chips. The Interrupt Matrix support is likely largely reusable, but will need some tweaks.

1 Like

Thank you very much for letting me know. I am interested in submitting a GSoC proposal on this project. At the moment, I don’t have the devices with me, and it would be mid-April if I order them right now. Is there anything that I can try out to show the ability to work on the project before the submission deadline (31st of March). Thank you very much.

There is another student currently interested in this project who has the hardware. 3 weeks is a long time I’m not sure what other accommodation we could make. You’ll have to see if you can propose some alternate ideas in giving us confidence you can complete the project.

1 Like

For information

[14:01:49.035] Disconnected
[14:01:50.036] Connected to /dev/ttyACM0
RTEMS Shell on /dev/console. Use 'help' to list commands.
SHLL [/] # CAN virtual registered at dev/can0
Setting CAN paths for tests to dev/can0 and dev/can0

SHLL [/] # rtems all
RTEMS: 7.0.0 (2edde64712c9d381a377f178fb577876ed8bf234-modified)
CPU: RISCV (RISCV)
BSP: esp32c3db
Tools: 15.2.0 20250808 (RTEMS 7, RSB 3546aa1e5662aa475bc0521ad2d1c66c39fe47ec, Newlib 038afec1)
Options: POSIX
SHLL [/] #  

RTEMS CAN/CAN FD stack information from ICE-V-Wireless. Run with reduced resources requirements in system.h and only with virtual controller. But SJA1000 should work with TWAI, when power and clock are enabled by respective registers and correct base, interrupt, registers span are set in SJA1000 registration.

1 Like

We have HW and SW to run PMSM control form NuttX on the board. The required peripherals are programmed over SPI into iCE40 FPGA and SPI is used then to set PWMs, read winding currents and read position from quadrature encoder in FPGA.

If SPI is implemented in RTEMS BSP, then it would be aeasy to run PXMC based application there, because it runs on Xilinx Zynq with Linux and RTEMS.

The OrtCAN CANopen implementation can be combined with it to build complete industrial system. But with Flash on SPI, there would be limitation in reliable maximal sampling frequency. The limit for NuttX has been about 500 Hz on this target.

1 Like

Progress, the RTEMS SJA1000 CAN driver seems to be ready, but without pins setup ends by bus error interrupts

Some idea how to obtain header files for ESP32C3 and ESP32C6.

There are System View Description (SVD) files available for these chips

There exists header files from SVD generator (primarily NuttX headers file format)

We have implemented headers generator for RETMS during TMS570 BSP development years ago. We have used reference manuals at that time as the source due to licensing problems. It has been tedious and required manual interventions into OCR based workflow

But these two project could be reused and combined and something reasonable can be prepared. It could help even to ARM BSPs (STM, NXP, Microchip) because SVD files are available for most of these chips today.

Next test

svdtoheaders -o -p ESP32C3_ -s esp32c3.svd -m esp32c3_map.h -r esp32c3_reg.h

seems to work. But I am for fork of svdtoheaders to adjust style to match RTEMS convention.

(SVD part combined into previous reply because Discourse blocks more than three replies from one user in row, when there is no response from other participants)

2 Likes

Thank you for the information. The takeaway for us is that we have a working foundation with the shell, but the next critical steps are implementing the SPI driver and refining the SVD-to-header pipeline to make the BSP scalable for the C-series without hardcoding the pins. Please correct me if I am wrong. Thanks.

I think that the decision about headers is critical one. I if the headers style is not taken from RTEMS, I would suggest to fork svdtoheaders and add option with name

-S, --style=[nuttx,rtems]

which would default to NuttX for now.

The NuttX style is esp32c3_map.h:

#define ESP32C3_xxx_BASE     0x....

esp32c3_reg.h:

/* APB_CTRL - APB (Advanced Peripheral Bus) Controller */
#define ESP32C3_APB_CTRL_BASE             0x60026000
#define ESP32C3_APB_CTRL_SYSCLK_CONF_OFFSET 0x0000
#define ESP32C3_APB_CTRL_SYSCLK_CONF      (ESP32C3_APB_CTRL_BASE + ESP32C3_APB_CTRL_SYSCLK_CONF_OFFSET)
#define ESP32C3_APB_CTRL_SYSCLK_CONF_PRE_DIV_CNT (0x3ff << 0) /* 000003ff: reg_pre_div_cnt */
#define ESP32C3_APB_CTRL_SYSCLK_CONF_PRE_DIV_CNT_MASK (0x3ff << 0)
#define ESP32C3_APB_CTRL_SYSCLK_CONF_CLK_320M_EN (1 << 10) /* 00000400: reg_clk_320m_en */
#define ESP32C3_APB_CTRL_SYSCLK_CONF_CLK_EN (1 << 11) /* 00000800: reg_clk_en */
#define ESP32C3_APB_CTRL_SYSCLK_CONF_RST_TICK_CNT (1 << 12) /* 00001000: reg_rst_tick_cnt */
#define ESP32C3_APB_CTRL_TICK_CONF_OFFSET 0x0004
#define ESP32C3_APB_CTRL_TICK_CONF        (ESP32C3_APB_CTRL_BASE + ESP32C3_APB_CTRL_TICK_CONF_OFFSET)
#define ESP32C3_APB_CTRL_TICK_CONF_XTAL_TICK_NUM (0xff << 0) /* 000000ff: reg_xtal_tick_num */
#define ESP32C3_APB_CTRL_TICK_CONF_XTAL_TICK_NUM_MASK (0xff << 0)

So may it be we can stay with that…

Or more RTEMS style is to use GENMASK and BIT

/* Error Code Capture Register */
#define REG_ECC_DIR BIT(5)
#define REG_ECC_ERCC GENMASK(7, 6)
#define REG_ECC_FUNC GENMASK(4, 0)
#define REG_ECC_ERCC_BIT (0)
#define REG_ECC_ERCC_FORM (1)
#define REG_ECC_ERCC_STUFF (2)
#define REG_ECC_ERCC_OTHER (3)

In TMS570 we have followed style Chris Johns and Sebastian Huber from LPC

#define PCLKSEL0_PCLK_UART1_MASK 0x00000300U

#define GET_PCLKSEL0_PCLK_UART1( reg ) \
  GET_FIELD( reg, PCLKSEL0_PCLK_UART1_MASK, 8 )

#define SET_PCLKSEL0_PCLK_UART1( reg, val ) \
  SET_FIELD( reg, val, PCLKSEL0_PCLK_UART1_MASK, 8 )

But I would stay with single mask per register field and use of FIELD_GET and FIELD_PREP.

I would not use overlay and or packed structures. It is better to define offsets and then use some IO access inline functions. Like we do in ctucanfd. There is a problem that I have not found generic whole RTEMS applicable IO access wrappers, Which is not so big problem for in-order CPUs, but there should be such such defines with proper barriers where required.

I would suggest to keep only peripherals base addresses in the device specif central files and attempt to unique other peripherals in per peripheral files with only esp32_ prefix and if required, documented differences between variants. May it be with specific fields disable to catch access to fields which are not implemented on specific variant of peripheral. I do not think that there would be much such deviations except for central power management, clock and reset which are chip specific and depends on integrated peripherals set.

For sure, keeping redundant definitions for I2C0,1,2… and SPI1,2 etc. would be nightmare and unusable for common drivers. It would worth to use python to build databases from all SVD files available for ESP32Cx and learn it to generate common headers specific for given peripheral, ESP_SPI, ESP_I2C which would even check for differences between instances and variants and documents these differences. But here should be single driver for all I2C channels, same for I2S. There could be more problems with SPI, because there could be more diferences for these which provide execute in place (XIP) functionality.

1 Like

There is interesting news, Espressif ESP32S31 is RISC-V based, has GMAC (Ethernet) in addition to WiFi, two CAN FD compatible TWAI controllers, 8-bit wide PSRAM connection and MMU

The peripherals combination can be guessed from LD script and SoC registers file.

Some more at CNX

So this one start to be really interesting for RTEMS development.

1 Like