#include "pwmclass.h" #include "gpio.h" typedef __SIZE_TYPE__ size_t; extern "C" { [[gnu::interrupt]] extern void DMA1_Channel2_IRQHandler( void ); }; static PwmClass * pInstance = nullptr; void DMA1_Channel2_IRQHandler( void ) { DMA1_Type::INTFR_DEF state (DMA1.INTFR); if (state.B.GIF2 != RESET) { DMA1.INTFCR.B.CGIF2 = SET; } else return; if (state.B.HTIF2 != RESET) { DMA1.INTFCR.B.CHTIF2 = SET; if (pInstance) pInstance->send(false); } if (state.B.TCIF2 != RESET) { DMA1.INTFCR.B.CTCIF2 = SET; if (pInstance) pInstance->send(true); } } /* * initialize TIM2 for PWM */ inline void PwmClass::TimInit() noexcept { // Enable GPIOA and TIM1 RCC.APB2PCENR.modify([] (RCC_Type::APB2PCENR_DEF & r) -> auto { r.B.IOPAEN = SET; r.B.IOPBEN = SET; //r.B.AFIOEN = SET; return r.R; }); RCC.APB1PCENR.B.TIM2EN = SET; // PA2 is TIM2_CH3, 10MHz Output alt func, push-pull GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.CNF2 = 2u; r.B.MODE2 = 1u; return r.R; }); // PB1 is DEN, active H Output 10 MHz, push-pull GPIOB.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.CNF1 = 0u; r.B.MODE1 = 1u; return r.R; }); GPIOB.BSHR.B.BS1 = SET; // set to H // Reset TIM2 to init all regs RCC.APB1PRSTR.B.TIM2RST = SET; RCC.APB1PRSTR.B.TIM2RST = RESET; // CTLR1: default is up, events generated, edge align // SMCFGR: default clk input is CK_INT // Prescaler TIM2.PSC.R = 0u; // 144 MHz // Auto Reload - sets period TIM2.ATRLR.R = MAXPWM - 1; // 24 kHz // CH3 Mode is output, PWM1 (CC3S = 00, OC3M = 110) TIM2.CHCTLR2_Output.modify([](TIM2_Type::CHCTLR2_Output_DEF & r) -> auto { r.B.OC3M = 0x6u; return r.R; }); // Enable TIM1 outputs TIM2.CCER.modify([](TIM2_Type::CCER_DEF & r) -> auto { // Enable CH3, CH3 output, positive pol r.B.CC3E = SET; //r.B.CC3P = SET; // negative return r.R; }); // Reload immediately + Trigger DMA TIM2.SWEVGR.B.UG = SET; TIM2.DMAINTENR.B.UDE = SET; } inline void PwmClass::DmaInit() noexcept { // Enable DMA RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto { r.B.SRAMEN = SET; r.B.DMA1EN = SET; return r.R; }); // DMA can be configured to attach to T2UP // The system can only DMA out at ~2.2MSPS. 2MHz is stable. DMA1.CNTR2 .R = FULL_LEN; DMA1.MADDR2.R = reinterpret_cast(buffer); DMA1.PADDR2.R = reinterpret_cast(& TIM2.CH3CVR); NVIC.EnableIRQ (DMA1_Channel2_IRQn); DMA1.CFGR2.modify([](DMA1_Type::CFGR2_DEF & r) -> auto { r.B.DIR = SET; // MEM2PERIPHERAL r.B.PL = 2u; // High 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 CH2 r.B.EN = SET; return r.R; }); } PwmClass::PwmClass() noexcept : count(0u), pL(buffer), pH(buffer + HALF_LEN), src(nullptr) { pInstance = this; TimInit (); DmaInit (); // Enable TIM2 TIM2.CTLR1.B.CEN = SET; }