#include "stm32c0xx.h"
volatile bool pingReady = false;
volatile bool pongReady = false;
// 1. Add these flags at the top
volatile bool dataReady = false;
float finalAverage = 0;
#define BUFFER_SIZE 2000
uint16_t adc_buffer[BUFFER_SIZE]; // Our Ping-Pong memory space
void setup(){
pinMode(A0, INPUT);
Serial.begin(115200);
while (!Serial); // Wait for Serial to be ready
Serial.println("DMA System Initializing...");
configure_dma_adc(); // Did you forget to call this?
Serial.println("ADC started in DMA Circular Mode.");
pinMode(LED_BUILTIN, OUTPUT);
}
void configure_dma_adc() {
// 1. POWER & CLOCKS
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// 2. GPIO PA0 (A0) as ANALOG
GPIOA->MODER |= (3 << GPIO_MODER_MODE0_Pos);
// 3. ADC CALIBRATION (CRITICAL STEP)
ADC1->CR &= ~ADC_CR_ADEN; // Ensure ADC is OFF
ADC1->CR |= ADC_CR_ADVREGEN; // Enable Voltage Regulator
delay(1); // Wait for regulator to stabilize
ADC1->CR |= ADC_CR_ADCAL; // Start Calibration
while (ADC1->CR & ADC_CR_ADCAL); // Wait until calibration is 0
// 4. ENABLE ADC
ADC1->ISR |= ADC_ISR_ADRDY; // Clear Ready flag
ADC1->CR |= ADC_CR_ADEN; // Enable ADC
while (!(ADC1->ISR & ADC_ISR_ADRDY)); // Wait for Ready
// 5. DMA CONFIG (THE "PIPES")
DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR);
DMA1_Channel1->CMAR = (uint32_t)adc_buffer;
DMA1_Channel1->CNDTR = BUFFER_SIZE;
// CCR: Circular + Memory Inc + 16-bit Size + Interrupts
DMA1_Channel1->CCR = DMA_CCR_CIRC | DMA_CCR_MINC |
DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 |
DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN;
// 6. LINK ADC TO DMA
ADC1->CFGR1 |= ADC_CFGR1_CONT | ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG;
ADC1->CHSELR = ADC_CHSELR_CHSEL0; // Select Channel 0 (PA0)
// 7. START CONVERSION
ADC1->CR |= ADC_CR_ADSTART;
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
// 1. Define the missing process_data function
void process_data(uint16_t* data, int length) {
// For now, let's just find the average of this buffer "half"
uint32_t sum = 0;
for(int i = 0; i < length; i++) {
sum += data[i];
}
float average = (float)sum / length;
// Print the result (Warning: In high-speed industry apps,
// you'd do this math in the loop, not the ISR!)
Serial.print("Buffer Half Average: ");
Serial.println(average);
}
// 3. Update the Handler Name
extern "C" void DMA1_Channel1_IRQHandler(void) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
if (DMA1->ISR & DMA_ISR_HTIF1) {
dataReady = true;
DMA1->IFCR |= DMA_IFCR_CHTIF1;
}
if (DMA1->ISR & DMA_ISR_HTIF1) {
pingReady = true; // Just set a flag and exit FAST
dataReady = true;
DMA1->IFCR |= DMA_IFCR_CHTIF1;
}
if (DMA1->ISR & DMA_ISR_HTIF1) {
process_data(&adc_buffer[0], 1000); // Ping
DMA1->IFCR |= DMA_IFCR_CHTIF1;
}
if (DMA1->ISR & DMA_ISR_TCIF1) {
process_data(&adc_buffer[1000], 1000); // Pong
DMA1->IFCR |= DMA_IFCR_CTCIF1;
}
}
void loop(){
if (pingReady) {
// Perform heavy math here (FFT, THD calculation, etc.)
process_data(&adc_buffer[0], 1000);
pingReady = false;
}
if (pongReady) {
process_data(&adc_buffer[1000], 1000);
pongReady = false;
}
if (dataReady) {
// Calculate average here...
// We only print if some time has passed (e.g., every 500ms)
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 500) {
Serial.print("DMA Active - Potentiometer Voltage: ");
// (Insert your ADC to Voltage math here)
Serial.println("V");
lastPrint = millis();
}
dataReady = false; // Reset the flag
}
}