#include "system.h" #include "oneway.h" #include "adcdma.h" static AdcDma * pInstance = nullptr; extern "C" void DMA1_Channel1_IRQHandler( void ) __attribute__((interrupt)); void DMA1_Channel1_IRQHandler( void ) { DMA1_Type::INTFR_DEF state (DMA1.INTFR); DMA1.INTFCR.R = state.R; // clear all if (!pInstance) return; if (state.B.HTIF1 != RESET) pInstance->send (false); else if (state.B.TCIF1 != RESET) pInstance->send (true); } static inline void EnableClock (void) noexcept { // Enable DMA RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto { r.B.SRAMEN = SET; r.B.DMA1EN = SET; return r.R; }); // Enable ADC + GPIOA RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto { r.B.ADC1EN = SET; r.B.IOPAEN = SET; return r.R; }); RCC.APB1PCENR.B.TIM3EN = SET; // Enable TIM3 RCC.CFGR0.B.ADCPRE = 3u; // 11: PCLK2 divided by 8 // max 14 MHz (18) ? // PIN PA2 / A2 GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.MODE2 = 0u; r.B.CNF2 = 0u; return r.R; }); } static inline void TimerInit (uint32_t us) noexcept { TIM3.PSC.R = 143u; // 1 MHz Fs TIM3.ATRLR.R = us - 1u; // TRGO update for ADC TIM3.CTLR2.B.MMS = 2u; } static inline void AdcCalibrate (void) noexcept { // RESET RCC.APB2PRSTR.B.ADC1RST = SET; RCC.APB2PRSTR.B.ADC1RST = RESET; // set channels ADC1.RSQR3__CHANNEL.B.SQ1__CHSEL = 2u; // CH2 ADC1.SAMPTR2_CHARGE2.B.SMP2_TKCG2 = 7u; /* ADC1.RSQR3__CHANNEL.B.SQ1__CHSEL = 16u; // teplota ADC1.SAMPTR1_CHARGE1.B.SMP16_TKCG16 = 7u; */ ADC1.RSQR1.B.L = 0u; // 1 regular conversion ADC1.CTLR1.B.SCAN = SET; ADC1.CTLR2.B.ADON = SET; //ADC1.CTLR2.B.TSVREFE = SET; ADC1.CTLR2.B.RSTCAL = SET; // Launch the calibration by setting RSTCAL while (ADC1.CTLR2.B.RSTCAL != RESET); // Wait until RSTCAL=0 ADC1.CTLR2.B.CAL = SET; // Launch the calibration by setting CAL while (ADC1.CTLR2.B.CAL != RESET); // Wait until CAL=0 } typedef __SIZE_TYPE__ size_t; static inline void Dma1Ch1Init (void * ptr) noexcept { // Configure the peripheral data register address DMA1.PADDR1.R = reinterpret_cast (& ADC1.RDATAR_DR_ACT_DCG); // Configure the memory address DMA1.MADDR1.R = reinterpret_cast (ptr); // Configure the number of DMA tranfer to be performs on DMA channel 1 DMA1.CNTR1 .R = FULL_LEN; // Configure increment, size, interrupts and circular mode DMA1.CFGR1.modify([] (DMA1_Type::CFGR1_DEF & r) -> auto { r.B.PL = 3u; // highest priority r.B.MEM2MEM = RESET; // periferal -> memory r.B.MINC = SET; // memory increment r.B.MSIZE = 1u; // 16-bit r.B.PSIZE = 1u; // 16-bit r.B.HTIE = SET; // INT Enable HALF r.B.TCIE = SET; // INT Enable FULL r.B.CIRC = SET; // Circular MODE // Enable DMA Channel 1 r.B.EN = SET; return r.R; }); } static inline void AdcPostInit (void) noexcept { ADC1.CTLR2.modify([](ADC1_Type::CTLR2_DEF & r) -> auto { r.B.DMA = SET; r.B.EXTTRIG = SET; r.B.EXTSEL = 4u; // TRGO event of timer 3 r.B.SWSTART = SET; return r.R; }); } //////////////////////////////////////////////////////////////////////////////////// AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) { pInstance = this; EnableClock (); TimerInit (1000u); NVIC.EnableIRQ (DMA1_Channel1_IRQn); AdcCalibrate(); Dma1Ch1Init (buffer); AdcPostInit (); // start timer TIM3.CTLR1.B.CEN = SET; } inline void AdcDma::send(const bool b) { if (!dst) return; if (b) dst->Send (pH, HALF_LEN); else dst->Send (pL, HALF_LEN); }