Post Go back to editing

MXC_UART_TransactionAsync RX interrupt seems being disabled by MXC_UART_Transaction (blocked) TX

Thread Summary

The user encountered issues with stopping ADC reading via UART when a key is pressed, due to mixing blocking and non-blocking UART APIs. The solution involved using DMA for UART transactions and ensuring the correct clock source (IBRO_CLK) was used for UART3 on the MAX32655FTHR. The provided code snippet demonstrates setting up DMA for UART RX and TX, and using a callback to stop ADC sampling upon key press.
AI Generated Content
Category: Software
Product Number: MAX32655
Software Version: N/A

I wrote a code below referring the MSDK sample UART code. The code below is not original but is conceptual one.

/* ADC reading continues until any key is pressed */

UART_INT_FLAG = 1;                // Int handler clears this

MXC_UART_TransactionAsync(&read_req);

do {

      adc_value =  ADC_ConversionRegisterRead();  // SPI coomunication

      MXC_UART_AsyncStop();      // Added this second

      MXC_UART_Transaction(adc_value);

      MXC_UART_TransactionAsync(&read_req);  // Added this first

} while (UART_INT_FLAG == 1);

What I want to do is stop ADC reading when any key is pressed on terminal software.

MXC_UART_TransactionAsync(&read_req) itself is working at the other part in my code but in this code, it doesn't. UART_INT_FLAG doesn't go to 0.

The MXC_UART_TransactionAsync() is running until any key will be pressed and during its waiting loop, MXC_UART_Transaction() -- blocking function -- is executed.

It seems the MXC_UART_Transaction clears the TransactionAsync's interrupt setting or waiting condition (???, not yet confirmed).

I added two lines (bold). First is to execute TransactionAsync() again but it returns E_BUSY (-6). So I added MXC_UART_AsyncStop() before the MXC_UART_Transaction but still doesn't work.

Even these added two lines work, there is a period that INT is disabled. MXC_UART_Transaction() takes long executing time because it is blocking serial communication so possibility to lost a received character is very high.

Is there any way (or code/API) to enable this? Best case is TransactionAsync's operation is not affected by the other codes.

Please advise.

By the way, my SPI problem last I posted solved writing low level code.

Regards,

Satoru

  • Hi Satoru,

    From your explanation, the main issue arises because MXC_UART_Transaction() (blocking) and MXC_UART_TransactionAsync() (non‑blocking) cannot be used together reliably. The blocking call reconfigures the UART hardware state and interferes with the interrupt mechanism required by the asynchronous transaction. As a result, the interrupt flag (UART_INT_FLAG) is never cleared, and your ADC loop does not exit as expected. 

    I can recommend these approaches:

    • Avoid mixing blocking and asynchronous APIs: Use either fully asynchronous (MXC_UART_TransactionAsync) or DMA‑based (MXC_UART_TransactionDMA) APIs for both RX and TX. This ensures that interrupts remain enabled and no characters are lost.
    • Use callback functions for control flow: Instead of polling UART_INT_FLAG, you can register a callback with the asynchronous transaction. When a key is pressed, the callback will be triggered, and you can stop the ADC loop safely.
    • DMA for higher reliability: For continuous ADC sampling and UART transfers, DMA is strongly recommended. It allows UART RX/TX to run in the background without blocking the CPU, minimizing the risk of data loss.

    This approach ensures that UART reception is not interrupted by blocking calls, and ADC sampling can continue until a key press is detected.

    I can also share a conceptual code snippet for your convenience:

    #include "mxc_device.h"
    #include "uart.h"
    #include "dma.h"
    // ... and other headers
    
    // Global stop flag set by RX callback
    volatile uint8_t g_stop_adc = 0;
    
    // RX request using DMA for reliability (still 1 byte is enough)
    static mxc_uart_req_t uart_rx_req = {
        .uart     = MXC_UART0,
        .txData   = NULL,
        .txLen    = 0,
        .rxData   = NULL,          // Will be set before start
        .rxLen    = 1,
        .callback = NULL
    };
    
    // TX request using DMA for sending samples
    static mxc_uart_req_t uart_tx_req = {
        .uart     = MXC_UART0,
        .txData   = NULL,          // Will be set to buffer
        .txLen    = 0,
        .rxData   = NULL,
        .rxLen    = 0,
        .callback = NULL
    };
    
    static void uart_rx_callback(mxc_uart_req_t* req, int error)
    {
        (void)req;
        if (error == E_NO_ERROR) {
            g_stop_adc = 1;
        } else {
            // Optionally restart RX DMA on error
            // MXC_UART_TransactionDMA(&uart_rx_req);
        }
    }
    
    static void start_keypress_detection_dma(void)
    {
        static uint8_t rx_byte;
        uart_rx_req.rxData   = &rx_byte;
        uart_rx_req.rxLen    = 1;
        uart_rx_req.callback = uart_rx_callback;
    
        // Start RX via DMA (non-blocking)
        MXC_UART_TransactionDMA(&uart_rx_req);
    }
    
    static void send_adc_value_dma(uint32_t value)
    {
        uart_tx_req.txData = (uint8_t*)&value;
        uart_tx_req.txLen  = sizeof(value);
    
        // Non-blocking TX via DMA
        int r = MXC_UART_TransactionDMA(&uart_tx_req);
        if (r == E_BUSY) {
            // UART/DMA busy: implement a queue or skip
        }
    }
    
    int main(void)
    {
        // Init clocks, DMA, UART, ADC and etc.
        MXC_DMA_Init();
        MXC_UART_Init(MXC_UART0, 115200, MXC_UART_APB_CLK);
    
        // Begin waiting for keypress via DMA RX
        start_keypress_detection_dma();
    
        while (!g_stop_adc) {
            uint32_t adc_value = ADC_ConversionRegisterRead();
            send_adc_value_dma(adc_value);
        }
    
        // Stop any pending async/DMA work
        MXC_UART_AsyncStop(MXC_UART0);
        while (1) { }
    }
    

    Since the code snippet has not been compiled and tested, it may contain errors and warnings. Please make the necessary changes yourself using Analog MSDK.

    Kind regards,

  • Hi Haluk,

    Thank you very much for your support every time!

    I tried to use DMA following your code, but it didn't work. Error code E_BAD_PARAM (-3) returned when I call  

    MXC_UART_TransactionDMA.
    I am using MAX32655FTHR. Below is my code that is modified your code.  In the code RX is activated but TX case was the same. 
    #include <stdio.h>
    #include <stdint.h>
    #include "mxc_device.h"
    #include "uart.h"
    #include "dma.h"
    #include "mxc_delay.h"
    
    // Global stop flag set by RX callback
    volatile uint8_t g_stop_adc = 0;
    
    // RX request using DMA for reliability (still 1 byte is enough)
    static mxc_uart_req_t uart_rx_req = {
        .uart     = MXC_UART3,
        .txData   = NULL,
        .txLen    = 0,
        .rxData   = NULL,          // Will be set before start
        .rxLen    = 1,
        .callback = NULL
    };
    
    static void uart_rx_callback(mxc_uart_req_t* req, int error)
    {
        (void)req;
        if (error == E_NO_ERROR) {
            g_stop_adc = 1;
        } else {
            // Optionally restart RX DMA on error
            // MXC_UART_TransactionDMA(&uart_rx_req);
        }
    }
    
    static void start_keypress_detection_dma(void)
    {
        static uint8_t rx_byte;
    	int16_t error;
    
    	uart_rx_req.rxData   = &rx_byte;
        uart_rx_req.rxLen    = 1;
        uart_rx_req.callback = uart_rx_callback;
    
        // Start RX via DMA (non-blocking)
    	if((error = MXC_UART_TransactionDMA(&uart_rx_req)) != E_NO_ERROR) {
    		printf("Error Starting Transaction on UARt3: %d\n", error);
    	}
    }
    
    int main(void)
    {
        // Init clocks, DMA, UART, ADC and etc.
        MXC_DMA_Init();
        MXC_UART_Init(MXC_UART3, 115200, MXC_UART_APB_CLK);
    
        // Begin waiting for keypress via DMA RX
        start_keypress_detection_dma();
    
        while (!g_stop_adc) {
    	}
    
        // Stop any pending async/DMA work
        MXC_UART_AsyncStop(MXC_UART3);
        printf("Key pressed!\n");
        while (1) {}
    }
    Would you please suggest what is wrong?
    Regards,
    Satoru
  • Hi Satoru,

    Anytime, I'm glad I can help.

    As for your problem, the return value E_BAD_PARAM (-3) occurs because the UART peripheral has not been linked with a valid DMA channel before calling MXC_UART_TransactionDMA().

    According to the uart.h driver documentation, DMA-driven UART transactions require either:

    • automatic DMA handler setup using

      MXC_UART_SetAutoDMAHandlers(MXC_UART3, true);

      which automatically acquires and assigns DMA channels internally, or

    • manual channel assignment using

      int ch = MXC_DMA_AcquireChannel();
      MXC_UART_SetRXDMAChannel(MXC_UART3, ch);

    Without one of these configurations, the UART driver will reject the transaction request and return E_BAD_PARAM.

    On the MAX32655FTHR, MXC_UART3 fully supports DMA operation, so adding the MXC_UART_SetAutoDMAHandlers() call before MXC_UART_TransactionDMA() will probably resolve the issue.

    #include <stdio.h>
    #include <stdint.h>
    #include "mxc_device.h"
    #include "uart.h"
    #include "dma.h"
    #include "mxc_delay.h"
     
    // Global stop flag set by RX callback
    volatile uint8_t g_stop_adc = 0;
     
    // RX request using DMA (1 byte is enough for keypress detection)
    static mxc_uart_req_t uart_rx_req = {
        .uart     = MXC_UART3,
        .txData   = NULL,
        .txLen    = 0,
        .rxData   = NULL,     // Will be set before start
        .rxLen    = 1,
        .callback = NULL
    };
     
    // UART RX callback: set flag when key received
    static void uart_rx_callback(mxc_uart_req_t* req, int error)
    {
        (void)req;
     
        if (error == E_NO_ERROR) {
            g_stop_adc = 1;
        } else {
            printf("UART RX error: %d\n", error);
        }
    }
     
    static void start_keypress_detection_dma(void)
    {
        static uint8_t rx_byte;
        int error;
     
        uart_rx_req.rxData   = &rx_byte;
        uart_rx_req.rxLen    = 1;
        uart_rx_req.callback = uart_rx_callback;
     
        // Ensure DMA channel is assigned automatically to UART3
        MXC_UART_SetAutoDMAHandlers(MXC_UART3, true);
     
        // Start RX via DMA (non-blocking)
        error = MXC_UART_TransactionDMA(&uart_rx_req);
        if (error != E_NO_ERROR) {
            printf("Error starting UART3 DMA transaction: %d\n", error);
        } else {
            printf("UART3 DMA RX started, waiting for keypress...\n");
        }
    }
     
    int main(void)
    {
        // Initialize DMA and UART peripherals
        MXC_DMA_Init();
    
        // Use IBRO clock — required for UART3 (LPUART)
        int error = MXC_UART_Init(MXC_UART3, 115200, MXC_UART_IBRO_CLK );
        if (error != E_NO_ERROR) {
            printf("UART3 Init failed: %d\n", error);
            return error;
        }
     
        // Begin waiting for keypress via DMA RX
        start_keypress_detection_dma();
     
        // Poll until a key is received
        while (!g_stop_adc) {
            // Idle loop — ADC sampling or other tasks could run here
        }
     
        // Stop any pending async/DMA work
        MXC_UART_AsyncStop(MXC_UART3);
     
        printf("\nKey pressed!\n");
     
        while (1) {
            // Application main loop
        }
    }

    Best regards,

    Haluk

  • Hi Haluk,

    Thank you for your support. All worked. ADC reading starts/stops with key input at a terminal.

    One thing I would like to add comment to all of readers.

    MXC_UART_Init(MXC_UART0, 115200, MXC_UART_APB_CLK);

    works but

    MXC_UART_Init(MXC_UART3, 115200, MXC_UART_APB_CLK);

    does not. so use

    MXC_UART_Init(MXC_UART3, 115200, MXC_UART_IBRO_CLK );

    This is very basic topic but I missed it at beginning.

    Regards,

    Satoru