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

PWM CONTROL — A TASK SETS THE DUTY, HARDWARE MAKES THE WAVE Setpoint src UART cmd / button Setpoint Queue Ramp / Control Task (periodic) xTaskDelayUntil(&wake, STEP_MS) move cur → target by ≤ SLEW PWM_WriteCompare(cur) HW PWM period + compare toggles in HW LED / Motor brightness / speed duty Slew-rate limiting = a smooth fade · A new setpoint can jump; the output must not. · Each tick, step the actual duty toward the target by at most SLEW counts — a bounded rate of change. · Fade time = distance / (SLEW per tick × tick rate). · Protects LEDs from flicker, motors from current spikes. The task shapes the trajectory; it never toggles the pin. Hardware vs. software PWM Hardware: the PWM block toggles the pin from a counter. CPU writes the compare register only when the duty changes — jitter-free, near-zero CPU. Software: a task/ISR toggles the pin every edge — high CPU, jitter under load. Use only if you must. Offload the waveform; let the RTOS set the setpoint. Glitch-free update: the PWM compare is double-buffered — a write takes effect at the next period boundary, so mid-cycle changes never produce a runt pulse.

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:

Slew-rate limiting — the setpoint jumps, the duty fades to it Each tick the control task moves the actual duty toward the target by at most SLEW counts 0% 100% time → (control ticks) setpoint (target) actual duty (slew-limited) slope = SLEW/tick The fade time is the distance divided by the slew rate — set SLEW for the look you want (LED fade) or the load (motor). Conceptual / idealized

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 vs. software PWM — who toggles the pin Same output waveform; hardware costs the CPU almost nothing, software pays for every edge PWM out HW: CPU PWM_WriteCompare() once … then nothing: the counter toggles the pin in hardware SW: CPU a CPU action at every edge — many interrupts/toggles per period, and jitter when the CPU is busy Takeaway: let the hardware PWM own the waveform; the task only writes the compare when the duty changes. Conceptual / idealized

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

  1. Who toggles the PWM pin in hardware PWM, and what is the CPU's only job? How does software PWM differ?
  2. What does slew-rate limiting do, and how is the fade time related to SLEW and the tick rate?
  3. Why does writing the compare mid-cycle not produce a glitch?
  4. 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.

© 2026 Air Supply Information Center (Air Supply BBS)