felix007 发表于 2022-1-17 15:50:41

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);
        }
}





dream717 发表于 2022-1-18 13:13:18

同问,在定时器中使能了中断,发现中断只进了1次,就完成了所有数据的采集,说明在第一次定时器触发ADC采样时,ADC连续采集了多次,导致DMA传输结束(采样前,将RAM中的数据清0.DMA传输完成中断后,RAM中的数据都改变了),那么是不是说明FM33lC046N的定时器触发ADC只是触发ADC开始采样,而不能按照定时的时间定时采样?

dream717 发表于 2022-1-18 13:21:13

同问,我在BSTIM32使能了中断,发现在整个采集过程中只中断了一次,也就是说,第一次中断后,就触发了ADC采样,ADC采样4次后,DMA产生传输完成中断。为了验证是采集了4次,我在开始采集前,将RAM中的数据清0了,采集完成后,这四个数据确实改变了。那么是不是说明FM33lC046N的定时器触发ADC,再由DMA传输,定时器只能起到开始采集的触发作用,不能进行定时触发采样,也就是不能用定时器进行定时采样?

我是一只鱼21 发表于 2022-1-18 15:42:17

是的,使用DMA传输数据时,当触发ADC启动信号到来后,会立马转换n次(DMA长度),LG芯片可以完全匹配这个需求,LC无法完全匹配。
PS:LC如果要实现这个功能的话,可以DMA长度设置为1(也就是转换两次),当DMA完成后,也就是4S转换了2个通道,可以在DMA中断里再次配置DMA使能和ram地址以及ADC使能实现上述功能

dream717 发表于 2022-1-18 16:13:39

我是一只鱼21 发表于 2022-1-18 15:42
是的,使用DMA传输数据时,当触发ADC启动信号到来后,会立马转换n次(DMA长度),LG芯片可以完全匹配这个需 ...

关键是现在我需要的采样率是1Msps,如果频繁产生中断(重新设置DMA),1Msps采样率达不到,DMA就没什么意义了。那么这款单片机的1Msps的采样率要如何实现?

我是一只鱼21 发表于 2022-1-19 14:00:18

dream717 发表于 2022-1-18 16:13
关键是现在我需要的采样率是1Msps,如果频繁产生中断(重新设置DMA),1Msps采样率达不到,DMA就没什么意 ...

1Msps采样率指的是一次的转换时间,也就是工作时钟16M,采样时间为最快4clk,转换时间是12clk,所以一次的转换采样率为1M。
ps:LC芯片ADC确实没有之前你说的那个需求功能,从LG开始的芯片采添加了这个功能

sigerio 发表于 2022-7-5 15:36:19

想请教一下怎么设置系统时钟的,在fm33lc0xx.h还是在其他地方

顾博文 发表于 2022-7-6 08:43:08

sigerio 发表于 2022-7-5 15:36
想请教一下怎么设置系统时钟的,在fm33lc0xx.h还是在其他地方

参考RCHF时钟配置示例
页: [1]
查看完整版本: BSTIM32定时器触发ADC采集,DMA传输到RAM