HAL庫(kù)DMA框架
介紹HAL庫(kù)中外設(shè)如何與DMA建立連接
外設(shè)句柄結(jié)構(gòu)體中包含有DMA句柄,如ADC
typedef struct __ADC_HandleTypeDef {
// ADC_TypeDef *Instance; /*!< Register base address */
// ADC_InitTypeDef Init; /*!< ADC required parameters */
DMA_HandleTypeDef *DMA_Handle; /*!< Pointer DMA Handler */
// HAL_LockTypeDef Lock; /*!< ADC locking object */
// __IO uint32_t State; /*!< ADC communication state */
// __IO uint32_t ErrorCode; /*!< ADC Error code */
}ADC_HandleTypeDef;
DMA句柄中包含中斷回調(diào)函數(shù)的函數(shù)指針接口,以及該父對(duì)象指針
typedef struct __DMA_HandleTypeDef
{
// DMA_Channel_TypeDef *Instance; /*!< Register base address */
// DMA_InitTypeDef Init; /*!< DMA communication parameters */
// HAL_LockTypeDef Lock; /*!< DMA locking object */
// __IO HAL_DMA_StateTypeDef State; /*!< DMA transfer state */
void *Parent; /*!< Parent object state */
void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);
void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);
void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);
void (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);
// __IO uint32_t ErrorCode;
// DMA_TypeDef *DmaBaseAddress;
// uint32_t ChannelIndex;
} DMA_HandleTypeDef;
在外設(shè)初始化時(shí),會(huì)對(duì)DMA進(jìn)行初始化,同時(shí)將兩者進(jìn)行關(guān)聯(lián)。這樣通過(guò)外設(shè)句柄就能操作DMA句柄
#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \
do \
{ \
(__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__); \
(__DMA_HANDLE__).Parent = (__HANDLE__); \
} while (0U)
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
在外設(shè)啟用DMA發(fā)送或接收時(shí),收發(fā)函數(shù)內(nèi)部會(huì)對(duì)外設(shè)掛載的DMA設(shè)置回調(diào)函數(shù),而這里使用的函數(shù)實(shí)體來(lái)自于外設(shè)預(yù)留的、關(guān)于DMA中斷的回調(diào)函數(shù)。
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length) {
// ...
/* Set the DMA transfer complete callback */
hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
/* Set the DMA half transfer complete callback */
hadc->DMA_Handle->XferHalfCpltCallback = ADC_DMAHalfConvCplt;
/* Set the DMA error callback */
hadc->DMA_Handle->XferErrorCallback = ADC_DMAError;
/* Start the DMA channel */
HAL_DMA_Start_IT(hadc->DMA_Handle, (uint32_t)&hadc->Instance->DR, (uint32_t)pData, Length);
// ...
}
賦值的回調(diào)函數(shù)為 ADC_DMAConvCplt ,其內(nèi)部調(diào)用了 HAL_ADC_ConvCpltCallback,HAL_ADC_ConvCpltCallback 才是最后用戶需要實(shí)現(xiàn)的。
void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma) {
/* Retrieve ADC handle corresponding to current DMA handle */
ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* Update state machine on conversion status if not in error state */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA))
{
/* Update ADC state machine */
SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);
// ...
/* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}
else
{
/* Call DMA error callback */
hadc->DMA_Handle->XferErrorCallback(hdma);
}
}
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
UNUSED(hadc);
}
DMA 中斷被啟動(dòng),并且掛載回調(diào)函數(shù)后,會(huì)在中斷中自動(dòng)運(yùn)行。
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
uint32_t flag_it = hdma->DmaBaseAddress->ISR;
uint32_t source_it = hdma->Instance->CCR;
/* Half Transfer Complete Interrupt management ******************************/
if (((flag_it & (DMA_FLAG_HT1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_HT) != RESET))
{
// ...
if(hdma->XferHalfCpltCallback != NULL) {
hdma->XferHalfCpltCallback(hdma); /* Half transfer callback */
}
}
/* Transfer Complete Interrupt management ***********************************/
else if (((flag_it & (DMA_FLAG_TC1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_TC) != RESET))
{
// ...
if(hdma->XferCpltCallback != NULL) {
hdma->XferCpltCallback(hdma);/* Transfer complete callback */
}
}
/* Transfer Error Interrupt management **************************************/
else if (( RESET != (flag_it & (DMA_FLAG_TE1 << hdma->ChannelIndex))) && (RESET != (source_it & DMA_IT_TE)))
{
// ...
if (hdma->XferErrorCallback != NULL) {
hdma->XferErrorCallback(hdma);/* Transfer error callback */
}
}
return;
}
void DMA1_Channel1_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_adc1);
}

浙公網(wǎng)安備 33010602011771號(hào)