PSoC5LP RTOS
Lab 16 — PWM Control
FreeRTOS on PSoC 5LP · Lab Series. Platform: CY8CKIT-059 (PSoC 5LP, Cortex-M3) · PSoC Creator 4.4 · FreeRTOS Kernel V11. Pipeline: setpoint → Queue → Ramp/Control task (periodic, slew-limited) → HW PWM → load. Pairs with Chapter 11 — Stream & Message Buffers & Chapter 16 — PWM & Actuation.
1. Introduction & Objectives
Dimming an LED or driving a motor is not about toggling a pin fast — the hardware PWM block already does that, jitter-free, for free. The RTOS job is to set the duty and, crucially, to shape how it changes: a target that jumps should reach the output as a smooth, slew-rate-limited fade, not a step. This lab builds a control task that receives a setpoint through a queue and ramps the actual duty toward it on a fixed grid, writing the PWM compare register.
After this lab you can:
- Set a hardware PWM duty from a task with PWM_WriteCompare, and explain the double-buffered glitch-free update.
- Slew-rate limit a setpoint so the output fades at a bounded rate.
- Relate fade time, slew step, and tick rate.
- Contrast hardware PWM (near-zero CPU) with software PWM (a CPU action per edge).
- Deliver a setpoint through a queue so the source and the controller are decoupled.
2. Prerequisites
Hardware: CY8CKIT-059 PSoC 5LP Prototyping Kit; RobotSoC Kit 1× LED (+ 220 Ω) for brightness, or a small motor through its driver; optional UART for commands.
Software: PSoC Creator 4.4 with the FreeRTOS V11 BaseProject.
Chapters (sync progress): Required — Chapter 16 (PWM & Actuation) and Chapter 11 (Stream & Message Buffers / inter-task delivery of the setpoint); Related — Chapter 2 (the periodic xTaskDelayUntil grid, from Lab 03/15); Peripheral prerequisite — PWM component configuration (period, compare, clock) is covered in the separate (non-FreeRTOS) Lab 08 (PWM).
3. Reading Materials / References
- Chapter 16 slides — PWM & Actuation (period vs compare, resolution, double-buffered compare).
- Chapter 11 slides — Stream & Message Buffers (delivering a setpoint between tasks).
- Lab 08 (non-RTOS) — configuring the PWM component and its clock.
- FreeRTOS / PSoC API: PWM_WriteCompare, PWM_WritePeriod, xTaskDelayUntil, xQueueReceive.
4. Background & Theory of Operation
The hardware owns the waveform. A PWM component counts a clock to a period and compares against a compare value; the pin is high while the counter is below compare. Duty = compare / period. Once started, the block toggles the pin entirely in hardware — the CPU is involved only when the duty changes, and then only to write the compare register. This is why PWM is offloaded: no per-edge interrupt, no jitter under load.
Software PWM is the opposite. If a task or ISR toggles the pin on every edge, the CPU pays for two actions per period forever, and any scheduling delay shows up as visible jitter (a flickering LED, a whining motor). Use software PWM only when no hardware channel is available.
Why slew-rate limit? A setpoint can change instantly — a command says "full", a button says "off". Sending that straight to the compare register snaps the output. For an LED that is a harsh jump; for a motor it is a current spike. Slew-rate limiting moves the actual duty toward the target by at most SLEW counts each control tick, so the output changes at a bounded rate. The fade time is simply:
fade time ≈ (target − current) / (SLEW per tick × tick rate)
Pick SLEW for the effect you want (a gentle LED fade) or the load can tolerate (a motor's acceleration limit).
Glitch-free updates. The PWM compare is double-buffered: a write takes effect at the next period boundary, not mid-cycle. So even though the control task writes asynchronously to the PWM's own timing, you never get a runt pulse. You can write the compare whenever you like and trust the hardware to apply it cleanly.
Decouple the setpoint. The target comes from somewhere — a UART command, a button, a sensor loop. A queue between that source and the control task keeps them independent: the source drops a new target in; the control task picks it up non-blocking on its next tick and keeps ramping. The source may be bursty; the controller stays periodic.
5. RTOS Task Architecture
A setpoint source (UART command or button) sends a target duty through the setpoint queue. The Ramp/Control task wakes on the xTaskDelayUntil grid, picks up any new target, steps the actual duty toward it by at most SLEW, and calls PWM_WriteCompare. The hardware PWM turns that duty into a waveform for the LED/motor. The panels explain the slew-rate fade and why hardware PWM beats software.
6. Duty & CPU Over Time
Slew-rate limiting — the setpoint jumps, the duty fades to it:
Each control tick moves the actual duty toward the target by at most SLEW, so a step setpoint becomes a bounded-rate ramp.
Hardware vs. software PWM — who toggles the pin:
Hardware: the CPU writes the compare once per change, then nothing. Software: a CPU action on every edge, with jitter under load.
The two diagrams carry the lesson: the task shapes the setpoint trajectory; the hardware makes the waveform. Keep slow, smooth control in software and fast, exact toggling in hardware.
7. Schematic Circuit & Pin Configuration
- PWM output → LED + 220 Ω → GND, or a motor driver input.
- UART → optional command source for the setpoint (duty NNN).
- Button → optional step source (up/down).
- Assign the pins in <project>.cydwr → Pins.
8. PSoC Creator Configuration
- A PWM component with a suitable clock; period = PWM_MAX + 1, so the duty range is 0..PWM_MAX.
- A Digital Output Pin on the PWM line (through the LED/driver); optional UART and button.
- FreeRTOSConfig.h (already set): configUSE_TIME_SLICING = 1 (course default), heap_4, tick rate adequate for STEP_MS.
- Choose the PWM frequency high enough to be flicker-free for an LED (≫ 100 Hz) or appropriate for the motor.
9. Provided Template
You are given Lab16_Template_main.c:
- Given: all includes (note #include "FreeRTOS_PSoC.h"), the setpoint queue, the handles, a clamp() helper, a demo setpoint task that cycles targets, the periodic xTaskDelayUntil skeleton with the non-blocking setpoint pickup, and a complete main() that starts the PWM and both tasks.
- You write: the slew step in vControlTask() (move cur toward target by ≤ SLEW, then PWM_WriteCompare(cur)), plus the Exp02/03 extensions.
- Do not change the boot sequence in main().
/* inside vControlTask, each tick: */
if (cur < target) cur += (target - cur > SLEW) ? SLEW : (target - cur);
else if (cur > target) cur -= (cur - target > SLEW) ? SLEW : (cur - target);
PWM_WriteCompare((uint8)cur); /* double-buffered: applied next period */
10. Lab Experiments
Exp01 — Basic: slew-limited fade. Fill in the slew step. With the demo setpoint cycling 0 → full → 64 → full → 0, watch the LED fade between levels instead of snapping. Expected: a smooth brightness ramp; the fade time matches distance / (SLEW × tick rate).
Exp02 — Advanced: fade shape and resolution. The eye is non-linear: equal duty steps do not look equally bright. Map the target through a gamma/stepped curve (e.g. square the normalized duty) before the slew, and compare the look. Try different SLEW and STEP_MS. Expected: a perceptually even fade, and a described relationship between SLEW, tick rate, and fade time.
Exp03 — Challenge: live setpoint and a safe slew. Replace the demo source with a UART command (duty 0..255) or buttons feeding the queue. For a motor, enforce a maximum slew so a "full" command still accelerates gently, and verify the controller stays periodic even while commands arrive in bursts. Expected: live control through the queue, a bounded acceleration, and no loss of the fixed control rate.
11. Testing & Verification
| # | Pass condition |
|---|---|
| Exp01 | Output fades between levels at a bounded rate; fade time matches the slew calculation. |
| Exp02 | A gamma/stepped mapping gives a perceptually even fade; SLEW/tick/fade relationship explained. |
| Exp03 | Live setpoints via the queue; bounded slew for the load; control rate stays fixed under bursts. |
Submit: your control task, your Exp02 fade-curve note with parameters, and your Exp03 live-setpoint + max-slew implementation.
12. Q&A & Troubleshooting
- Output snaps instead of fading → the slew step is missing or SLEW ≥ the full range; reduce SLEW.
- Visible flicker → PWM frequency too low; raise the PWM clock / lower the period.
- Fade too slow / too fast → adjust SLEW or STEP_MS; fade time = distance / (SLEW × tick rate).
- Runt pulse on change → you bypassed the double-buffer by also writing the period mid-cycle; only write the compare.
- Control rate drifts → you used vTaskDelay; seed xLastWakeTime once and use xTaskDelayUntil.
- Setpoint lost → the queue filled because the source is faster than the controller; that is fine for "latest wins", but size SP_Q_LEN or keep only the newest.
13. Analysis Questions & Lab Report
- Who toggles the PWM pin in hardware PWM, and what is the CPU's only job? How does software PWM differ?
- What does slew-rate limiting do, and how is the fade time related to SLEW and the tick rate?
- Why does writing the compare mid-cycle not produce a glitch?
- Why deliver the setpoint through a queue rather than having the source write the PWM directly?
Your report should include your control task, your fade-curve experiment, and answers to the four questions.