你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

使用DMA的one shot模式采样AD如何再次启动?

[复制链接]
灰泥鳅 提问时间:2020-11-23 19:28 /
        我想通过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请求,详情如下图:
DMA one shot mode.png
        目前我已使用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;
}        



收藏 评论2 发布时间:2020-11-23 19:28

举报

2个回答
灰泥鳅 回答时间:2020-11-23 19:32:57
自己顶一下。

灰泥鳅 回答时间:2020-11-25 21:20:58
已找到解决方法:禁止DMA再使用即可。

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版