1010#include "driver/parlio_tx.h"
1111#include "parlio_priv.h"
1212
13+ #if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
14+ static bool parlio_tx_gdma_eof_callback (gdma_channel_handle_t dma_chan , gdma_event_data_t * event_data , void * user_data );
15+ #endif
1316static void parlio_tx_default_isr (void * args );
1417
1518static esp_err_t parlio_tx_create_trans_queue (parlio_tx_unit_t * tx_unit , const parlio_tx_unit_config_t * config )
@@ -342,14 +345,6 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
342345 // set sample clock edge
343346 parlio_ll_tx_set_sample_clock_edge (hal -> regs , config -> sample_edge );
344347
345- #if SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
346- // always use DMA EOF as the Parlio TX EOF if supported
347- parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DMA_EOF );
348- #else
349- // In default, use DATA LEN EOF as the Parlio TX EOF
350- parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DATA_LEN );
351- #endif // SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
352-
353348 // clear any pending interrupt
354349 parlio_ll_clear_interrupt_status (hal -> regs , PARLIO_LL_EVENT_TX_MASK );
355350
@@ -364,6 +359,7 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
364359
365360 portMUX_INITIALIZE (& unit -> spinlock );
366361 atomic_init (& unit -> fsm , PARLIO_TX_FSM_INIT );
362+ atomic_init (& unit -> buffer_need_switch , false);
367363 // return TX unit handle
368364 * ret_unit = unit ;
369365 ESP_LOGD (TAG , "new tx unit(%d,%d) at %p, out clk=%" PRIu32 "Hz, queue_depth=%zu, idle_mask=%" PRIx32 ,
@@ -426,12 +422,30 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
426422 if (cbs -> on_trans_done ) {
427423 ESP_RETURN_ON_FALSE (esp_ptr_in_iram (cbs -> on_trans_done ), ESP_ERR_INVALID_ARG , TAG , "on_trans_done callback not in IRAM" );
428424 }
425+ if (cbs -> on_buffer_switched ) {
426+ ESP_RETURN_ON_FALSE (esp_ptr_in_iram (cbs -> on_buffer_switched ), ESP_ERR_INVALID_ARG , TAG , "on_buffer_switched callback not in IRAM" );
427+ }
429428 if (user_data ) {
430429 ESP_RETURN_ON_FALSE (esp_ptr_internal (user_data ), ESP_ERR_INVALID_ARG , TAG , "user context not in internal RAM" );
431430 }
432431#endif
433432
433+ if (cbs -> on_buffer_switched ) {
434+ #if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
435+ // workaround for DIG-559
436+ ESP_RETURN_ON_FALSE (tx_unit -> data_width > 1 , ESP_ERR_NOT_SUPPORTED , TAG , "on_buffer_switched callback is not supported for 1-bit data width" );
437+
438+ gdma_tx_event_callbacks_t gdma_cbs = {
439+ .on_trans_eof = parlio_tx_gdma_eof_callback ,
440+ };
441+ ESP_RETURN_ON_ERROR (gdma_register_tx_event_callbacks (tx_unit -> dma_chan , & gdma_cbs , tx_unit ), TAG , "install DMA callback failed" );
442+ #else
443+ ESP_RETURN_ON_FALSE (false, ESP_ERR_NOT_SUPPORTED , TAG , "on_buffer_switched callback is not supported" );
444+ #endif
445+ }
446+
434447 tx_unit -> on_trans_done = cbs -> on_trans_done ;
448+ tx_unit -> on_buffer_switched = cbs -> on_buffer_switched ;
435449 tx_unit -> user_data = user_data ;
436450 return ESP_OK ;
437451}
@@ -443,8 +457,8 @@ static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_
443457 .buffer = (void * )t -> payload ,
444458 .length = (t -> payload_bits + 7 ) / 8 ,
445459 .flags = {
446- // if transmission is loop, we don't need to generate the EOF, as well as the final mark
447- .mark_eof = !t -> flags .loop_transmission ,
460+ // if transmission is loop, we don't need to generate the EOF for 1-bit data width, DIG-559
461+ .mark_eof = tx_unit -> data_width == 1 ? !t -> flags .loop_transmission : true ,
448462 .mark_final = !t -> flags .loop_transmission ,
449463 }
450464 };
@@ -462,13 +476,6 @@ static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_
462476static void parlio_tx_do_transaction (parlio_tx_unit_t * tx_unit , parlio_tx_trans_desc_t * t )
463477{
464478 parlio_hal_context_t * hal = & tx_unit -> base .group -> hal ;
465-
466- if (t -> flags .loop_transmission ) {
467- // Once a loop transmission is started, it cannot be stopped until it is disabled
468- // If SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA is supported, setting the eof condition to PARLIO_LL_TX_EOF_COND_DMA_EOF again is harmless
469- parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DMA_EOF );
470- }
471-
472479 tx_unit -> cur_trans = t ;
473480
474481 // If the external clock is a non-free-running clock, it needs to be switched to the internal free-running clock first.
@@ -497,7 +504,30 @@ static void parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio_tx_trans_
497504 // reset tx fifo after disabling tx core clk to avoid unexpected rempty interrupt
498505 parlio_ll_tx_reset_fifo (hal -> regs );
499506 parlio_ll_tx_set_idle_data_value (hal -> regs , t -> idle_value );
500- parlio_ll_tx_set_trans_bit_len (hal -> regs , t -> payload_bits );
507+
508+ // set EOF condition
509+ if (t -> flags .loop_transmission ) {
510+ if (tx_unit -> data_width == 1 ) {
511+ // for 1-bit data width, we need to set the EOF condition to DMA EOF
512+ parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DMA_EOF );
513+ } else {
514+ // for other data widths, we still use the data length EOF condition,
515+ // but let the `bit counter` + `data width` for each cycle is never equal to the configured bit lens.
516+ // Thus, we can skip the exact match, prevents EOF
517+ parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DATA_LEN );
518+ parlio_ll_tx_set_trans_bit_len (hal -> regs , 0x01 );
519+ }
520+ } else {
521+ // non-loop transmission
522+ #if SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
523+ // for DMA EOF supported target, we need to set the EOF condition to DMA EOF
524+ parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DMA_EOF );
525+ #else
526+ // for DMA EOF not supported target, we need to set the bit length to the configured bit lens
527+ parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DATA_LEN );
528+ parlio_ll_tx_set_trans_bit_len (hal -> regs , t -> payload_bits );
529+ #endif // SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
530+ }
501531
502532 if (tx_unit -> bs_handle ) {
503533 // load the bitscrambler program and start it
@@ -592,12 +622,6 @@ esp_err_t parlio_tx_unit_disable(parlio_tx_unit_handle_t tx_unit)
592622 parlio_ll_tx_start (hal -> regs , false);
593623 parlio_ll_enable_interrupt (hal -> regs , PARLIO_LL_EVENT_TX_MASK , false);
594624
595- #if !SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
596- // Once a loop teansmission transaction is started, it can only be stopped in disable function
597- // change the EOF condition to be the data length, so the EOF will be triggered normally in the following transaction
598- parlio_ll_tx_set_eof_condition (hal -> regs , PARLIO_LL_TX_EOF_COND_DATA_LEN );
599- #endif // !SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
600-
601625#if CONFIG_PM_ENABLE
602626 // release power management lock
603627 if (tx_unit -> pm_lock ) {
@@ -622,7 +646,8 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
622646
623647#if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
624648 if (config -> flags .loop_transmission ) {
625- ESP_RETURN_ON_FALSE (parlio_ll_tx_support_dma_eof (NULL ), ESP_ERR_NOT_SUPPORTED , TAG , "loop transmission is not supported by this chip revision" );
649+ ESP_RETURN_ON_FALSE (parlio_ll_tx_support_dma_eof (NULL ) || tx_unit -> data_width > 1 , ESP_ERR_NOT_SUPPORTED , TAG ,
650+ "1-bit data width loop transmission is not supported by this chip revision" );
626651 }
627652#else
628653 ESP_RETURN_ON_FALSE (config -> flags .loop_transmission == false, ESP_ERR_NOT_SUPPORTED , TAG , "loop transmission is not supported on this chip" );
@@ -653,6 +678,7 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
653678 tx_unit -> cur_trans -> payload = payload ;
654679 tx_unit -> cur_trans -> payload_bits = payload_bits ;
655680 parlio_mount_buffer (tx_unit , tx_unit -> cur_trans );
681+ atomic_store (& tx_unit -> buffer_need_switch , true);
656682 } else {
657683 TickType_t queue_wait_ticks = portMAX_DELAY ;
658684 if (config -> flags .queue_nonblocking ) {
@@ -701,6 +727,31 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
701727 return ESP_OK ;
702728}
703729
730+ #if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
731+ static bool parlio_tx_gdma_eof_callback (gdma_channel_handle_t dma_chan , gdma_event_data_t * event_data , void * user_data )
732+ {
733+ parlio_tx_unit_t * tx_unit = (parlio_tx_unit_t * ) user_data ;
734+ bool need_yield = false;
735+ bool expected_state = true;
736+ // invoke callback to notify the application
737+ parlio_tx_buffer_switched_callback_t on_buffer_switched = tx_unit -> on_buffer_switched ;
738+ if (on_buffer_switched ) {
739+ if (atomic_compare_exchange_strong (& tx_unit -> buffer_need_switch , & expected_state , false)) {
740+ parlio_tx_buffer_switched_event_data_t edata = {
741+ // we use 2 dma links to do the buffer switch in loop transmission
742+ .old_buffer_addr = gdma_link_get_buffer (tx_unit -> dma_link [1 - tx_unit -> cur_trans -> dma_link_idx ], 0 ),
743+ .new_buffer_addr = gdma_link_get_buffer (tx_unit -> dma_link [tx_unit -> cur_trans -> dma_link_idx ], 0 ),
744+ };
745+ if (on_buffer_switched (tx_unit , & edata , tx_unit -> user_data )) {
746+ need_yield = true;
747+ }
748+ }
749+ }
750+
751+ return need_yield ;
752+ }
753+ #endif // SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
754+
704755static void parlio_tx_default_isr (void * args )
705756{
706757 parlio_tx_unit_t * tx_unit = (parlio_tx_unit_t * )args ;
0 commit comments