first session prepared

lecture
Gerardo Marx 2 weeks ago
commit 63a43ec0ef

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@ -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
}

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Loading…
Cancel
Save