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.

[参考译文] TM4C123GH6PM:8位 DMA 通道阵列[1024]发送到32位 CPU 寄存器

Guru**** 2535750 points
Other Parts Discussed in Thread: TM4C123GH6PM

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1113312/tm4c123gh6pm-dma-channel-array-1024-of-8bit-send-to-32bit-cpu-register

器件型号:TM4C123GH6PM

您好!

是否可以设置 UDMA 通道以发送 8位到32位 CPU 寄存器的阵列[1024]?

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

    尊敬的 Kevin:

    您在这里提出的问题有多种可能的含义。

    您是否希望将8位数据发送到32位寄存器、在该寄存器中填充4次传输、 或者、您是否希望每次发送数据时、其他24位都填充为0、例如为 UART FIFO 向 UARTDR 发送8位?

    此致、

    Ralph Jacobi

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

    非常感谢您的回答。
    UDMA 通道连接到 GPIO 端口。
    触发器是 GPIO 端口。
    数据源是一个32位的1024数组。
    目的是一个定时器匹配寄存器。
    每个 GPIO 触发器应始终从数组发送一个项目到计时器的匹配寄存器。
    在此配置中、一切正常。
    但我只发送小于255的十进制值。
    我的 SRAM 已停止运行。
    如果我可以在32位的1024数组中创建一个8位的1024数组。 我可以节省大量内存。

    在这里我的配置:

    void init_uDMA()
    {
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA));
        
        // general uDMA setup
        MAP_uDMAEnable();
        MAP_uDMAControlBaseSet(uDMAControlTable);
        MAP_IntEnable(INT_UDMAERR);
        
        // led signal setup
        MAP_uDMAChannelAssign(UDMA_CH5_GPIOB);
        MAP_uDMAChannelAttributeDisable(UDMA_CH5_GPIOB, 
                                        UDMA_ATTR_ALTSELECT | 
                                        UDMA_ATTR_HIGH_PRIORITY | 
                                        UDMA_ATTR_REQMASK | 
                                        UDMA_ATTR_USEBURST);
        
        MAP_uDMAChannelControlSet(UDMA_CH5_GPIOB | UDMA_PRI_SELECT, 
                                  UDMA_SIZE_32 | UDMA_SRC_INC_32 | 
                                  UDMA_DST_INC_NONE | UDMA_ARB_1);
        
        MAP_uDMAChannelControlSet(UDMA_CH5_GPIOB | UDMA_ALT_SELECT, 
                                  UDMA_SIZE_32 | UDMA_SRC_INC_32 | 
                                  UDMA_DST_INC_NONE | UDMA_ARB_1);
    }

    void startStreamPri(uint16_t size)
    {
        MAP_uDMAChannelTransferSet(UDMA_CH5_GPIOB | UDMA_PRI_SELECT,
                                       UDMA_MODE_PINGPONG, &streamData_PRI,
                                       (void *)(TIMER1_BASE + TIMER_O_TAMATCHR), 
                                       size);
            
        DEBUG_PD6 = GPIO_PIN_6; // PRISTART
        MAP_uDMAChannelEnable(UDMA_CH5_GPIOB | UDMA_PRI_SELECT);
        streamStatus_PRI = ENABLED;
    }
    
    void startStreamAlt(uint16_t size)
    {
        MAP_uDMAChannelTransferSet(UDMA_CH5_GPIOB | UDMA_ALT_SELECT,
                                       UDMA_MODE_PINGPONG, &streamData_ALT,
                                       (void *)(TIMER1_BASE + TIMER_O_TAMATCHR), 
                                       size);
            
        DEBUG_PC4 = GPIO_PIN_4; // ALTSTART
        MAP_uDMAChannelEnable(UDMA_CH5_GPIOB | UDMA_ALT_SELECT);
        streamStatus_ALT = ENABLED;
    }

    static uint32_t streamData_PRI
    static uint32_t streamData_ALT

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

    尊敬的 Kevin:

    我看到、这是一个有趣的用例、我以前没有尝试过类似的操作。 我在我的末尾没有发现任何真正的问题、因为您正在更新寄存器值、所以虽然 DMA 说 "对于任何给定的传输、源数据和目标数据大小必须相同"、但我认为在这种情况下、您可以摆脱这种情况。

    但是、如果不是、我在这里的理解是、您的目标是将所有内容存储为8位值:

    [引用 userid="512790" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1113312/tm4c123gh6pm dma-channel-array-1024-of -8bit-send-to-32ite-cpu-register/4126403#412432]/如果可以引用81024位数组和81024位数组、则可以引用81024位数组。]

    因此、如果您无法成功进行8位传输、那么您可能可以找到一种方法来键入 cast 数据以进行传输? 我以前没有尝试过这样的情况、但这是我们想到的下一个解决方案。

    此致、

    Ralph Jacobi

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

    我尝试键入数据、但没有成功。
    您能建议我如何键入数据吗?

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

    尊敬的 Kevin:

    由于它通过引用传递可能是不可能的、因此我找不到一种简单的方法来这样做。 在我深入探讨之前、您是否曾尝试过简单地制作8位数组? 如果是、编译或 DMA 时是否出现错误?

    此致、

    Ralph Jacobi

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

    您是指必须创建一个8位数组、使用此配置:

    MAP_uDMAChannelControlSet(UDMA_CH5_GPIOB | UDMA_PRI_SELECT, 
                                  UDMA_SIZE_32 | UDMA_SRC_INC_32 | 
                                  UDMA_DST_INC_NONE | UDMA_ARB_1);

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

    尊敬的 Kevin:

    否、您还需要将其配置为发送8位数据大小。 因此、为8位传输配置 uDMA 并使用8位阵列。

    此致、

    Ralph Jacobi

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

    我这么做了。

    似乎这些值没有到达计时器匹配寄存器。

    我有一个 DMA 完成中断、我可以看到 DMA 正在工作。

    编辑:

    我使用逻辑分析仪观察到信号、在第一次传输后、可以在匹配寄存器中看到:

    0b0000'0000'0000'0000'0110'0010'0110'0010

    但它必须是 DEZ 74。

    出什么问题了?

    EDIT2:

    匹配寄存器中的值为:

    0b0000'0000'0000'0000'0000'0000'0110'0010

    在我启动 uDMA 通道后、会出现以下情况:

    0b0000'0000'0000'0000'0100'1010'0100'1010

    但它必须:

    0b100'1010

    DEZ 编号为74。

    为什么这个数字在 BIN 中是有疑问的?

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

    尊敬的 Kevin:

    您能否共享当前代码以了解如何配置计时器和 UDMA、以便我可以查看它并在电路板上运行它以进一步测试?

    此致、

    Ralph Jacobi

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

    void init_SYS_CLOCK()
    {
        MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | 
                       SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
        
        MAP_SysCtlDelay(10);
    }
    

    void init_uDMA()
    {
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA));
        
        // general uDMA setup
        MAP_uDMAEnable();
        MAP_uDMAControlBaseSet(uDMAControlTable);
        MAP_IntEnable(INT_UDMAERR);
        
        MAP_uDMAChannelAssign(UDMA_CH5_GPIOB);
        MAP_uDMAChannelAttributeDisable(UDMA_CH5_GPIOB, 
                                        UDMA_ATTR_ALTSELECT | 
                                        UDMA_ATTR_HIGH_PRIORITY | 
                                        UDMA_ATTR_REQMASK | 
                                        UDMA_ATTR_USEBURST);
        
        MAP_uDMAChannelControlSet(UDMA_CH5_GPIOB | UDMA_PRI_SELECT, 
                                  UDMA_SIZE_8 | UDMA_SRC_INC_8 | 
                                  UDMA_DST_INC_NONE | UDMA_ARB_1);
        
        MAP_uDMAChannelControlSet(UDMA_CH5_GPIOB | UDMA_ALT_SELECT, 
                                  UDMA_SIZE_8 | UDMA_SRC_INC_8 | 
                                  UDMA_DST_INC_NONE | UDMA_ARB_1);
    }

    void init_TIMER()
    {
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
        while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1));
        
        MAP_GPIOPinConfigure(GPIO_PB4_T1CCP0);
        MAP_GPIOPinConfigure(GPIO_PB5_T1CCP1);
        
        MAP_GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_4);
        MAP_GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_5);
        
        MAP_TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR | 
                           TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);
        
        MAP_TimerLoadSet(TIMER1_BASE, TIMER_BOTH, 99);
        
        MAP_TimerMatchSet(TIMER1_BASE, TIMER_A, 98);
        
        MAP_TimerMatchSet(TIMER1_BASE, TIMER_B, 23);
        
        MAP_TimerEnable(TIMER1_BASE, TIMER_BOTH);
    }

    void init_GPIO_B()
    {
        MAP_GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_0, 
                       GPIO_DIR_MODE_IN);
        
        MAP_GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA, 
                         GPIO_PIN_TYPE_STD_WPU);
        
        MAP_GPIODMATriggerEnable(GPIO_PORTB_BASE, GPIO_PIN_0);
        
        MAP_GPIOIntTypeSet(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_FALLING_EDGE);
        MAP_GPIOIntEnable(GPIO_PORTB_BASE, GPIO_INT_DMA);
        
        // ------------------ //
        // Priority Levels
        // Priority 4 = 0xE0 
        // Priority 3 = 0x60
        // Priority 2 = 0x20
        // Priority 1 = 0x00
        // ------------------ //
        
        MAP_IntPrioritySet(INT_GPIOB, 0x20); // Priority 2
        MAP_IntEnable(INT_GPIOB);
    }

    void startStreamPri(uint16_t size)
    {
        MAP_uDMAChannelTransferSet(UDMA_CH5_GPIOB | UDMA_PRI_SELECT,
                                       UDMA_MODE_PINGPONG, &streamData_PRI,
                                       (void *)(TIMER1_BASE + TIMER_O_TAMATCHR), 
                                       size);
            
        DEBUG_PD6 = GPIO_PIN_6; // PRISTART
        MAP_uDMAChannelEnable(UDMA_CH5_GPIOB | UDMA_PRI_SELECT);
        streamStatus_PRI = ENABLED;
    }
    
    void startStreamAlt(uint16_t size)
    {
        MAP_uDMAChannelTransferSet(UDMA_CH5_GPIOB | UDMA_ALT_SELECT,
                                       UDMA_MODE_PINGPONG, &streamData_ALT,
                                       (void *)(TIMER1_BASE + TIMER_O_TAMATCHR), 
                                       size);
            
        DEBUG_PC4 = GPIO_PIN_4; // ALTSTART
        MAP_uDMAChannelEnable(UDMA_CH5_GPIOB | UDMA_ALT_SELECT);
        streamStatus_ALT = ENABLED;
    }

    static uint8_t streamData_PRI[1024];
    static uint8_t streamData_ALT[1024];

    必须桥接端口:

    需要使用电缆桥接:PB0 <--> PB5

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

    尊敬的 Kevin:

    因此、我复制了8位大小数组的问题、但我尚未找到解决该问题的方法、但我确实确定了一个折衷方案。

    如果使用16位数组大小和16位传输、我看到了正确的数据传输到计时器匹配寄存器。 这会将您使用的缓冲器大小减少50%、这一点值得注意。

    现在我不知道是否有办法使8位传输正常工作、因为我怀疑问题是计时器寄存器的全尺寸为16位、我不相信有办法让它正常工作 接受高8位为"0"、而不是重复数据。

    此致、

    Ralph Jacobi

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

    非常感谢!

    这将对我有所帮助。

    我从未用16位来测试它;-)

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

    尊敬的 Kevin:

    很高兴这对您有很大帮助。 我和我的同事交谈过、我们怀疑计时器正在从 DMA 读取数据、直到它获得16位来填充匹配寄存器、而 DMA 只广播数据、直到计时器指示它已成功获取数据、 这就是计时器获取重复8位数据的原因。 我们看不到该问题的解决方法、因此最佳解决方案将是16位值、因此我很高兴这能为您提供帮助。

    此致、

    Ralph Jacobi