/*
* NUCLEO-C031C6 BARE-METAL CODE - LED BLINK + BUTTON INTERRUPT
*
* Board: Nucleo-C031C6 (STM32C031C6, Cortex-M0+)
* LED: PA5 (User LED LD2/LD4)
* Button: PC13 (User Button B1 - active low)
*
* Behavior:
* - LED blinks continuously at 1Hz
* - Pressing button toggles LED state (interrupt-driven)
*/
#include "stm32c0xx.h"
/* Simple delay function (approximate) */
void delay_ms(uint32_t ms) {
for (volatile uint32_t i = 0; i < (ms * 4000); i++);
}
/* LED toggle function */
void led_toggle(void) {
GPIOA->ODR ^= (1 << 5);
}
/* LED ON function */
void led_on(void) {
GPIOA->ODR |= (1 << 5);
}
/* LED OFF function */
void led_off(void) {
GPIOA->ODR &= ~(1 << 5);
}
/* EXTI4_15 Interrupt Handler */
void EXTI4_15_IRQHandler(void) {
/* Check if EXTI line 13 triggered the interrupt */
if (EXTI->FPR1 & (1 << 13)) {
/* Clear the pending flag */
EXTI->FPR1 = (1 << 13);
/* Toggle LED on button press */
led_toggle();
}
}
int main(void) {
/* ============================================
* STEP 1: ENABLE CLOCKS
* ============================================ */
/* Enable clock for GPIOA (LED on PA5) */
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
/* Enable clock for GPIOC (Button on PC13) */
RCC->IOPENR |= RCC_IOPENR_GPIOCEN;
/* Enable clock for SYSCFG (for EXTI configuration) */
RCC->APBENR2 |= RCC_APBENR2_SYSCFGEN;
/* ============================================
* STEP 2: CONFIGURE LED (PA5) AS OUTPUT
* ============================================ */
/* Clear mode bits for PA5 (bits 10-11) */
GPIOA->MODER &= ~(GPIO_MODER_MODE5);
/* Set as output (01 binary) */
GPIOA->MODER |= (GPIO_MODER_MODE5_0);
/* Configure as push-pull (default after reset) */
GPIOA->OTYPER &= ~GPIO_OTYPER_OT5;
/* Configure as low speed */
GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED5;
/* ============================================
* STEP 3: CONFIGURE BUTTON (PC13) AS INPUT
* ============================================ */
/* Clear mode bits for PC13 (set as input) */
GPIOC->MODER &= ~(GPIO_MODER_MODE13);
/* Enable internal pull-up on PC13 */
GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPD13);
GPIOC->PUPDR |= GPIO_PUPDR_PUPD13_0; // Pull-up
/* ============================================
* STEP 4: CONFIGURE EXTI LINE 13 FOR PC13
* ============================================ */
/*
* For STM32C0: EXTI lines are configured through SYSCFG_CFGR1
* Bits 27:24 control EXTI13 (bits 24-27)
* Value 0 = PAx, 1 = PBx, 2 = PCx, 3 = PDx, etc.
*/
/* Clear the bits for EXTI13 (bits 27:24 of SYSCFG_CFGR1) */
SYSCFG->CFGR1 &= ~(0xF << 24);
/* Set to 2 for PC13 (GPIO Port C) */
SYSCFG->CFGR1 |= (2 << 24);
/* ============================================
* STEP 5: CONFIGURE EXTI TRIGGER MODE
* ============================================ */
/* Clear rising edge trigger for line 13 */
EXTI->RTSR1 &= ~(1 << 13);
/* Set falling edge trigger (button press: HIGH -> LOW) */
EXTI->FTSR1 |= (1 << 13);
/* ============================================
* STEP 6: ENABLE EXTI INTERRUPT
* ============================================ */
/* Unmask EXTI line 13 (enable interrupt) */
EXTI->IMR1 |= (1 << 13);
/* ============================================
* STEP 7: ENABLE INTERRUPT IN NVIC
* ============================================ */
/* EXTI4_15 interrupt number = 31 */
NVIC_EnableIRQ(EXTI4_15_IRQn);
/* Set priority (0 = highest) */
NVIC_SetPriority(EXTI4_15_IRQn, 0);
/* ============================================
* STEP 8: MAIN LOOP - BLINK LED
* ============================================ */
/* Turn LED OFF initially */
led_off();
while (1) {
/* Turn LED ON */
led_on();
delay_ms(500);
/* Turn LED OFF */
led_off();
delay_ms(500);
}
/* Should never reach here */
return 0;
}