#include "STM32F0x1.h" #include "CortexM0.h" #include "gpio.h" #include "adcdma.h" #include "oneway.h" static constexpr uint32_t AdcChanel = 2u; static constexpr uint32_t AdcPin = 2u; static inline void EnableClock (void) { RCC.APB2ENR.B.ADCEN = SET; RCC.AHBENR.B.DMA1EN = SET; RCC.APB1ENR.B.TIM3EN = SET; } static inline void Timer3Init (uint32_t us) { TIM3.PSC.R = 47u; TIM3.ARR.R = us - 1u; // Preload, enable TIM3.CR1.B.ARPE = SET; // TRGO update for ADC TIM3.CR2.B.MMS = 2; } typedef __SIZE_TYPE__ size_t; static inline void Dma1Ch1Init (void * ptr) { // Enable DMA transfer on ADC and circular mode ADC.CFGR1.B.DMAEN = SET; ADC.CFGR1.B.DMACFG = SET; // Configure the peripheral data register address DMA1.CPAR1.R = reinterpret_cast (&(ADC.DR)); // Configure the memory address DMA1.CMAR1.R = reinterpret_cast (ptr); // Configure the number of DMA tranfer to be performs on DMA channel 1 DMA1.CNDTR1.R = FULL_LEN; // Configure increment, size, interrupts and circular mode DMA1.CCR1.modify([] (auto & r) -> auto { r.B.MINC = SET; r.B.MSIZE = 1u; r.B.PSIZE = 1u; r.B.HTIE = SET; r.B.TCIE = SET; r.B.CIRC = SET; return r.R; }); // Enable DMA Channel 1 DMA1.CCR1.B.EN = SET; } static inline void AdcCalibrate (void) { // Ensure that ADEN = 0 // Clear ADEN if (ADC.CR.B.ADEN != RESET) { ADC.CR.B.ADEN = RESET; } // Launch the calibration by setting ADCAL ADC.CR.B.ADCAL = SET; // Wait until ADCAL=0 while (ADC.CR.B.ADCAL != RESET); //__NOP(); //__NOP(); // This 2 NOPs are to ensure 2 ADC Cycles before setting ADEN bit } static inline void AdcInit (void) { // PCLK / 2 - jitter ADC.CFGR2.B.JITOFF_D2 = SET; // Select TRG TIM3 ADC.CFGR1.modify([] (auto & r) -> auto { r.B.EXTEN = 1u; r.B.EXTSEL = 3u; return r.R; }); // Select CHSELx ADC.CHSELR.R = (1 << AdcChanel); // Select a sampling mode of 000 ADC.SMPR.R = 1u; } static inline void AdcStart (void) { ADC.CR.B.ADEN = SET; TIM3.CR1.B.CEN = SET; ADC.CR.B.ADSTART = SET; } static AdcDma * Instance = nullptr; AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) { Instance = this; EnableClock (); AdcCalibrate(); GpioClass in (GpioPortA, AdcPin, GPIO_Mode_AN); Timer3Init (1000); NVIC_EnableIRQ (DMA1_CH1_IRQn); Dma1Ch1Init (buffer); AdcInit (); AdcStart (); } /* void AdcDma::dmaIrq (void) { volatile DMA_ISR_s status (DMA1.ISR); current = nullptr; if (status.B.HTIF1) current = ptr_l; if (status.B.TCIF1) current = ptr_h; // znuluj příznaky DMA1.IFCR.R = status.R; if (!current) return; // zpracuj data, pokud je potřeba send (current, PERIOD); ~led; } */ extern "C" void DMA1_Channel1_IRQHandler (void) { volatile DMA1_Type::ISR_DEF status (DMA1.ISR); // znuluj příznaky DMA1.IFCR.R = status.R; if (!Instance) return; if (status.B.HTIF1 != RESET) Instance->send (false); else if (status.B.TCIF1 != RESET) Instance->send (true); } inline void AdcDma::send(const bool b) { if (!dst) return; if (b) dst->Send (pH, HALF_LEN); else dst->Send (pL, HALF_LEN); }