项目场景:
平台: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
位置零