RISC-V/stm32f051/adcdma.cpp

120 lines
3.1 KiB
C++
Raw Normal View History

2024-03-07 13:46:47 +01:00
#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);
}