ST意法半导体
直播中

汪潇潇

8年用户 905经验值
私信 关注
[问答]

将DMA与由定时器触发的ADC结合使用时的报错问题求解

大家好,
我使用的是 STM32L412KB 芯片,目前我有一个 ADC 通道配置为在 tiM15 的上升沿触发转换。我将定时器设置为 1kHz 方波。在 ADC 中断处理程序中,我切换板上的 LED,当我探测 LED 上的信号时,它显示 500 Hz(它切换每个 ADC 转换,所以这是有道理的)。当我尝试使用 DMA 通道将数据从 ADC 通道传输到循环缓冲区时,我的问题就出现了。我将 DMA 配置为在完整传输完成后中断(100 个 16 位值)。当我用 DMA 中断处理程序切换 LED 进行相同的测试时,我得到一个 1.4 MHz 的方波,这是没有意义的。单个 ADC 转换需要 1ms,要传输 100 个样本,我应该在信号上看到 100ms 的周期。在调试模式下,我可以看到值被正确地传输到指定的内存位置,但是 DMA 中断发生了一些奇怪的事情。这是我的代码:
(抱歉,我没有使用 HAL 库或 CUBE)
  • #define blocksize 100
  • uint16_t dma_buffer[blocksize];
  • /* ADC1 is connected to Channel 1 of DMA1 */
  • /* C1S */
  • void dma_setup(void){
  •         /* we want dma to directly send the adc captures to memory */
  •         dma_clock_enable();
  •         DMA1_Channel1->CCR &= (uint32_t)~0x7FFF; /* clear the config register */
  •         DMA1_Channel1->CCR |= (uint32_t)(1<<10); /* set memory transfer from periph to mem as 16-bit */
  •         DMA1_Channel1->CCR |= (uint32_t)(1<<8);
  •         DMA1_Channel1->CCR |= (uint32_t)(1<<7); /* increment memory (store next adc value in next array location) */
  •         DMA1_Channel1->CCR |= (uint32_t)(1<<5); /* circular mode, wrap to start of array */
  •         DMA1_Channel1->CCR |= (uint32_t)(1<<1); /* enable full transfer complete interrupt */
  •         DMA1_Channel1->CCR |= (uint32_t)(3<<12); /* highest priority level */
  •         /* select ADC1 as request for DMA1 Channel1 */
  •         DMA1_CSELR->CSELR &= (uint32_t)~0xF;
  •         /* connect adc handle to dma handle */
  •         DMA1_Channel1->CPAR = ADC1_BASE + 0x40;
  •         /* connect memory handle to dma handle */
  •         DMA1_Channel1->CMAR = (unsigned int)dma_buffer;
  •         /* set number of samples to transfer */
  •         DMA1_Channel1->CNDTR = blocksize;
  •         NVIC_SetPriority(DMA1_Channel1_IRQn, 1);
  •         NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  •         /* enable the channel */
  •         DMA1_Channel1->CCR |= (uint32_t)(0x1);
  • }
  • void DMA1_Channel1_IRQHandler(void){
  •           DMA1->IFCR &= (uint32_t)~(1);
  •                 Green_LED_Toggle();
  • }
  • #define numSamples 20
  • uint16_t ADC_Buffer[numSamples] = {0xFFF};
  • uint16_t counter = 0;
  • void amplifier_init(void){
  •         /* Assume clock to GPIOB is already enabled (is it?) */
  •         /* Configure mode as output*/
  •         GPIOB->MODER &= ~0x0000000CUL;
  •         GPIOB->MODER |= 0x00000004UL;
  •         /* Configure output type as push-pull */
  •         GPIOB->OTYPER &= ~0x00000002UL;
  •         /* Configure as no pull up, no pull down */
  •         GPIOB->PUPDR &= ~0x0000000CUL;
  • }
  • void adc_wakeup(void){
  •         /* exit deep powerdown mode */
  •         ADC1->CR &= (uint32_t)~(1<<29);
  •         /* enable adc voltage regulator */
  •         ADC1->CR |= (uint32_t)(1<<28);
  •         delay(1);
  • }
  • void adc_start(void){
  •   /* enable adc1 */
  •         ADC1->CR |= (uint32_t)0x01;
  •         /* wait until it's ready */
  •         while((ADC1->ISR & ((uint32_t)0x01))==0);
  •         /* start conversions */
  •         ADC1->CR |= (uint32_t)(1<<2);
  • }
  • void adc_init(void){
  •         adc_pin_setup();
  •         adc_clock_enable();
  •         adc_wakeup();
  •         /* system clock must be selected as adc clock -- PLLSAI1 unavailable on STM32L412KB */
  •         RCC->CCIPR |= (uint32_t)(3<<28);
  •         /* disable adc and conversions */
  •         ADC1->CR &= (uint32_t)~(0x01);
  •         ADC1->CR &= (uint32_t)~(1<<2);
  •         /* set clock prescalar to 1 (use system clock -- 80 MHz) */
  •         ADC12_COMMON->CCR &= (uint32_t)~(0xF<<18);
  •         /* synchronous clock mode */
  •         ADC12_COMMON->CCR &= (uint32_t)~(3<<16);
  •         ADC12_COMMON->CCR |= (uint32_t)(1<<16);
  •         /* set as independent (no master/slave) */
  •         ADC12_COMMON->CCR &= (uint32_t)~(0x1F);
  •         /* hardware trigger detection on rising edge */
  •         ADC1->CFGR &= (uint32_t)~(3<<10);
  •         ADC1->CFGR |= (uint32_t)(1<<10);
  •         /* select TIM15 TRGO as the ADC trigger*/
  •         ADC1->CFGR &= (uint32_t)~(0xF<<6);
  •         ADC1->CFGR |= (uint32_t)(0xE<<6);
  •         /* single conversion mode*/
  •         ADC1->CFGR &= (uint32_t)~(1<<13);
  •         /* data alignment = right */
  •         ADC1->CFGR &= (uint32_t)~(1<<5);
  •         /* 12-bit resolution */
  •         ADC1->CFGR &= (uint32_t)~(3<<3);
  •         /* channel 9 as first conversion */
  •         ADC1->SQR1 &= (uint32_t)~(0x1F<<6);
  •         ADC1->SQR1 |= (uint32_t)(9<<6);
  •         /* only 1 conversion */
  •         ADC1->SQR1 &= (uint32_t)~(0xF);
  •         /* set sampling time to 92.5 adc cycles */
  •         ADC1->SMPR1 &= (uint32_t)~(3<<(3*9));
  •         ADC1->SMPR1 |= (uint32_t)(5<<(3*9));
  •         /* single ended mode for channel 9 */
  •         ADC1->DIFSEL &= (uint32_t)~(1<<9);
  •         /* enable circular dma requests */
  •         ADC1->CFGR |= (uint32_t)(0x3);
  •         // Enable EOC interrupt
  •         ADC1->IER |= ADC_IER_EOC;
  •         // Set priority of ADC interrupt and enable the interrupt
  •         NVIC_SetPriority(ADC1_2_IRQn, 1);
  •         NVIC_EnableIRQ(ADC1_2_IRQn);
  •         adc_start();
  • }
  • void ADCx_IRQHandler(uint16_t * buffer, uint16_t * counter){
  •                 if(ADC1->ISR & ADC_ISR_EOC){
  •                         Green_LED_Toggle();
  •                         buffer[*counter] = ADC1->DR;
  •                         (*counter)++;
  •                         if((*counter) >= numSamples){
  •                                 (*counter) = 0;
  •                         }
  •                 }
  • }
  • void ADC1_2_IRQHandler(void){
  •         ADCx_IRQHandler(ADC_Buffer, &counter);
  • }






回帖(1)

李萍

2023-1-30 11:45:21
当我用 DMA 中断处理程序切换 LED 进行相同的测试时,我得到一个 1.4 MHz 的方波,这是没有意义的。
听起来你没有清除导致中断的标志,所以它一直在循环。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分