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?

4 REPLIES 4
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

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);