#include <stdint.h>
/* ================= RCC ================= */
#define RCC_BASE 0x40021000UL
#define RCC_IOPENR (*(volatile uint32_t *)(RCC_BASE + 0x2C))
#define RCC_APB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x40))
#define RCC_APB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x44))
/* ================= GPIOA ================= */
#define GPIOA_BASE 0x50000000UL
#define GPIOA_MODER (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
#define GPIOA_AFRL (*(volatile uint32_t *)(GPIOA_BASE + 0x20))
/* ================= ADC1 ================= */
#define ADC_BASE 0x40012400UL
#define ADC_ISR (*(volatile uint32_t *)(ADC_BASE + 0x00))
#define ADC_CR (*(volatile uint32_t *)(ADC_BASE + 0x08))
#define ADC_CFGR1 (*(volatile uint32_t *)(ADC_BASE + 0x0C))
#define ADC_CHSELR (*(volatile uint32_t *)(ADC_BASE + 0x28))
#define ADC_DR (*(volatile uint32_t *)(ADC_BASE + 0x40))
/* ================= TIM2 ================= */
#define TIM2_BASE 0x40000000UL
#define TIM2_CR1 (*(volatile uint32_t *)(TIM2_BASE + 0x00))
#define TIM2_EGR (*(volatile uint32_t *)(TIM2_BASE + 0x14))
#define TIM2_CCMR1 (*(volatile uint32_t *)(TIM2_BASE + 0x18))
#define TIM2_CCER (*(volatile uint32_t *)(TIM2_BASE + 0x20))
#define TIM2_PSC (*(volatile uint32_t *)(TIM2_BASE + 0x28))
#define TIM2_ARR (*(volatile uint32_t *)(TIM2_BASE + 0x2C))
#define TIM2_CCR1 (*(volatile uint32_t *)(TIM2_BASE + 0x34))
/* ================= ADC INIT ================= */
void adc_init(void)
{
RCC_IOPENR |= (1 << 0); // Enable GPIOA
RCC_APB2ENR |= (1 << 9); // Enable ADC
GPIOA_MODER |= (3 << (0 * 2)); // PA0 analog mode
ADC_CR |= (1 << 31); // ADC calibration
while (ADC_CR & (1 << 31));
ADC_CR |= (1 << 0); // Enable ADC
while (!(ADC_ISR & (1 << 0))); // Wait ready
ADC_CHSELR = (1 << 0); // Channel 0
}
/* ================= PWM INIT ================= */
void pwm_init(void)
{
RCC_APB1ENR |= (1 << 0); // Enable TIM2
GPIOA_MODER &= ~(3 << (5 * 2));
GPIOA_MODER |= (2 << (5 * 2)); // PA5 AF mode
GPIOA_AFRL &= ~(0xF << (5 * 4));
GPIOA_AFRL |= (2 << (5 * 4)); // AF2 (TIM2)
TIM2_PSC = 79; // Prescaler
TIM2_ARR = 4095; // 12-bit PWM
TIM2_EGR = 1; // UPDATE EVENT (important)
TIM2_CCMR1 |= (6 << 4); // PWM mode 1
TIM2_CCMR1 |= (1 << 3); // Preload enable
TIM2_CCER |= (1 << 0); // Enable CH1
TIM2_CR1 |= (1 << 0); // Enable timer
}
/* ================= ADC READ ================= */
uint16_t adc_read(void)
{
ADC_CR |= (1 << 2); // Start conversion
while (!(ADC_ISR & (1 << 2))); // Wait EOC
return (uint16_t)ADC_DR; // 0–4095
}
/* ================= MAIN ================= */
int main(void)
{
adc_init();
pwm_init();
while (1)
{
TIM2_CCR1 = adc_read(); // Brightness control
}
}