RISC-V/V003/ch32v003/pcmdma.cpp
2024-05-07 11:46:49 +02:00

117 lines
3.4 KiB
C++

#include "system.h"
#include "pcmdma.h"
#include "gpio.h"
static PcmDma * pInstance = nullptr;
extern "C" void DMA1_Channel5_IRQHandler( void ) __attribute__((interrupt));
void DMA1_Channel5_IRQHandler( void ) {
DMA1_Type::INTFR_DEF state (DMA1.INTFR);
DMA1.INTFCR.R = state.R; // clear all
if (!pInstance) return;
if (state.B.HTIF5 != RESET) pInstance->send(false);
else if (state.B.TCIF5 != RESET) pInstance->send(true);
}
/*
* initialize TIM1 for PWM
*/
static inline void tim1pwm_init () noexcept {
// Enable GPIOD and TIM1
RCC.APB2PCENR.modify([] (RCC_Type::APB2PCENR_DEF & r) -> auto {
r.B.IOPDEN = SET;
//r.B.IOPCEN = SET;
r.B.TIM1EN = SET;
return r.R;
});
// PD0 is T1CH1N, PD2 is T1CH1, 10MHz Output alt func, push-pull
GPIOD.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
r.B.CNF0 = 2u;
r.B.MODE0 = 1u;
r.B.CNF2 = 2u;
r.B.MODE2 = 1u;
return r.R;
});
/* Alternative
AFIO.PCFR.B.TIM1RM = 1u;
// PC3 is T1CH1N, PC6 is T1CH1, 10MHz Output alt func, push-pull
GPIOC.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
r.B.CNF3 = 2u;
r.B.MODE3 = 1u;
r.B.CNF6 = 2u;
r.B.MODE6 = 1u;
return r.R;
});
*/
// Reset TIM1 to init all regs
RCC.APB2PRSTR.B.TIM1RST = SET;
RCC.APB2PRSTR.B.TIM1RST = RESET;
// CTLR1: default is up, events generated, edge align
// SMCFGR: default clk input is CK_INT
// Prescaler
TIM1.PSC.R = 0u;
// Auto Reload - sets period
TIM1.ATRLR.R = MAXPWM - 1;
TIM1.CCER.modify([](TIM1_Type::CCER_DEF & r) -> auto {
// Enable CH1N, CH1 output, positive pol
r.B.CC1NE = SET;
r.B.CC1E = SET;
/*
r.B.CC1NP = SET; // active Low
r.B.CC1P = SET;
*/
return r.R;
});
// CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
TIM1.CHCTLR1_Output.modify([](TIM1_Type::CHCTLR1_Output_DEF & r) -> auto {
r.B.OC1M = 0x6u;
return r.R;
});
// Enable TIM1 outputs
TIM1.BDTR.modify([](TIM1_Type::BDTR_DEF & r) -> auto {
r.B.MOE = SET;
//r.B.DTG = 48u; // Dead time 1us
return r.R;
});
// Reload immediately + Trigger DMA
TIM1.SWEVGR.B.UG = SET;
TIM1.DMAINTENR.B.UDE = SET;
// Enable TIM1
TIM1.CTLR1.B.CEN = SET;
}
typedef __SIZE_TYPE__ size_t;
static inline void dma1ch5_init (void * ptr) noexcept {
// Enable DMA
RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto {
r.B.SRAMEN = SET;
r.B.DMA1EN = SET;
return r.R;
});
// DMA5 can be configured to attach to T1UP
// The system can only DMA out at ~2.2MSPS. 2MHz is stable.
DMA1.CNTR5 .R = FULL_LEN;
DMA1.MADDR5.R = reinterpret_cast<size_t>(ptr);
DMA1.PADDR5.R = reinterpret_cast<size_t>(& TIM1.CH1CVR);
NVIC.EnableIRQ (DMA1_Channel5_IRQn);
DMA1.CFGR5.modify([](DMA1_Type::CFGR5_DEF & r) -> auto {
r.B.DIR = SET; // MEM2PERIPHERAL
r.B.PL = 3u; // Highest priority.
r.B.PSIZE = 1u; // 16-bit peripheral
r.B.MSIZE = 1u; // 16-bit memory
r.B.MINC = SET; // Increase memory.
r.B.CIRC = SET; // Circular mode.
r.B.HTIE = SET; // Half-trigger
r.B.TCIE = SET; // Whole-trigger
// Enable DMA1 ch5
r.B.EN = SET;
return r.R;
});
}
PcmDma::PcmDma() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
pInstance = this;
tim1pwm_init ();
dma1ch5_init (buffer);
}