ST意法半导体
登录
直播中
汪潇潇
8年用户
905经验值
私信
关注
[问答]
将DMA与由定时器触发的ADC结合使用时的报错问题求解
开启该帖子的消息推送
ADC
大家好,
我使用的是
STM32
L412KB 芯片,目前我有一个 ADC 通道配置为在
ti
M15 的上升沿触发转换。我将定时器设置为 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 的方波,这是没有意义的。
听起来你没有清除导致中断的标志,所以它一直在循环。
当我用 DMA 中断处理程序切换 LED 进行相同的测试时,我得到一个 1.4 MHz 的方波,这是没有意义的。
听起来你没有清除导致中断的标志,所以它一直在循环。
举报
更多回帖
rotate(-90deg);
回复
相关问答
ADC
请问如何用Cube生成
定时器
2
触发
双
ADC
同步采集并用
DMA
传输?
2022-02-28
1219
请问
DMA
在事件
触发
时是如何工作?
2022-12-05
499
求助,请问有关于
定时器
触发
ADC
连续采样
dma
传输的例程吗?
2023-03-06
402
求助,请问有关于
定时器
触发
ADC
连续采样
dma
传输的例程吗?
2023-02-13
438
如何去实现
ADC
定时器
触发
+
DMA
双缓冲的设计呢
2022-01-25
885
stm32 AD
定时器
触发
转换时的转换时间
2013-11-26
8119
定时器
触发
ADC
采样如何去实现呢
2021-11-23
3251
如何使用STM32F429
定时器
去
触发
ADC
采样呢
2021-10-25
1711
如何使用
ADC
定时器
触发
和
DMA
来存储数据呢?
2023-01-17
461
dSPIC33CKxx单片机AD+
定时器
触发
2019-05-29
2698
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分