This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CC3235MODASF:到 GPIO 的 DMA 输出

Guru**** 2523240 points
Other Parts Discussed in Thread: CC3200

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/1000399/cc3235modasf-dma-output-to-gpio

器件型号:CC3235MODASF
Thread 中讨论的其他器件:CC3200

您好!

我尝试设置 DMA、但在查找文档和示例时遇到一些问题。

我要做的是:  

向 GPIOA1 (GPIO8-GPIO15)传输234个字节、每个字节后跟 GPIO28上的脉冲

目前、我在没有 DMA 的情况下执行它。  

for(unsigned int column=0; column < 234; column++)
{
 HWREG(GPIO_D0_D7_PORT + ((uint32_t)GPIO_D0_D7_PIN << 2)) = pArray[column];
 HWREG(GPIO_EPD_CLK_PORT + ((uint32_t)GPIO_EPD_CLK_PIN << 2U)) = GPIO_EPD_CLK_PIN);
 HWREG(GPIO_EPD_CLK_PORT + ((uint32_t)GPIO_EPD_CLK_PIN << 2U)) = 0);
}
Code

这会导致 信号不够清晰、无法满足我们的应用需求。

请参阅 GPIO28上的输出(根据我的理解、由于循环展开2、有两个脉冲在附近、我想较长的延迟是由于分支+最后是一些我不理解的流水线填充)

现在、我将尝试设置 DMA、以便一次将1个字节传输到 GPIO。 然后、我计划使用 timercallback 在 GPIO28上生成脉冲、并对下一个 DMA 传输进行 trig (我想不出更好/更便宜的方法来使传输与 GPIO28上的脉冲同步)

但这似乎不起作用。

配置:

void GPIO2DMA_Configure(unsigned char gpioDataBuf[10])
{

    //Set channel 
    uDMAChannelAssign(UDMA_CH28_GPIOA1);  
    
    //Not sure this is needed
    uDMAChannelAttributeDisable(UDMA_CH28_GPIOA1, UDMA_ATTR_ALTSELECT);


    uDMAChannelControlSet(UDMA_CH28_GPIOA1 | UDMA_PRI_SELECT, // Use primary
                          UDMA_SIZE_8|UDMA_SRC_INC_8|UDMA_DST_INC_NONE | // one transfer is 8 bits, increase source address, keep destination address
                          UDMA_ARB_1 // transfer 1 byte and wait for next request
                          );//set for control table


    uDMAChannelTransferSet(UDMA_CH28_GPIOA1 | UDMA_PRI_SELECT, 
                           UDMA_MODE_BASIC,     //Basic transfer, waits for next request
                           &gpioDataBuf,        //Source is in memory
                           (void*)(GPIOA1_BASE)(void*)+ ((uint32_t)0xFF << 2)), //Destination is GPIO
                           sizeof(gpioDataBuf)); 

    uDMAChannelEnable(UDMA_CH28_GPIOA1);


    uDMAChannelRequest(UDMA_CH28_GPIOA1);

//    /*power up uDMA module*/
//    PRCMPowerDomainOn(PRCM_DOMAIN_PERIPH);
//    PRCMPeripheralRunEnable(PRCM_PERIPH_UDMA);
//    PRCMPeripheralSleepEnable(PRCM_PERIPH_UDMA);
//    PRCMLoadSet();

}

测试:

    unsigned char gpioDataBuf[10] = {0,1,2,3,4,5,6,7,8,9};

    GPIO2DMA_Configure(gpioDataBuf);

    for (int i=0; i<10; i++)
    {
        uDMAChannelRequest(UDMA_CH28_GPIOA1);
        WAIT_S(1);
    }

我的问题:

我的设置是否正常?  

我应该使用 UDMA_CH28_GPIOA1还是  UDMA_CH28_SW?

是否有一些有关 DMA 设置的文档/示例、如我要做的那样? 我在 《技术参考手册》和 https://software-dl.ti.com/simplelink/esd/simplelink_msp432e4_sdk/2.30.00.14/docs/driverlib/msp432e4/html/group__udma__api.html#ga938c21dc70cb6e11e6eb826de0fa21c3上找到了一些内容 ,但这一点并不明显;)

谢谢、

C é dric

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    C é dric、您好!

    UDMA_CH28_GPIOA1应该正确、因为您希望 DMA 从 RAM 连接到 GPIOA1。

    遗憾的是、除了 TRM 和 API 文档之外、没有更多资源可用于使用 DMA。

    这种 DMA 转 GPIO 输出的用途是什么? 您是否正在尝试创建并行数据接口?

    有关您的设置的几个注意事项:

    1.您可能需要设置一个硬件定时器外设,以便在达到某个级别/值时触发 DMA 传输。 与您以前的仅软件方法相比、这应该使事情更加一致。

    2.您不需要使用 uDMAChannelRequestI() API -一旦您设置了传输并启用了 DMA 通道+触发源,它就应该在不需要调用该函数的情况下运行。

    此致、

    Michael

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michael、

    感谢您的回复!

    是的、它是一个用于驱动 eink 显示的并行数据接口。

    同时、我设法让 timerA 触发 DMA 通道 UDMA_CH8_TIMERRA0_A 但仍有太多的开销无法使用。

    我不理解如何在整个234字节传输完成后在传输完成时获得中断。  

    发件人文档:

    The interrupt handler for the uDMA is for transfer completion when the channel UDMA_CHANNEL_SW is used and for error interrupts. The interrupts for each peripheral channel are handled through the individual peripheral interrupt handlers.

    由于我需要一个链接到 timerA 的通道、我假设我必须使用 timerA 的中断。

    有两个相关的方面:

    TIMER_TIMA_DMA          0x00000020  // TimerA DMA Done interrupt
    
    TIMER_TIMA_TIMEOUT      0x00000001  // TimerA time out interrupt

    但是、这两个都在第一个 DMA 传输之后调用、而不是在第234次 DMA 传输之后调用。

    我使用以下命令配置计时器:

    void InitTimerTiDrivers()
    {
    
        Timer_Params params;
        int ret;
    
        ret = sem_init(&dmaSync,0,0);
        if(ret != 0)
        {
            ERROR_PRINT("Semaphore init failed, error code : %d", ret);
    //        return ret;
        }
    
    
        Timer_init();
    
        Timer_Params_init(&params);
    
        params.period = 8;
        params.periodUnits = Timer_PERIOD_COUNTS;
        params.timerMode = Timer_FREE_RUNNING;
        params.timerCallback = NULL;
    
        timer_handle = Timer_open(CC3220SF_LAUNCHXL_TIMER0, &params);
    
        if (timer_handle == NULL)
        {
            ERROR_PRINT("timer ");
        }
    //    TimerIntClear(TIMERA0_BASE, TIMER_TIMA_DMA);
    
        TimerIntRegister(TIMERA0_BASE, TIMER_A, TimerFinished);
        TimerIntEnable(TIMERA0_BASE, TIMER_TIMA_DMA);
        TimerDMAEventSet(TIMERA0_BASE, TIMER_DMA_TIMEOUT_A);
    
    }

    注:

    我尝试使用 Timer_Continuous_callback 配置回调、结果相同。

    我使用 TI 驱动程序来配置计时器、使用 driverlib 来配置 DMA、我认为这是可以的。  

    有没有关于 如何在 DMA 完成后获取中断的指针?

    谢谢!

    C é dric

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    C é dric、您好!

    仅当 DMA 通道处于停止状态时、TIMER_TINA_DMA 中断才应触发。 您是将 DMA 传输设置为一个字、还是将其设置为完整的234字节?

    一个潜在问题是、您似乎将 TI 驱动程序调用与原始低级 driverlib 调用混合在一起。 这可能可行、但您必须小心交互、例如中断处理。 默认情况下、TI 驱动程序将为每个已打开的外设注册其自己的中断处理程序、并在底层 RTOS 中注册、这可能会导致您的中断检测问题。


    您应该完全不使用 TI 驱动程序并通篇使用原始 driverlib、或者修改 TI 驱动程序文件以便使用您的新 driverlib 调用。 我建议您修改 TimerCC32XX.c 文件以使用您的修改、以便您不必担心 TI 驱动程序为您处理的其余低级硬件和电源管理设置。 将该文件从 SDK 复制到本地项目空间可能是最简单的、这样您就不需要重建完整的 TI 驱动程序库。

    现在、为了通过您使用的 GPIO 执行无缝并行传输、您可能还需要考虑 DMA 交替传输。 这将确保传输的时间更好、因为重复排队等待 DMA 传输返回后、延迟会大大减少。

    有一个 E2E 主题、我将介绍如何设置计时器+ DMA 来执行传输。 该线程处理中的 ADC 数据、但您可以使用计时器执行相同的功能、只需将 DMA 配置为输出到 GPIO 寄存器即可

    https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/702668/ccs-cc3220-configuring-timer-dma-adc-for-continuous-sampling?ReplyFilter=Answers&ReplySortBy=Answers&ReplySortOrder=Descending

    请看一下提供的示例 driverlib、它用于连接 DMA +计时器外设、并根据您的代码进行仔细检查。 它最初用于 CC3200、但 CC3235使用与 CC3200完全相同的 DMA 和硬件计时器、更改为相同的寄存器映射、因此提供的指令和代码仍然有效。

    如果您对该代码有任何疑问、请告诉我。

    此致、

    Michael

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    非常感谢您提供的链接和信息、它确实提供了帮助!

    我设法使其正常工作、现在对其进行了调整、使其能够在 PWM 模式下输出时钟、其中 JTAG_TCK PWMTimerCC32XX_PIN_19具有 timer1B、而 DMA 的数据由同一定时器触发。

    现在、它以较低的频率工作、我尝试达到~4Mhz、并有一个问题:

    我将 DMA 配置为在下降沿触发。 我在 PWM 下降沿和 DMA 输出之间看到~220ns 的延迟。  

    请参阅下面的测量值:红色是 PWM 输出、黄色是由 DMA 触发的 GPIO。

    这里是1MHz PWM、但在2MHz PWM 下、我看到同样的220ns 延迟。

    是否有任何延迟来自何处的想法? (我的主任务在 PWM Hwi 回调中发布的信标上挂起、因此它不应堵塞 CPU/总线)

    谢谢、

    C é dric

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    C é dric、您好!

    很高兴您的并行接口能够正常工作!

    您看到的延迟可能是来自计时器外设-> DMA -> GPIO 的信号路径固有的延迟。 如果您确定应用中没有任何其他可能导致该延迟的东西、那么我怀疑您看到的性能与您将得到的性能一样好。

    此致、

    Michael

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Michael、

    好的、我们将在这种情况下完成。

    感谢您的帮助!

    C é dric