cubemx配置ADC+DMA转换后,代码在 adc.c 中将ADC_REG_InitStruct.DMATransfer 属性设置为:
LL_ADC_REG_DMA_TRANSFER_UNLIMITED 或者
LL_ADC_REG_DMA_TRANSFER_LIMITED(在MX中配置时只有这两选项)
,都会在初始化ADC时同时使能DMA。
cpp
/* ADC init function */
void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_ADC1);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
/**ADC GPIO Configuration
PA0 ------> ADC_IN0
PA5 ------> ADC_IN5
PA6 ------> ADC_IN6
PA7 ------> ADC_IN7
PB0 ------> ADC_IN8
PB1 ------> ADC_IN9
*/
GPIO_InitStruct.Pin = OTP_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(OTP_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = VSENSE_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(VSENSE_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = OVP1_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(OVP1_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = OVP2_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(OVP2_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SIGNAL1_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(SIGNAL1_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SIGNAL2_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(SIGNAL2_GPIO_Port, &GPIO_InitStruct);
/* ADC DMA Init */
/* ADC Init */
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_0);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_5);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_6);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_7);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_8);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_9);
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
ADC_InitStruct.Clock = LL_ADC_CLOCK_ASYNC;
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
LL_ADC_Init(ADC1, &ADC_InitStruct);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_REG_SetSequencerScanDirection(ADC1, LL_ADC_REG_SEQ_SCAN_DIR_FORWARD);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_239CYCLES_5);
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
开启通道转换前,如果调用了 LL_ADC_StartCalibration 开启ADC校准,ADC的DMA转换通道顺序会错乱(比如原本通道0的数据会跑掉其他通道去),在该函数的表述中就有
In case of usage of ADC with DMA transfer:
* On this STM32 serie, ADC DMA transfer request should be disabled
* during calibration: * @note In case of usage of ADC with DMA transfer:
* On this STM32 serie, ADC DMA transfer request should be disabled
* during calibration:
* Calibration factor is available in data register
* and also transfered by DMA.
* To not insert ADC calibration factor among ADC conversion data
* in array variable, DMA transfer must be disabled during
* calibration.
* (DMA transfer setting backup and disable before calibration,
* DMA transfer setting restore after calibration.
* Refer to functions @ref LL_ADC_REG_GetDMATransfer(),
* @ref LL_ADC_REG_SetDMATransfer() ).
cpp
/**
* @brief Start ADC calibration in the mode single-ended
* or differential (for devices with differential mode available).
* @note On this STM32 serie, a minimum number of ADC clock cycles
* are required between ADC end of calibration and ADC enable.
* Refer to literal @ref LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES.
* @note In case of usage of ADC with DMA transfer:
* On this STM32 serie, ADC DMA transfer request should be disabled
* during calibration:
* Calibration factor is available in data register
* and also transfered by DMA.
* To not insert ADC calibration factor among ADC conversion data
* in array variable, DMA transfer must be disabled during
* calibration.
* (DMA transfer setting backup and disable before calibration,
* DMA transfer setting restore after calibration.
* Refer to functions @ref LL_ADC_REG_GetDMATransfer(),
* @ref LL_ADC_REG_SetDMATransfer() ).
* @note On this STM32 serie, setting of this feature is conditioned to
* ADC state:
* ADC must be ADC disabled.
* @rmtoll CR ADCAL LL_ADC_StartCalibration
* @param ADCx ADC instance
* @retval None
*/
__STATIC_INLINE void LL_ADC_StartCalibration(ADC_TypeDef *ADCx)
{
/* Note: Write register with some additional bits forced to state reset */
/* instead of modifying only the selected bit for this function, */
/* to not interfere with bits with HW property "rs". */
MODIFY_REG(ADCx->CR,
ADC_CR_BITS_PROPERTY_RS,
ADC_CR_ADCAL);
}
由于在初始化时开启了DMA使能,会导致ADC在校准时产生的数据也被DMA搬运;应在 LL_ADC_StartCalibration 前 ADC_REG_InitStruct.DMATransfer 设置为 LL_ADC_REG_DMA_TRANSFER_NONE
LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_NONE);
关闭ADCDMA转换使能;