PSoC5LP RTOS
Lab 02 — FreeRTOS Kernel Integration
FreeRTOS on PSoC 5LP · Lab Series. Platform: CY8CKIT-059 (PSoC 5LP, Cortex-M3) · PSoC Creator 4.4 · FreeRTOS Kernel V11. Pairs with Chapter 0 — Why an RTOS?
1. Introduction & Objectives
Lab 01 showed why an RTOS helps. This lab makes the kernel actually run on the PSoC 5LP. You add the FreeRTOS kernel to a PSoC Creator project, let FreeRTOS_Init() install the three Cortex-M3 exception handlers into the vector table, create one task, and start the scheduler — then confirm it keeps running forever without a HardFault.
After this lab you can:
- Name the three kernel exceptions — SVC, PendSV, SysTick — and what each does.
- Explain what FreeRTOS_Init() does and why it must run before vTaskStartScheduler().
- Define RTOS_USED and say what happens if it is missing.
- Build and run a single-task project and confirm the Idle task fills the spare time.
- Recognize the boot order and the failure modes (HardFault, #error, and heap too small).
2. Prerequisites
Hardware: CY8CKIT-059 PSoC 5LP Prototyping Kit; RobotSoC Kit 1× LED + 220 Ω (or the on-board LED); optional 2nd LED for the Idle hook.
Software: PSoC Creator 4.4 with the FreeRTOS V11 BaseProject (kernel + portable/GCC/ARM_CM3, FreeRTOSConfig.h, FreeRTOS_PSoC.c/.h).
Chapters (sync progress): Required — Chapter 0 (Why an RTOS?); Peripheral prerequisite — basic GPIO is covered in the separate (non-FreeRTOS) Lab 02.
3. Reading Materials / References
- Chapter 0 slides — Why an RTOS? (toolchain, boot order, first project, pitfalls).
- FreeRTOS API: xTaskCreate, vTaskStartScheduler.
- Cortex-M3 reference: SVC, PendSV, SysTick exceptions.
4. Background & Theory of Operation
What "integration" means. FreeRTOS is portable C plus a small port layer for each CPU. On the PSoC 5LP that port is portable/GCC/ARM_CM3, and the glue that wires it to Cypress's startup is FreeRTOS_PSoC.c/.h. Dropping the files in is not enough — the kernel needs to own three Cortex-M3 exceptions, and the build must know the RTOS is in use.
The three kernel exceptions.
- SVC (supervisor call) — used once to launch the very first task when the scheduler starts.
- PendSV — the context switch. It runs at the lowest interrupt priority, so it switches tasks only after all real ISRs have completed. Every task-to-task switch goes through here.
- SysTick — the periodic tick (1 kHz here = 1 ms). It is the kernel's time base: it drives vTaskDelay, timeouts, and the decision to switch tasks.
FreeRTOS_Init() and the vector table. On the PSoC 5LP the interrupt vectors live in RAM (CyRamVectors[]). FreeRTOS_Init() writes the three handlers above into that table. This is why it must run before vTaskStartScheduler(): if you create and start tasks while the handlers are not yet installed, the first context switch jumps to the wrong place and the chip takes a HardFault.
RTOS_USED. The port guards itself with #ifdef RTOS_USED. You define it in Build Settings → ARM GCC → Compiler → Preprocessor Definitions. If it is missing, the build deliberately stops at an #error so you cannot ship a half-integrated kernel.
The Idle task. vTaskStartScheduler() automatically creates one Idle task at priority 0. Whenever no other task is Ready, the Idle task runs — so the CPU always has something to do, and the kernel has a place to free deleted tasks. If the heap cannot fit the Idle (and Timer) task, the scheduler cannot start, and control falls through past vTaskStartScheduler().
5. Kernel Boot & Vector Table
Left — the boot order in main(): enable interrupts, FreeRTOS_Init() (install handlers), start peripherals, create the task, start the scheduler. Right — what FreeRTOS_Init() installs: SVC, PendSV, and SysTick into CyRamVectors[]. Get the order wrong, or leave RTOS_USED undefined, and the project will not run.
6. What Happens After the Scheduler Starts
Once vTaskStartScheduler() runs, SysTick fires every millisecond. The LED task runs briefly, then blocks in vTaskDelay; while it is blocked, the Idle task runs; PendSV performs each context switch. This is the machinery you are turning on in this lab — the later labs put real work into these task slots.
7. Schematic Circuit & Pin Configuration
- LED → GPIO + 220 Ω → GND (or the on-board LED).
- (Optional Exp03) LED_IDLE → a second GPIO + 220 Ω → GND.
- Assign the pins in <project>.cydwr → Pins.
8. PSoC Creator Configuration
- One Digital Output Pin (LED). Optional second pin (LED_IDLE) for Exp03.
- Add the FreeRTOS kernel and portable/GCC/ARM_CM3 to the project; keep FreeRTOSConfig.h and FreeRTOS_PSoC.c/.h from the BaseProject.
- Define RTOS_USED in the compiler preprocessor settings.
- FreeRTOSConfig.h essentials: configCPU_CLOCK_HZ matching the real clock, configTICK_RATE_HZ = 1000, heap_4, configTOTAL_HEAP_SIZE large enough for the Idle/Timer task plus your task.
9. Provided Template
You are given Lab02_Template_main.c:
- Given: all includes — note #include "FreeRTOS_PSoC.h" (defines FreeRTOS_Init()), the task handle, and a complete main() with the correct boot order. vLedTask has a vTaskDelay placeholder so the project builds and runs. An optional Idle-hook block is included (commented out) for Exp03.
- You write: the body of vLedTask() (toggle + vTaskDelay), per the TODO(Exp01) comment.
- Do not change the boot sequence in main().
- The handout also lists an integration checklist (kernel files, FreeRTOSConfig.h, FreeRTOS_PSoC.c/.h, RTOS_USED).
int main(void)
{
CyGlobalIntEnable;
FreeRTOS_Init(); /* MUST be before the scheduler */
LED_Start();
xTaskCreate(vLedTask, "Led",
configMINIMAL_STACK_SIZE + 32u, NULL,
tskIDLE_PRIORITY + 1u, &hLed);
vTaskStartScheduler(); /* never returns */
for (;;) { }
}
10. Lab Experiments
Exp01 — Basic: make the kernel run. Complete the integration checklist, define RTOS_USED, write vLedTask(), build, and program. Expected: the LED blinks steadily at 1 Hz under the scheduler, and the program never returns from vTaskStartScheduler().
Exp02 — Advanced: break it on purpose, then explain. Reproduce the two classic failures, one at a time, observe, then restore: (1) remove RTOS_USED → the build stops at an #error in FreeRTOS_PSoC.h. (2) move xTaskCreate before FreeRTOS_Init() → the scheduler faults at start (HardFault) because the handlers are not installed yet. Expected: you can state the cause of each failure in one sentence.
Exp03 — Challenge: see the Idle task. Set configUSE_IDLE_HOOK = 1, enable the vApplicationIdleHook() block, and wire LED_IDLE. Lower the blink task's vTaskDelay and watch the idle LED dim as the blink task uses more CPU. Expected: you can argue, from the idle LED, that a blocked task leaves the CPU to Idle. (Optional: add a second task and confirm both run.)
11. Testing & Verification
| # | Pass condition |
|---|---|
| Exp01 | Project builds with RTOS_USED; LED blinks at a steady 1 Hz under the scheduler. |
| Exp02a | Without RTOS_USED, the build stops at the #error (not a random compile error). |
| Exp02b | Creating the task before FreeRTOS_Init() causes a HardFault at scheduler start. |
| Exp03 | The idle LED visibly tracks spare CPU time; you can explain it. |
Submit: your vLedTask() body, a note of what each Exp02 failure looked like, and your Exp03 observation.
12. Q&A & Troubleshooting
- Build stops at an #error → RTOS_USED not defined in the compiler preprocessor settings.
- HardFault at start → task created before FreeRTOS_Init(), or the kernel files/handlers are not integrated.
- Code runs past vTaskStartScheduler() → heap too small for the Idle/Timer task; raise configTOTAL_HEAP_SIZE.
- LED never blinks but no fault → vLedTask uses CyDelay, or the pin/LED_Start() is wrong.
- Tick seems wrong → configCPU_CLOCK_HZ does not match the real CPU clock.
13. Analysis Questions & Lab Report
- What does each of SVC, PendSV, and SysTick do for the kernel?
- Why must FreeRTOS_Init() run before vTaskStartScheduler()? What fails if it does not?
- What is RTOS_USED for, and what happens if it is undefined?
- What is the Idle task, when does it run, and why does the scheduler always need it?
Your report should include your task body, your Exp02 observations, and answers to the four questions.