#include "system.h" #include "adcscope.h" #include "structures.h" static AdcClass * AdcClassInstance = nullptr; enum TRANSFER_SIZES { XFER_BYTE = 0, XFER_HALF, XFER_WORD, }; static const unsigned DmaLenTable [] = { DATA_FULL_LEN * ADC_MAXCHANNELS, ADC_MAXCHANNELS * 2, }; static constexpr unsigned LSH = 2u, DIVL = 36u, DIVH = 36'000u; static const TimeBaseDescriptor BaseTable [] { {(2u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 2us {(5u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 5us {(10u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 10us {(20u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 20us {(50u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 50us {(100u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 100us {(200u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 200us {(500u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 500us {(1000u << LSH) - 1u, DIVL - 1u, TIME_BASE_CONTINUOUS}, // 1ms {(2u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 2ms {(5u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 5ms {(10u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 10ms {(20u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 20ms {(50u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 50ms {(100u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 100ms {(200u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 200ms {(500u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 500ms {(1000u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 1s }; 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 + GPIOC 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 PA2, PA3 / A2,A3 GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.MODE2 = 0u; r.B.CNF2 = 0u; r.B.MODE3 = 0u; r.B.CNF3 = 0u; return r.R; }); } static inline void Timer3Init (const TimeBaseDescriptor & tb) noexcept { TIM3.PSC.R = tb.presc; // 4 MHz Fs TIM3.ATRLR.R = tb.divider; // 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.RSQR3__CHANNEL.B.SQ2 = 3u; // CH3 ADC1.RSQR1.B.L = ADC_MAXCHANNELS - 1U; // 2 regular conversion static constexpr unsigned ts = 0u; ADC1.SAMPTR2_CHARGE2.B.SMP2_TKCG2 = ts; ADC1.SAMPTR2_CHARGE2.B.SMP3_TKCG3 = ts; ADC1.CTLR1.B.SCAN = SET; 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 } typedef __SIZE_TYPE__ size_t; static inline void Dma1Ch1Init (const void * ptr, const unsigned n = 0u) 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 = DmaLenTable [n]; // DATA_FULL_LEN * ADC_MAXCHANNELS; // 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 = XFER_HALF;// 16-bit r.B.PSIZE = XFER_HALF;// 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; }); } /* *********************************************************************************************/ void AdcClass::Init () { AdcClassInstance = this; EnableClock (); Timer3Init (BaseTable [6]); NVIC.EnableIRQ (DMA1_Channel1_IRQn); AdcCalibrate(); Dma1Ch1Init (buffer); AdcPostInit (); // start timer TIM3.CTLR1.B.CEN = SET; } // nekonzistentni, ale funkcni void SampleRing::ReloadTimer(const unsigned int n) { const TimeBaseDescriptor & tb = BaseTable [n]; TIM3.CTLR1.B.CEN = RESET; TIM3.CNT.R = 0u; TIM3.PSC.R = tb.presc; TIM3.ATRLR.R = tb.divider; TIM3.CTLR1.B.CEN = SET; if (tb.mode != m_mode) { if (!AdcClassInstance) return; const DATA_BLOCK * buffer = AdcClassInstance->setPtrH (tb.mode); DMA1.CFGR1.B.EN = RESET; NVIC.DisableIRQ (DMA1_Channel1_IRQn); Dma1Ch1Init (buffer, tb.mode); // m_head = m_tail = m_lenght = 0u; m_mode = tb.mode; NVIC.EnableIRQ (DMA1_Channel1_IRQn); } } /* *********************************************************************************************/ void AdcClass::drq() { led << false; DMA1_Type::INTFR_DEF state (DMA1.INTFR); DMA1.INTFCR.R = state.R; // clear all if (state.B.HTIF1 != RESET) { ring.write (ptrl); } else if (state.B.TCIF1 != RESET) { ring.write (ptrh); } led << true; } extern "C" { [[gnu::interrupt]] extern void DMA1_Channel1_IRQHandler(); } void DMA1_Channel1_IRQHandler( void ) { if (AdcClassInstance) AdcClassInstance->drq(); }