RISC-V/V203/usb/ch32v203/adcscope.cpp
2024-10-21 12:09:29 +02:00

168 lines
5.9 KiB
C++

#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<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 = 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();
}