cancel
Showing results for 
Search instead for 
Did you mean: 

Unregister or Disable UART DMA XferHalfCpltCallback anyone?

jrgert
Associate III

I've tried to disable the XferHalfCpltCallback when using UART DMA transmit without any luck. I believe that you cannot change the callbacks, or disable them.

Observations:

  1. When you call HAL_UART_Transmit_DMA(), the callbacks are set to predefined UART functions. This happens right before HAL_DMA_Start_IT() which then checks for NULL callbacks and decides whether to enable/disable the interrupts.
  2. The interrupts always get enabled and callbacks always get called.
  3. The HAL has code to disable the interrupt if a NULL callback is found, but they are never NULL per item 1.
  4. Calling HAL_DMA_UnRegisterCallback() is moot.

Ideas?

7 REPLIES 7
S.Ma
Principal

I guess you need to hack the DMA half transfer interrupt enable control bit yourself.

Ron Koch
Associate II

Where should this hack be done?

Sorry, I joined to commiserate more than provide a solution...

I added the hack right after the HAL call:

comms_top_tx_status = HAL_UART_Transmit_DMA(&huart6, tx_packet_ptr, (uint16_t) (COMMS_TOP_TX_PACKET_SIZE));

hdma_usart6_tx.Instance->CR &= ~DMA_IT_HT;

But at this point the DMA is off and running. It looks like a race to disable the interrupt before it fires. It seems to work when I'm doing my long transfers of 30 bytes, but what if the transfer length was short? I'm not even sure it's ok to hack this bit while the xfer is executing.

You could filter execution of your interrupt handler based on the TC (xfer complete) flag. But the problem I'm having is that the second half of the transfer is garbage. So I'm suspicions of the half complete interrupt feature and its handling.

STeve D
Associate II

A few years late to this, but it looks like the hal_dma still enables the half-transfer interrupt without any clear way to disable it without hacking the hal, as S.Ma mentions. This hack can be done by commenting out the following line in HAL_DMA_Start_IT:

// ((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR  |= BDMA_CCR_HTIE;

However, I was worried that if our hal was ever updated I'd lose my "fix". So decided to handle the problem in the interrupt instead. Just checking to make sure the full transfer flag has occurred before doing stuff. And ignoring the half-transfer interrupt.

void DMA1_Stream0_IRQHandler(void) {
    NVIC_ClearPendingIRQ(DMA1_Stream0_IRQn);
    if (__HAL_DMA_GET_FLAG(&m_hdma_spi1_rx, HAL_DMA_GET_TC_FLAG_INDEX(&m_hdma_spi1_rx))) {
        // reading is complete, reenable interrupt
        HAL_DMA_IRQHandler(&m_hdma_spi1_rx);
        do_more_stuff(&m_stuff);
    }
}

where m_hdma_spi1_rx is:

static DMA_HandleTypeDef m_hdma_spi1_rx = {
    .Instance = DMA1_Stream0,
    .Init =
        {
            .Request = DMA_REQUEST_SPI1_RX,
            .Direction = DMA_PERIPH_TO_MEMORY,
            .PeriphInc = DMA_PINC_DISABLE,
            .MemInc = DMA_MINC_ENABLE,
            .PeriphDataAlignment = DMA_PDATAALIGN_BYTE,
            .MemDataAlignment = DMA_MDATAALIGN_BYTE,
            .Mode = DMA_NORMAL,
            .Priority = DMA_PRIORITY_HIGH,
            .FIFOMode = DMA_FIFOMODE_DISABLE,
        },
};

Hope this is helpful

Javier1
Principal

__HAL_DMA_DISABLE_IT(&hdma_usart2_tx,DMA_IT_HT);

we dont need to firmware by ourselves, lets talk

I seem to be having a similar issue, I am several hours today on it and need to speak out loud!

Basically, I have a half-duplex transceiver connected to USART2:

  • data is received in DMA on a circular buffer
  • I intend to transmit the incoming data in a loop back fashion for debugging
  • I need then to activate the transmit mode of the external transceiver by toggling a GPIO
  • then I transmit data
  • transmitted data are triggering the receive_DMA, so I create an infinite loop

Is maybe disabling the DMA interrupt on receiving path while transmitting a feasible idea?

 

I reply to myself to clear the statement there and provide solution. Actually it was silly topic and probably not relevant for the previous thread - excuse me!

My issue was: 

  • I needed USART_DE signal, but I did not let HAL taking care of it.
  • Instead I declared it as a GPIO and wanted to explicitly toggle the pin depending on receive or transmit phase.
  • solution: HAL driver will take care of DE pin, whenever Hardware flow control (RS485) is selected in project configurator.
  • Then Receive/Transmit functions can be used seamlessly (no need to take care of DE pin)

But, as Ron Koch said earlier, it is re-enabled in 

HAL_DMA_Start_IT()

 and calling 

__HAL_DMA_DISABLE_IT()

afterwards would be a race.