Skip to content

File HalDma.hpp

File List > fw > rbcx-coprocessor > include > utils > HalDma.hpp

Go to the documentation of this file.

#include "stm32f1xx_hal_dma.h"

// HAL_DMA_PollForTransfer, despite its name, can't be used
// for polling. When it hits timeout (even the 0 one), HAL_DMA_STATE_READY is set
// into the State member, regardless of whether the transfer is actually done or not.
// So you can't poll for whether the transfer is done. With the Poll function. What the fuck.
//
// This version will never set the State to HAL_DMA_STATE_READY on Timeout,
// only on error or when it is really done.
//
// Countless hours were wasted because of this garbage.
//
// Copied from https://github.com/STMicroelectronics/STM32CubeF1/blob/441b2cbdc25aa50437a59c4bffe22b88e78942c9/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c
inline HAL_StatusTypeDef HAL_DMA_PollForTransfer_Really(
    DMA_HandleTypeDef* hdma, uint32_t CompleteLevel, uint32_t Timeout) {
    uint32_t temp;
    uint32_t tickstart = 0U;

    if (HAL_DMA_STATE_BUSY != hdma->State) {
        /* no transfer ongoing */
        hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
        __HAL_UNLOCK(hdma);
        return HAL_ERROR;
    }

    /* Polling mode not supported in circular mode */
    if (RESET != (hdma->Instance->CCR & DMA_CCR_CIRC)) {
        hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
        return HAL_ERROR;
    }

    /* Get the level transfer complete flag */
    if (CompleteLevel == HAL_DMA_FULL_TRANSFER) {
        /* Transfer Complete flag */
        temp = __HAL_DMA_GET_TC_FLAG_INDEX(hdma);
    } else {
        /* Half Transfer Complete flag */
        temp = __HAL_DMA_GET_HT_FLAG_INDEX(hdma);
    }

    /* Get tick */
    tickstart = HAL_GetTick();

    while (__HAL_DMA_GET_FLAG(hdma, temp) == RESET) {
        if ((__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma))
                != RESET)) {
            /* When a DMA transfer error occurs */
            /* A hardware clear of its EN bits is performed */
            /* Clear all flags */
            hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);

            /* Update error code */
            SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TE);

            /* Change the DMA state */
            hdma->State = HAL_DMA_STATE_READY;

            /* Process Unlocked */
            __HAL_UNLOCK(hdma);

            return HAL_ERROR;
        }
        /* Check for the Timeout */
        if (Timeout != HAL_MAX_DELAY) {
            if ((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout)) {
                /* Update error code */
                SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TIMEOUT);

                /* Change the DMA state */
                // Disabled, because it makes no fucking sense.
                //hdma->State = HAL_DMA_STATE_READY;

                /* Process Unlocked */

                // Don't unlock until transfer done.
                //__HAL_UNLOCK(hdma);

                return HAL_ERROR;
            }
        }
    }

    if (CompleteLevel == HAL_DMA_FULL_TRANSFER) {
        /* Clear the transfer complete flag */
        __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));

        /* The selected Channelx EN bit is cleared (DMA is disabled and
    all transfers are complete) */
        hdma->State = HAL_DMA_STATE_READY;
    } else {
        /* Clear the half transfer complete flag */
        __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
    }

    /* Process unlocked */
    __HAL_UNLOCK(hdma);

    return HAL_OK;
}