BSTIM32定时器触发ADC采集,DMA传输到RAM
请教一下,FM33lC046N开发板,系统时钟64M,设置BSTIM32触发ADC采集,然后经DAM传输到RAM。采集2个通道,一个是参考电压,一个需要采样的ADC输入引脚,定时器设置4S采集一次,采集4次,16S后输出采集信息。不设置DMA时,可以按照定时器间隔采集输出。设置DMA传输后,4S后,就完成所有采样,将所有数据传输,感觉是连续发送了4次DMA请求。手册上32.4.12 DMA 单次模式下会一直重复搬运过程,才会导致DMA会将所有数据传输?1.这两个函数是定时器和ADC初始化:
void AdcTrigTimerInit(void)
{
//定时器初始化数据结构定义
FL_BSTIM32_InitTypeDef TimerBaseInitStruct;
TimerBaseInitStruct.prescaler = 64000-1;
TimerBaseInitStruct.autoReload = 4000-1;
TimerBaseInitStruct.autoReloadState = FL_ENABLE;
TimerBaseInitStruct.clockSource = FL_RCC_BSTIM32_CLK_SOURCE_APB2CLK;
FL_BSTIM32_Init(BSTIM32,&TimerBaseInitStruct );
FL_BSTIM32_SetTriggerOutput(BSTIM32,FL_BSTIM32_TRGO_UPDATE);
FL_BSTIM32_ClearFlag_Update(BSTIM32);
FL_BSTIM32_Disable(BSTIM32);
}
void AdcInit(void)
{
FL_GPIO_InitTypeDef GPIO_InitStruct;
FL_ADC_CommonInitTypeDef ADC_CommonInitStruct;
FL_ADC_InitTypeDef defaultInitStruct;
FL_NVIC_ConfigTypeDef InterruptConfigStruct;
GPIO_InitStruct.pin = FL_GPIO_PIN_9;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.pull = FL_DISABLE;
GPIO_InitStruct.remapPin = FL_DISABLE;
FL_GPIO_Init( GPIOC, &GPIO_InitStruct );
ADC_CommonInitStruct.clockSource =FL_RCC_ADC_CLK_SOURCE_RCHF;
ADC_CommonInitStruct.clockPrescaler = FL_RCC_ADC_PSC_DIV8;
FL_ADC_CommonInit(&ADC_CommonInitStruct);
defaultInitStruct.conversionMode = FL_ADC_CONV_MODE_SINGLE;
defaultInitStruct.autoMode = FL_ADC_SINGLE_CONV_MODE_AUTO;
defaultInitStruct.waitMode = FL_ENABLE;
defaultInitStruct.overrunMode = FL_ENABLE;
defaultInitStruct.scanDirection = FL_ADC_SEQ_SCAN_DIR_BACKWARD;
defaultInitStruct.externalTrigConv = FL_ADC_TRIGGER_EDGE_RISING;
defaultInitStruct.triggerSource = FL_ADC_TRGI_BSTIM1;
defaultInitStruct.fastChannelTime = FL_ADC_FAST_CH_SAMPLING_TIME_256_ADCCLK;
defaultInitStruct.lowChannelTime = FL_ADC_SLOW_CH_SAMPLING_TIME_256_ADCCLK;
defaultInitStruct.oversamplingMode = FL_DISABLE;
defaultInitStruct.overSampingMultiplier = FL_ADC_OVERSAMPLING_MUL_2X;
defaultInitStruct.oversamplingShift = FL_ADC_OVERSAMPLING_SHIFT_1B;
FL_ADC_Init(ADC,&defaultInitStruct );
FL_ADC_SetTriggerSource(ADC,FL_ADC_TRGI_BSTIM1);
FL_ADC_SetTriggerEdge(ADC,FL_ADC_TRIGGER_EDGE_RISING);
FL_ADC_EnableIT_EndOfConversion(ADC);
InterruptConfigStruct.preemptPriority = 0x02;
FL_NVIC_Init(&InterruptConfigStruct,ADC_IRQn );
}
2.这两个是DMA配置的,在需要开始采样的时候调用:
void ADC_DMA(uint16_t *buffer, uint32_t length)
{
FL_DMA_InitTypeDef DMA_InitStruct = {0};
FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};
DMA_InitStruct.periphAddress = FL_DMA_PERIPHERAL_FUNCTION1;
DMA_InitStruct.direction = FL_DMA_DIR_PERIPHERAL_TO_RAM;
DMA_InitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE;
DMA_InitStruct.dataSize = FL_DMA_BANDWIDTH_16B;
DMA_InitStruct.priority = FL_DMA_PRIORITY_HIGH;
DMA_InitStruct.circMode = FL_DISABLE;
FL_DMA_Init(DMA, &DMA_InitStruct, FL_DMA_CHANNEL_4);
DMA_ConfigStruct.memoryAddress = (uint32_t)buffer;
DMA_ConfigStruct.transmissionCount = length - 1;
FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, FL_DMA_CHANNEL_4);
FL_ADC_SetDMAMode(ADC,FL_ADC_DMA_MODE_SINGLE);
FL_ADC_EnableDMAReq(ADC);
FL_DMA_Enable(DMA);
}
uint16_t DMAResult;
void GetDMAChannelSample(uint32_t channel)
{
FL_NVIC_ConfigTypeDef InterruptConfigStruct;
FL_VREF_EnableVREFBuffer(VREF);//使能VREF BUFFER
FL_ADC_DisableSequencerChannel(ADC, FL_ADC_ALL_CHANNEL);//清空打开的通道
FL_ADC_EnableSequencerChannel(ADC, FL_ADC_INTERNAL_VREF1P2);//通道选择VREF
FL_ADC_EnableSequencerChannel(ADC, channel);//通道选择
ADC_DMA(DMAResult, 4);
InterruptConfigStruct.preemptPriority = 0x01;
FL_NVIC_Init(&InterruptConfigStruct,DMA_IRQn );
FL_DMA_EnableIT_TransferComplete(DMA,FL_DMA_CHANNEL_4);
FL_ADC_ClearFlag_EndOfConversion(ADC);//清标志
FL_ADC_Enable(ADC); // 启动ADC
mymemset((u8*)DMAResult,0,4*2);
iCnt =0;
FL_BSTIM32_ClearFlag_Update(BSTIM32);
//使能LGPTIM
FL_BSTIM32_Enable(BSTIM32);
}
3.DMA传输完成中断,传输完了就停止定时器,停止ADC
Y&H Wang:
void DMA_IRQHandler(void)
{
if(FL_DMA_IsEnabledIT_TransferComplete(DMA,FL_DMA_CHANNEL_4) && FL_DMA_IsActiveFlag_TransferComplete(DMA,FL_DMA_CHANNEL_4))
{
FL_DMA_ClearFlag_TransferHalfComplete(DMA,FL_DMA_CHANNEL_4);
FL_DMA_ClearFlag_TransferComplete(DMA, FL_DMA_CHANNEL_4);
FL_BSTIM32_Disable(BSTIM32);
FL_ADC_Disable(ADC); // 关闭ADC
FL_ADC_DisableSequencerChannel(ADC, FL_DMA_CHANNEL_4);//通道关闭
FL_ADC_DisableSequencerChannel(ADC, FL_ADC_INTERNAL_VREF1P2);//通道关闭VREF
FL_VREF_DisableVREFBuffer(VREF);//关闭VREF BUFFER
msg_send_msg(MSG_ADC_DMA,0);
}
}
同问,在定时器中使能了中断,发现中断只进了1次,就完成了所有数据的采集,说明在第一次定时器触发ADC采样时,ADC连续采集了多次,导致DMA传输结束(采样前,将RAM中的数据清0.DMA传输完成中断后,RAM中的数据都改变了),那么是不是说明FM33lC046N的定时器触发ADC只是触发ADC开始采样,而不能按照定时的时间定时采样? 同问,我在BSTIM32使能了中断,发现在整个采集过程中只中断了一次,也就是说,第一次中断后,就触发了ADC采样,ADC采样4次后,DMA产生传输完成中断。为了验证是采集了4次,我在开始采集前,将RAM中的数据清0了,采集完成后,这四个数据确实改变了。那么是不是说明FM33lC046N的定时器触发ADC,再由DMA传输,定时器只能起到开始采集的触发作用,不能进行定时触发采样,也就是不能用定时器进行定时采样? 是的,使用DMA传输数据时,当触发ADC启动信号到来后,会立马转换n次(DMA长度),LG芯片可以完全匹配这个需求,LC无法完全匹配。
PS:LC如果要实现这个功能的话,可以DMA长度设置为1(也就是转换两次),当DMA完成后,也就是4S转换了2个通道,可以在DMA中断里再次配置DMA使能和ram地址以及ADC使能实现上述功能 我是一只鱼21 发表于 2022-1-18 15:42
是的,使用DMA传输数据时,当触发ADC启动信号到来后,会立马转换n次(DMA长度),LG芯片可以完全匹配这个需 ...
关键是现在我需要的采样率是1Msps,如果频繁产生中断(重新设置DMA),1Msps采样率达不到,DMA就没什么意义了。那么这款单片机的1Msps的采样率要如何实现? dream717 发表于 2022-1-18 16:13
关键是现在我需要的采样率是1Msps,如果频繁产生中断(重新设置DMA),1Msps采样率达不到,DMA就没什么意 ...
1Msps采样率指的是一次的转换时间,也就是工作时钟16M,采样时间为最快4clk,转换时间是12clk,所以一次的转换采样率为1M。
ps:LC芯片ADC确实没有之前你说的那个需求功能,从LG开始的芯片采添加了这个功能 想请教一下怎么设置系统时钟的,在fm33lc0xx.h还是在其他地方 sigerio 发表于 2022-7-5 15:36
想请教一下怎么设置系统时钟的,在fm33lc0xx.h还是在其他地方
参考RCHF时钟配置示例
页:
[1]