110 lines
3.6 KiB
C++
110 lines
3.6 KiB
C++
#include "system.h"
|
|
#include "oneway.h"
|
|
#include "adcdma.h"
|
|
|
|
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);
|
|
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 + 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 / A2
|
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
|
r.B.MODE2 = 0u;
|
|
r.B.CNF2 = 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.B.SQ1__CHSEL = 2u; // CH2
|
|
ADC1.RSQR1.B.L = 0u; // 1 regular conversion
|
|
ADC1.SAMPTR2_CHARGE2.B.SMP2_TKCG2 = 7u;
|
|
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 (void * ptr) noexcept {
|
|
// Configure the peripheral data register address
|
|
DMA1.PADDR1.R = reinterpret_cast<size_t> (& ADC1.RDATAR_DR_ACT_DCG);
|
|
// Configure the memory address
|
|
DMA1.MADDR1.R = reinterpret_cast<size_t> (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 ();
|
|
Timer3Init (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);
|
|
}
|