#include "system.h" #include "oneway.h" #include "adc.h" typedef __SIZE_TYPE__ size_t; static AdcDma * pInstance = nullptr; extern "C" { [[gnu::interrupt]] extern void DMA1_Channel1_IRQHandler(); } void DMA1_Channel1_IRQHandler( void ) { DMA1_Type::INTFR_DEF state (DMA1.INTFR); if (state.B.GIF1 != RESET) { // Zřejmě zbytečné, ale pokud používám víc DMA DMA1.INTFCR.B.CGIF1 = SET; // kanálů, pak to tak má být. } else return; // Událost nevznikla pro kanál 1. if (state.B.HTIF1 != RESET) { DMA1.INTFCR.B.CHTIF1 = SET; if (pInstance) pInstance->send (false); } if (state.B.TCIF1 != RESET) { DMA1.INTFCR.B.CTCIF1 = SET; if (pInstance) 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; // PCLK2 divided by 8 as ADC clock (18 MHz, ! pretaktovano 14 MHz max). // PIN PA0 / A0, PA1 / A1 GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.MODE0 = 0u; r.B.CNF0 = 0u; r.B.MODE1 = 0u; r.B.CNF1 = 0u; return r.R; }); } static inline void Timer3Init (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.modify([](ADC1_Type::RSQR3__CHANNEL_DEF & r) -> auto { r.B.SQ1__CHSEL = 1u; // CH1 //r.B.SQ2 = 1u; // CH1 return r.R; }); ADC1.RSQR1.B.L = 0u; // 1 regular conversion ADC1.SAMPTR2_CHARGE2.modify([](ADC1_Type::SAMPTR2_CHARGE2_DEF & r) -> auto { r.B.SMP0_TKCG0 = 7u; r.B.SMP1_TKCG1 = 7u; return r.R; }); ADC1.CTLR1.modify([](ADC1_Type::CTLR1_DEF & r) -> auto { r.B.SCAN = SET; //r.B.BUFEN = SET; //r.B.PGA = 3u; // x64 return r.R; }); ADC1.CTLR2.B.ADON = 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 } 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; }); } inline void AdcDma::DmaInit () { // 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 (buffer); // 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.DIR = RESET; 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; }); } //////////////////////////////////////////////////////////////////////////////////// AdcDma::AdcDma() noexcept : pL (buffer), pH (buffer + HALF_LEN), dst (nullptr) { pInstance = this; EnableClock (); Timer3Init (1000u); NVIC.EnableIRQ (DMA1_Channel1_IRQn); AdcCalibrate(); DmaInit (); 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); }