RCC Peripheral — Tiva C
- Eslam El Hefny
- Tutorials, Tiva c
- April 5, 2025
Overview
The System Control (SYSCTL) block on the TM4C123 manages all clock sources, the PLL, peripheral clock gating, reset control, and power modes. Configuring the clock correctly is the very first thing any firmware does, because every peripheral’s timing depends on knowing the exact system clock frequency.
Beginner Level — What & Why
What is the RCC / System Clock?
Every digital circuit needs a heartbeat — a regular tick that drives all operations. The RCC (Reset and Clock Control, called SYSCTL in TivaWare) configures that heartbeat. You choose the clock source, multiply it with the PLL to reach higher speeds, and then divide the result to get the exact frequency your firmware needs.
Real-World Analogy
Think of the clock system like a car’s gearbox. The engine (crystal oscillator, 16 MHz) runs at a fixed speed. The PLL is like a turbocharger that multiplies that speed to 400 MHz internally. The SYSDIV divider is like the gearbox ratio that reduces it back down to a usable road speed — 80 MHz.
What Problem Does It Solve?
- Defines the execution speed of all CPU instructions
- Gates (enables/disables) individual peripheral clocks to save power
- Provides a stable, accurate frequency for baud-rate generation, PWM periods, and timer intervals
Key Terms
| Term | Meaning |
|---|---|
| MOSC | Main Oscillator — external 16 MHz crystal on LaunchPad |
| PIOSC | Precision Internal OSC — 16 MHz ±3%, no crystal needed |
| PLL | Phase-Locked Loop — multiplies clock to 400 MHz |
| SYSDIV | System Divider — divides PLL output to final clock |
| RCGC | Running Clock Gate Control — enables peripheral clocks |
| PRGPIO | Peripheral Ready register — confirms clock is stable |
Intermediate Level — How It Works
Clock Tree
16 MHz Crystal (MOSC)
|
PLL × 25 = 400 MHz (internal VCO)
|
÷ 2 (fixed predivide) = 200 MHz
|
SYSDIV (1–16) → 200 / SYSDIV = system clock
Example: SYSDIV = 2.5 → 200 / 2.5 = 80 MHz
Key Registers
| Register | Address | Description |
|---|---|---|
| RCC | 0x400FE060 |
Run-Mode Clock Config (use when ≤ 16 MHz) |
| RCC2 | 0x400FE070 |
Extended RCC — needed for PLL and SYSDIV > 16 |
| MOSCCTL | 0x400FE07C |
Main Oscillator Control |
| PLLSTAT | 0x400FE168 |
PLL lock status (bit 0 = locked) |
| RCGCGPIO | 0x400FE608 |
GPIO clock gate (bits 0-5 = Port A-F) |
| RCGCUART | 0x400FE618 |
UART clock gate |
| RCGCTIMER | 0x400FE604 |
Timer clock gate |
| RCGCADC | 0x400FE638 |
ADC clock gate |
| PRGPIO | 0x400FEA08 |
GPIO peripheral ready flags |
TivaWare Clock Configuration
/* Set 80 MHz: PLL from 16 MHz crystal, divide by 2.5 */
SysCtlClockSet(SYSCTL_SYSDIV_2_5 | // ÷2.5 → 80 MHz
SYSCTL_USE_PLL | // use PLL (400 MHz)
SYSCTL_OSC_MAIN | // use main oscillator
SYSCTL_XTAL_16MHZ); // 16 MHz crystal
/* Verify the result */
uint32_t ui32SysClock = SysCtlClockGet(); // should return 80000000
/* Enable peripheral clocks */
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
/* Wait until peripherals are ready */
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF));
Common SYSCTL_SYSDIV Macros
| Macro | Divider | Resulting Clock |
|---|---|---|
SYSCTL_SYSDIV_1 |
1 | 200 MHz (too fast, limited by flash wait states) |
SYSCTL_SYSDIV_2_5 |
2.5 | 80 MHz (recommended maximum) |
SYSCTL_SYSDIV_4 |
4 | 50 MHz |
SYSCTL_SYSDIV_5 |
5 | 40 MHz |
SYSCTL_SYSDIV_8 |
8 | 25 MHz |
SYSCTL_SYSDIV_10 |
10 | 20 MHz |
SYSCTL_SYSDIV_16 |
16 | 12.5 MHz |
Advanced Level — Deep Dive
Bare-Metal PLL Configuration
#include "inc/hw_types.h"
#include "inc/hw_sysctl.h"
void Clock_Init80MHz(void)
{
/* Step 1: Enable MOSC (main oscillator) */
/* MOSCCTL register: clear NOXTAL bit to enable 16 MHz crystal */
HWREG(SYSCTL_MOSCCTL) &= ~(SYSCTL_MOSCCTL_NOXTAL);
/* Optionally set crystal verification */
HWREG(SYSCTL_MOSCCTL) |= SYSCTL_MOSCCTL_CVAL;
/* Step 2: Switch to MOSC temporarily while we configure PLL */
/* RCC2: set USERCC2 so RCC2 overrides RCC */
HWREG(SYSCTL_RCC2) |= SYSCTL_RCC2_USERCC2;
/* Bypass PLL (use oscillator directly while PLL locks) */
HWREG(SYSCTL_RCC2) |= SYSCTL_RCC2_BYPASS2;
/* Select MOSC as clock source */
HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_OSCSRC2_M;
HWREG(SYSCTL_RCC2) |= SYSCTL_RCC2_OSCSRC2_MO; // main osc
/* Clear XTAL field and set to 16 MHz in RCC */
HWREG(SYSCTL_RCC) &= ~SYSCTL_RCC_XTAL_M;
HWREG(SYSCTL_RCC) |= SYSCTL_RCC_XTAL_16MHZ;
/* Step 3: Enable PLL by clearing PWRDN bit */
HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_PWRDN2;
/* Step 4: Set divisor for 80 MHz using DIV400 trick
* With DIV400=1, effective divisor = (SYSDIV2 + 1 + SYSDIV2LSB*0.5)
* For 80 MHz: 400/(4+1) = 80 → SYSDIV2 = 4, LSB = 1 */
HWREG(SYSCTL_RCC2) |= SYSCTL_RCC2_DIV400;
/* Clear SYSDIV2 field [28:23] */
HWREG(SYSCTL_RCC2) &= ~(SYSCTL_RCC2_SYSDIV2_M | SYSCTL_RCC2_SYSDIV2LSB);
/* Set SYSDIV2 = 4 (bits [28:23]) and SYSDIV2LSB = 1 (bit 22) */
HWREG(SYSCTL_RCC2) |= (4 << 23) | SYSCTL_RCC2_SYSDIV2LSB;
/* Step 5: Wait for PLL to lock */
while (!(HWREG(SYSCTL_PLLSTAT) & SYSCTL_PLLSTAT_LOCK));
/* Step 6: Switch CPU to use the PLL output */
HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_BYPASS2;
}
Peripheral Clock Gating (Bare Metal)
/* Enable GPIO Port F clock: bit 5 of RCGCGPIO */
HWREG(SYSCTL_RCGCGPIO) |= (1U << 5);
/* Busy-wait until the peripheral is ready */
while (!(HWREG(SYSCTL_PRGPIO) & (1U << 5)));
SysCtlClockSet vs SysCtlClockSetxtal
SysCtlClockSet is the legacy function used on TM4C123. It accepts combined flags:
SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL |
SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
For TM4C129x (different device), use SysCtlClockFreqSet which takes a target frequency directly. Do not mix them.
Power and Sleep Modes
/* Enable peripheral in Sleep mode (keeps clock while CPU sleeps) */
SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0);
/* Enable peripheral in Deep Sleep mode */
SysCtlPeripheralDeepSleepEnable(SYSCTL_PERIPH_UART0);
/* Enter Sleep mode (WFI) — wakes on any interrupt */
SysCtlSleep();
/* Enter Deep Sleep mode — wakes on specific interrupts */
SysCtlDeepSleep();
Gotchas
- Never read from a peripheral before enabling its clock — bus fault will occur.
- PLLSTAT must show LOCK before switching away from bypass — otherwise you get an unstable clock.
SysCtlClockGet()relies on the same flags you passed toSysCtlClockSet()— it does not read hardware. If you use bare-metal setup,SysCtlClockGet()will return wrong values.- Flash wait states are automatically managed by the TivaWare
SysCtlClockSet()call.
Step-by-Step Example
/*
* rcc_clock_demo.c
* Configures 80 MHz clock, reads it back, and blinks at exact 1Hz
* Board : TM4C123GXL EK LaunchPad
* SDK : TivaWare_C_Series-2.2.x
*/
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
int main(void)
{
uint32_t ui32SysClock;
/* Step 1: Configure 80 MHz system clock from 16 MHz crystal + PLL */
SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL |
SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
/* Step 2: Read back actual clock frequency */
ui32SysClock = SysCtlClockGet();
/* ui32SysClock should equal 80,000,000 */
/* Step 3: Enable Port F clock for LED */
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF));
/* Step 4: Configure PF2 (Blue LED) as output */
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
/* Step 5: Blink at exactly 1 Hz using SysCtlDelay
* SysCtlDelay(n) burns 3n CPU cycles.
* Half period = 500 ms = 0.5 * 80,000,000 cycles = 40,000,000 cycles
* SysCtlDelay count = 40,000,000 / 3 = 13,333,333 */
uint32_t ui32HalfPeriod = ui32SysClock / 6; // = 13,333,333
while (1)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2); // ON
SysCtlDelay(ui32HalfPeriod); // 500 ms
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0); // OFF
SysCtlDelay(ui32HalfPeriod); // 500 ms
}
}
Summary
| Key Point | Details |
|---|---|
| Main oscillator | 16 MHz crystal (MOSC) on LaunchPad |
| PLL VCO | 400 MHz internal |
| Recommended clock | 80 MHz (SYSDIV_2_5) |
| SysCtlClockSet | Configures PLL, source, and divider in one call |
| SysCtlClockGet | Returns current system clock frequency |
| Peripheral gating | SysCtlPeripheralEnable / Disable |
| Peripheral ready | SysCtlPeripheralReady polls PRGPIO/PRUART etc. |
| PLLSTAT | Must show LOCK before removing bypass |