#include "stm32c031xx.h"
/* ===== ADC bits ===== */
#define ADC_CR_ADEN_BIT (1U << 0)
#define ADC_CR_ADSTART_BIT (1U << 2)
#define ADC_CR_ADVREGEN_BIT (1U << 28)
#define ADC_CR_DEEPPWD_BIT (1U << 29)
#define ADC_CR_ADCAL_BIT (1U << 31)
#define ADC_ISR_ADRDY_BIT (1U << 0)
#define ADC_ISR_EOC_BIT (1U << 2)
// ^^^ all this shit is initialization part
/* =========================================================
Small software delays
========================================================= */
/* Short delay used only during ADC regulator startup */
static void small_delay(volatile uint32_t n)
{
while (n--) {
__asm__("nop");
}
}
/* Approximate delay in milliseconds for visible LED blinking */
static void delay_ms(volatile uint32_t ms)
{
volatile uint32_t i;
while (ms--) {
for (i = 0; i < 4000; i++) {
__asm__("nop");
}
}
}
/* =========================================================
ADC initialization: PA0 = analog input, channel 0
========================================================= */
static void adc_init(void)
{
/* 1. Enable GPIOA clock */
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
/* 2. Set PA0 to analog mode */
GPIOA->MODER |= (3U << 0);
/* 3. Enable ADC clock */
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
/* 4. Exit deep-power-down mode */
ADC1->CR &= ~ADC_CR_DEEPPWD_BIT;
/* 5. Enable internal ADC voltage regulator */
ADC1->CR |= ADC_CR_ADVREGEN_BIT;
/* 6. Wait for regulator stabilization */
small_delay(20000);
/* 7. Start ADC calibration */
ADC1->CR |= ADC_CR_ADCAL_BIT;
/* Wait until calibration is complete */
while (ADC1->CR & ADC_CR_ADCAL_BIT) {
}
/* 8. Select channel 0 (PA0) */
ADC1->CHSELR = (1U << 0);
/* 9. Enable ADC */
ADC1->CR |= ADC_CR_ADEN_BIT;
/* 10. Wait until ADC is ready */
while (!(ADC1->ISR & ADC_ISR_ADRDY_BIT)) {
}
}
/* =========================================================
ADC single conversion
========================================================= */
static uint16_t adc_read(void)
{
/* 11. Start one conversion by software */
ADC1->CR |= ADC_CR_ADSTART_BIT;
/* 12. Wait until conversion is complete */
while (!(ADC1->ISR & ADC_ISR_EOC_BIT)) {
}
/* 13. Return 12-bit result: 0 to 4095 */
return (uint16_t)ADC1->DR;
}
/* =========================================================
LED output: PA5
========================================================= */
static void led_init(void)
{
/* Enable GPIOA clock */
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
/* Set PA5 as general-purpose output */
GPIOA->MODER &= ~(3U << (5U * 2U));
GPIOA->MODER |= (1U << (5U * 2U));
}
static void led_toggle(void)
{
GPIOA->ODR ^= (1U << 5);
}
/* =========================================================
Main
========================================================= */
int main(void)
{
uint16_t adc_value;
uint32_t delay_value_ms;
adc_init();
led_init();
while (1)
{
/* Read analog value from channel 0 */
adc_value = adc_read();
/* Map ADC range 0..4095 to delay range 100..2000 ms */
delay_value_ms = 10U + ((uint32_t)adc_value * 190U) / 4095U;
/* Toggle LED using the computed delay */
led_toggle();
delay_ms(delay_value_ms);
}
}Loading
st-nucleo-c031c6
st-nucleo-c031c6