我想通过DMA采集ADC数据,使用的芯片具体型号是STM32F030K6T6,发现DMA有one shot mode和circular mode。若使用one shot mode则只能触发一次AD采样,之后即使重新启动AD也无法再次触发。通过查询官方的RM0360 号文档《STM32F030x4_x6_x8_xC and STM32F070x6_xB advanced ARM-based 32-bit MCUs (version 4)》的ADC部分,发现,对于one shot mode,一旦传输完成即使重启AD也不会再次发送DMA请求,详情如下图: 目前我已使用circular mode解决,但我想既然官方给出这种模式,不至于说只有上电第一次能够触发吧,所以想请教老司机们是否有办法让one shot mode也能够多次触发。 附one shot mode操作的主要代码,主要功能就是将进入DMA中断的次数通过串口打印出来,实际操作只有1次: void ADC_Enable(void) { ADC1->CR |= ADC_CR_ADEN; } void ADC_Start(void) { ADC1->CR |= ADC_CR_ADSTART; } void ADC_Stop(void) { ADC1->CR |= ADC_CR_ADSTP; } /********************************************************* * 函数名称:void ADC_Calibrate(void) * 函数功能:ADC校准 * 入口参数:无 * 出口参数:无 * 返回参数:无 * 注意事项: * * 维护记录: * 2020.11.23 Created By Peng Yongjun * 参考RM0360? STM32F030x4_x6_x8_xC and STM32F070x6_xB advanced ARM-based 32-bit MCUs? (version 4).pdf *********************************************************/ void ADC_Calibrate(void) { /* (1) Ensure that ADEN = 0 */ /* (2) Clear ADEN by setting ADDIS*/ /* (3) Clear DMAEN */ /* (4) Launch the calibration by setting ADCAL */ /* (5) Wait until ADCAL=0 */ if ((ADC1->CR & ADC_CR_ADEN) != 0) /* (1) */ { ADC1->CR |= ADC_CR_ADDIS; /* (2) */ } while ((ADC1->CR & ADC_CR_ADEN) != 0) { /* For robust implementation, add here time-out management */ } ADC1->CFGR1 &= ~ADC_CFGR1_DMAEN; /* (3) */ ADC1->CR |= ADC_CR_ADCAL; /* (4) */ while ((ADC1->CR & ADC_CR_ADCAL) != 0) /* (5) */ { /* For robust implementation, add here time-out management */ } } /********************************************************* * 函数名称:void ADC_CLK_ConfigEnable(void) * 函数功能:ADC时钟使能 * 入口参数: * 出口参数: * 返回参数: * 注意事项: * * 维护记录: * 2020.11.23 Created By Peng Yongjun *********************************************************/ void ADC_CLK_ConfigEnable(void) { /* This code selects the HSI14 as clock source. */ /* (1) Enable the peripheral clock of the ADC */ /* (2) Start HSI14 RC oscillator */ /* (3) Wait HSI14 is ready */ /* (4) Select HSI14 by writing 00 in CKMODE (reset value) */ RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */ RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */ while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0) /* (3) */ { /* For robust implementation, add here time-out management */ } //ADC1->CFGR2 &= (~ADC_CFGR2_CKMODE); /* (4) */ } void InitAdcDMAShot(void) { GPIO_InitTypeDef gpioInitStruct = {0}; // __HAL_RCC_ADC1_CLK_ENABLE(); //---------------PA0 PA1 PA5 PA6 as analog------------------- //gpioInitStruct.Alternate = gpioInitStruct.Mode = GPIO_MODE_ANALOG; gpioInitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_5 | GPIO_PIN_6; gpioInitStruct.Pull = GPIO_NOPULL; //gpioInitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &gpioInitStruct); /*-----------------------------------------------------*/ ADC_CLK_ConfigEnable(); // 使能ADC时钟 ADC_Calibrate(); // 校准 ADC1->CFGR1 |= /*ADC_CFGR1_CONT | */ADC_CFGR1_SCANDIR; /* (2) */ ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL5 | ADC_CHSELR_CHSEL6 | ADC_CHSELR_CHSEL16; /* (3) */ ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */ // ADC1->IER = ADC_IER_EOCIE | ADC_IER_EOSEQIE | ADC_IER_OVRIE; /* (5) */ ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; /* (6) */ /* (1) Enable the peripheral clock on DMA */ /* (2) Enable DMA transfer on ADC - DMACFG is kept at 0 for one shot mode */ /* (3) Configure the peripheral data register address */ /* (4) Configure the memory address */ /* (5) Configure the number of DMA tranfer to be performs on DMA channel 1 */ /* (6) Configure increment, size and interrupts */ /* (7) Enable DMA Channel 1 */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */ ADC1->CFGR1 |= ADC_CFGR1_DMAEN; /* (2) */ DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */ DMA1_Channel1->CMAR = (uint32_t)(u16_adcBuffer); /* (4) */ DMA1_Channel1->CNDTR = ADC_CHANNEL_MAX; /* (5) */ DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_TEIE | DMA_CCR_TCIE ; /* (6) */ DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */ NVIC_EnableIRQ(DMA1_Ch1_IRQn); //使能DMA1 CH1中断 NVIC_SetPriority(DMA1_Ch1_IRQn,0); //设置DMA1 CH1中断优先级 ADC_Enable(); } int main(void) { // 时钟、端口、定时器等初始化。 InitAdcDMAShot(); while(1) { if(1秒标志为1) { 清零1秒标志 ADC_Start(); // 重启AD采样 printf("dmaCnt: %d\n", u32_dmaIntCnt); } } } //DMA1通道1中断函数 void DMA1_Channel1_IRQHandler(void) { extern uint32_t u32_dmaIntCnt; u32_dmaIntCnt++; DMA1->IFCR |= DMA_IFCR_CHTIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CGIF1; } |
自己顶一下。 |
已找到解决方法:禁止DMA再使用即可。 |