#include "stm32c0xx.h"
// Hard delay padding blocks for raw cycle synchronization
void delay_us(volatile uint32_t us) {
volatile uint32_t count = us * 3UL;
while (count > 0) {
count--;
__NOP();
}
}
void delay_ms(volatile uint32_t ms) {
while (ms > 0) {
delay_us(1000);
ms--;
}
}
// Pure C square-wave toggle engine mapping PA5
void play_tone(uint32_t frequency_hz, uint32_t duration_ms) {
if (frequency_hz == 0) {
GPIOA->ODR &= ~GPIO_ODR_OD5;
delay_ms(duration_ms);
return;
}
uint32_t half_period_us = 1000000UL / (frequency_hz * 2);
uint32_t total_cycles = (duration_ms * 1000UL) / (half_period_us * 2);
for (uint32_t i = 0; i < total_cycles; i++) {
GPIOA->ODR |= GPIO_ODR_OD5; // Drive PA5 High
delay_us(half_period_us);
GPIOA->ODR &= ~GPIO_ODR_OD5; // Drive PA5 Low
delay_us(half_period_us);
}
// Reduced silent gap (9ms) between faster notes for crisp separation
GPIOA->ODR &= ~GPIO_ODR_OD5;
delay_ms(9);
}
void setup(void) {
// 1. Enable GPIOA peripheral clock
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
delay_ms(5);
// 2. Configure PA0 to PA3 explicitly as Input Mode (00)
GPIOA->MODER &= ~(GPIO_MODER_MODE0 | GPIO_MODER_MODE1 | GPIO_MODER_MODE2 | GPIO_MODER_MODE3);
// 3. Clear and activate internal Pull-Up Resistors (01) for pins PA0-PA3
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD0 | GPIO_PUPDR_PUPD1 | GPIO_PUPDR_PUPD2 | GPIO_PUPDR_PUPD3);
GPIOA->PUPDR |= (GPIO_PUPDR_PUPD0_0 | GPIO_PUPDR_PUPD1_0 | GPIO_PUPDR_PUPD2_0 | GPIO_PUPDR_PUPD3_0);
// 4. Configure PA5 as Output Mode (01)
GPIOA->MODER &= ~(GPIO_MODER_MODE5);
GPIOA->MODER |= GPIO_MODER_MODE5_0;
}
void loop(void) {
// Read lower 4 bits of GPIOA IDR and invert them.
uint32_t switch_state = (~GPIOA->IDR) & 0x0F;
switch (switch_state) {
case 0x01: // Switch 1 Only -> "Drunken Sailor" (Accelerated)
play_tone(294, 90); // D4
play_tone(294, 90); // D4
play_tone(294, 90); // D4
play_tone(294, 90); // D4
play_tone(294, 90); // D4
play_tone(294, 90); // D4
play_tone(349, 90); // F4
play_tone(440, 180); // A4
play_tone(392, 90); // G4
play_tone(392, 90); // G4
play_tone(392, 90); // G4
play_tone(392, 90); // G4
play_tone(330, 90); // E4
play_tone(330, 90); // E4
play_tone(330, 180); // E4
break;
case 0x02: // Switch 2 Only -> "London Bridge Is Falling Down" (Accelerated)
play_tone(392, 120); // G4
play_tone(440, 60); // A4
play_tone(392, 90); // G4
play_tone(349, 90); // F4
play_tone(330, 90); // E4
play_tone(349, 90); // F4
play_tone(392, 180); // G4
play_tone(294, 90); // D4
play_tone(330, 90); // E4
play_tone(349, 180); // F4
play_tone(330, 90); // E4
play_tone(349, 90); // F4
play_tone(392, 180); // G4
break;
case 0x04: // Switch 3 Only -> "Frere Jacques" (Accelerated)
play_tone(261, 120); // C4
play_tone(294, 120); // D4
play_tone(330, 120); // E4
play_tone(261, 120); // C4
// Repeat phrase
play_tone(261, 120); // C4
play_tone(294, 120); // D4
play_tone(330, 120); // E4
play_tone(261, 120); // C4
// Next phrase
play_tone(330, 120); // E4
play_tone(349, 120); // F4
play_tone(392, 240); // G4
break;
case 0x08: // Switch 4 Only -> "US National Anthem" (Accelerated)
play_tone(392, 90); // G4
play_tone(330, 90); // E4
play_tone(261, 180); // C4
play_tone(330, 90); // E4
play_tone(392, 90); // G4
play_tone(523, 270); // C5
play_tone(659, 90); // E5
play_tone(587, 90); // D5
play_tone(523, 180); // C5
play_tone(330, 90); // E4
play_tone(370, 90); // F#4
play_tone(392, 270); // G4
break;
default:
// No switches down -> absolute silence
GPIOA->ODR &= ~GPIO_ODR_OD5;
delay_ms(10);
break;
}
}