查看: 2056|回复: 4

[求助] 磁增量编码器+MKV30双adc采集+dma传输获得的上位机图样异常

[复制链接]

该用户从未签到

2

主题

5

帖子

0

注册会员

Rank: 2

积分
177
最后登录
2024-11-13
发表于 2024-10-29 16:10:47 | 显示全部楼层 |阅读模式
大佬们麻烦帮忙看一下,卡了好几天了,用的MKV30F128VFM,我对编码器的A,B相进行了16位adc采集,用dma通道0和通道1将A,B相adc采集结果传输到了内存后再从串口发出,但从上位机上观察到的图像只有一路adc的采集图像是完好的正弦波,另一个图像出现周期性缺失
int main(void)
{
    uart_transfer_t xfer;
    uart_transfer_t sendXfer;
    uart_transfer_t receiveXfer;
          uint8_t ch;
    edma_config_t config;
        float32_t atanPos = 0;                                                                                      
  float32_t atanPosL = 0;       
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
        #ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
    /* Init FSL debug console. */
    BOARD_InitDebugConsole();                                                                          
#endif
   // BOARD_InitBootPeripherals();

          UART_SetBaudRate(UART0, 2500000UL, UART0_CLOCK_SOURCE);
          UART_Init(UART0_PERIPHERAL, &UART0_config, UART0_CLOCK_SOURCE);
               
    DMAMUX_Init(DMA_DMAMUX_BASEADDR);
                EDMA_Init(DMA_DMA_BASEADDR, &DMA_config);
          DMAMUX_SetSource(DMA_DMAMUX_BASEADDR, DMA_CH0_DMA_CHANNEL, DMA_CH0_DMA_REQUEST);
          DMAMUX_SetSource(DMA_DMAMUX_BASEADDR, DMA_CH1_DMA_CHANNEL, DMA_CH1_DMA_REQUEST);
          DMAMUX_SetSource(UART0_RX_DMAMUX_BASEADDR, UART0_RX_DMA_CHANNEL, UART0_RX_DMA_REQUEST);
                DMAMUX_EnableChannel(DMA_DMAMUX_BASEADDR, DMA_CH1_DMA_CHANNEL);
          DMAMUX_EnableChannel(UART0_RX_DMAMUX_BASEADDR, UART0_RX_DMA_CHANNEL);
                DMAMUX_EnableChannel(UART0_TX_DMAMUX_BASEADDR, UART0_TX_DMA_CHANNEL);
                EDMA_CreateHandle(&DMA_CH0_Handle, DMA_DMA_BASEADDR, DMA_CH0_DMA_CHANNEL);
                EDMA_CreateHandle(&DMA_CH1_Handle, DMA_DMA_BASEADDR, DMA_CH1_DMA_CHANNEL);

                ADC16_Init(ADC0_PERIPHERAL, &ADC0_config);                         //adc0初始化
    ADC16_EnableHardwareTrigger(ADC0_PERIPHERAL, false);              
    ADC16_SetChannelMuxMode(ADC0_PERIPHERAL, ADC0_muxMode);            /
    ADC16_Init(ADC1_PERIPHERAL, &ADC1_config);
    ADC16_EnableHardwareTrigger(ADC1_PERIPHERAL, false);
    ADC16_SetChannelMuxMode(ADC1_PERIPHERAL, ADC1_muxMode);
                ADC16_EnableDMA(ADC0, true);
                ADC16_EnableDMA(ADC1, true);
                ADC16_SetChannelConfig(ADC0, ADC0_CH0_CONTROL_GROUP, &ADC0_channelsConfig[1]);                       //设置adc0通道
          ADC16_SetChannelConfig(ADC1, ADC1_CH2_CONTROL_GROUP, &ADC1_channelsConfig[0]);                       //设置adc1通道
          EnableIRQ(BOARD_Z_IRQ);
               
                EDMA_SetCallback(&DMA_CH0_Handle, EDMA_Callback_0, NULL);
                EDMA_PrepareTransfer(&g_transferConfig0, (uint16_t*) (ADC0->R), sizeof(uint16_t),                                 //传输准备(传输结构,源地址,源地址数值大小
                         (void *)g_adc16SampleDataArray0, sizeof(uint16_t), sizeof(uint16_t),                        //目标地址,目标地址大小,传输单位大小
                         sizeof(g_adc16SampleDataArray0), kEDMA_PeripheralToMemory);                                 //传输总数据大小,输出模式(外设到内存))
          EDMA_SubmitTransfer(&DMA_CH0_Handle, &g_transferConfig0);                                                         //设置传输
//         EDMA_SetChannelLink(DMA0, DMA_CH1_DMA_CHANNEL, kEDMA_MajorLink,DMA_CH0_DMA_CHANNEL);                              //连接通道
//                DMA0->TCD[0].CITER_ELINKYES= sizeof(g_adc16SampleDataArray1) / sizeof(uint16_t);
          DMA0->TCD[0].DLAST_SGA  = -1 * sizeof(g_adc16SampleDataArray0);                                                   //tcd[0],dma通道0,目标地址偏移        
    DMA0->TCD[0].ATTR        |= DMA_ATTR_SMOD_MASK;                                                                 
         /* 发送结束中断触发. */
          EDMA_EnableChannelInterrupts(DMA_DMA_BASEADDR, DEMO_DMA_CHANNEL, kEDMA_MajorInterruptEnable);
         #if defined(FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT) && FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT
    /* Enable async DMA request. */
    EDMA_EnableAsyncRequest(DMA_DMA_BASEADDR, DEMO_DMA_CHANNEL, true);                                               //启用dma异步传输
   #endif /* FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT */
       

                EDMA_SetCallback(&DMA_CH1_Handle,EDMA_Callback_1, NULL);
                                                                                                 EDMA_PrepareTransfer(&g_transferConfig1, (uint16_t*) (ADC1->R), sizeof(uint16_t),
                         (void *)g_adc16SampleDataArray1, sizeof(uint16_t), sizeof(uint16_t),
                         sizeof(g_adc16SampleDataArray1), kEDMA_PeripheralToMemory);
          EDMA_SubmitTransfer(&DMA_CH1_Handle, &g_transferConfig1);
          EDMA_SetChannelLink(DMA0, DMA_CH1_DMA_CHANNEL, kEDMA_MajorLink,DMA_CH0_DMA_CHANNEL);
          DMA0->TCD[1].DLAST_SGA  = -1 * sizeof(g_adc16SampleDataArray1);
//                DMA0->TCD[1].CITER_ELINKYES= sizeof(g_adc16SampleDataArray1) / sizeof(uint16_t);
                DMA0->TCD[1].ATTR        |= DMA_ATTR_SMOD_MASK;       
          EDMA_StartTransfer(&DMA_CH1_Handle);

                txFAdeal(g_adc16SampleDataArray0[0],g_adc16SampleDataArray1[0],0,0,0);
                sendXfer.data        = txFAbuff;
    sendXfer.dataSize    = 10;
    receiveXfer.data     = g_rxBuffer;
    receiveXfer.dataSize = 10;
    txOnGoing = true;
    GPIO_PinWrite(GPIOD,BOARD_INITPINS_RS485EN_PIN,1);
    while (1)
    {
//                        if(g_Transfer_Done_ch0||g_Transfer_Done_ch1)
//                        {
                        g_Transfer_Done_ch0 = false;
                                g_Transfer_Done_ch1 = false;
                        while(!g_Transfer_Done_ch0&&!g_Transfer_Done_ch1){};
                               
                         int normalized_value1 = g_adc16SampleDataArray0[0] - sinoffset;                        //adc值范围归化
                         int normalized_value2 = g_adc16SampleDataArray1[0] - cosoffset;
                        atanPos = atan2f(normalized_value2, normalized_value1);
                                if(atanPos<0) atanPos = 2 * pi + atanPos;
                        arctan = atanPos * 10000 ;
                                if(count_0>count_1 )count_Z = count_0 - count_1;
                                else count_Z = count_1 - count_0;
                  txFAdeal(g_adc16SampleDataArray0[0],g_adc16SampleDataArray1[0],count_Z,0,arctan);
                        if(txOnGoing == false)
                        {
                                txFAdeal(g_adc16SampleDataArray0[0],g_adc16SampleDataArray1[0],count_Z,0,arctan);
                                sendXfer.data        = txFAbuff;
                                txOnGoing = true;
                        }
                        UART_WriteBlocking(UART0,txFAbuff,sizeof(txFAbuff));
                }
}
//CHA adc0 dma回调
static void EDMA_Callback_0(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds)
{
        if (transferDone)
        {
                g_Transfer_Done_ch0 = true;
   // EDMA_StartTransfer(&DMA_CH0_Handle);

        }
}
//CHB adc1 dma回调
static void EDMA_Callback_1(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds)
{
//EDMA_StartTransfer(&DMA_CH1_Handle);
        handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
        if (transferDone)
        {
                g_Transfer_Done_ch1 = true;
               
        }
}

20241029155751.png
红色的正弦波图线是采集到的A路信号,蓝色正弦波图线是采集到的B路信号,两个图像相差四分之个周期的相位,黑色图像是A路和B路的反正切数值,紫色那条有尖峰的图线是编码器单位时间内的位移量是根据两次反正切的差值求的,且我将edma重启的代码更换到dma0的回调函数中并改SetChannelLink为dma通道0链接通道1后这个缺失的现象从A路信号图线转移到了B路信号图线,而A路信号又变得玩好了,这是什么原因?
回复

使用道具 举报

  • TA的每日心情
    开心
    2025-7-10 13:07
  • 签到天数: 43 天

    连续签到: 1 天

    [LV.5]常住居民I

    59

    主题

    555

    帖子

    0

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    1542

    热心会员

    最后登录
    2025-11-19
    发表于 2024-10-30 10:38:56 | 显示全部楼层
    如果两个DMA通道共享同一个中断向量,可能需要检查中断优先级的配置,确保高优先级的中断不会阻塞低优先级的中断处理。检查串口发送函数UART_WriteBlocking能不能及时发送所有数据,或者有可能因为缓冲区溢出或其他原因导致数据丢失。
    签到签到
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    2

    主题

    5

    帖子

    0

    注册会员

    Rank: 2

    积分
    177
    最后登录
    2024-11-13
     楼主| 发表于 2024-10-30 11:07:09 | 显示全部楼层
    这个现象编码器变化速度越快越明显,我提高编码器转动速度后发现,正弦图像异常的那位点后好像整个波形向做移动了一样。
    20241030110241.png
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    2

    主题

    5

    帖子

    0

    注册会员

    Rank: 2

    积分
    177
    最后登录
    2024-11-13
     楼主| 发表于 2024-10-30 11:14:44 | 显示全部楼层
    y369369 发表于 2024-10-30 10:38
    如果两个DMA通道共享同一个中断向量,可能需要检查中断优先级的配置,确保高优先级的中断不会阻塞低优先级 ...

    两个通道中断是分开配置的,我在配置通道1的TCD时关闭了硬件清除DMA_ERQ寄存器中对应通道的DMA请求位,然后又用EDMA_SetChannelLink把通道1连接了通道0,从代码逻辑上通道1优先级是比通道0高的,会不会是因为这个问题导致通道0的数据没有及时更新导致的这个情况
    #define DMA_CH0_DMA_REQUEST kDmaRequestMux0ADC0
    /* Selected eDMA channel number. */
    #define DMA_CH0_DMA_CHANNEL 0
    /* DMA interrupt vector ID (number). */
    #define DMA_DMA_CH_INT_DONE_0_IRQN DMA0_IRQn
    /* DMA eDMA source request. */
    #define DMA_CH1_DMA_REQUEST kDmaRequestMux0ADC1
    /* Selected eDMA channel number. */
    #define DMA_CH1_DMA_CHANNEL 1
    /* DMA interrupt vector ID (number). */
    #define DMA_DMA_CH_INT_DONE_1_IRQN DMA1_IRQn
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    2

    主题

    5

    帖子

    0

    注册会员

    Rank: 2

    积分
    177
    最后登录
    2024-11-13
     楼主| 发表于 2024-10-30 11:27:36 | 显示全部楼层
    y369369 发表于 2024-10-30 10:38
    如果两个DMA通道共享同一个中断向量,可能需要检查中断优先级的配置,确保高优先级的中断不会阻塞低优先级 ...

    这种两个通道,中断阻塞另一个通道的情况要如何配置才能避免阻塞?是不是要更改一下dma的传输逻辑,由于我通道1关闭了硬件清除DMA_ERQ寄存器中对应通道的DMA请求位,基本上adc每采集结束就会请求dma通道1传输,这个频率还是很高的,而通道0是通道1传输结束自动连接开始传输。而串口传输我用的是库函数的阻塞传输,在传输前是有个数组编码函数来把adc0和adc1传输过来的数值进行编码成发送指令,adc在16位模式下,串口发送频率在66us一次,只有dma传输一路adc来看,adc采集和串口发送是正常的
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-11-22 10:40 , Processed in 0.121484 second(s), 26 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表