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.

[参考译文] TM4C129EKCPDT:将触发计时器 Timer2A 从 TIMER_CFG_A_PERIODENT 模式更改为 TIMER_CFG_PWM 模式时、DMA 停止工作

Guru**** 2430620 points
Other Parts Discussed in Thread: EK-TM4C1294XL

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1541348/tm4c129ekcpdt-dma-stops-working-when-changing-the-trigger-timer-timer2a-from-timer_cfg_a_periodic-mode-to-timer_cfg_pwm-mode

器件型号:TM4C129EKCPDT
Thread 中讨论的其他器件:EK-TM4C1294XL

工具/软件:

您好、

我使用 TImer2A 作为 DMA 触发器、将数据块移动到 GPIO 端口。 如果计时器处于 TIMER_CFG_A_PERIODENT 模式、则一切都正常运行。

方法是通过并行通信将数据传输到外围器件。  其中一个位用作锁存信号、用于让外设知道数据已就绪。 通过这种方法、我必须重复存储器中的每个字节、以允许锁存信号在中间变化。

为了改善机制并避免重复、我认为将 Timer2A 更改为 PWM 模式并将 PWM 信号输出到 T2CCP0 (PA4)、并使用 PWM 输出作为锁存信号。

但是、一旦我切换到 PWM 模式、DMA 就会停止工作。

我没有忘记在 PWM 模式下调用 TImerMatchSet ()。  

我还将 PA4 正确配置为 T2CCP0、并且在这个引脚上看到了 PWM 信号。 这意味着 Timer2 PWM 可以工作、但不再与 DMA 一起工作。

以下是我的代码:

#define LED_CLK_PORT  SYSCTL_PERIPH_GPIOA
#define LED_CLK_BASE GPIO_PORTA_BASE   
#define LED_CLK      GPIO_PIN_4



#define LED_DATA_PORT  SYSCTL_PERIPH_GPIOD
#define LED_DATA_BASE GPIO_PORTD_BASE   
#define LED_R1      GPIO_PIN_0
#define LED_G1      GPIO_PIN_1
#define LED_B1      GPIO_PIN_2
#define LED_R2      GPIO_PIN_3
#define LED_G2      GPIO_PIN_4
#define LED_B2      GPIO_PIN_5
#define LED_CLKE  GPIO_PIN_6

#define LED_LAD GPIO_PIN_7

#define LED_DATA_PINS  (LED_R1 | LED_G1 | LED_B1 | LED_R2 | LED_G2 | LED_B2 | LED_CLKE)

#define LED_LAD_ON      GPIOPinWrite (LED_DATA_BASE、LED_LAD、0xff)
#define LED_LAD_OFF   GPIOPinWrite (LED_DATA_BASE、LED_LAD、0x00)


#define LED_CTRL_PORT  SYSCTL_PERIPH_GPIOE
#define LED_CTRL_BASE GPIO_PORTE_BASE   

#define LED_A   GPIO_PIN_0
#define LED_B   GPIO_PIN_1
#define LED_C   GPIO_PIN_2
#define LED_D   GPIO_PIN_3
#define LED_OE GPIO_PIN_4

#define LED_CTRL_PINS (LED_A | LED_B | LED_C | LED_D | LED_OE)

#define LED_ROW_SEL (x)   GPIOPinWrite (LED_CTRL_BASE、LED_CTRL_PINS、LED_OE |(x))
#define LED_ROW_ON      GPIOPinWrite (LED_CTRL_BASE、LED_OE、0x00)

Void
dmaInit()


  //************************************************************************************

  SysCtlPeripheralEnable (LED_DATA_PORT);
  SysCtlPeripheralEnable (LED_CTRL_PORT);

  HWREG (LED_DATA_BASE + GPIO_O_LOCK)= 0x4C4F434B;
  HWREG (LED_DATA_BASE + GPIO_O_CR)= 0xff;
  GPIOPinTypeGPIOOutput (LED_DATA_BASE、LED_DATA_PINS | LED_LAD);
  GPIOPadConfigSet (LED_DATA_BASE、LED_DATA_PINS | LED_LAD、GPIO_strength_2mA、GPIO_PIN_TYPE_STD);
  GPIOPinWrite (LED_DATA_BASE、LED_DATA_PINS | LED_LAD、0x00);
  HWREG (LED_DATA_BASE + GPIO_O_LOCK)= 0xaaaaaaaaaa;

  GPIOPinTypeGPIOOutput (LED_CTRL_BASE、LED_CTRL_PINS);
  GPIOPadConfigSet (LED_CTRL_BASE、LED_CTRL_PINS、GPIO_strength_4mA、GPIO_PIN_TYPE_STD);
  GPIOPinWrite (LED_CTRL_BASE、LED_CTRL_PINS、LED_OE);

  SysCtlPeripheralEnable (SYSCTL_PERIPH_TIMER2);
  while(!SysCtlPeripheralReady (SYSCTL_PERIPH_TIMER2)){}
  TimerConfigure (TIMER2_BASE、TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODENT);
  TimerDisable (TIMER2_BASE、TIMER_A);//配置前禁用
  TimerLoadSet (TIMER2_BASE、TIMER_A、20);
  TimerMatchSet (TIMER2_BASE、TIMER_A、10);
  TimerControlLevel (TIMER2_BASE、TIMER_A、0);
  //使计时器能够在超时时触发 DMA
  TimerDMAEventSet (TIMER2_BASE、TIMER_DMA_TIMEOUT_A);

  GPIOPinConfigure (GPIO_PA4_T2CCP0);
  GPIODirModeSet (LED_CLK_BASE、LED_CLK、GPIO_DIR_MODE_HW);
  GPIOPadConfigSet (LED_CLK_BASE、LED_CLK、GPIO_strength_2mA、GPIO_PIN_TYPE_STD);


  SysCtlPeripheralEnable (SYSCTL_PERIPH_UDMA);
  while(!SysCtlPeripheralReady (SYSCTL_PERIPH_UDMA)){}
  uDMAEnable();
  uDMAControlBaseSet (DmaControlTable);
  uDMAChannelAssign (UDMA_CH14_TIMER2A);//确保这是 Timer0A 的正确通道
  uDMAChannelControlSet (UDMA_CH14_TIMER2A | UDMA_PRI_SELECT、
             UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
  uDMAChannelAttributeDisable (UDMA_CH14_TIMER2A、UDMA_ALT_SELECT | UDMA_ATTR_HIGH_Priority | UDMA_ATTR_REQMASK);
  TimerEnable (TIMER2_BASE、TIMER_A);

  SysCtlPeripheralEnable (SYSCTL_PERIPH_TIMER3);
  while(!SysCtlPeripheralReady (SYSCTL_PERIPH_TIMER3)){}
  TimerDisable (TIMER3_BASE、TIMER_A);//配置前禁用
  TimerConfigure (TIMER3_BASE、TIMER_CFG_PERIODENT);//或 TIMER_CFG_PERIODY_UP
  TimerLoadSet (TIMER3_BASE、TIMER_A、SysClock / 60 - 1);//4 位颜色
  IntPrioritySet (INT_TIMER3A、WATCHDOG_PERIORITY);
  IntEnable (INT_TIMER3A);
  TimerIntEnable (TIMER3_BASE、TIMER_TIMA_TIMEOUT);
  TimerEnable (TIMER3_BASE、TIMER_A);

}

Void
Timer3aIsr ()

  TimerIntClear (TIMER3_BASE、TIMER_TIMA_TIMEOUT);

  uDMAChannelTransferSet (UDMA_CH14_TIMER2A | UDMA_PRI_SELECT、
                UDMA_MODE_BASIC、
                帧、
                (void *)(LED_DATA_BASE +(GPIO_O_DATA +(0x7f << 2)))、
                LED_FRAME_LEN);

  uDMAChannelEnable (UDMA_CH14_TIMER2A);
  ...

}

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

    尊敬的 Tianlei:

     我认为不可能在 PWM 模式下使用计时器向 UDMA 模块生成 DMA 请求。 它在周期模式下工作。 我创建了一个测试用例、但它 在 PWM 模式下不工作以生成 DMA 请求、我还搜索 e2e 存档以确认相同的内容。  我将提出另一种解决方案、即使用外围散射收集模式。  请参阅下图、另请参阅数据表以了解详细信息。 您可以使用 SRC A 将锁存信号存储为高电平、使用 SRC B 存储并行数据、使用 SRC 将锁存信号存储为低电平。 基本上、将三个传输连接起来。  

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

    尊敬的 Charles:

    感谢对的确认和建议。 我需要的不是传输开始和结束时的锁存信号、而是在正在传输的每个字节内。 我曾经发送每个字节两次、以便可以在中间插入锁存边缘。

    由于 PWM 模式下的计时器无法与 DMA 一起使用、我提出了不同的想法、即我将使用两个相同的计时器(例如 Time2A 和 TImer2B)、以便一个用于 DMA、另一个用于生成 PWM 信号。 这样、我可以在每个 DMA 字节周期的中间生成锁存信号。 为避免 DMA 结束后出现过多的锁存信号、我正在使用传输的数据中的 1 位作为锁存信号的掩码、并在传输的帧中再添加一个字节。 对于正常数据、该位将为 1、对于最后一个字节、该位将为 0。 该位将与 PWM 信号进行与运算、以确保在 DMA 传输后不会出现错误的锁存。

    我尝试将 MASK 和 PWM 的输出设置为 OD、以便可以将它们连接在一起、只是为了发现此方法在 10MHz 不能很好地工作。 但无论如何、这种方法可以是一种解决方案、我将使用逻辑门来执行和。

    受您的分散采集 DMA 理念的启发、我也认为我可以使用这种方法在常规帧传输之后设置额外的 DMA 传输。 额外的 DMA 仅用于关闭 PWM 计时器。 这样、我甚至不需要掩码位。

    但是、我不确定是否可以这样做。 我的帧传输为 8 位、但将配置发送到计时器控制寄存器以关闭计时器需要 16 位数据。

    是否可以对任何外设寄存器、尤其是 GPTM 控制 (GPTMCTL) 寄存器进行 DMA?

    是否可以使用散点收集方法来传输具有不同数据大小的任务?  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    但是、我不确定这是否可行。 我的帧传输为 8 位、但将配置发送到计时器控制寄存器以关闭计时器需要 16 位数据。

    通常、GTPM 模块寄存器各为 32 位、您可以对其进行 8 位、16 位或 32 位写入。 因此、向 GPTMCTL 写入 8 位将有效。 您可以首先尝试使用 CPU 执行 8 位写入来进行概念验证。

    [引述 userid=“52689" url="“ url="~“~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1541348/tm4c129ekcpdt-dma-stops-working-when-changing-the-trigger-timer-timer2a-from-timer_cfg_a_periodic-mode-to-timer_cfg_pwm-mode/5930132

    是否可以对任何外设寄存器、尤其是 GPTM 控制 (GPTMCTL) 寄存器进行 DMA?

    [/报价]

    是的。 GPTMCTL 不受特权模式保护、因此、您可以使用 DMA 对其进行写入。  

    是否可以使用散点收集方法来传输具有不同数据大小的任务?  [/报价]

    是的。 散射收集方法中的每个控制结构相互独立。 您可以有不同的数据大小。  

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

    谢谢 Charles。 是否有使用散点收集操作的示例代码? 我花了一段时间,但我仍然无法使基本操作正常工作。

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

    尊敬的 Tianlei:

     是的、 C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\UDMA_SPACT_TRACK 中有一个。

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

    谢谢 Charles。  我有散聚模式工作,但不幸的是,它不满足我的需要。

    问题在于、在散点收集模式下、传输不再跟随计时器。 我无法控制传输速度。

    我将尝试乒乓模式。

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

    尊敬的 Charles:

    我能够运行乒乓模式、它按照我的预期处理锁存信号。 不过、我发现这种方法(将计时器的 PWM 输出用于锁存信号)并不可靠。 当 MCU 忙于执行某些任务时、会出现很多传输错误。

    我猜测的原因是、虽然计时器会触发 DMA 传输、但不能保证 DMA 立即启动。 如果由于总线仲裁而导致一些延迟、锁存信号将与数据不同步。

    我将它与我的旧方法进行比较,它在每次数据传输中都嵌入了锁存信号,旧方法的可靠性是坚如磐石的。   

    我不得不放弃 PWM 型锁存信号的想法。

    我还有一个想法:我能够使用计时器在一种短模式下工作、并设置负载和比较寄存器、使其输出 PWM 信号。 我能够与数据一起生成方波(其中一个数据位用于方波。 此位将在每次传输时交替)。 我希望在方波的每个上升沿和下降沿生成一个脉冲信号、以便该脉冲可用作锁存信号。

    如果我可以使用上升沿和下降沿复位计时器、计时器将能够生成所需的脉冲。

    这种方法将要求计时器有 2 个外部引脚、一个用于边沿检测、一个用于 PWM 输出。 这是可能的吗?  

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

    尊敬的 Tianlei:

    [引述 userid=“52689" url="“ url="~“~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1541348/tm4c129ekcpdt-dma-stops-working-when-changing-the-trigger-timer-timer2a-from-timer_cfg_a_periodic-mode-to-timer_cfg_pwm-mode/5932526

    我还有一个想法:我能够使用计时器在一种短模式下工作、并设置负载和比较寄存器、使其输出 PWM 信号。 我能够与数据一起生成方波(其中一个数据位用于方波。 此位将在每次传输时交替)。 我希望在方波的每个上升沿和下降沿生成一个脉冲信号、以便该脉冲可用作锁存信号。

    如果我可以使用上升沿和下降沿复位计时器、计时器将能够生成所需的脉冲。

    [/报价]

    为什么方波信号不足以直接用于外部外设? 如果您的外部外设将进行边缘检测、那么该方波信号的高相位和低相位持续多长时间并不重要、对吧? 当然、您可以添加外部逻辑、通过触发器和 EXOR 门、从方波信号生成脉冲。  

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

    您好 Charles、

    嵌入式 CLK 信号与数据位只有数据波特的一半频率、因此外部外设必须同时检测上升沿和下降沿。 再加上 CLK 随数据同时变化、我需要找出一种方法来将边沿延迟一点。

    其实,我又回到了 Scatter-collect 方法。 一种新思路是在通用模式下使用 EPI 接口。 我认为我能够从 EPI 的 CLK 和 WR 获得 CLK 信号的正确时序。 这对我来说几乎是一个完美的解决方案。

    此致、

    Tianlei

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

    尊敬的 Tianlei:

     上周、我建议在 GP 模式下使用 EPI、因为它可以输出超过 8 位的并行数据。 但我的印象是,你的数据只有 8 位,你的大多数内部工作的 UDMA+GPIO 设置已经工作,因此,我没有建议 EPI 的想法。 请告诉我 EPI 是如何为您工作的。  

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

    尊敬的 Charles:

    我需要您的帮助来设置重复的 Scatter-collect 转移。

    每次传输中我有 2 个任务(存储器到存储器 DMA)、我希望传输由计时器触发。 目标是当计时器运行时、固件不需要干预、传输将在计时器的每个周期重复发生。

    首先、这是一个可以实现的目标吗?

    我不能让它发生。 我已经添加了第三个任务、以通过备用信道重新加载主信道的控制字段。

    此致、

    Tianlei

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引述 userid=“52689" url="“ url="~“~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1541348/tm4c129ekcpdt-dma-stops-working-when-changing-the-trigger-timer-timer2a-from-timer_cfg_a_periodic-mode-to-timer_cfg_pwm-mode/5938047

    每次传输中我有 2 个任务(存储器到存储器 DMA)、我希望传输由计时器触发。 目标是当计时器运行时、固件不需要干预、传输将在计时器的每个周期重复发生。

    首先、这是一个可以实现的目标吗?

    [/报价]

    外设散聚应该能够支持存储器到存储器传输的其中一项任务。  

    9.2.6.6 外围设备散点集
    外围散聚模式与 Memory Scatter-collect 非常相似、不同之处在于传输
    由发出 μ μDMA 请求的外设控制。 在检测到来自外设的请求时、
    n ü μDMA 控制器使用主控制结构将一个条目从列表复制到备用
    然后执行传输。 在此传输结束时、即主控制
    结构将下一个任务复制到备用控制结构。 如果下一个任务是 A
    存储器到存储器传输、执行将立即开始并运行至完成;如果是下一个任务、则运行至完成
    是外设类型传输、μ μDMA 将等待外设请求开始。

    [引述 userid=“52689" url="“ url="~“~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1541348/tm4c129ekcpdt-dma-stops-working-when-changing-the-trigger-timer-timer2a-from-timer_cfg_a_periodic-mode-to-timer_cfg_pwm-mode/5938047

    我不能让它发生。 我已经添加了第三个任务、以通过备用信道重新加载主信道的控制字段。

    [/报价]

    在 Memory Scatter 收集说明中、可以循环该列表。 但是、为什么您不简单地使用计时器中断再次触发散聚?  

    传输。 可以通过让最后一个条目复制主控件来循环列表
    指向列表开头(或指向新列表)的结构。 也可以触发 SET
    编程写入软件触发器来直接执行传输
    对于另一个通道、或间接地、通过导致产生 μ μDMA 请求的外设操作来实现。

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

    尊敬的 Charles:  

    你是对的。 在计时器 ISR 中触发 DMA 会更简单。 我最初认为我可能需要经常触发 DMA、每秒最多可触发 1M 个计时器、但后来我发现情况并非如此。 因此、ISR 方法对我很有用。

    我曾尝试在通用模式下使用 DMA 连接 EPI、并从 EPI CLK 和 WR 获得了完美的 CLK 信号。  

    由于 EPI CLS 是可配置的、因此我也可以完全控制传输速度。

    这里还有一个问题:我正在使用 EPI 进行数据传输、此后、我将需要使用另一个 GPIO 端口来输出一些控制信号(我已完全使用 EPI 数据引脚)。 如果目标是 GPIO 端口、那么内存散聚 DMA 的速度是多少? 测量值约为 17Mbps、只需确认该值。

    谢谢、

    Tianlei

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    如果目标是 GPIO 端口、内存 Scatter-collect DMA 的速度是多少? 测量值约为 17Mbps、只需确认该值。

    尊敬的 Tianlei:

     我们没有这样的数据。 因此、我不知道实际的吞吐量是什么。 GPIO 可在以系统时钟速度运行的 AHB 总线上访问。 如果系统时钟为 120MHz、则理论上它可以在每个周期切换 GPIO。 如果仅对 GPIO 执行写入操作、则最大速率为 60Mbps。 请记住、UDMA 不仅执行写入、还需要先从源读取。 UDMA 可能会产生额外的延迟、例如重新加载控制结构、在通道之间进行仲裁以及对 UDMA 中断做出响应的 CPU。 所有这些都会降低 理论上的最大吞吐量。   

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

    谢谢查尔斯!