commit 63a43ec0ef842454959a5ef54665f2c7e7c0946d Author: Gerardo Marx Date: Tue Oct 20 22:22:48 2026 -0600 first session prepared diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..7cb54d1 --- /dev/null +++ b/Readme.md @@ -0,0 +1,612 @@ +# ePWM Generation, Interrupts, and Trip-Zone Protection on the TMS320F28379D + +This project demonstrates how to configure the enhanced Pulse Width Modulator (**ePWM**) peripheral of the Texas Instruments **TMS320F28379D** using two register-access methods. The implementation uses **CPU1 with C2000 bit-field structures** and **CPU2 with `HWREG()` / `HWREGH()` register access from driverlib**. + +The guide follows an incremental approach: begin with an almost-empty program, find the relevant peripheral registers in C2000Ware, configure one submodule at a time, and verify each result with an oscilloscope. The supplied source files serve as the initial examples; any identified concerns are documented at the end rather than being changed without notice. + +# 1. Hardware and software requirements + +- TMS320F28379D microcontroller or compatible board (confirm that the listed GPIOs are exposed); we are using the `LAUNCHXL-F28379D` board development kit. +- Code Composer Studio (CCS), version 20.5.0 or above. +- C2000Ware and its device-support headers and/or driverlib, or previously installed the `C2000Ware_26_00_00_00`. +- Oscilloscope or logic analyzer to observe PWM and diagnostic GPIOs. +- A safe logic-level input or suitable test switch for trip-zone experiments. +- Initially **do not connect the PWM signals to power semiconductor gates**; verify the outputs and fault response at logic level. + +**Timing assumption:** the examples configure an ePWM module input clock of **100 MHz** and the time-base clock (`TBCLK`) of **50 MHz**. The device system clock, `EPWMCLKDIV`, `HSPCLKDIV`, and `CLKDIV` must agree with these assumptions. + +# 2. Project objectives and expected behavior + +The two source files are `pwm_cpu1_bitfield.c` and `pwm_cpu2_driverlib.c`. + +| CPU | ePWM | Outputs | Counter mode | Intended PWM frequency | Initial comparison | +|---|---|---|---|---|---| +| CPU1 | ePWM1 | GPIO0 / GPIO1 | Up-count (sawtooth counter) | 10 kHz | `CMPA = 1999`, approximately 40% | +| CPU1 | ePWM2 | GPIO2 / GPIO3 | Up-down (triangular counter) | 5 kHz | `CMPA = 1750`, parameter `m = -0.3` | +| CPU2 | ePWM4 | GPIO6 / GPIO7 | Up-count (sawtooth counter) | approximately 15 kHz | `CMPA = 1999`, approximately 60% | +| CPU2 | ePWM5 | GPIO8 / GPIO9 | Up-down (triangular counter) | 4 kHz | code uses `m = +0.7`, subject to review | + +Additional tasks: + +- **ePWM1 interrupt:** intended at `TBCTR = 0`, once per PWM cycle; toggle **GPIO22**. +- **ePWM5 interrupt:** intended at `TBCTR = 0` **and** `TBCTR = TBPRD`, twice per PWM cycle; toggle **GPIO52**. +- **Trip-zone input:** GPIO97 is routed through Input X-BAR 1 as `TZ1` to request a one-shot shutdown of ePWM1, ePWM2, ePWM4, and ePWM5 outputs. +- **Trip-zone ISRs:** CPU1 receives ePWM1/ePWM2 trip interrupts; CPU2 receives ePWM4/ePWM5 trip interrupts. + +The output pairs use the dead-band submodule. The two signals must be checked on the oscilloscope: *do not assume complementary outputs are safe for a power stage without measuring the dead time and fault behavior*. + +# 3. General program flow + +## CPU1 + +1. Initialize system clocks and the interrupt controller. +2. Select ePWM clock division and assign peripheral ownership across CPU1/CPU2. +3. Enable the clock gates for ePWM1/ePWM2. +4. Disable `TBCLKSYNC` while preparing the time-base counters. +5. Configure time-base (`TB`), counter-compare (`CC`), action qualifier (`AQ`), and dead-band (`DB`). +6. Configure event trigger (`ET`) for ePWM1 and trip zone (`TZ`) for ePWM1/ePWM2. +7. Register the ePWM and trip-zone interrupt service routines. +8. Configure GPIO0–GPIO3, diagnostic GPIO22, the GPIO52 ownership, and Input X-BAR from GPIO97. +9. Clear initial interrupt/fault flags as appropriate **only after confirming the fault is inactive**. +10. Enable synchronization after **both CPUs are ready**, then enter the main loop. + +## CPU2 + +1. Initialize the interrupt controller and vector table. +2. Enable the clock gates for ePWM4/ePWM5 on CPU2. +3. Configure `TB`, `CC`, `AQ`, and `DB` with direct register operations. +4. Configure the ePWM5 event-trigger interrupt and the ePWM4/ePWM5 trip zones. +5. Register and enable the CPU2 interrupt paths. +6. Signal configuration readiness to CPU1 using an explicit interprocessor synchronization mechanism. +7. Enter the main loop. + +**Dual-core note:** CPU1 controls cross-CPU ownership selection and shared startup coordination. Independent writes to `TBCLKSYNC` from both programs do not constitute a reliable synchronization protocol. + +# 4.0 Create a dual CPU project ready for bitfield and driverlib +1. Open a new folder (6-epwm-example); not a workspace +2. Import project from `C2000Ware_26_01_00_00`: `driverlib/f2837xd/examples/dual/empty_projects/css` +3. Change project names + - `gpio_bitfield_cpu1` + - `gpio_driverlib_cpu2` +- Change the `.c` files also + +# 4. Start from an almost-empty CPU1 program (bit-field approach) + +```c +#include "F28x_Project.h" +#include "driverlib.h" +#include "device.h" + +__interrupt void epwm1_isr(void) { /* TODO */ } +__interrupt void epwm1_trip_isr(void) { /* TODO */ } +__interrupt void epwm2_trip_isr(void) { /* TODO */ } + +void main(void) +{ + // 1. Initialize the system and interrupts. + // 2. Select ePWM clocks and assign CPU ownership. + // 3. Enable ePWM1 and ePWM2 clocks. + // 4. Stop time-base synchronization. + // 5. Configure TB and CC. + // 6. Configure AQ and dead band. + // 7. Configure event triggers and trip zones. + // 8. Register and enable interrupts. + // 9. Configure PWM GPIOs, diagnostic pins, and X-BAR. + // 10. Confirm fault conditions and synchronize startup. + for (;;) {} +} +``` + +The following sections progressively fill in these steps. Register names are those used in the **provided source**. + +## 5. CPU1: system initialization and peripheral ownership + +The provided source initializes the system and interrupt tables: + +```c +InitSysCtrl(); +InitPieCtrl(); +IER = 0x0000; +IFR = 0x0000; +InitPieVectTable(); +``` + +The CPU1 program sets the ePWM module input clock divisor and allocates the peripherals: + +```c +EALLOW; +ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV = 1; +DevCfgRegs.CPUSEL0.bit.EPWM1 = 0; +DevCfgRegs.CPUSEL0.bit.EPWM2 = 0; +DevCfgRegs.CPUSEL0.bit.EPWM4 = 1; +DevCfgRegs.CPUSEL0.bit.EPWM5 = 1; +EDIS; +``` + +- `0` indicates CPU1 ownership and `1` indicates CPU2 ownership in these fields. +- Establish peripheral ownership **before CPU2 configures its modules**. +- Check the resulting `EPWMCLK` from the actual system clock and clock-divider settings. + +Enable the CPU1 modules and stop time-base synchronization during setup: + +```c +EALLOW; +CpuSysRegs.PCLKCR2.bit.EPWM1 = 1; +CpuSysRegs.PCLKCR2.bit.EPWM2 = 1; +CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0; +EDIS; +``` + +**Register research:** locate the definitions of `CPUSEL0`, `PCLKCR2`, `PCLKCR0`, and `PERCLKDIVSEL` in the F2837xD device headers. Record their bit fields and the clock/ownership dependencies. + +## 6. CPU1: time-base submodule (TB) + +The time-base submodule selects counter mode and defines the switching period. + +```c +// ePWM1: up-count +EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; +EPwm1Regs.TBCTL.bit.CLKDIV = 0; +EPwm1Regs.TBCTL.bit.HSPCLKDIV = 1; +EPwm1Regs.TBCTL.bit.PRDLD = 0; +EPwm1Regs.TBCTL.bit.CTRMODE = 0; +EPwm1Regs.TBPRD = 5000 - 1; + +// ePWM2: up-down count +EPwm2Regs.TBCTL.bit.FREE_SOFT = 2; +EPwm2Regs.TBCTL.bit.CLKDIV = 0; +EPwm2Regs.TBCTL.bit.HSPCLKDIV = 1; +EPwm2Regs.TBCTL.bit.PRDLD = 0; +EPwm2Regs.TBCTL.bit.CTRMODE = 2; +EPwm2Regs.TBPRD = 5000; +``` + +With the assumed clock: + +\[ +f_{TBCLK}=\frac{100\ \mathrm{MHz}}{2\cdot1}=50\ \mathrm{MHz}. +\] + +For up-count mode, using a zero-based period register: + +\[ +f_{PWM}\approx\frac{f_{TBCLK}}{TBPRD+1}. +\] + +For up-down mode: + +\[ +f_{PWM}=\frac{f_{TBCLK}}{2TBPRD}. +\] + +Therefore: + +- ePWM1: `TBPRD = 4999` → **10 kHz**. +- ePWM2: `TBPRD = 5000` → **5 kHz**. + +**Exercise:** use the oscilloscope to compare the PWM periods of the up-count and up-down examples. Explain why an up-down counter requires twice as many `TBCLK` ticks for a complete PWM period. + +## 7. CPU1: counter-compare submodule (CC) + +The compare register determines the positions of edges generated by the action qualifier. + +```c +// ePWM1 +EPwm1Regs.CMPCTL.bit.SHDWAMODE = 0; +EPwm1Regs.CMPCTL.bit.LOADAMODE = 0; +EPwm1Regs.CMPA.bit.CMPA = 1999; + +// ePWM2 +EPwm2Regs.CMPCTL.bit.SHDWAMODE = 0; +EPwm2Regs.CMPCTL.bit.LOADAMODE = 0; +EPwm2Regs.CMPA.bit.CMPA = + (uint16_t)(((-0.3 + 1.0) / 2.0) * 5000); +``` + +For the *pre-dead-band ePWM1 A waveform* with high at zero and low at `CAU`, a useful nominal approximation is: + +\[ +D\approx\frac{CMPA}{TBPRD+1}=\frac{1999}{5000}\approx 0.40. +\] + +The ePWM2 source defines an **initial modulation parameter**, not a continuously varying modulation signal: + +\[ +CMPA=\frac{m+1}{2}TBPRD, +\qquad m=-0.3\Rightarrow CMPA=1750. +\] + +The requested modulation range `-0.97` to `+0.97` appears in the source-file comments, but **the supplied example does not implement a time-varying modulation algorithm**. Students can later update `CMPA` periodically to implement one. + +**Exercise:** derive `CMPA` for `m = 0`, `m = +0.5`, and `m = -0.5`. Explain the waveform using the action-qualifier edge definitions; do not assume the modulation parameter is numerically equal to the final PWM duty cycle. + +## 8. CPU1: action-qualifier submodule (AQ) + +The action qualifier converts timer events into logic-level transitions. + +| Event | Description | Relevant fields | +|---|---|---| +| `ZRO` | Counter reaches zero | `AQCTLA.ZRO`, `AQCTLB.ZRO` | +| `CAU` | Up-count reaches compare A | `AQCTLA.CAU`, `AQCTLB.CAU` | +| `CAD` | Down-count reaches compare A | `AQCTLA.CAD`, `AQCTLB.CAD` | + +```c +// ePWM1: initial high at zero, low at up-count CMPA +EPwm1Regs.AQCTLA.bit.ZRO = 2; +EPwm1Regs.AQCTLB.bit.ZRO = 2; +EPwm1Regs.AQCTLA.bit.CAU = 1; +EPwm1Regs.AQCTLB.bit.CAU = 1; + +// ePWM2: high on up CMPA, low on down CMPA +EPwm2Regs.AQCTLA.bit.CAU = 2; +EPwm2Regs.AQCTLB.bit.CAU = 2; +EPwm2Regs.AQCTLA.bit.CAD = 1; +EPwm2Regs.AQCTLB.bit.CAD = 1; +``` + +The source configures both **pre-dead-band A and B** paths with matching actions; the desired output polarity is subsequently generated using the dead-band polarity selection. Distinguish between *signals before dead band* and *physical ePWMxA/ePWMxB pins*. + +## 9. CPU1: dead-band submodule (DB) + +Dead band introduces timing separation between switching transitions. The supplied code selects two delay generators and a polarity arrangement: + +```c +EPwm1Regs.DBCTL.bit.IN_MODE = 1; +EPwm1Regs.DBCTL.bit.POLSEL = 2; +EPwm1Regs.DBCTL.bit.OUT_MODE = 3; +EPwm1Regs.DBRED.all = 100; +EPwm1Regs.DBFED.all = 100; + +EPwm2Regs.DBCTL.bit.IN_MODE = 1; +EPwm2Regs.DBCTL.bit.POLSEL = 2; +EPwm2Regs.DBCTL.bit.OUT_MODE = 3; +EPwm2Regs.DBRED.all = 250; +EPwm2Regs.DBFED.all = 250; +``` + +For `TBCLK = 50 MHz`, assuming the dead-band counter uses the same clock and no additional division: + +\[ +t_{DB}=\frac{DBRED\text{ or }DBFED}{50\times10^6}. +\] + +| Module | DBRED | DBFED | Nominal rising/falling delay | +|---|---:|---:|---:| +| ePWM1 | 100 | 100 | 2 µs | +| ePWM2 | 250 | 250 | 5 µs | + +**Exercise:** measure the time between relevant complementary output transitions. Confirm that no overlapping high pulses occur; also calculate whether the desired minimum pulse width can accommodate the chosen dead time. + +## 10. CPU1: ePWM1 event-trigger interrupt + +The supplied code generates an interrupt when the counter reaches zero, nominally once each 10 kHz PWM period: + +```c +EPwm1Regs.ETSEL.bit.INTEN = 1; +EPwm1Regs.ETSEL.bit.INTSEL = 1; +EPwm1Regs.ETPS.bit.INTPRD = 1; +``` + +Register the handler and enable its PIE/CPU paths: + +```c +EALLOW; +PieVectTable.EPWM1_INT = &epwm1_isr; +EDIS; +PieCtrlRegs.PIEIER3.bit.INTx1 = 1; +IER |= 0x4U; // CPU interrupt group 3 +``` + +The ISR from the source toggles GPIO22, clears the ePWM flag, and acknowledges PIE group 3: + +```c +__interrupt void epwm1_isr(void) +{ + GpioDataRegs.GPATOGGLE.bit.GPIO22 = 1; + EPwm1Regs.ETCLR.bit.INT = 1; + PieCtrlRegs.PIEACK.bit.ACK3 = 1; +} +``` + +Since each ISR **toggles** rather than emits a complete pulse, GPIO22 should have an idealized waveform frequency of **5 kHz**, even though the interrupt rate is **10 kHz**. This assumes the CPU can reliably service all interrupts. + +**Exercise:** measure GPIO22 independently from GPIO0 and identify the difference between PWM frequency, interrupt frequency, and toggle-output frequency. + +## 11. CPU1: one-shot trip-zone protection + +The supplied project routes GPIO97 through `INPUT1SELECT` and enables the `TZ1` one-shot source in both ePWM modules: + +```c +EALLOW; +InputXbarRegs.INPUT1SELECT = 97U; + +EPwm1Regs.TZSEL.bit.OSHT1 = 1; +EPwm1Regs.TZCTL.bit.TZA = 2; +EPwm1Regs.TZCTL.bit.TZB = 2; +EPwm1Regs.TZEINT.bit.OST = 1; + +EPwm2Regs.TZSEL.bit.OSHT1 = 1; +EPwm2Regs.TZCTL.bit.TZA = 2; +EPwm2Regs.TZCTL.bit.TZB = 2; +EPwm2Regs.TZEINT.bit.OST = 1; +EDIS; +``` + +The `TZA = 2` and `TZB = 2` actions select **force-low** behavior for the corresponding ePWM outputs. The one-shot fault is designed to **latch** until software explicitly clears it. + +Enable both trip-zone interrupts: + +```c +EALLOW; +PieVectTable.EPWM1_TZ_INT = &epwm1_trip_isr; +PieVectTable.EPWM2_TZ_INT = &epwm2_trip_isr; +EDIS; +PieCtrlRegs.PIEIER2.bit.INTx1 = 1; +PieCtrlRegs.PIEIER2.bit.INTx2 = 1; +IER |= 0x2U; // CPU interrupt group 2 +``` + +**Important protection rule:** the original CPU1 ISRs clear `TZCLR.INT` and `TZCLR.OST` immediately. This is not an adequate fault-latching strategy for an actual power converter. For a safe experiment, **record the fault and keep PWM inhibited** until the input is no longer active and a deliberate software restart has been performed. Do not automatically clear the one-shot latch within the trip ISR merely to resume operation. + +Also confirm GPIO97's input pad, multiplexing, and qualification are correctly configured on the selected board, and test the active polarity. Setting `INPUT1SELECT` alone does not fully document the external electrical behavior of that pin. + +## 12. CPU1: GPIO setup and startup + +The original program sets GPIO0–GPIO3 for ePWM1A/B and ePWM2A/B, GPIO22 for interrupt diagnostics, and GPIO52 for CPU2 diagnostics. For example: + +```c +EALLOW; +GpioCtrlRegs.GPAGMUX1.bit.GPIO0 = 0; +GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; +GpioCtrlRegs.GPAGMUX1.bit.GPIO1 = 0; +GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; +GpioCtrlRegs.GPAGMUX1.bit.GPIO2 = 0; +GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; +GpioCtrlRegs.GPAGMUX1.bit.GPIO3 = 0; +GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1; + +GpioCtrlRegs.GPAGMUX2.bit.GPIO22 = 0; +GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 0; +GpioCtrlRegs.GPADIR.bit.GPIO22 = 1; + +GpioCtrlRegs.GPBGMUX2.bit.GPIO52 = 0; +GpioCtrlRegs.GPBMUX2.bit.GPIO52 = 0; +GpioCtrlRegs.GPBDIR.bit.GPIO52 = 1; +GpioCtrlRegs.GPBCSEL3.bit.GPIO52 = 2; // CPU2 ownership +EDIS; +``` + +The supplied source also configures GPIO6–GPIO9 on CPU1 for ePWM4/ePWM5 output routing. Keep this separate from the CPU2 ePWM module configuration; **CPU ownership of an ePWM peripheral is not identical to ownership of an individual GPIO pin**. + +Before enabling `TBCLKSYNC`, ensure CPU2 configuration is complete, protective inputs are in an appropriate state, and initial flags are handled. The source currently ends with: + +```c +EALLOW; +CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; +EDIS; +for (;;) {} +``` + +A complete dual-core laboratory example should introduce a startup handshake so this action occurs only after both cores finish configuration. + +## 13. CPU2: start from an almost-empty program (HWREG approach) + +```c +#include "driverlib.h" +#include "device.h" + +__interrupt void epwm5_isr(void) { /* TODO */ } +__interrupt void epwm4_trip_isr(void) { /* TODO */ } +__interrupt void epwm5_trip_isr(void) { /* TODO */ } + +void main(void) +{ + // 1. Initialize CPU2 interrupt module and vector table. + // 2. Enable ePWM4 and ePWM5 peripheral clocks. + // 3. Configure time-base and counter-compare registers. + // 4. Configure action qualifiers and dead band. + // 5. Configure event triggers and trip zones. + // 6. Register and enable interrupts. + // 7. Notify CPU1 that CPU2 configuration is complete. + for (;;) {} +} +``` + +For this section, the student should locate: + +- `hw_memmap.h`: peripheral base addresses such as `EPWM4_BASE`, `EPWM5_BASE`, `CPUSYS_BASE`. +- `hw_epwm.h`: offsets such as `EPWM_O_TBCTL`, `EPWM_O_CMPA`, `EPWM_O_AQCTLA`, and `EPWM_O_TZCLR`. +- `hw_sysctl.h`: clock-gate register offsets. +- `hw_pie.h` and `hw_ints.h`: PIE register offsets and interrupt-vector identifiers. + +`HWREGH(address)` accesses a 16-bit register location, while `HWREG(address)` accesses a 32-bit register location. For `CMPA`, students should determine whether a 32-bit access covers both `CMPA` and `CMPAHR`; never assume an arbitrary bit mask or `|=` operation overwrites all intended compare bits. + +## 14. CPU2: initialize modules and configure the time base + +```c +Interrupt_initModule(); +Interrupt_initVectorTable(); + +EALLOW; +HWREG(CPUSYS_BASE + SYSCTL_O_PCLKCR2) |= (uint32_t)0x18U; +EDIS; + +// Time-base: values from the supplied CPU2 program +HWREGH(EPWM4_BASE + EPWM_O_TBCTL) = 0xC080; +HWREGH(EPWM5_BASE + EPWM_O_TBCTL) = 0xC082; +HWREGH(EPWM4_BASE + EPWM_O_TBPRD) = 3333 - 1; +HWREGH(EPWM5_BASE + EPWM_O_TBPRD) = 6250; +``` + +The `TBCTL` register words encode free-run debug behavior, clock prescalers, and up/up-down counter selection. Students should **decode every bit field** using the TI technical reference manual before using these values. + +With `TBCLK = 50 MHz`: + +- ePWM4: `50 MHz / 3333 ≈ 15.0015 kHz`. +- ePWM5: `50 MHz / (2 × 6250) = 4 kHz`. + +The CPU2 source also clears the `TBCLKSYNC` bit during configuration and sets it again at the end. In the final dual-core application, replace this unsynchronized startup behavior with a **CPU1-coordinated release**. + +## 15. CPU2: counter comparison and action qualifier + +The supplied code uses: + +```c +// Configure CMPCTL shadow/load bits. +HWREGH(EPWM4_BASE + EPWM_O_CMPCTL) &= 0xffefU; +HWREGH(EPWM4_BASE + EPWM_O_CMPCTL) &= 0xfffcU; +HWREGH(EPWM4_BASE + EPWM_O_CMPA) |= (uint32_t)0x07CF0000U; + +HWREGH(EPWM5_BASE + EPWM_O_CMPCTL) &= 0xffefU; +HWREGH(EPWM5_BASE + EPWM_O_CMPCTL) &= 0xfffcU; +HWREGH(EPWM5_BASE + EPWM_O_CMPA + 1) = + (uint16_t)(((0.7 + 1.0) / 2.0) * 5000); +``` + +The ePWM4 compare constant encodes `0x07CF = 1999` as the upper 16-bit comparison value. **Review** the `|=` access before using it repeatedly because it does not clear previous compare bits. The CPU2 ePWM5 line computes `4250` from a hard-coded `5000`, whereas its actual `TBPRD` is `6250`. If the intended formula is `(m + 1) × TBPRD / 2`, the result for `m = 0.7` should be **5312** after C conversion to an integer (the unrounded mathematical result is 5312.5). This is a source-code discrepancy to correct as a student exercise. + +The source configures the AQ registers with these writes: + +```c +// ePWM4: high at ZRO, low at CAU +HWREGH(EPWM4_BASE + EPWM_O_AQCTLA) = 0; +HWREGH(EPWM4_BASE + EPWM_O_AQCTLB) = 0; +HWREGH(EPWM4_BASE + EPWM_O_AQCTLA) |= 0x0002U; +HWREGH(EPWM4_BASE + EPWM_O_AQCTLB) |= 0x0002U; +HWREGH(EPWM4_BASE + EPWM_O_AQCTLA) |= 0x0010U; +HWREGH(EPWM4_BASE + EPWM_O_AQCTLB) |= 0x0010U; + +// ePWM5: high at CAU, low at CAD +HWREGH(EPWM5_BASE + EPWM_O_AQCTLA) = 0; +HWREGH(EPWM5_BASE + EPWM_O_AQCTLB) = 0; +HWREGH(EPWM5_BASE + EPWM_O_AQCTLA) |= 0x0020U; +HWREGH(EPWM5_BASE + EPWM_O_AQCTLB) |= 0x0020U; +HWREGH(EPWM5_BASE + EPWM_O_AQCTLA) |= 0x0040U; +HWREGH(EPWM5_BASE + EPWM_O_AQCTLB) |= 0x0040U; +``` + +**Exercise:** identify which bits correspond to the ZRO, CAU, and CAD fields, and reproduce the expected output-edge sequence before inserting dead band. + +## 16. CPU2: dead-band setup + +```c +HWREGH(EPWM4_BASE + EPWM_O_DBCTL) = (uint16_t)0x1BU; +HWREGH(EPWM4_BASE + EPWM_O_DBRED) = 100; +HWREGH(EPWM4_BASE + EPWM_O_DBFED) = 100; + +HWREGH(EPWM5_BASE + EPWM_O_DBCTL) = (uint16_t)0x1BU; +HWREGH(EPWM5_BASE + EPWM_O_DBRED) = 250; +HWREGH(EPWM5_BASE + EPWM_O_DBFED) = 250; +``` + +These are the CPU2 register-word equivalents of the CPU1 dead-band setup. The intended delays are **2 µs** for ePWM4 and **5 µs** for ePWM5 under the assumed 50 MHz clock. + +## 17. CPU2: ePWM5 interrupt and GPIO52 diagnostic + +The provided CPU2 program writes: + +```c +HWREGH(EPWM5_BASE + EPWM_O_ETSEL) |= (uint16_t)0xBU; +HWREGH(EPWM5_BASE + EPWM_O_ETPS) |= (uint16_t)0x1U; +``` + +`ETSEL = 0x000B` enables interrupt generation with selection `INTSEL = 3` (**counter zero OR counter period**). In up-down mode, this creates two selected events in one PWM cycle. `ETPS.INTPRD = 1` selects every event. + +```c +__interrupt void epwm5_isr(void) +{ + HWREG(GPIODATA_BASE + GPIO_O_GPBTOGGLE) = (uint32_t)0x100000U; + HWREGH(EPWM5_BASE + EPWM_O_ETCLR) |= (uint16_t)0x1U; + HWREGH(PIECTRL_BASE + PIE_O_ACK) |= (uint16_t)0x4U; +} +``` + +If all interrupts are serviced, two events per 4 kHz PWM cycle imply an **8 kHz interrupt rate** and a **4 kHz GPIO52 toggle waveform**. Real timing depends on CPU interrupt latency and system load. + +The PIE configuration in the supplied program is: + +```c +Interrupt_register(INT_EPWM5, &epwm5_isr); +HWREGH(PIECTRL_BASE + PIE_O_IER3) |= (uint16_t)0x10U; +IER |= (uint16_t)0x4U; +``` + +The corresponding ePWM5 trip-zone interrupt belongs to PIE **group 2**, channel 5; ePWM4 trip-zone belongs to group 2, channel 4. + +## 18. CPU2: one-shot trip-zone configuration + +The CPU2 source selects `TZ1` for ePWM4/ePWM5, forces both PWM outputs low, and enables the OST interrupt: + +```c +EALLOW; +HWREGH(EPWM4_BASE + EPWM_O_TZSEL) |= (uint16_t)0x100U; +HWREGH(EPWM4_BASE + EPWM_O_TZCTL) = (uint16_t)0xAU; +HWREGH(EPWM4_BASE + EPWM_O_TZEINT) = (uint16_t)0x4U; + +HWREGH(EPWM5_BASE + EPWM_O_TZSEL) |= (uint16_t)0x100U; +HWREGH(EPWM5_BASE + EPWM_O_TZCTL) = (uint16_t)0xAU; +HWREGH(EPWM5_BASE + EPWM_O_TZEINT) = (uint16_t)0x4U; +EDIS; +``` + +The handlers are registered with: + +```c +Interrupt_register(INT_EPWM4_TZ, &epwm4_trip_isr); +Interrupt_register(INT_EPWM5_TZ, &epwm5_trip_isr); +HWREGH(PIECTRL_BASE + PIE_O_IER2) |= (uint16_t)0x18U; +IER |= (uint16_t)0x2U; +``` + +**Do not carry over the source's unconditional clearing of both `TZCLR.INT` and `TZCLR.OST` as an automatic restart strategy.** For a hardware-protection demonstration, first inspect the latched fault state, require the unsafe condition to be removed, then implement an explicit authorized reset procedure. + +## 19. Controlled test procedure + +1. **Clock verification:** confirm system clock, module clock, and time-base clock before relying on calculated frequencies. +2. **CPU1, one module at a time:** observe GPIO0/1 at 10 kHz, then GPIO2/3 at 5 kHz. Measure duty cycle and dead time. +3. **CPU2, one module at a time:** observe GPIO6/7 at about 15 kHz and GPIO8/9 at 4 kHz, after CPU ownership and startup coordination are established. +4. **Interrupt diagnostics:** measure GPIO22 and GPIO52 and compare with the computed event rates. +5. **Trip-zone test:** with no power switching stage connected, activate the fault input and verify all eight ePWM outputs are forced low and remain disabled while the one-shot latch is set. +6. **Fault recovery test:** remove the fault, verify that recovery requires deliberate software action, and confirm outputs return only when commanded. + +Keep a table of *calculated values, measured values, percent error, and observations*. Use the same oscilloscope time base for corresponding before/after captures where feasible. + +## 20. Technical checks before final submission + +The following items are not silently corrected in this guide, because students should understand their cause and consequences. + +- **CPU2 `CMPA` access:** ePWM4 uses a bitwise `|=` for an existing compare register. A fresh assignment with an appropriate mask or field selection is preferable when a known numeric value is required. +- **ePWM5 modulation inconsistency:** its compare formula uses `5000` while `TBPRD = 6250`. Derive and implement a period-consistent formula. +- **Static rather than variable modulation:** both `m = -0.3` and `m = +0.7` are compile-time constants. A real variable modulation implementation needs an update algorithm and bounded comparisons. +- **Fault protection:** one-shot latches must not be routinely cleared inside trip interrupts, especially with a connected power stage. +- **GPIO97:** verify its actual input mapping and active signal polarity; include proper input configuration and conditioning for the selected hardware. +- **Dual-core coordination:** CPU2 readiness and CPU1-controlled synchronization require a defined interprocessor handshake. +- **CPU startup:** determine where CPU2 is booted and initialized in the system; the CPU1 source does not explicitly document a CPU2 boot handshake. +- **Shared and peripheral clocks:** check per-CPU ePWM clock gates, ownership timing, and the state of `TBCLKSYNC` before using the output. +- **Debug configuration:** test the intended behavior when execution is halted, considering `FREE_SOFT` and external-power safety requirements. +- **Output-safe states:** force-low actions must be verified at *physical pins*, not inferred from register writes alone. + +## 21. Questions for students + +1. Which registers determine the ePWM counter frequency, count mode, and PWM output frequency? +2. Why does up-down counting require twice the `TBPRD` count interval of up-count mode for the same output frequency? +3. What is the distinction between counter comparison (`CMPA`) and action qualifier (`AQ`)? +4. How do `DBRED`, `DBFED`, `IN_MODE`, and `POLSEL` affect complementary outputs? +5. What are the expected interrupt rates and GPIO toggle-waveform frequencies for ePWM1 and ePWM5? +6. Why is `TBCLKSYNC` disabled during configuration and why does its restoration need coordination between CPUs? +7. What does a one-shot trip-zone latch do? What checks should occur before it is cleared? +8. Why is `|=` risky when programming a register that should receive an entirely new comparison value? +9. How would you replace a fixed modulation parameter with a slowly varying reference while preserving safe limits? +10. How can an oscilloscope demonstrate that complementary PWM signals do not overlap? + +## 22. Relevant Texas Instruments references + +- [TMS320F28379D product and datasheet](https://www.ti.com/product/TMS320F28379D) +- [F2837xD ePWM Driverlib API Guide](https://software-dl.ti.com/C2000/docs/C2000_driverlib_api_guide/f2837xd/build/html/modules/epwm.html) +- [TMS320F2837xD Microcontroller Workshop](https://software-dl.ti.com/trainingTTO/trainingTTO_public_sw/c28x28379/F2837xD_Microcontroller_MDW_2-0.pdf) + +Refer also to the **TMS320F2837xD Technical Reference Manual**, particularly the ePWM, system control, interrupt controller, GPIO, and Input X-BAR chapters. In the installed C2000Ware, consult `F2837xD_epwm.h`, `F2837xD_sysctrl.h`, `F2837xD_gpio.h`, `hw_epwm.h`, `hw_memmap.h`, `hw_pie.h`, and `hw_ints.h` as applicable to the selected code style. + +--- + +**Status:** Teaching draft based on the supplied code. Hardware behavior, trip-zone polarity, register-level details, and dual-core startup must be validated on the selected TMS320F28379D board before the implementation is used to control a power stage. diff --git a/ia-presentation/epwm.iapresenter/assets/clk 1.jpg b/ia-presentation/epwm.iapresenter/assets/clk 1.jpg new file mode 100644 index 0000000..4d1449a Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/clk 1.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/clk.jpg b/ia-presentation/epwm.iapresenter/assets/clk.jpg new file mode 100644 index 0000000..45015aa Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/clk.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/epwm-architecture.jpg b/ia-presentation/epwm.iapresenter/assets/epwm-architecture.jpg new file mode 100644 index 0000000..a56a28e Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/epwm-architecture.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/epwm-reg-1.jpg b/ia-presentation/epwm.iapresenter/assets/epwm-reg-1.jpg new file mode 100644 index 0000000..d912285 Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/epwm-reg-1.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/epwm-reg-2.jpg b/ia-presentation/epwm.iapresenter/assets/epwm-reg-2.jpg new file mode 100644 index 0000000..71a66c3 Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/epwm-reg-2.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/epwm-reg-3.jpg b/ia-presentation/epwm.iapresenter/assets/epwm-reg-3.jpg new file mode 100644 index 0000000..8063acb Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/epwm-reg-3.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/epwm-reg-4.jpg b/ia-presentation/epwm.iapresenter/assets/epwm-reg-4.jpg new file mode 100644 index 0000000..6a491dc Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/epwm-reg-4.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/time-base-1.jpg b/ia-presentation/epwm.iapresenter/assets/time-base-1.jpg new file mode 100644 index 0000000..df6da38 Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/time-base-1.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/time-base-2.jpg b/ia-presentation/epwm.iapresenter/assets/time-base-2.jpg new file mode 100644 index 0000000..ffdce4b Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/time-base-2.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/time-base-3.jpg b/ia-presentation/epwm.iapresenter/assets/time-base-3.jpg new file mode 100644 index 0000000..7b45c70 Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/time-base-3.jpg differ diff --git a/ia-presentation/epwm.iapresenter/assets/time-base-4.jpg b/ia-presentation/epwm.iapresenter/assets/time-base-4.jpg new file mode 100644 index 0000000..4ac4c6f Binary files /dev/null and b/ia-presentation/epwm.iapresenter/assets/time-base-4.jpg differ diff --git a/ia-presentation/epwm.iapresenter/info.json b/ia-presentation/epwm.iapresenter/info.json new file mode 100644 index 0000000..dd8601d --- /dev/null +++ b/ia-presentation/epwm.iapresenter/info.json @@ -0,0 +1,11 @@ +{ + "creatorIdentifier" : "net.ia.presenter", + "net.ia.presenter" : { + "localFileIdentifier" : "DEB4D812-BF8E-42C4-9E2F-FC92F46F89A7", + "preset" : "Default", + "template" : "zurich" + }, + "transient" : false, + "type" : "net.daringfireball.markdown", + "version" : 2 +} \ No newline at end of file diff --git a/ia-presentation/epwm.iapresenter/text.md b/ia-presentation/epwm.iapresenter/text.md new file mode 100644 index 0000000..c140dba --- /dev/null +++ b/ia-presentation/epwm.iapresenter/text.md @@ -0,0 +1,172 @@ +# Enhanced Pulse Width Modulation +--- + +# 1. ePWM Module Overview + TMS320F28379D Microcontroller + +--- + +# What is ePWM? + Enhanced Pulse Width Modulation + Hardware-based PWM generation + Configurable frequency and duty cycle + Advanced control and protection features + +--- + +# ePWM in the F28379D + 12 independent ePWM modules + ePWM1 to ePWM12 + Controlled by CPU1 or CPU2 + Multiple configurable submodules +--- + +# ePWM Architecture + +/assets/epwm-architecture.jpg +size: contain +x: left + + Time-Base (TB) + Counter-Compare (CC) + Action Qualifier (AQ) + Dead-Band (DB) + Event Trigger (ET) + Trip-Zone (TZ) + +--- +# Advanced ePWM Features + Event Trigger (ET) + Interrupts and ADC triggers + Dead-Band (DB) + Complementary switching delays + Trip-Zone (TZ) + Fault detection and protection + +--- +# Summary + - The Time Base Sub-module generates the carrier waveform and also sets the PWM frequency. + - The Event Trigger and Interrupt Sub-module generates interrupts and can also start converting measured analog signals to digital form. + - The Counter Compare Sub-module performs a fine comparison between the carrier waveform and four possible values that can be modulation signals or duty ratios. + - The Action Qualifier Sub-module can be used to decide what action (gating signals) to take based on comparison results. + - The Dead Band Sub-module can be used to insert a dead band between complementary gating signals to prevent a shoot-through fault. + - The Trip Zone Sub-module can turn off the gating signals based on fault feedback or user off signals. + +--- +# 2. Preparing the ePWM Module + - Before configuring the ePWM module, a few preparations need to be made. + - There is a maximum limit to the clock frequency that the ePWM module can accept as input. This differs from the processor's maximum clock (200 MHz). + - Since the ePWM module is shared, we must decide which CPU controls it. By default, it is CPU1. + - Once we decide which CPU controls the ePWM module, we must enable the clock signal to the ePWM module in the peripheral clock control register of that CPU. + +--- +# ePWM Clock Frequency +/assets/clk 1.jpg +size: contain + The maximum ePWM clock frequency is 100 MHz. + The maximum processor clock frequency is 200 MHz. + +--- + +# ePWM Clock Divider +## PERCLKDIVSEL Register +/assets/epwm-reg-1.jpg +size: contain + EPWMCLKDIV determines the ePWM clock divider. + EPWMCLKDIV = 0 → EPWMCLK = SYSCLK + EPWMCLKDIV = 1 → EPWMCLK = SYSCLK / 2 + For SYSCLK = 200 MHz, use EPWMCLKDIV = 1. + +--- + +# ePWM CPU Selection +## CPUSEL0 Register +/assets/epwm-reg-2.jpg +size: contain + The ePWM modules can be controlled by CPU1 or CPU2. + By default, all ePWM modules are assigned to CPU1. + Bit = 0 → CPU1 + Bit = 1 → CPU2 + +--- + +# ePWM Peripheral Clock +## PCLKCR2 Register +/assets/epwm-reg-3.jpg +size: contain + Each ePWM module has an individual clock enable bit. + The controlling CPU must enable the corresponding peripheral clock. + Bit = 0 → Clock disabled + Bit = 1 → Clock enabled +--- + +# ePWM Clock Synchronization +## PCLKCR0 Register +/assets/epwm-reg-4.jpg +size: contain + TBCLKSYNC → Time-Base clock synchronization + GTBCLKSYNC → Global Time-Base clock synchronization + TBCLKSYNC = 1 → Start the ePWM Time-Base clocks. + GTBCLKSYNC = 1 → Start ePWM Time-Base clocks globally in synchronization. + GTBCLKSYNC overrides TBCLKSYNC. +--- +# 3. Time Base Sub-module + The Time Base Sub-module sets up the carrier waveform through a counter similar to the timers in the previous section. + The timers in the Time Base Sub-module can count in different directions: up (sawtooth), down (reverse sawtooth), and up-down (triangular). + The Time Base Sub-module can synchronize with either an external pin or other ePWM modules. + The Time Base Sub-module cannot generate interrupts like the timers in the previous section. + The simplest example will use the Time Base Sub-module in combination with the Counter Compare Sub-module and the Action Qualifier Sub-module. + +--- + +# Time Base Sub-module +## TBPRD Register +/assets/time-base-1.jpg + 16-bit period register. + This period register is mirrored by default. + This means another register acts as a clone. + Any reads or writes to TBPRD are actually from or to the mirror register. + The mirror register's value is loaded into TBPRD at a scheduled time, so writing to TBPRD does not change the switching-cycle interval mid-cycle. + +--- + +# Time Base Sub-module +## TBCTL Register +/assets/time-base-2.jpg + Bits 14–15 (FREE_SOFT) are similar to the timer. FREE = 1 implies a free-running timer. + Bits 10–12 (CLKDIV) provide the option of dividing EPWMCLK when generating slower switching-frequency gating signals. + Bits 7–9 (HSPCLKDIV) also provide the option of dividing EPWMCLK when generating slower switching-frequency gating signals. + Bit 2 (PHSEN), bits 4–5 (SYNCOSEL), bit 6 (SWFSYNC), and bit 13 (PHSDIR) are related to the synchronization feature. +--- + +# Time Base Sub-module +## Counter Modes — CTRMODE + +/assets/time-base-3.jpg +size: contain + + Bits 0–1 (CTRMODE) determine how the counter will count. + CTRMODE = 0 (00): The counter counts upwards from 0 to the value in the period register, then returns to 0 and starts again. + CTRMODE = 1 (01): The counter counts downwards from the value in the period register to 0, then returns to the period value and starts again. + CTRMODE = 2 (10): The counter counts upwards from 0 to the value in the period register, then counts down to 0 and starts again. + CTRMODE = 3 (11): The counter is stopped (default). + +--- + +# Time Base Sub-module +## Period Load — PRDLD + Bit 3 (PRDLD) is the Period Load Bit. + This determines when to load the period mirror register value into the period register TBPRD. + By default, when we write to the PRD register, we write to the mirror register PRDM. This is shadow mode. + This feature prevents disturbances if a write to the period register occurs during a PWM cycle. + The change is reflected only when the counter becomes 0. This occurs at the end of a cycle (down mode) or at the beginning of a cycle (up and up-down modes). + Setting PRDLD to 1 enables immediate load mode, where any write to the period register takes effect immediately, even in the middle of a cycle. + +--- + +# Time Base Sub-module +## TBSTS Register +/assets/time-base-4.jpg + The TBSTS register indicates the timer's status. + CTRDIR is a read-only bit. It is 0 if the counter is counting down and 1 if it is counting up. + The processor sets CTRMAX when the counter reaches the maximum value: 0xFFFF. \ No newline at end of file diff --git a/ia-presentation/epwm.iapresenter/thumb.png b/ia-presentation/epwm.iapresenter/thumb.png new file mode 100644 index 0000000..ec81a9c Binary files /dev/null and b/ia-presentation/epwm.iapresenter/thumb.png differ