Other Parts Discussed in Thread: TMS320F280041, C2000WARE
器件型号: TMS320F280041
主题: C2000WARE 中讨论的其他器件
您好 TI 社区、
我正在从事 ISR 驱动的 ePWM 实现、以驱动 C2000 MCU 上的 WS2813-Mini LED、这是 TMS320F280041(F28004x 系列、使用支持 C2000Ware DriverLib 和 syscfg 的工程)。
目标是在 800ns 周期((TBPRD=79 @ 100MHz,向上计数模式)下为“0"(“(300ns 高电平/ 500ns 低电平)和“1"(“(500ns 高电平/ 300ns 低电平)生成一个具有精确占空比的连续比特流。
到目前为止、我实现这一目标的策略是设置一个简单的 ePWM 模块、该模块将在每个周期 (COUNTER = PERIOD) 结束时产生中断。在这个 ISR 中、我们将获取在下一个周期中使用的模块比较器 A 的 CMP 值、以实现所需的 LED 编码。
为此、我决定进行以下 EPWM 初始化:
void EPWM_init()
{
EPWM_setEmulationMode(LED_DRIVER_BASE, EPWM_EMULATION_FREE_RUN);
EPWM_setClockPrescaler(LED_DRIVER_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
EPWM_setTimeBasePeriod(LED_DRIVER_BASE, 200);
EPWM_setTimeBaseCounter(LED_DRIVER_BASE, 0);
EPWM_setTimeBaseCounterMode(LED_DRIVER_BASE, EPWM_COUNTER_MODE_UP);
EPWM_disablePhaseShiftLoad(LED_DRIVER_BASE);
EPWM_setPhaseShift(LED_DRIVER_BASE, 0);
EPWM_setCounterCompareValue(LED_DRIVER_BASE, EPWM_COUNTER_COMPARE_A, 0);
EPWM_setCounterCompareShadowLoadMode(LED_DRIVER_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);
EPWM_setCounterCompareValue(LED_DRIVER_BASE, EPWM_COUNTER_COMPARE_B, 0);
EPWM_setCounterCompareShadowLoadMode(LED_DRIVER_BASE, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
EPWM_setActionQualifierAction(LED_DRIVER_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
EPWM_setRisingEdgeDelayCountShadowLoadMode(LED_DRIVER_BASE, EPWM_RED_LOAD_ON_CNTR_ZERO);
EPWM_disableRisingEdgeDelayCountShadowLoadMode(LED_DRIVER_BASE);
EPWM_setFallingEdgeDelayCountShadowLoadMode(LED_DRIVER_BASE, EPWM_FED_LOAD_ON_CNTR_ZERO);
EPWM_disableFallingEdgeDelayCountShadowLoadMode(LED_DRIVER_BASE);
EPWM_enableInterrupt(LED_DRIVER_BASE);
EPWM_setInterruptSource(LED_DRIVER_BASE, EPWM_INT_TBCTR_PERIOD);
EPWM_setInterruptEventCount(LED_DRIVER_BASE, 1);
}
每次请求 LED 配置时、都会调用以下函数:
void ledDriverSendConfig(void)
{
// Don't start new transmission if one is already in progress
if (gLedDriver.isTransmitting)
{
return;
}
// Build the CMPA sequence from current configuration
ledDriverBuildCmpaSequence();
// Initialize transmission state
gLedDriver.currentIdx = 1U;
gLedDriver.isTransmitting = true;
// CRITICAL: Disable motor control ISR during LED transmission
// This prevents motor ISR from interrupting LED data stream
Interrupt_disable(INT_ADCC_CONFIG_1);
// Make sure counter is frozen to prepare for first PWM period
EPWM_setTimeBaseCounterMode(LED_DRIVER_BASE, EPWM_COUNTER_MODE_STOP_FREEZE);
// Reset ePWM counter to start fresh
EPWM_setTimeBaseCounter(LED_DRIVER_BASE, 0U);
// Load first CMPA value
EPWM_setCounterCompareValue(LED_DRIVER_BASE,
EPWM_COUNTER_COMPARE_A,
gLedDriver.cmpaSequence[0]);
// Clear any pending interrupt flags
EPWM_clearEventTriggerInterruptFlag(LED_DRIVER_BASE);
// Enable ePWM interrupt to start transmission
EPWM_enableInterrupt(LED_DRIVER_BASE);
// Start ePWM counter
EPWM_setTimeBaseCounterMode(LED_DRIVER_BASE, EPWM_COUNTER_MODE_UP);
}
在 ISR 例程中、我运行以下命令:
__interrupt void ledDriverISR(void)
{
GPIO_writePin(isrLedDriver, 1);
if (gLedDriver.currentIdx < gLedDriver.sequenceSize)
{
uint16_t cmpaValue = gLedDriver.cmpaSequence[gLedDriver.currentIdx];
EPWM_setCounterCompareValue(LED_DRIVER_BASE, EPWM_COUNTER_COMPARE_A, cmpaValue);
gLedDriver.currentIdx++;
}
else
{
EPWM_setTimeBaseCounterMode(LED_DRIVER_BASE, EPWM_COUNTER_MODE_STOP_FREEZE);
EPWM_disableInterrupt(LED_DRIVER_BASE);
Interrupt_enable(INT_ADCC_CONFIG_1); // Re-enable motor int
gLedDriver.isTransmitting = false;
gLedDriver.currentIdx = 0U;
}
// Clear ePWM interrupt flag
EPWM_clearEventTriggerInterruptFlag(LED_DRIVER_BASE);
// Clear PIE interrupt flag for this group
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
// Optional: Toggle GPIO for timing measurement
GPIO_writePin(isrLedDriver, 0);
}
我还在 ePWM(计数器=周期)中断开始时放置了一个 GPIO 切换开关。
但是、我遇到了一些问题:
- 问题 1:第一个占空比似乎损坏、只有在一个 PWM 周期后、模块的输出才是所需的输出。 则脉冲宽度是否为 300ns。 我得到以下波形输出:

- 图例:红色波形= ledISR | Orange Waverform = LED 配置信号、EPWM 输出
- 分析:
- 请注意第一个周期是如何正确的 (1.548us、而不是 300ns)。
- 请注意、当 LED 中断被编程为在 COUNTER = PERIOD 时触发时、LED 中断似乎在占空比中间触发、这在后续周期中会发生。
- 有什么想法为什么会发生这种情况?
- 问题 2:现在我在 2us PWM 周期内工作。 所需的时间实际上是 800ns、我这样做是因为我遇到了一些与__interrupt void ledDriverISR (void) 例程相关的开销问题。 我正在考虑实现 DMA、以减少下一个 CMP 值获取操作开销。 你有什么想法? 我无法想到任何其他方法来通过 PWM 实现该目的、而没有在每个周期结束时使用中断...
感谢您的关注。
此致、
Martin Blochre