Skip to content

Add ESP-IDF 6.0 support with dual 5.x/6.x compatibility - #463

Closed
Bwooce wants to merge 5 commits into
vroland:mainfrom
Bwooce:idf6-support
Closed

Add ESP-IDF 6.0 support with dual 5.x/6.x compatibility#463
Bwooce wants to merge 5 commits into
vroland:mainfrom
Bwooce:idf6-support

Conversation

@Bwooce

@Bwooce Bwooce commented Jan 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ESP-IDF 6.0 support while maintaining full backward compatibility with IDF 5.x (tested against 5.5). All changes use #if ESP_IDF_VERSION guards so both major versions compile cleanly for both ESP32 and ESP32-S3 targets.

Closes #450

Detailed changes

Build system (CMakeLists.txt)

  • Added IDF 6.x branch for component registration: IDF 6 splits legacy driver into sub-components (esp_hal_dma, esp_driver_rmt, esp_driver_gpio), so these are now listed as explicit REQUIRES for IDF_VERSION_MAJOR > 5
  • Existing IDF 4.x and 5.x branches are untouched

LCD driver — ESP32-S3 (src/output_lcd/lcd_driver.c)

  • LCD peripheral signals: struct renamed from lcd_periph_signals.panels[0].member / lcd_periph_rgb_signals.panels[0].member to array soc_lcd_rgb_signals[0].member in IDF 6. Replaced LCD_PERIPH_SIGNALS macro with LCD_PERIPH_SIG(member) to abstract the access pattern across all three naming conventions
  • LCD signal struct: forward-declared soc_lcd_rgb_signal_desc_t and extern soc_lcd_rgb_signals directly instead of including hal/lcd_periph.h, which in IDF 6 transitively pulls in hal/i2s_ll.h causing conflicts
  • GDMA API: gdma_new_channel() replaced by gdma_new_ahb_channel() in IDF 6 — takes 3 args (config, tx_chan, rx_chan) and gdma_channel_alloc_config_t no longer has a direction member
  • RMT peripheral clock: periph_module_enable(PERIPH_RMT_MODULE) removed in IDF 6 (PERIPH_RMT_MODULE no longer exists in shared_periph_module_t). Replaced with rmt_ll_enable_bus_clock() + rmt_ll_reset_register() inside PERIPH_RCC_ATOMIC() blocks
  • RMT LL rename: rmt_ll_enable_periph_clock() renamed to rmt_ll_enable_group_clock() in IDF 6
  • RMT types: rmt_item32_t removed with legacy RMT driver in IDF 6 — defined locally with identical layout
  • RMT signals struct: rmt_periph_signals.groups[0] renamed to array soc_rmt_signals[0] in IDF 6
  • RMT channel count: SOC_RMT_CHANNELS_PER_GROUP removed — replaced with RMT_LL_CHANS_PER_INST from hal/rmt_ll.h
  • RMT periph header: moved from soc/rmt_periph.h to hal/rmt_periph.h in IDF 6
  • LCD LL interrupt macro: IDF 5.5+ added a wrapper macro around lcd_ll_enable_interrupt() that references __DECLARE_RCC_ATOMIC_ENV, requiring the caller to be inside a PERIPH_RCC_ATOMIC() block. Guard lowered to >= 5.5.0 (not just 6.0)

RMT pulse driver — ESP32 (src/output_i2s/rmt_pulse.c)

  • Legacy RMT driver removed: driver/rmt.h (rmt_config(), rmt_set_tx_intr_en(), rmt_config_t) completely removed in IDF 6. Replaced init with direct register writes matching what rmt_config() did internally — the actual pulse generation already used direct RMTMEM access
  • RMT types: locally defined rmt_item32_t and rmt_block_mem_t for IDF 6 (same approach as lcd_driver.c)
  • Peripheral clock: same PERIPH_RCC_ATOMIC() + LL function pattern as lcd_driver.c
  • GPIO routing: gpio_matrix_out() replaced with esp_rom_gpio_connect_out_signal() via esp_rom_gpio.h

I2S data bus — ESP32 (src/output_i2s/i2s_data_bus.c)

  • Peripheral clock: periph_module_enable(PERIPH_I2S1_MODULE) removed in IDF 6 — replaced with i2s_ll_enable_bus_clock(1, true) + i2s_ll_reset_register(1) inside PERIPH_RCC_ATOMIC(). Same for disable in i2s_bus_deinit()
  • GPIO signal macros: I2S1O_DATA_OUT0_IDX / I2S1O_WS_OUT_IDX lost their transitive include path in IDF 6 — added explicit #include "soc/gpio_sig_map.h"
  • GPIO routing: gpio_matrix_out() replaced with esp_rom_gpio_connect_out_signal() for IDF 6

ADC temperature sensing (src/board/epd_board_common.c)

  • Legacy ADC API removed: adc1_get_raw(), esp_adc_cal_characterize(), esp_adc_cal_raw_to_voltage() all removed in IDF 6
  • Reimplemented epd_board_temperature_init_v2() and epd_board_ambient_temperature_v2() using the oneshot ADC driver (adc_oneshot_new_unit, adc_oneshot_config_channel, adc_oneshot_read) + new calibration API (adc_cali_create_scheme_line_fitting, adc_cali_raw_to_voltage)

Cache header path (src/output_lcd/render_lcd.c)

  • rom/cache.h may be relocated in IDF 6 — added __has_include fallback to esp32s3/rom/cache.h

SPIRAM config (src/highlevel.c)

  • IDF 6 unifies CONFIG_ESP32_SPIRAM_SUPPORT / CONFIG_ESP32S3_SPIRAM_SUPPORT under CONFIG_SPIRAM — added it as an additional check

Demo build (examples/demo/main/CMakeLists.txt)

  • GCC 15 (shipped with IDF 6) treats -Wbidi-chars= as an error for Unicode bidirectional control characters in the generated font header files. Added -Wno-error=bidi-chars= compile option

CI (.github/workflows/main.yml)

  • Added release-v6.0 to the build matrix for both ESP32 and ESP32-S3 (switch to v6.0 once the stable Docker tag exists)
  • Added IDF 6 extended examples (mirrors the v5.4 set)
  • Set continue-on-error: true for IDF 6 while it is pre-release
  • IDF 6 kconfgen crashes on large sdkconfig.defaults from IDF 5 (upstream bug: choice.selection is None). CI uses minimal sdkconfig.defaults for IDF 6 builds as a workaround
  • Added comment noting Arduino-ESP32 IDF 6 support is pending upstream

CI results

Target IDF 5.2 IDF 5.3 IDF 5.4 IDF 6.0
ESP32-S3 demo PASS PASS PASS PASS
ESP32 demo PASS PASS PASS PASS
screen_diag PASS PASS
dragon PASS PASS
grayscale_test PASS PASS
calibration_helper PASS PASS
www-image PASS FAIL (*)
Arduino weather PASS (v5.3.2)

(*) www-image fails on IDF 6 due to GCC 15 warnings-as-errors in the third-party bitbank2/jpegdec managed component (-Werror=pointer-to-int-cast, -Werror=shift-negative-value), not epdiy code. Requires an upstream fix to jpegdec.

Test plan

  • CI passes for IDF 5.2, 5.3, 5.4 (all green)
  • CI passes for IDF 6.0 ESP32 and ESP32-S3 demo builds
  • CI passes for IDF 6.0 extended examples (except www-image — third-party dependency)
  • Verify demo runs correctly on physical ESP32-S3 hardware with IDF 6.0
  • Verify demo runs correctly on physical ESP32 hardware with IDF 6.0
  • Once IDF 6.0 reaches stable release, switch release-v6.0 to v6.0 and remove continue-on-error

@Bwooce

Bwooce commented Jan 26, 2026

Copy link
Copy Markdown
Contributor Author

(yes, created with Claude the clanker. Hence the way longer description than I would have written, but it's useful to see the reasoning). I'll get the tests passing before clicking ready-for-review,

@Bwooce
Bwooce marked this pull request as ready for review January 27, 2026 06:52
@martinberlin

Copy link
Copy Markdown
Collaborator

@Bwooce please fix as soon as possible the failed automatic checks if you want to get this merged

Use #if ESP_IDF_VERSION guards throughout to support both IDF 5.x and 6.x.

Key changes:
- CMakeLists.txt: add IDF 6 component requirements (esp_driver_dma, etc.)
- lcd_driver.c: migrate LCD periph signals, GDMA, RMT LL APIs for IDF 6;
  wrap lcd_ll_enable_interrupt in PERIPH_RCC_ATOMIC() for IDF >= 5.5
- rmt_pulse.c: replace legacy RMT driver init with direct register access
  for IDF 6; define rmt_item32_t locally (removed from IDF 6 headers)
- i2s_data_bus.c: replace periph_module_enable with i2s_ll bus clock
  functions; add missing gpio_sig_map.h include for IDF 6
- epd_board_common.c: migrate ADC temperature sensing from legacy
  adc1_get_raw/esp_adc_cal to oneshot ADC + calibration API for IDF 6
- render_lcd.c: guard rom/cache.h include path for IDF 6
- highlevel.c: add CONFIG_SPIRAM check (unified Kconfig name in IDF 6)
- demo CMakeLists.txt: suppress -Wbidi-chars= errors from generated fonts
  when building with GCC 15 (shipped with IDF 6)
- CI: add IDF v6.0 to build matrix with continue-on-error while pre-release

Closes vroland#450
- Run clang-format on lcd_driver.c, highlevel.c, rmt_pulse.c
- CI: use release-v6.0 Docker image (v6.0 tag doesn't exist yet)
IDF 6 kconfgen crashes (upstream bug: choice.selection is None) when
processing the large sdkconfig.defaults files generated by IDF 5.
Clear the target-specific files and use minimal defaults for IDF 6.
Keep martinberlin's __DECLARE_RCC_ATOMIC_ENV (0) workaround from vroland#452
in lcd_driver.h, but #undef it in lcd_driver.c for IDF >= 5.5 where
PERIPH_RCC_ATOMIC() uses the symbol as a variable declaration. The (0)
define and PERIPH_RCC_ATOMIC() are incompatible on 5.5+.

Also add missing #endif for the IDF 5+ guard around RMTMEM/
rmt_block_mem_t, which was lost during rebase with vroland#461.
@Bwooce

Bwooce commented Feb 3, 2026

Copy link
Copy Markdown
Contributor Author

All checks are now passing. The one remaining failure is www-image on IDF 6.0, which is caused by GCC 15 warnings-as-errors in the third-party bitbank2/jpegdec managed component (shift-negative-value, pointer-to-int-cast), not epdiy code. I've submitted a fix upstream (bitbank2/JPEGDEC#113), waiting on their review.

The IDF 6.0 jobs have continue-on-error: true so the overall workflow reports success, but the individual check still shows as failed.

@martinberlin

Copy link
Copy Markdown
Collaborator

@Bwooce what is the status here?
Shall I write Larry Bank and ask about an update in JPEGDEC?

I will try to add your PR about I2C next weekend. Sorry but it was stale, and not working properly, in the tests I run.

@Bwooce

Bwooce commented Feb 21, 2026

Copy link
Copy Markdown
Contributor Author

I'll go chase the missing upstream PR Martin, it's not a very active repo. I could also try and work around it, it's literally due to a "warnings now treated as errors" change in IDF 6 which uses GCC 15 so the PR is nice-to-have functionally but working around it long-term would be incorrect.

@martinberlin

Copy link
Copy Markdown
Collaborator

No problem. I will try to test your update. I've a v7 board to share with you if you would like to try it, just need to pay the shipping.

@vroland vroland left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, sorry to be late to the party, just a suggestion if it doesn't burn too many tokens: We could separate the ADC and RMT migrations into separate PRs, since those should be backwards compatible. The ADC I can test while travelling, the RMT I can't test right now because I don't have an older board with me.
Then we can rebase the 6.0 branch, which should become much smaller. At that point, if the JPEGDEC dependency is not updated, I'd be fine with moving the www-image example into a separate repo that only builds with 5.x or hacks, while all the remaining examples should build cleanly with 6.0.


#include <esp_idf_version.h>

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may not need to be conditional, since the oneshot adc driver was introduced in IDF V5, and we don't support IDF 4.x anymore. Then we remove the old implementation. Could also be moved into a separate PR.

#include <driver/gpio.h>
#include "esp_rom_gpio.h"

void rmt_pulse_init(gpio_num_t pin) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I don't think we gain much by keeping both implementations. We can just migrate to the new implementation. Also maybe in a separate PR?

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
// IDF 6.x: rmt_mem_t and rmt_item32_t removed with legacy driver.
// Define compatible types for direct RMT memory access.
#include <soc/rmt_reg.h>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be included in the rmt migration, then it doesn't need to be duplicated in I2S and LCD driver.

@martinberlin

Copy link
Copy Markdown
Collaborator

@vroland in the top of that further upgrades of IDF won't let you use the old I2C legacy driver. This happened already with me on a C5 board (Yes C5 works also to drive parallel using the new Parlio driver)

https://github.com/martinberlin/i2c_bus this is the super simple component I built so you can just use one I2C bus for many different I2C peripherals without running into the warning "I2C is already initialised" this would be also something cool to implement into epdiy. As many people uses it for home automation, connecting other i2c sensors to the board.

@vroland

vroland commented Apr 12, 2026

Copy link
Copy Markdown
Owner

If I understand your component correctly, it would still require people to use your component if they want to re-use the I2C bus? If that's the case, wouldn't it make more sense to migrate to the new I2C driver and provide a way to optionally initialize epdiy with an existing bus? Then we don't introduce another custom way of doing things.

vroland added a commit that referenced this pull request Apr 12, 2026
Since IDF 4.x support is dropped, we can migrate to the new ADC driver.
This was extracted from #463 by
@Bwooce.
@martinberlin

Copy link
Copy Markdown
Collaborator

If I understand your component correctly, it would still require people to use your component if they want to re-use the I2C bus? If that's the case, wouldn't it make more sense to migrate to the new I2C driver and provide a way to optionally initialize epdiy with an existing bus? Then we don't introduce another custom way of doing things.

Yeah sure what I was saying is that it would be nice to use something like this inside epdiy itself. So then we have only one file to modify where I2C is handled making it easy to update it without searching in what other parts of the code is instantiated (PCA9535, TPS65185)
Just an idea that I though can bring a more cohesive and maintainable code

vroland added a commit that referenced this pull request May 7, 2026
Since IDF 4.x support is dropped, we can migrate to the new ADC driver.
This was extracted from #463 by
@Bwooce.
vroland added a commit that referenced this pull request May 7, 2026
Since IDF 4.x support is dropped, we can migrate to the new ADC driver. 
This was extracted from #463 by
@Bwooce.
vroland added a commit that referenced this pull request Jun 7, 2026
vroland added a commit that referenced this pull request Jun 13, 2026
This PR adds the remaining ESP-IDF 6.0 support work from #463 on top of
current main, after the ADC and RMT migrations from that original PR
were split out and addressed separately. It updates CI to build against
the stable v6.0 image, adds the remaining IDF 6 build requirements and
SDK config workaround, and adapts the ESP32 I2S and ESP32-S3 LCD paths
for IDF 6 API/header changes while reusing the existing rmt_compat
abstraction rather than carrying over the older duplicated RMT
compatibility code.
@vroland

vroland commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Superseeded by #477

@vroland vroland closed this Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make it possible to compile in ESP-IDF version 6.1

3 participants