STM32G474的DAC具有4个内部通道以及3个外部通道。
此篇以TIM+DMA + DAC实现3通道转换,且三通道相互独立控制。不需要独立使用则可以节省1TIM+DMA+DAC。
对于三通道独立使用DAC配置如下:
__align(32) volatile uint16_t DAC1_ConvertedValue[40];//转换数组
__align(32) volatile uint16_t DAC2_ConvertedValue[40];
__align(32) volatile uint16_t DAC3_ConvertedValue[40];
void Dac1_Dma_Init(void)
{
DAC_ChannelConfTypeDef DAC_Config;
DAC1_Handle.Instance = DAC1;
if (HAL_DAC_Init(&DAC1_Handle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
DAC_Config.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE; //指定DAC输出是否连接到芯片外围
DAC_Config.DAC_DMADoubleDataMode = DISABLE; //指定在选择的通道中是否应该启用DMA双数据模式
DAC_Config.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_ABOVE_160MHZ;//指定频率接口模式
DAC_Config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; //指定DAC通道输出缓冲区是否启用或禁用
DAC_Config.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE; //指定DAC模式
DAC_Config.DAC_SignedFormat = DISABLE; //指定在选择的通道中是否应该使用已签署的格式
DAC_Config.DAC_Trigger = DAC_TRIGGER_T4_TRGO; //指定选择的DAC通道的外部触发器TIM4
DAC_Config.DAC_Trigger2 = DAC_TRIGGER_NONE; //指定选择的DAC通道的外部二次触发器
DAC_Config.DAC_UserTrimming = DAC_TRIMMING_FACTORY;//指定平边模式
if (HAL_DAC_ConfigChannel(&DAC1_Handle, &DAC_Config, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DACEx_SelfCalibrate(&DAC1_Handle, &DAC_Config, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
DAC_Config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; //TIM6
if (HAL_DAC_ConfigChannel(&DAC1_Handle, &DAC_Config, DAC_CHANNEL_2) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DACEx_SelfCalibrate(&DAC1_Handle, &DAC_Config, DAC_CHANNEL_2) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DAC_Start_DMA(&DAC1_Handle, DAC_CHANNEL_1, (uint32_t*)DAC1_ConvertedValue, 40, DAC_ALIGN_12B_R) != HAL_OK)//需要转换传输的数有40个
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DAC_Start_DMA(&DAC1_Handle, DAC_CHANNEL_2, (uint32_t*)DAC2_ConvertedValue, 40, DAC_ALIGN_12B_R) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
void Dac2_Dma_Init(void)
{
DAC_ChannelConfTypeDef DAC_Config;
DAC2_Handle.Instance = DAC2;
if (HAL_DAC_Init(&DAC2_Handle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
DAC_Config.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;
DAC_Config.DAC_DMADoubleDataMode = DISABLE;
DAC_Config.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_ABOVE_160MHZ;
DAC_Config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
DAC_Config.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
DAC_Config.DAC_SignedFormat = DISABLE;
DAC_Config.DAC_Trigger = DAC_TRIGGER_T7_TRGO; //TIM7
DAC_Config.DAC_Trigger2 = DAC_TRIGGER_NONE;
DAC_Config.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
if (HAL_DAC_ConfigChannel(&DAC2_Handle, &DAC_Config, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DACEx_SelfCalibrate(&DAC2_Handle, &DAC_Config, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DAC_Start_DMA(&DAC2_Handle, DAC_CHANNEL_1, (uint32_t*)DAC3_ConvertedValue, 40, DAC_ALIGN_12B_R) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
以上为三通道DAC配置。
对于DMA的配置则如下:
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
if(hdac->Instance == DAC1)
{
__HAL_RCC_DAC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
DAC1DMA_Handler.Instance = DMA1_Channel1;
DAC1DMA_Handler.Init.Request = DMA_REQUEST_DAC1_CHANNEL1;
DAC1DMA_Handler.Init.Direction = DMA_MEMORY_TO_PERIPH;
DAC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
DAC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;
DAC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DAC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
DAC1DMA_Handler.Init.Mode = DMA_CIRCULAR;
DAC1DMA_Handler.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&DAC1DMA_Handler) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
DAC2DMA_Handler.Instance = DMA1_Channel2;
DAC2DMA_Handler.Init.Request = DMA_REQUEST_DAC1_CHANNEL2;
DAC2DMA_Handler.Init.Direction = DMA_MEMORY_TO_PERIPH;
DAC2DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
DAC2DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;
DAC2DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DAC2DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
DAC2DMA_Handler.Init.Mode = DMA_CIRCULAR;
DAC2DMA_Handler.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&DAC2DMA_Handler) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(hdac,DMA_Handle1,DAC1DMA_Handler);
__HAL_LINKDMA(hdac,DMA_Handle2,DAC2DMA_Handler);
}
else if(hdac->Instance == DAC2)
{
__HAL_RCC_DAC2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
DAC3DMA_Handler.Instance = DMA1_Channel3;
DAC3DMA_Handler.Init.Request = DMA_REQUEST_DAC2_CHANNEL1;
DAC3DMA_Handler.Init.Direction = DMA_MEMORY_TO_PERIPH;
DAC3DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
DAC3DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;
DAC3DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DAC3DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
DAC3DMA_Handler.Init.Mode = DMA_CIRCULAR;
DAC3DMA_Handler.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&DAC3DMA_Handler) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(hdac,DMA_Handle1,DAC3DMA_Handler);
}
}
以下为3个定时器配置,当定时时间到达,DAC将会转换一次。
void Dac_config_Init(uint8_t num)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
switch(num)
{
case DacTim1:
TIMx_Handle[num].Instance = TIM4;
break;
case DacTim2:
TIMx_Handle[num].Instance = TIM6;
break;
case DacTim3:
TIMx_Handle[num].Instance = TIM7;
break;
}
TIMx_Handle[num].Init.Prescaler = 1 - 1;
TIMx_Handle[num].Init.Period = 170 * 5 - 1;//5us
TIMx_Handle[num].Init.RepetitionCounter = 0;
TIMx_Handle[num].Init.CounterMode = TIM_COUNTERMODE_UP;
TIMx_Handle[num].Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIMx_Handle[num].Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&TIMx_Handle[num]) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&TIMx_Handle[num], &sClockSourceConfig) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&TIMx_Handle[num], &sMasterConfig) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
以上为STM32G474对于3个TIM+DAC+DMA的使用,对于双通道同步输出则只需要简单修改即可。以上配置DMA传输数据为每个通道40个。定时器是每5us转换一次,转换时三通道同步转换,转换值由数组中的参数决定。