120 lines
3.1 KiB
C++
120 lines
3.1 KiB
C++
|
#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<size_t> (&(ADC.DR));
|
||
|
// Configure the memory address
|
||
|
DMA1.CMAR1.R = reinterpret_cast<size_t> (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);
|
||
|
}
|