#include <stdint.h>
// --- HARDWARE MAPPING (From Datasheet) ---
// Base Addresses
#define TEMP_RCC_BASE 0x40021000 // Reset & Clock Control
#define TEMP_GPIOA_BASE 0x50000000 // GPIO Port A
#define MY_EXTI_BASE 0x40021800
#define MY_NVIC_ISER 0xE000E100
// Register Offsets & References
// Note: We use 'volatile' so the compiler doesn't optimize the memory access away
#define TEMP_RCC_IOPENR *(volatile uint32_t*)(TEMP_RCC_BASE + 0x34)
#define TEMP_GPIOA_MODER *(volatile uint32_t*)(TEMP_GPIOA_BASE + 0x00)
#define TEMP_GPIOA_ODR *(volatile uint32_t*)(TEMP_GPIOA_BASE + 0x14)
#define TEMP_GPIOA_IDR *(volatile uint32_t*)(TEMP_GPIOA_BASE + 0x10)
#define EXTI_RTSR1 *(volatile uint32_t*)(MY_EXTI_BASE + 0x00)
#define EXTI_FTSR1 *(volatile uint32_t*)(MY_EXTI_BASE + 0x04)
#define EXTI_IMR1 *(volatile uint32_t*)(MY_EXTI_BASE + 0x80)
#define EXTI_RPR1 *(volatile uint32_t*)(MY_EXTI_BASE + 0x0C)
#define NVIC_ISER *(volatile uint32_t*)(MY_NVIC_ISER + 0x0C)
// --- THE INTERRUPT SERVICE ROUTINE (ISR) ---
// This name is special; it's defined in the startup code/vector table.
extern "C" void EXTI0_1_IRQHandler(void) {
// 1. Check if the interrupt came from Line 1 (Pin 1)
if (EXTI_RPR1 & (1 << 1)) {
TEMP_GPIOA_ODR ^= (1 << 6); // Toggle LED
// 2. CLEAR the interrupt flag!
// In EXTI, you write a '1' to the bit to clear it (RC_W1 logic).
EXTI_RPR1 |= (1 << 1);
}
}
void manual_delay(int count) {
for (volatile int i = 0; i < count; i++);
}
int main() {
// 1. Enable Clock for GPIOA (Bit 0 of IOPENR)
TEMP_RCC_IOPENR |= (1 << 0);
// 2. Configure PA5 as Output
// MODER has 2 bits per pin. Pin 5 uses bits 10 & 11.
// Setting to '01' makes it a General Purpose Output.
TEMP_GPIOA_MODER &= ~(3 << 12); // Clear bits 10 and 11
TEMP_GPIOA_MODER |= (1 << 12); // Set bit 10 to 1
TEMP_GPIOA_MODER &= ~(3 << 2); // Clear bits 10 and 11
NVIC_ISER |= (1 << 5);
while (1) {
// The CPU can now sleep or do other work here.
// The LED toggle happens automatically via hardware!
}
}