Professor Giriraja C. V.'s Exam Pattern • Full Unit I & II + Lab Peripherals (50 Marks)
Based on the official September 2026 examination paper, here is the exact question structure and marking formula:
| Question Type & Marks | Topics Tested | Evaluation Criteria (How to Get 50/50) |
|---|---|---|
| Part 1: Theory & Advantages [5M] (Q1: BTL1) |
Cortex-M Processor Family Advantages, Architecture overview. | List 5 crisp points from 1 23ECE313_ES_Ch4 Text 1.pdf (Low power/WIC, Thumb-2, NVIC 12-cycle latency, OS support with MSP/PSP, CoreSight debug). |
| Part 2: Assembly & Stack Trace [5M] (Q2: BTL2) |
Instruction execution (LDR, MOVS flags, IT blocks, STMDB/LDMIA, Full Descending Stack, ICI bits). | Calculate exact register hex values, draw 4-byte memory map addresses, explain EPSR ICI bits preventing multi-cycle restart. |
| Part 3: Hardware Interfacing [5M] (Q3: BTL2) |
JTAG vs SWD, CoreSight host connection, SWJ-DP, DAP, AHB-AP. | Draw host-to-core DAP interconnect diagram from 5 23ECE313_ES_Ch15_Txt 1a.pdf. Explain non-intrusive memory access while CPU runs. |
| Part 4: Timing Waveforms [15M] (Q4, Q5, Q6: 5M each, BTL2) |
1. SysTick task switching timeline. 2. Interrupt pending & activation state machine. 3. Context switch IRQ blocking & PendSV solution. |
"With the help of a neat timing diagram" is mandatory. Must draw the exact waveforms from Ch12 and Ch_Txt1 slides with timeline states. |
| Part 5: Low Power / Core Feature [5M] (Q7: BTL2) |
Wake-Up Interrupt Controller (WIC) in Deep Sleep, Sleep-on-Exit. | Draw WIC always-on power domain block diagram and list the 7-step sequence of events restoring CPU clocks. |
| Part 6: Applied Coding & Circuit [15M] (Q8: 5M + Q9: 10M, BTL3) |
• Q8: PWM Duty Cycle control (MOSFET, 3V from 5V DC). • Q9: Analog sensor (PA0), Relay Fan (PA5), UART PuTTY display. |
Must draw both Circuit Diagram AND write complete C code with exact registers (MODER, AFR, ARR, CCR1, ADC1->SQR3, CR2, BRR). |
Click on any question below to expand the complete 50/50 model answer, exact circuit schematics, and slide diagram citations:
1 23ECE313_ES_Ch4 Text 1.pdf (Slide 16)LDR R0, =0x40000000
LDR SP, =0x800000F0
LDR R1, =0x12349876
LDR R2, =0xABCDEF12
MOVS R3, 0x00
IT EQ
STMDB SP!, {R0-R2}
STOP B STOP
LDR R0, =0x40000000 -> R0 = 0x40000000.LDR SP, =0x800000F0 -> SP = 0x800000F0.LDR R1, =0x12349876 -> R1 = 0x12349876.LDR R2, =0xABCDEF12 -> R2 = 0xABCDEF12.MOVS R3, 0x00 -> Moves 0 into R3. Because the instruction has the 'S' suffix, it updates the condition flags in APSR. Since result is 0, the Z (Zero) flag is set to 1.IT EQ -> If-Then block with condition EQ (Equal / Z == 1). Since Z == 1, the condition evaluates to TRUE. The following instruction executes!STMDB SP!, {R0-R2} -> Store Multiple Decrement Before with write-back (!).
0x0C).| Register | Final Value | Explanation |
|---|---|---|
| R0 | 0x40000000 | Unchanged by STMDB |
| R1 | 0x12349876 | Unchanged by STMDB |
| R2 | 0xABCDEF12 | Unchanged by STMDB |
| SP | 0x800000E4 | Decremented by 12 bytes (3 words) |
| Address | Stored 32-bit Value | Stored Register |
|---|---|---|
0x800000F0 | Unmodified Data | Original SP Base |
0x800000EC | 0xABCDEF12 | R2 (Highest register at highest address) |
0x800000E8 | 0x12349876 | R1 |
0x800000E4 | 0x40000000 | R0 (Lowest register at lowest address) ← New SP |
0x800000E0 | Unmodified Data | Below current SP |
(Directly from Slide Deck 1: Ch4 Text 1, Slide 42)
STMDB is a multi-cycle store instruction. If an interrupt occurs halfway through executing STMDB (e.g. after pushing R2 and R1, but before R0), the processor saves the transfer progress into the ICI bits inside the Execution Program Status Register (EPSR). Upon return from the interrupt via EXC_RETURN, the processor inspects the saved ICI bits and resumes execution directly from the remaining transfer (storing R0) instead of restarting the entire instruction from the beginning. This reduces interrupt latency and prevents duplicate bus transactions.
SWCLK (clock) and SWDIO (bidirectional data), with an optional SWO (Serial Wire Output) pin for trace data.
PSP).COUNTFLAG, and asserts Exception 15 (SysTick).MSP).BX LR with EXC_RETURN = 0xFFFFFFFD triggers hardware unstacking of R0-R3, R12, LR, PC, xPSR from Task B's stack. The CPU resumes execution of Task B in Thread mode.
NVIC_ISPR). The interrupt is now Pending.NVIC_ISER.BASEPRI / PRIMASK registers.
PENDSVSET bit and exits immediately, allowing the external IRQ to run with zero delay. PendSV executes only after all pending IRQs complete!
SLEEPDEEP in SCR and executes WFI.#include "stm32f4xx.h"
int main(void) {
// 1. Enable AHB1 clock for GPIOA and APB1 clock for TIM2
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// 2. Configure PA5 as Alternate Function Mode ('10')
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (2U << (5 * 2));
// 3. Connect PA5 to AF1 (TIM2_CH1) via AFR[0] (Bits [23:20] = 0001)
GPIOA->AFR[0] &= ~(0xFU << (5 * 4));
GPIOA->AFR[0] |= (1U << (5 * 4)); // 0x1 selects AF1
// 4. Set Timebase: 1 kHz PWM frequency at 16 MHz clock
TIM2->PSC = 0; // Clock = 16 MHz
TIM2->ARR = 15999; // Period = 16 MHz / 16000 = 1 ms (1 kHz)
// 5. Set 60% Duty Cycle for 3V average output from 5V supply: CCR1 = 9600
TIM2->CCR1 = 9600;
// 6. Configure Channel 1 for PWM Mode 1 (OC1M = 110) with Preload Enable
TIM2->CCMR1 |= (6U << 4) | TIM_CCMR1_OC1PE;
// 7. Enable Output on Channel 1
TIM2->CCER |= TIM_CCER_CC1E;
// 8. Enable Auto-Reload Preload and start counter
TIM2->CR1 |= TIM_CR1_ARPE | TIM_CR1_CEN;
while (1) {
// Continuous 60% PWM waveform generated autonomously by hardware
}
}
#include "stm32f4xx.h"
#include
void USART2_Init(void);
void USART2_SendChar(char c);
void USART2_SendString(char *str);
void ADC1_PA0_Init(void);
uint32_t ADC1_Read(void);
void delay_ms(uint32_t ms) {
uint32_t count = (SystemCoreClock / 10000) * ms;
for (volatile uint32_t i = 0; i < count; i++) { __NOP(); }
}
int main(void) {
char buffer[80];
uint32_t adc_val = 0;
float voltage = 0.0f;
// 1. Initialize Peripherals
USART2_Init();
ADC1_PA0_Init();
// 2. Configure PA5 as General Output for Relay Control
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (1U << (5 * 2)); // Output mode '01'
USART2_SendString("--- Sensor & Relay Monitoring System Online ---
");
while (1) {
// Read 12-bit ADC value
adc_val = ADC1_Read();
// Convert code to voltage: V = (ADC / 4095) * 3.3
voltage = ((float)adc_val / 4095.0f) * 3.3f;
// Relay Control Logic: Threshold 2.2V corresponds to code 2730
if (adc_val >= 2730) {
GPIOA->ODR |= (1U << 5); // Relay ON (Fan runs)
} else {
GPIOA->ODR &= ~(1U << 5); // Relay OFF (Fan stopped)
}
// Transmit readings over UART to PuTTY Serial Monitor
snprintf(buffer, sizeof(buffer), "ADC: %lu | Volt: %.2f V | Fan: %s
",
adc_val, voltage, (adc_val >= 2730) ? "ON" : "OFF");
USART2_SendString(buffer);
delay_ms(500); // 500 ms sampling period
}
}
// USART2 Configuration: PA2 as TX (AF7), 9600 Baud at 16 MHz
void USART2_Init(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
GPIOA->MODER &= ~(3U << (2 * 2));
GPIOA->MODER |= (2U << (2 * 2)); // Alternate Function '10'
GPIOA->AFR[0] &= ~(0xFU << (2 * 4));
GPIOA->AFR[0] |= (7U << (2 * 4)); // AF7 for USART2
USART2->BRR = 0x0683; // 9600 Baud at 16 MHz
USART2->CR1 = USART_CR1_TE | USART_CR1_UE; // Transmitter Enable & Module Enable
}
void USART2_SendChar(char c) {
while (!(USART2->SR & USART_SR_TXE)); // Wait for TX data register empty
USART2->DR = c;
}
void USART2_SendString(char *str) {
while (*str) { USART2_SendChar(*str++); }
}
// ADC1 Configuration on PA0 (Channel 0)
void ADC1_PA0_Init(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
GPIOA->MODER |= (3U << (0 * 2)); // PA0 Analog Mode '11'
ADC1->SQR1 = 0; // 1 conversion
ADC1->SQR3 = 0; // Channel 0 first
// Sample time: 84 cycles for Channel 0 (SMPR2 bits [2:0] = 100)
ADC1->SMPR2 |= (4U << 0);
ADC1->CR2 |= ADC_CR2_ADON; // Power ON ADC
}
uint32_t ADC1_Read(void) {
ADC1->CR2 |= ADC_CR2_SWSTART; // Trigger conversion
while (!(ADC1->SR & ADC_SR_EOC)); // Wait for End Of Conversion
return ADC1->DR; // Read 12-bit value (clears EOC)
}
Mirroring the exact difficulty, BTL taxonomy, and question pattern of Professor Giriraja C. V. Click to reveal complete solutions and slide citations:
2 23ECE313_ES_Ch_Txt1.pdf (Slide 11)LDR R0, =0x20000000
LDR SP, =0x20000200
LDR R1, =0x11223344
LDR R2, =0x55667788
SUBS R3, R1, R2
IT MI
STMDB SP!, {R0, R2}
STOP B STOP
LDR R0, =0x20000000 -> R0 = 0x20000000.LDR SP, =0x20000200 -> SP = 0x20000200.LDR R1, =0x11223344 -> R1 = 0x11223344.LDR R2, =0x55667788 -> R2 = 0x55667788.SUBS R3, R1, R2 -> Subtracts R2 from R1. Since R1 < R2, the result is negative. The N (Negative) flag in APSR is set to 1.IT MI -> If-Then block with condition MI (Minus / Negative: N == 1). Since N = 1, condition evaluates to TRUE.STMDB SP!, {R0, R2} -> Pushes 2 registers (8 bytes = 0x08).
0x200001FC, R0 is placed at 0x200001F8.| Register / Address | Value |
|---|---|
| R0 | 0x20000000 |
| R1 | 0x11223344 |
| R2 | 0x55667788 |
| SP | 0x200001F8 |
0x200001FC | 0x55667788 (R2) |
0x200001F8 | 0x20000000 (R0) |
| Feature | Halt Mode | Debug Monitor Mode |
|---|---|---|
| CPU State | Completely stopped (halted) | Executes Exception 12 handler |
| SysTick Timer | Stopped | Continues running |
| Interrupts | Masked/pended | Higher-priority interrupts can still preempt |
| Application | Bare-metal firmware debugging | Safety-critical motor control / RTOS |
0x00000000 and loads it directly into the Main Stack Pointer (MSP). This ensures a valid stack exists before executing any code!0x00000004 and loads it directly into the Program Counter (PC). This word contains the address of the Reset_Handler function. Bit 0 of this address must be 1 to specify Thumb state.Reset_Handler in Privileged Thread Mode.
PRIGROUP field in the Application Interrupt and Reset Control Register (AIRCR) splits the priority bits into two fields:
SHCSR.
Configured by setting SLEEPONEXIT in System Control Register (SCR). After ISR completes, the processor skips Thread Mode and returns directly to sleep, eliminating stack restore overhead in interrupt-only systems.
SEV instruction pulses TXEV pin to wake other cores. WFE (Wait For Event) sleeps until RXEV is asserted.
#include "stm32f4xx.h"
void delay_seconds(uint32_t seconds) {
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM5 clock
TIM5->PSC = 15999; // 1 ms tick (16 MHz / 16000)
TIM5->ARR = (seconds * 1000) - 1; // Reload value
TIM5->CNT = 0; // Reset count
TIM5->CR1 |= TIM_CR1_CEN; // Start timer
while (!(TIM5->SR & TIM_SR_UIF)); // Wait for overflow UIF flag
TIM5->SR &= ~TIM_SR_UIF; // Clear flag
TIM5->CR1 &= ~TIM_CR1_CEN; // Stop timer
}
int main(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (1U << (5 * 2)); // Output mode '01'
while (1) {
GPIOA->ODR ^= (1U << 5); // Toggle LED
delay_seconds(2); // 2-second delay
}
}
#include "stm32f4xx.h"
void EXTI13_Init(void) {
// 1. Enable Clocks for GPIOA (LED), GPIOC (Button), and SYSCFG
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOCEN;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
// 2. PA5 as Output (LED), PC13 as Input (Button)
GPIOA->MODER |= (1U << (5 * 2));
GPIOC->MODER &= ~(3U << (13 * 2));
// 3. Connect EXTI13 to Port C in SYSCFG_EXTICR4 (bits [7:4] = 0010)
SYSCFG->EXTICR[3] &= ~(0xFU << 4);
SYSCFG->EXTICR[3] |= (0x2U << 4); // Port C
// 4. Configure Falling-edge Trigger in FTSR (Button press pulls to 0)
EXTI->FTSR |= (1U << 13);
EXTI->RTSR &= ~(1U << 13);
// 5. Unmask interrupt line 13 in IMR
EXTI->IMR |= (1U << 13);
// 6. Enable in NVIC
NVIC_SetPriority(EXTI15_10_IRQn, 2);
NVIC_EnableIRQ(EXTI15_10_IRQn);
}
void EXTI15_10_IRQHandler(void) {
if (EXTI->PR & (1U << 13)) {
GPIOA->ODR ^= (1U << 5); // Toggle LED
EXTI->PR = (1U << 13); // Clear pending bit (WRITE 1 TO CLEAR!)
}
}
int main(void) {
EXTI13_Init();
while (1) {
__WFI(); // Sleep until button press interrupt
}
}
Comprehensive coverage of Unit 1, Unit 2, and Peripheral Interfacing. Click any question to reveal complete step-by-step solutions, slide citations, register breakdowns, and schematics:
1 23ECE313_ES_Ch4 Text 1.pdf (Slides 19, 23, 27)
EXC_RETURN.0xE0000000 - 0xE00FFFFF), and restricts MPU regions marked privileged-only. Prevents user bugs from crashing the operating system. Cannot directly switch back to privileged mode; must execute an SVC (Supervisory Call).
0 = Privileged thread execution.1 = Unprivileged thread execution.0 = Use Main Stack Pointer (MSP) in Thread mode.1 = Use Process Stack Pointer (PSP) in Thread mode.2 23ECE313_ES_Ch_Txt1.pdf (Slide 12)
Cortex-M3 provides two 1 MB bit-band regions mapped to 32 MB alias regions:
0x20000000 - 0x200FFFFF ──► Alias: 0x22000000 - 0x23FFFFFF0x40000000 - 0x400FFFFF ──► Alias: 0x42000000 - 0x43FFFFFFIn the alias region, every single bit in the bit-band region is mapped to an entire 32-bit (4-byte) word. Therefore:
8 × 4 = 32 bytes in the alias region.n × 4 bytes.Bit_Word_Addr = Alias_Base + (Byte_Offset × 32) + (Bit_Number × 4)Byte_Offset = Target_Address - Bit_Band_Base
0x40020014 (Peripheral Region)50x400000000x420000000x40020014 - 0x40000000 = 0x00020014 (in decimal: 131,092 bytes)0x00020014 × 0x20 = 0x00400280 (decimal: 131,092 × 32 = 4,194,944 = 0x400280)5 × 4 = 20 = 0x000000140x42000000 + 0x00400280 + 0x00000014 = 0x424002940x42400294. Writing 1 to this address sets PA5; writing 0 clears PA5.
ODR |= (1<<5)) corrupt adjacent bits. Bit-banding prevents this completely!LDR, ORR, STR) with a single atomic STR instruction.3 23ECE313_ES_Ch12_Txt1.pdf (Slides 10–14, 23)| Feature | Precise Bus Fault | Imprecise Bus Fault |
|---|---|---|
| Cause | Synchronous bus error (Instruction fetch, data read, or non-buffered write). | Asynchronous bus error caused by the Write Buffer during buffered writes. |
| Stacked PC Value | Exact: Stacked PC points directly to the instruction that triggered the bus error. | Inaccurate: The processor moved on while the write buffer was writing. Stacked PC points to an arbitrary later instruction! |
| Fault Address Register (BFAR) | Valid: BFSR->BFARVALID = 1. BFAR register contains the exact faulting memory address. |
Invalid: BFSR->BFARVALID = 0. The memory address that triggered the fault is lost. |
| Status Flag in BFSR | PRECISERR (Bit 1) = 1 |
IMPRECISERR (Bit 2) = 1 |
To maximize execution throughput, Cortex-M incorporates an internal Write Buffer on the system bus. When a program writes to memory, the write data is queued in the buffer, and the CPU immediately proceeds to execute subsequent instructions without waiting for bus acknowledgement. If the bus later rejects the transaction (e.g. invalid peripheral address, slave timeout), the error arrives cycles later. By then, the CPU is already executing unrelated code!
Because imprecise bus faults make debugging nearly impossible (unknown PC and unknown address), ARM provides a hardware override:
// Set DISDEFWBUF bit (Bit 1) in ACTLR (Address: 0xE000E008)
SCB->ACTLR |= SCB_ACTLR_DISDEFWBUF_Msk; // Disables Write BufferEffect: Disabling the write buffer forces all write operations to complete synchronously before the next instruction executes. When the faulty write occurs, it immediately triggers a Precise Bus Fault, allowing the developer to inspect the exact stacked PC and read the faulty address from BFAR!
1 23ECE313_ES_Ch4 Text 1.pdf (Slide 17)
Clock Cycle: | T1 | T2 | T3 | T4 | T5 |
Instr 1 (ADD): | Fe | De | Ex | | |
Instr 2 (SUB): | | Fe | De | Ex | |
Instr 3 (MOV): | | | Fe | De | Ex |
When a branch instruction (e.g., B label, BL, BX) reaches the Execute stage and the branch is taken, the instructions already fetched and decoded in stages 1 and 2 are invalid and must be flushed (discarded).
Clock Cycle: | T1 | T2 | T3 | T4 | T5 |
Instr 1 (B target):| Fe | De | Ex | | | <-- Branch target computed in Ex
Instr 2 (Next): | | Fe | De | FLUSH | | <-- Discarded!
Instr 3 (Next+1): | | | Fe | FLUSH | | <-- Discarded!
Target Instr 1: | | | | Fe | De | Ex <-- 2 cycle branch penalty!
3 23ECE313_ES_Ch12_Txt1.pdf (Slides 28–34)
The SVC (Supervisory Call) instruction generates a synchronous software exception used by unprivileged user application tasks to request privileged operating system services (file system, hardware drivers, memory allocation).
SVC #number (e.g. SVC #3).[SP+0] = R0, [SP+4] = R1, [SP+8] = R2, [SP+12] = R3, [SP+16] = R12, [SP+20] = LR, [SP+24] = Return PC, [SP+28] = xPSR.EXC_RETURN into LR.SVC_Handler using the vector fetched from vector table entry 11 (offset 0x0000002C).__asm void SVC_Handler(void) {
TST LR, #4 // Test Bit 2 of EXC_RETURN (0 = MSP, 1 = PSP)
ITE EQ
MRSEQ R0, MSP // Stack pointer was MSP, pass in R0
MRSNE R0, PSP // Stack pointer was PSP, pass in R0
B SVC_Handler_C // Branch to C handler with stack frame pointer in R0
}
void SVC_Handler_C(uint32_t *svc_args) {
// svc_args[6] is the stacked Return PC!
// Since Thumb-2 SVC is a 2-byte opcode [0xDF, SVC_#],
// subtract 2 bytes from Return PC to point directly to the SVC instruction!
uint8_t svc_number = ((uint8_t *)svc_args[6])[-2];
switch (svc_number) {
case 0: // Read Service
svc_args[0] = OS_Read(svc_args[1], svc_args[2]); // Return in R0
break;
case 1: // Write Service
svc_args[0] = OS_Write(svc_args[1], svc_args[2]);
break;
default:
break;
}
}
svc_args[0] (stacked R0), which hardware automatically restores into register R0 upon unstacking!
1 23ECE313_ES_Ch4 Text 1.pdf (Slides 31–33)| Register | Width | Effective Priority Level | Exceptions Blocked | Assembly Instructions |
|---|---|---|---|---|
| PRIMASK | 1 bit | 0 (Highest configurable priority) | Blocks all interrupts with configurable priority. NMI and HardFault still execute! | CPSID i (Disable IRQs)CPSIE i (Enable IRQs) |
| FAULTMASK | 1 bit | -1 (HardFault priority level) | Blocks all interrupts and all configurable faults (MemManage, BusFault, UsageFault) plus HardFault. Only NMI can execute! Cleared automatically on exception exit. | CPSID f (Disable All)CPSIE f (Enable All) |
| BASEPRI | Up to 8 bits | Configurable threshold N | Blocks only interrupts with priority level ≥ N (numerically equal or lower priority). Leaves higher priority interrupts (< N) active. When set to 0, masking is disabled. | MSR BASEPRI, R0MRS R0, BASEPRI |
In hard real-time systems, critical tasks (e.g. emergency motor stop, radar timing) must never experience interrupt latency. By setting BASEPRI to a mid-level threshold (e.g. priority 3), the OS scheduler can protect its internal queues without blocking ultra-high-priority hard real-time interrupts (priorities 0, 1, and 2)!
2 23ECE313_ES_Ch_Txt1.pdf (Slides 25–28)Occurs when an interrupt arrives while the processor is already servicing another interrupt, or during the completion phase of an ISR.
Traditional: [ ISR 1 ] ──► [ Unstack (16c) ] ──► [ Restack (16c) ] ──► [ ISR 2 ] (32+ cycles)
Cortex-M3: [ ISR 1 ] ──► [ Tail-Chain (6 cycles) ] ───────────────► [ ISR 2 ] (6 cycles!)
Occurs when a higher-priority interrupt arrives while the processor is in the middle of stacking registers for an earlier, lower-priority interrupt.
STM32F446RE_Timers_PWM_ADC_Mazidi.pdf (Slides 4–9)f_PWM = 10 kHz16 MHzPSC = 0 (Counter frequency = 16 MHz / 1 = 16 MHz)ARR = (16,000,000 / 10,000) - 1 = 1600 - 1 = 1599CCR1 = 0.75 × (ARR + 1) = 0.75 × 1600 = 1200#include "stm32f4xx.h"
void PWM_TIM2_PA5_Init(void) {
// 1. Enable Clock for GPIOA (AHB1) and TIM2 (APB1)
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// 2. Configure PA5 as Alternate Function mode (MODER bits [11:10] = '10')
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (2U << (5 * 2));
// 3. Set Alternate Function to AF1 (TIM2_CH1) in AFR[0] (Bits [23:20] = 0x01)
GPIOA->AFR[0] &= ~(0xFU << (5 * 4));
GPIOA->AFR[0] |= (1U << (5 * 4));
// 4. Configure TIM2 Time Base: 10 kHz
TIM2->PSC = 0; // Prescaler = 0 (16 MHz timer clock)
TIM2->ARR = 1599; // Auto-reload value (Period = 1600 cycles = 100 us)
// 5. Configure 75% Duty Cycle
TIM2->CCR1 = 1200; // Compare match value (75% of 1600)
// 6. Set PWM Mode 1 (OC1M = '110') and enable Preload (OC1PE = 1) in CCMR1
TIM2->CCMR1 &= ~(7U << 4);
TIM2->CCMR1 |= (6U << 4); // PWM Mode 1: High until counter > CCR1
TIM2->CCMR1 |= TIM_CCMR1_OC1PE;
// 7. Enable Channel 1 Output in CCER (CC1E = 1, Active High polarity)
TIM2->CCER |= TIM_CCER_CC1E;
// 8. Enable Main Counter in CR1 (CEN = 1)
TIM2->CR1 |= TIM_CR1_CEN;
}
int main(void) {
PWM_TIM2_PA5_Init();
while (1) {
// Hardware timer generates 10 kHz 75% PWM automatically!
}
}
STM32F446RE_Timers_PWM_ADC_Mazidi.pdf (Slides 11–17)3.3V / 4095 ≈ 0.8058 mV/count.V_th = 2.0V.Threshold = (2.0V / 3.3V) × 4095 = 2481.8 ≈ 2482.16 MHz / (16 × 115200) = 8.6805.
0x08, Fraction = 0.6805 × 16 ≈ 11 = 0x0B.
USART2->BRR = 0x008B.#include "stm32f4xx.h"
void System_Init(void) {
// 1. Enable Peripheral Clocks
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // GPIOA clock
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // ADC1 clock (APB2)
RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // USART2 clock (APB1)
// 2. Configure PA0 as Analog Mode for ADC1_IN0 (MODER[1:0] = '11')
GPIOA->MODER |= (3U << (0 * 2));
// 3. Configure PA5 as General Purpose Output for Fan Control (MODER[11:10] = '01')
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (1U << (5 * 2));
// 4. Configure PA2 as Alternate Function AF7 for USART2_TX (MODER[5:4] = '10')
GPIOA->MODER &= ~(3U << (2 * 2));
GPIOA->MODER |= (2U << (2 * 2));
GPIOA->AFR[0] &= ~(0xFU << (2 * 4));
GPIOA->AFR[0] |= (7U << (2 * 4)); // AF7 = USART2
// 5. Configure ADC1
ADC1->CR1 = 0; // 12-bit resolution
ADC1->SMPR2 |= (4U << (0 * 3)); // 84 cycles sample time for Channel 0
ADC1->SQR1 = 0; // 1 conversion in regular sequence
ADC1->SQR3 = 0; // 1st conversion is Channel 0 (PA0)
ADC1->CR2 |= ADC_CR2_ADON; // Enable ADC1 power
// 6. Configure USART2 (115200 Baud @ 16 MHz, 8-N-1)
USART2->BRR = 0x008B; // 115200 baud
USART2->CR1 |= USART_CR1_TE | USART_CR1_UE; // Transmitter enable & USART enable
}
uint16_t ADC1_Read(void) {
ADC1->CR2 |= ADC_CR2_SWSTART; // Start software conversion
while (!(ADC1->SR & ADC_SR_EOC)); // Wait until End Of Conversion flag is set
return ADC1->DR; // Read 12-bit data (clears EOC flag)
}
void UART2_SendString(char *str) {
while (*str) {
while (!(USART2->SR & USART_SR_TXE)); // Wait for Transmit Data Register Empty
USART2->DR = (*str++ & 0xFF); // Transmit byte
}
}
int main(void) {
System_Init();
while (1) {
uint16_t adc_val = ADC1_Read();
// Check if analog voltage > 2.0V (ADC Count > 2482)
if (adc_val > 2482) {
GPIOA->ODR |= (1U << 5); // Turn ON Fan
UART2_SendString("ALERT: HIGH TEMP! FAN ACTIVATED
");
} else {
GPIOA->ODR &= ~(1U << 5); // Turn OFF Fan
}
// Small software delay between readings
for (volatile int i = 0; i < 500000; i++);
}
}
Final master preparation set covering deep architectural traps, vector alignments, MPU sub-regions, and multi-peripheral integration:
2 23ECE313_ES_Ch_Txt1.pdf (Slides 14–18)
The MPU divides the 4 GB memory map into up to 8 programmable regions (numbered 0 to 7). A background region with default privileged access permissions can be enabled via PRIVDEFENA.
MPU->CTRL: Enables MPU (ENABLE bit), enables default memory map in privileged mode (PRIVDEFENA), and enables MPU during HardFault and NMI (HFNMIENA).MPU->RNR: Region Number Register (0 to 7) to select active region.MPU->RBAR: Region Base Address Register (must be aligned to region size).MPU->RASR: Region Attribute and Size Register:
SIZE bits [5:1]: Region size = 2^(SIZE+1) bytes (minimum 32 bytes).AP bits [26:24]: Access Permissions (Privileged RW / User None, Privileged RO / User RO, etc.).XN bit [28]: Execute Never (prevents code execution from data/stack).TEX, C, B bits: Cache and write buffer memory attributes.SRD bits [15:8]: Sub-Region Disable field.SRD field contains 8 bits (one bit for each sub-region).1 to bit k disables sub-region k, allowing that slice to fall through to lower priority region rules or the background region.When an instruction fetch or data access violates MPU permissions (or attempts to execute in an XN region), the processor aborts the transaction and triggers a MemManage Fault. The fault address is stored in MMFAR, and status flags are set in MFSR.
1 23ECE313_ES_Ch4 Text 1.pdf (Slides 25, 48)
ARM Cortex-M processors exclusively execute the Thumb-2 instruction set. They do NOT possess a 32-bit ARM instruction decoder state. Therefore, the T-bit (Bit 24) in the EPSR MUST ALWAYS BE 1 during instruction execution.
BX / BLX):In the ARM architecture, when executing an indirect branch via a register (e.g. BX R0, BLX R3, or loading PC via LDR PC, [R1]), Bit 0 of the target address is used by hardware to update the T-bit:
1 ──► Sets EPSR T-bit to 1 (Thumb State). Target instruction executed at Address & ~1.0 ──► Attempts to clear EPSR T-bit to 0 (ARM State).// Example: Function resides at Flash address 0x08001000
void (*my_func)(void) = (void (*)(void))0x08001000; // EVEN ADDRESS (Bit 0 = 0)
my_func(); // Executes BX R0 with R0 = 0x08001000
Hardware attempts to switch the CPU into ARM state by clearing the T-bit to 0. Since Cortex-M does not support ARM state, the core detects an illegal state transition and immediately triggers a UsageFault with INVSTATE (Invalid State) bit set in UFSR!
0x08001001 for a function physically located at 0x08001000).
2 23ECE313_ES_Ch_Txt1.pdf (Slides 20, 34–37)
Every Cortex-M vector table begins with 16 system exception vectors (Vectors 0 to 15), followed by N external interrupt vectors (IRQ0 to IRQ N-1). Each vector entry is a 32-bit (4-byte) pointer.
Total Vector Table Size = (16 System Exceptions + N External IRQs) × 4 bytes
The base address programmed into VTOR (Address: 0xE000ED08) must be aligned to a power-of-2 boundary that is greater than or equal to the total table size, with an absolute minimum hardware alignment of 128 bytes (32 words).
16 + 32 = 48 words.48 × 4 = 192 bytes.0x00 (Bits [7:0] = 0).16 + 75 = 91 words.91 × 4 = 364 bytes.0x200 (Bits [8:0] = 0).4 23ECE313_ES_Ch14_Txt 1a.pdf (Slides 5–12); 5 23ECE313_ES_Ch15_Txt 1a.pdf (Slides 4–10)
| Trace Unit | Full Name | Primary Function & Exam Keywords |
|---|---|---|
| DWT | Data Watchpoint and Trace | Contains 4 hardware watchpoint comparators. Monitors data memory accesses (triggering trace on read/write to a specific variable). Measures cycle counts (CYCCNT) for profiling. |
| ITM | Instrumentation Trace Macrocell | Enables high-speed software printf debugging without UART hardware. Application writes directly to ITM stimulus registers (e.g. ITM->PORT[0]), which outputs data over the 1-pin SWO (Serial Wire Output) line. |
| ETM | Embedded Trace Macrocell | Reconstructs the exact instruction execution history in real time. Captures every branch taken/not-taken and exception entry to provide full instruction trace back in time. |
| TPIU | Trace Port Interface Unit | Acts as a hardware multiplexer and serializer. Formats and combines data streams from ITM and ETM, outputting them to external debug hardware (e.g. Keil ULINKpro, Segger J-Trace) via SWO or multi-pin Trace Port. |
1 23ECE313_ES_Ch4 Text 1.pdf (Slides 14–15)
0x00000000 - 0x1FFFFFFF), primarily Flash/ROM.0x00000000 - 0x1FFFFFFF).0x20000000), Peripherals (0x40000000), and External Memories (0x60000000). Can also fetch instructions from SRAM.Cortex-M uses a Harvard architecture enabled by a multi-layer AHB matrix. Because instruction fetches (on I-Code) and data accesses (on System Bus or D-Code) travel over independent physical buses simultaneously, the processor can fetch an instruction and perform a data load/store in the exact same clock cycle without bus contention!
Connects the high-speed AHB system bus to lower-power peripherals (USART, SPI, I2C, Timers, ADC). The APB bridge translates AHB burst transfers into simplified APB read/write cycles and operates at lower clock frequencies to save power.
1 23ECE313_ES_Ch4 Text 1.pdf (Slide 75); 3 23ECE313_ES_Ch12_Txt1.pdf (Slide 44)NRST), independent watchdog timer, or software command (SYSRESETREQ). Resets processor core and all peripherals, but preserves debug logic so active debug sessions are not dropped.VECTRESET.The Application Interrupt and Reset Control Register allows software to trigger a clean system reboot:
To prevent accidental system resets caused by errant software or stack corruption, writes to AIRCR MUST write the secret unlock key 0x05FA into bits [31:16] (VECTKEY field). If any other value is written, the entire write is rejected by hardware!
void System_SelfReset(void) {
__DSB(); // Ensure all outstanding memory transactions finish
SCB->AIRCR = (0x05FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk;
__DSB(); // Wait for reset to assert
while (1); // Trap until hardware reset executes
}
3 23ECE313_ES_Ch12_Txt1.pdf (Slides 38–42)| Mode | Core Clock | Peripherals & Clocks | Voltage Regulator | Wakeup Sources & Latency |
|---|---|---|---|---|
| Sleep Mode | Gated (Off) | Running (HSI, HSE, PLL, Timers active) | Main Regulator ON | Any interrupt. Fast wakeup (< 10 cycles). |
| Deep Sleep (Stop) | Gated (Off) | High-speed clocks stopped. SRAM and register contents retained. | Low-power regulator mode | EXTI, RTC alarm, WIC. Medium wakeup (~few microseconds). |
| Standby Mode | Off | Entire core domain powered down. SRAM lost! Only Backup Domain active. | Regulator Powered Down | Wakeup pin (WKUP), RTC alarm, NRST. Cold boot reset sequence. |
0 = Enter standard Sleep mode on WFI; 1 = Enter Deep Sleep / Stop mode on WFI.WFE.In Deep Sleep mode, the main core power domain and NVIC clocks are shut down to achieve microamp currents. The WIC is a small, ultra-low-power shadow controller that stays powered. When an external line asserts an interrupt, the WIC signals the Power Management Unit to wake the main voltage regulator, restore clocks, and hand off the pending interrupt directly to the NVIC!
3 23ECE313_ES_Ch12_Txt1.pdf (Slides 35–37); lab/systick.c
f_CPU = 16 MHz = 16,000,000 HzT = 1 ms = 0.001 sN = 16,000,000 × 0.001 = 16,000 cyclesLOAD down to 0 (a total of LOAD + 1 states):SysTick->LOAD = 16,000 - 1 = 15,999 (0x3E7F)#include "stm32f4xx.h"
void SysTick_Delay_ms(uint32_t ms) {
// 1. Disable SysTick during configuration
SysTick->CTRL = 0;
// 2. Load count value for 1 ms (16,000 cycles at 16 MHz)
SysTick->LOAD = 15999;
// 3. Clear current value register and clear COUNTFLAG
SysTick->VAL = 0;
// 4. Enable SysTick with Processor Clock (Bit 2: CLKSOURCE = 1, Bit 0: ENABLE = 1)
// No interrupt enable (TICKINT = 0)
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
// 5. Loop for the requested number of milliseconds
for (uint32_t i = 0; i < ms; i++) {
// Wait until COUNTFLAG (Bit 16) is set to 1 by hardware
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
}
// 6. Disable SysTick after delay finishes
SysTick->CTRL = 0;
}
int main(void) {
// Enable GPIOA clock and configure PA5 as output
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (1U << (5 * 2));
while (1) {
GPIOA->ODR ^= (1U << 5); // Toggle PA5 LED
SysTick_Delay_ms(500); // Accurate 500 ms delay
}
}
7 23ECE313_ES_ Mazidi.pdf & STM32F446RE_Timers_PWM_ADC_Mazidi.pdf__WFI()) while TIM2 continuously outputs PWM on PA5.EXTI15_10_IRQHandler):
SWSTART).EOC flag is set in ADC1->SR.TIM2->CCR1.EXTI->PR = (1U << 13);.#include "stm32f4xx.h"
void System_Peripherals_Init(void) {
// 1. Enable Peripheral Clocks
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOCEN; // GPIOA & GPIOC
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADC1EN; // SYSCFG & ADC1
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // TIM2
// 2. Configure PC13 as Digital Input with Pull-Up (Pushbutton)
GPIOC->MODER &= ~(3U << (13 * 2)); // Input mode ('00')
GPIOC->PUPDR &= ~(3U << (13 * 2));
GPIOC->PUPDR |= (1U << (13 * 2)); // Pull-Up ('01')
// 3. Configure PA0 as Analog Mode (ADC1_IN0)
GPIOA->MODER |= (3U << (0 * 2)); // Analog mode ('11')
// 4. Configure PA5 as Alternate Function AF1 (TIM2_CH1 PWM)
GPIOA->MODER &= ~(3U << (5 * 2));
GPIOA->MODER |= (2U << (5 * 2)); // Alternate function ('10')
GPIOA->AFR[0] &= ~(0xFU << (5 * 4));
GPIOA->AFR[0] |= (1U << (5 * 4)); // AF1 = TIM2_CH1
// 5. Configure EXTI13 for PC13
SYSCFG->EXTICR[3] &= ~(0xFU << 4);
SYSCFG->EXTICR[3] |= (2U << 4); // Port C = 0x2
EXTI->FTSR |= (1U << 13); // Falling trigger
EXTI->IMR |= (1U << 13); // Unmask interrupt line 13
NVIC_SetPriority(EXTI15_10_IRQn, 2);
NVIC_EnableIRQ(EXTI15_10_IRQn);
// 6. Configure ADC1 (Channel 0, PA0)
ADC1->SMPR2 |= (4U << 0); // 84 cycles sample time
ADC1->SQR1 = 0; // 1 conversion
ADC1->SQR3 = 0; // Channel 0
ADC1->CR2 |= ADC_CR2_ADON; // Turn on ADC
// 7. Configure TIM2 for 1 kHz PWM with 12-bit range (ARR = 4095)
TIM2->PSC = 3; // 16 MHz / 4 = 4 MHz timer clock
TIM2->ARR = 4095; // Matches 12-bit ADC resolution!
TIM2->CCR1 = 2048; // Initial 50% duty cycle
TIM2->CCMR1 |= (6U << 4) | TIM_CCMR1_OC1PE; // PWM Mode 1
TIM2->CCER |= TIM_CCER_CC1E; // Enable channel 1 output
TIM2->CR1 |= TIM_CR1_CEN; // Start counter
}
// EXTI15_10 Interrupt Handler for Button Press
void EXTI15_10_IRQHandler(void) {
if (EXTI->PR & (1U << 13)) {
// Start ADC conversion on PA0
ADC1->CR2 |= ADC_CR2_SWSTART;
while (!(ADC1->SR & ADC_SR_EOC)); // Wait for conversion
uint16_t adc_val = ADC1->DR; // Read 12-bit analog value (0-4095)
// Dynamically update PWM duty cycle (matches ARR = 4095)
TIM2->CCR1 = adc_val;
// Clear interrupt pending bit (WRITE 1 TO CLEAR)
EXTI->PR = (1U << 13);
}
}
int main(void) {
System_Peripherals_Init();
while (1) {
__WFI(); // Sleep until button press interrupt arrives
}
}
Professor Giriraja C. V. prioritizes neat, properly labeled diagrams. Master every essential visual representation directly extracted from the course slides:
Key Exam Notes: Shows transitions between Thread Mode (Privileged/Unprivileged) and Handler Mode (Always Privileged). Reset enters Thread Privileged. Exceptions force transition to Handler Mode. Exit via EXC_RETURN.
Key Exam Notes: Bit 0 = nPRIV (0: Privileged, 1: Unprivileged). Bit 1 = SPSEL (0: MSP, 1: PSP in Thread mode). Handler mode always forces MSP.
Key Exam Notes: SRAM: 0x20000000 (1MB) mapped to Alias 0x22000000 (32MB). Peripheral: 0x40000000 (1MB) mapped to Alias 0x42000000 (32MB). Formula: Alias = Base + (ByteOffset * 32) + (Bit * 4).
Key Exam Notes: I-Code (Instruction fetch from Flash), D-Code (Literal pool data from Flash), System Bus (SRAM & Peripherals). Harvard architecture allows concurrent code and data transfers.
Key Exam Notes: Step 1: Read address 0x00000000 into MSP. Step 2: Read address 0x00000004 into PC (Reset Handler address). Step 3: Branch to Reset Handler. Bit 0 of PC must be 1 (Thumb state).
Key Exam Notes: Visual memory layout of initial MSP (e.g. 0x20008000 top of SRAM) and Reset Handler vector with LSB=1 (e.g. 0x08000101 for code at 0x08000100).
Key Exam Notes: Shows how PRIGROUP bits [10:8] split 8-bit priority into Preempt Priority (determines nesting) and Sub-Priority (determines pending resolution when preemption is equal).
Key Exam Notes: Timing diagram showing interrupt pulse latching into pending state, transition from Pending to Active upon ISR entry, and clearing of pending bit.
Key Exam Notes: Without PendSV, SysTick preempting an external IRQ causes delayed IRQ completion. PendSV (lowest priority) defers context switching until all active IRQs complete!
Key Exam Notes: 8 words pushed by hardware: R0, R1, R2, R3, R12, LR, Return PC, xPSR. SVC immediate extracted from ((uint8_t*)stacked_pc)[-2].
Key Exam Notes: Core clock gated, PLL disabled. WIC stays powered, detects external edge, signals PMU to restore high-speed regulator and clocks, and transfers control to NVIC.
Key Exam Notes: DWT (Data watchpoints & cycle counting), ITM (printf via SWO pin), ETM (Instruction trace), TPIU (Trace packet serializer). Differentiates intrusive vs non-intrusive debug.
Reviewed and audited by Senior Embedded Systems Faculty. These are the subtle technical corner cases where 90% of students lose marks:
Question: "Calculate the vector table size and alignment for 75 external interrupts."
Total Vectors = 16 (Core) + 75 (External) = 91 words.
Table Size = 91 × 4 = 364 bytes.
Alignment Rule: ARMv7-M VTOR requires alignment to the next power of 2 ≥ size.
Question: "Why is BFAR not always valid during a BusFault?"
BFSR->BFARVALID = 0 (Fault address in BFAR is completely invalid).SCB->ACTLR |= SCB_ACTLR_DISDEFWBUF_Msk to disable write buffer. This forces precise faults where BFARVALID = 1!Question: "Explain how Cortex-M returns from an exception handler."
LR on exception entry. You MUST memorize these three:
0xFFFFFFF9: Return to Thread Mode using MSP (Main Stack Pointer).0xFFFFFFFD: Return to Thread Mode using PSP (Process Stack Pointer).0xFFFFFFE9: Return to Handler Mode using MSP (Nested exception return).Question: "Why does SP decrement by 0x24 (36 bytes) instead of 0x20 (32 bytes) during an interrupt?"
32 + 4 = 36 bytes (0x24)! Controlled by CCR->STKALIGN. Bit 9 of stacked xPSR records if padding was added.Question: "What happens if a function pointer points to address 0x08002000?"
UsageFault.0x08002001).Coding Trap: In EXTI15_10_IRQHandler, how do you clear the interrupt?
EXTI->PR &= ~(1U << 13); (Fails to clear! Writing 0 does nothing!).EXTI->PR = (1U << 13); (Must write a 1 to clear pending status!).Circuit Design Trap: Whenever the question asks to interface a Relay or DC Motor:
Coding Trap: Always enable clocks in RCC->AHB1ENR, RCC->APB1ENR, or RCC->APB2ENR before touching any peripheral register. Touching a peripheral register without its clock enabled triggers an immediate BusFault!