使用DMA+ADC采集PWM电平的实现方法

项目场景:

平台:TC377、iLLD
当电动汽车(EV)进行充电时充电桩(EVSE)将通过产生PWM来控制基本的通信流程,其中PWM的频率固定为1kHz,通过改变占空比来确定输出功率的大小,通过3%-7%占空比表示直流充电需要进行高级通信。

问题描述

基于需要同时采样电压和占空比的需求,传统的ADC采集的方式将导致采样点的不确定性,当进行采样的时候不知道采样点是高电平或是低电平,最致命的是当PWM的上升沿或下降沿没那么陡峭的时候,很大概率会采到一个不确定的电压,这是很致命的。

解决方案:

由于在汽车充电的应用中PWM的频率固定为1kHz,所以这就为我提供了采用了DMA+ADC的采集方式,进行解决,具体原理是使用ADC的自动采样模式然后将中断方式改为DMA,每采样一个值触发结果寄存器中断,DMA将采到的值搬运到分配的buff区,下一次采样后地址往后偏移,只要采样周期足够小(至少小于1kHz的1%占空比),并且采集足够一个周期以上的数据,再对DMA保存的数据进行排序,筛选出所需要的数据即可

iLLD库的DMA和ADC配置:

(1)DMA

void DMA_Init(void)
{
    /* Create module configuration */
    IfxDma_Dma_Config dmaConfig;
    IfxDma_Dma_initModuleConfig(&dmaConfig, &MODULE_DMA);

    /* Initialize module */
    IfxDma_Dma dma;
    IfxDma_Dma_initModule(&dma, &dmaConfig);

    /* Initial configuration for the channel */
    IfxDma_Dma_ChannelConfig dmaChnsCfg;
    IfxDma_Dma_initChannelConfig(&dmaChnsCfg, &dma);



    dmaChnsCfg.transferCount = N_TRANSFER;                                                      /* Number of transfers per transaction                          */
    dmaChnsCfg.requestMode = IfxDma_ChannelRequestMode_completeTransactionPerRequest;           /* Complete a full transaction on request                       */

    dmaChnsCfg.moveSize = IfxDma_ChannelMoveSize_16bit;                                         /* Size of the data to be moved                                 */
    dmaChnsCfg.operationMode = IfxDma_ChannelOperationMode_continuous;                          /* DMA channel stays enabled after one request                  */
    dmaChnsCfg.hardwareRequestEnabled = TRUE;                                                   /* DMA as Interrupt Service Provider                            */
    dmaChnsCfg.blockMode = IfxDma_ChannelMove_1;//每次请求完成一次传输


    /* Source and destination addresses */

	/*源地址配置*/
    dmaChnsCfg.sourceAddress = SRC_ADDR;                                                        /* Address of EVADC Group 0 Result Register 0                   */
    dmaChnsCfg.sourceAddressIncrementStep = IfxDma_ChannelIncrementStep_1;
    dmaChnsCfg.sourceAddressIncrementDirection = IfxDma_ChannelIncrementDirection_positive;
    dmaChnsCfg.sourceCircularBufferEnabled = TRUE;                                              /* Enable the source circular buffering                         */
    dmaChnsCfg.sourceAddressCircularRange = IfxDma_ChannelIncrementCircular_none;

    /*目的地址偏移32位   源地址不变*/
    dmaChnsCfg.destinationAddress = ADC_DMA_data;                                                  /* Start address of LMURAM                                      */
    dmaChnsCfg.destinationAddressIncrementStep = IfxDma_ChannelIncrementStep_1;
    dmaChnsCfg.destinationAddressIncrementDirection = IfxDma_ChannelIncrementDirection_positive;//目的地址偏移递增
    /* Destination address remains the same after transfer          */
    dmaChnsCfg.destinationCircularBufferEnabled = TRUE;                                         /* Enable the destination circular buffering                    */
    dmaChnsCfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_1024;

    /* Interrupt generated after transactions */
    /*禁止中断*/
    dmaChnsCfg.channelInterruptEnabled = FALSE;                                                  /* Enable the interrupt generation                              */

    dmaChnsCfg.channelInterruptControl = IfxDma_ChannelInterruptControl_thresholdLimitMatch;    /* DMA triggers an interrupt once the full transaction is done  */
    dmaChnsCfg.channelInterruptTypeOfService = IfxSrc_Tos_cpu0;                                 /* CPU0 is the Interrupt Service Provider of this interrupt     */
    dmaChnsCfg.channelInterruptPriority = ISR_PRIORITY_DMA;                                     /* Assign a priority to the interrupt                           */

    /* Channel specific configurations */
    dmaChnsCfg.channelId = (IfxDma_ChannelId) ADC_DMA_CHANNEL;                                      /* Select the Channel 1                                         */
//    ADC_DMA_data = DEST_ADDR;

    /* Initialize the DMA channel */
    IfxDma_Dma_initChannel(&g_DMAchn, &dmaChnsCfg);
}

主要需要注意的配置是

1、dmaChnsCfg.operationMode = IfxDma_ChannelOperationMode_continuous;代表持续搬运,

2、dmaChnsCfg.moveSize = IfxDma_ChannelMoveSize_16bit;表示要搬运的数据大小(每个ADC采样值)

3、dmaChnsCfg.destinationAddressCircularRange = IfxDma_ChannelIncrementCircular_1024;

4、表示循环缓冲区为1024个字节,dmaChnsCfg.channelInterruptEnabled = FALSE;禁止DMA搬运时产生中断

(2)ADC

void F_EVADC_InitGroup_8(IfxEvadc_Adc_Group *Local_adcGroup, IfxEvadc_GroupId Local_GroupId)
{
    /* ============================================================================================================
     *                                          EVADC module configuration
     * ============================================================================================================
     */
    /* Create configuration */
    IfxEvadc_Adc_Config adcConfig;
    /* Assign default values to the configuration */
    IfxEvadc_Adc_initModuleConfig(&adcConfig, &MODULE_EVADC);

    /* Initialize the module */
    IfxEvadc_Adc_initModule(&g_evadc, &adcConfig);

    /* ============================================================================================================
     *                                           EVADC group configuration
     * ============================================================================================================
     */
    /* Create and initialize group configuration with default values */
	IfxEvadc_Adc_GroupConfig adcGroupConfig;
	IfxEvadc_Adc_initGroupConfig(&adcGroupConfig, &g_evadc);
    adcGroupConfig.groupId = Local_GroupId;
    adcGroupConfig.master = Local_GroupId;
    adcGroupConfig.startupCalibration = TRUE;
    /* Enable the Queue 0 */
    adcGroupConfig.arbiter.requestSlotQueue0Enabled = TRUE;
//    /* Enable all gates in "always" mode (no edge detection) */
    adcGroupConfig.queueRequest[0].triggerConfig.gatingMode = IfxEvadc_GatingMode_always;

    /* Initialize the group */
    IfxEvadc_Adc_initGroup(Local_adcGroup, &adcGroupConfig);

    /* ============================================================================================================
     *                                          EVADC channel configuration
     * ============================================================================================================
     */
	{
		IfxEvadc_Adc_initChannelConfig(&adcChannelConfig_CP, Local_adcGroup);

		adcChannelConfig_CP.channelId = (IfxEvadc_ChannelId)(14);
		adcChannelConfig_CP.resultRegister = (IfxEvadc_ChannelResult)(14); // use result register #1 for all channels

		/* Assign the DMA channel as priority of the interrupt in order to trigger the DMA when a new result is
		* available.
		*/
		adcChannelConfig_CP.resultPriority = ADC_DMA_CHANNEL;
		/* Assign the DMA as service provider for the interrupt */
		adcChannelConfig_CP.resultServProvider = IfxSrc_Tos_dma;

		// initialize the channel
		IfxEvadc_Adc_initChannel(&adcChannel_CP, &adcChannelConfig_CP);

//		Local_adcGroup->group->RCR[14].B.SRGEN = 0;
	}

    /* Start the queue */
    IfxEvadc_Adc_startQueue(Local_adcGroup, IfxEvadc_RequestSource_queue0);

	// Add channel to queue with refill enabled

	IfxEvadc_Adc_addToQueue(&adcChannel_CP, IfxEvadc_RequestSource_queue0, IFXEVADC_QUEUE_REFILL);

}

这里使用了G8CH14,需要注意的配置是:

1、adcChannelConfig_CP.resultServProvider = IfxSrc_Tos_dma;绑定应答源为DMA(否则会出发MCU中断)

2、adcChannelConfig_CP.resultPriority = ADC_DMA_CHANNEL;绑定DMA通道,与DMA配置重DMA通道保持一致

3、adcGroupConfig.arbiter.requestSlotQueue0Enabled = TRUE;使能该队列

4、IfxEvadc_Adc_startQueue(Local_adcGroup, IfxEvadc_RequestSource_queue0);启动队列(否则队列不开始采样)

提示:之后又遇到一个bug当我将一个组设置为DMA触发的时候,这个组的其他通道采样到数值后也会触发DMA,这就导致了DMA搬运的目的地址中出现了一堆重复的采样值,解决方法是将除该通道外的其他通道的Local_adcGroup->group->RCR[chnIx].B.SRGEN位置零

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值