#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(ptr); DMA1.PADDR5.R = reinterpret_cast(& 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); }