2020#include "esp_adc/adc_oneshot.h"
2121#include "esp_adc/adc_continuous.h"
2222#include "esp_adc/adc_cali_scheme.h"
23+ #include "esp_heap_caps.h"
2324
2425#if CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_REV_MIN_FULL >= 300
2526// NOTE: These weak definitions allow successful linkage if the real efuse calibration functions are missing.
@@ -403,43 +404,40 @@ adc_continuous_result_t *adc_result = NULL;
403404static bool adcContinuousDetachBus (void * adc_unit_number ) {
404405 adc_unit_t adc_unit = (adc_unit_t )adc_unit_number - 1 ;
405406
407+ // Guard against double-cleanup: check if already cleaned up
406408 if (adc_handle [adc_unit ].adc_continuous_handle == NULL ) {
407409 return true;
408- } else {
409- esp_err_t err = adc_continuous_deinit (adc_handle [adc_unit ].adc_continuous_handle );
410+ }
411+
412+ // Clean up ADC driver
413+ esp_err_t err = adc_continuous_deinit (adc_handle [adc_unit ].adc_continuous_handle );
414+ if (err != ESP_OK ) {
415+ return false;
416+ }
417+ adc_handle [adc_unit ].adc_continuous_handle = NULL ;
418+
419+ // Clean up calibration handle if exists
420+ if (adc_handle [adc_unit ].adc_cali_handle != NULL ) {
421+ #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
422+ err = adc_cali_delete_scheme_curve_fitting (adc_handle [adc_unit ].adc_cali_handle );
410423 if (err != ESP_OK ) {
411424 return false;
412425 }
413- adc_handle [adc_unit ].adc_continuous_handle = NULL ;
414- if (adc_handle [adc_unit ].adc_cali_handle != NULL ) {
415- #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
416- err = adc_cali_delete_scheme_curve_fitting (adc_handle [adc_unit ].adc_cali_handle );
417- if (err != ESP_OK ) {
418- return false;
419- }
420426#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
421- err = adc_cali_delete_scheme_line_fitting (adc_handle [adc_unit ].adc_cali_handle );
422- if (err != ESP_OK ) {
423- return false;
424- }
425- #else
426- log_e ("ADC Calibration scheme is not supported!" );
427+ err = adc_cali_delete_scheme_line_fitting (adc_handle [adc_unit ].adc_cali_handle );
428+ if (err != ESP_OK ) {
427429 return false;
428- #endif
429430 }
431+ #else
432+ log_e ("ADC Calibration scheme is not supported!" );
433+ return false;
434+ #endif
430435 adc_handle [adc_unit ].adc_cali_handle = NULL ;
431-
432- //set all used pins to INIT state
433- for (uint8_t channel = 0 ; channel < SOC_ADC_CHANNEL_NUM (adc_unit ); channel ++ ) {
434- int io_pin ;
435- adc_oneshot_channel_to_io (adc_unit , channel , & io_pin );
436- if (perimanGetPinBusType (io_pin ) == ESP32_BUS_TYPE_ADC_CONT ) {
437- if (!perimanClearPinBus (io_pin )) {
438- return false;
439- }
440- }
441- }
442436 }
437+
438+ // Don't call perimanClearPinBus() here - the peripheral manager already handles it.
439+ // This callback is only responsible for cleaning up the IDF's ADC driver and calibration handles.
440+ // It does NOT free the adc_result buffer. The caller is responsible for freeing adc_result.
443441 return true;
444442}
445443
@@ -549,6 +547,14 @@ bool analogContinuous(const uint8_t pins[], size_t pins_count, uint32_t conversi
549547 }
550548#endif
551549
550+ #if CONFIG_IDF_TARGET_ESP32P4
551+ // Align conversion frame size to cache line size (required for DMA on targets with cache)
552+ uint32_t alignment_remainder = adc_handle [adc_unit ].conversion_frame_size % CONFIG_CACHE_L1_CACHE_LINE_SIZE ;
553+ if (alignment_remainder != 0 ) {
554+ adc_handle [adc_unit ].conversion_frame_size += (CONFIG_CACHE_L1_CACHE_LINE_SIZE - alignment_remainder );
555+ }
556+ #endif
557+
552558 adc_handle [adc_unit ].buffer_size = adc_handle [adc_unit ].conversion_frame_size * 2 ;
553559
554560 //Conversion frame size buffer cant be bigger than 4092 bytes
@@ -626,8 +632,21 @@ bool analogContinuousRead(adc_continuous_result_t **buffer, uint32_t timeout_ms)
626632 uint32_t bytes_read = 0 ;
627633 uint32_t read_raw [used_adc_channels ];
628634 uint32_t read_count [used_adc_channels ];
629- uint8_t adc_read [adc_handle [ADC_UNIT_1 ].conversion_frame_size ];
630- memset (adc_read , 0xcc , sizeof (adc_read ));
635+
636+ // Allocate DMA buffer with cache line alignment (required for ESP32-P4 and other targets with cache)
637+ size_t buffer_size = adc_handle [ADC_UNIT_1 ].conversion_frame_size ;
638+ #if CONFIG_IDF_TARGET_ESP32P4
639+ uint8_t * adc_read = (uint8_t * )heap_caps_aligned_alloc (CONFIG_CACHE_L1_CACHE_LINE_SIZE , buffer_size , MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL );
640+ #else
641+ uint8_t * adc_read = (uint8_t * )heap_caps_malloc (buffer_size , MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL );
642+ #endif
643+ if (adc_read == NULL ) {
644+ log_e ("Failed to allocate DMA buffer" );
645+ * buffer = NULL ;
646+ return false;
647+ }
648+
649+ memset (adc_read , 0xcc , buffer_size );
631650 memset (read_raw , 0 , sizeof (read_raw ));
632651 memset (read_count , 0 , sizeof (read_count ));
633652
@@ -638,6 +657,8 @@ bool analogContinuousRead(adc_continuous_result_t **buffer, uint32_t timeout_ms)
638657 } else {
639658 log_e ("Reading data failed with error: %X" , err );
640659 }
660+ free (adc_read );
661+ adc_read = NULL ;
641662 * buffer = NULL ;
642663 return false;
643664 }
@@ -676,6 +697,8 @@ bool analogContinuousRead(adc_continuous_result_t **buffer, uint32_t timeout_ms)
676697 }
677698 }
678699
700+ free (adc_read );
701+ adc_read = NULL ;
679702 * buffer = adc_result ;
680703 return true;
681704
@@ -708,16 +731,29 @@ bool analogContinuousStop() {
708731}
709732
710733bool analogContinuousDeinit () {
711- if (adc_handle [ADC_UNIT_1 ].adc_continuous_handle != NULL ) {
712- esp_err_t err = adc_continuous_deinit (adc_handle [ADC_UNIT_1 ].adc_continuous_handle );
713- if (err != ESP_OK ) {
714- return false;
734+ if (adc_handle [ADC_UNIT_1 ].adc_continuous_handle == NULL ) {
735+ log_i ("ADC Continuous was not initialized" );
736+ return true;
737+ }
738+
739+ // Clear all used pins from peripheral manager
740+ // This will trigger adcContinuousDetachBus() callback which cleans up the ADC driver
741+ for (uint8_t channel = 0 ; channel < SOC_ADC_CHANNEL_NUM (ADC_UNIT_1 ); channel ++ ) {
742+ int io_pin ;
743+ adc_oneshot_channel_to_io (ADC_UNIT_1 , channel , & io_pin );
744+ if (perimanGetPinBusType (io_pin ) == ESP32_BUS_TYPE_ADC_CONT ) {
745+ if (!perimanClearPinBus (io_pin )) {
746+ return false;
747+ }
715748 }
749+ }
750+
751+ // Free the result buffer (callback doesn't do this)
752+ if (adc_result != NULL ) {
716753 free (adc_result );
717- adc_handle [ADC_UNIT_1 ].adc_continuous_handle = NULL ;
718- } else {
719- log_i ("ADC Continuous was not initialized" );
754+ adc_result = NULL ;
720755 }
756+
721757 return true;
722758}
723759
0 commit comments