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

90 lines
3.1 KiB
C++

#include "STM32F0x1.h"
#include "CortexM0.h"
#include "gpio.h"
#include "pcmdma.h"
typedef __SIZE_TYPE__ size_t;
/* TIMER:
* fs = 8000Hz, ft = 3 * fs = 24000Hz
* reload = SystemCoreClock / ft = 48000000Hz / 24000Hz = 2000
* PINY : +PA9[AF2], -PB0[AF2] => TIM1:CH2
* DMA : TIM1_UP = 5
*/
static void Dma1Ch5Init (void * addr) {
// Configure the peripheral data register address etc
DMA1. CPAR5.R = reinterpret_cast<size_t> (& (TIM1.CCR2));
DMA1. CMAR5.R = reinterpret_cast<size_t> (addr);
DMA1.CNDTR5.R = FULL_LEN;
// Configure increment, size, interrupts and circular mode
DMA1.CCR5.modify([](auto & ccr) -> auto {
ccr.B.MINC = SET;
ccr.B.MSIZE = 1u;
ccr.B.PSIZE = 1u;
ccr.B.DIR = SET;
ccr.B.HTIE = SET; // Po půlce přerušit.
ccr.B.TCIE = SET; // Po dokončení přerušit.
ccr.B.CIRC = SET;
ccr.B.EN = RESET;
return ccr.R;
});
}
static PcmDma * PcmDmaInstance = nullptr;
PcmDma::PcmDma() noexcept : pL(buffer), pH(buffer + HALF_LEN) {
PcmDmaInstance = this;
const GpioClass de (GpioPortA, 12);
de << true; // použitý hardware používá jako budič sluchátek 75176 (RS485), nutno vybavit
for (unsigned n=0; n<FULL_LEN; n++) buffer[n] = MAXPWM >> 1;
GpioClass pin1p (GpioPortA, 9, GPIO_Mode_AF);
GpioClass pin1n (GpioPortB, 0, GPIO_Mode_AF);
pin1p.setAF (2);
pin1n.setAF (2);
// 1. Enable clock peripheral
RCC.APB2ENR.B.TIM1EN = SET;
RCC.AHBENR. B.DMA1EN = SET;
// 2. Timer
TIM1.PSC.R = 0u;
TIM1.ARR.R = MAXPWM - 1;
TIM1.RCR.R = 0u;
// OC preload, CC output, Mode 6 = PWM1
TIM1.CCMR1_Output.modify([](TIM1_Type::CCMR1_Output_DEF & r) -> auto {
r.B.OC2PE = SET;
r.B.OC2M = 6u;
return r.R;
});
// povol pin + negaci
TIM1.CCER.modify([](TIM1_Type::CCER_DEF & r) -> auto {
r.B.CC2E = SET;
r.B.CC2NE = SET;
return r.R;
});
// Set Output, dead time
TIM1.BDTR.modify([](TIM1_Type::BDTR_DEF & r) -> auto {
//r.B.DTG = 48u; // dead: 1 us
r.B.MOE = SET; // Main output enable
//r.B.OSSR = 1u; // Off-state selection for Run mode - TODO
return r.R;
});
// Preload
TIM1.CR1.modify([](TIM1_Type::CR1_DEF & r) -> auto {
r.B.ARPE = SET; // TIM1_ARR register is buffered
r.B.URS = SET; // Only counter overflow/underflow generates an update DMA request
return r.R;
});
/* Update DMA request enable
* Spustíme DMA - sice budou dlouhé buffery, ale přerušení jen po 20ms */
TIM1.EGR.B.UG = SET; // Reinitialize the counter and generates an update of the registers
TIM1.DIER.B.UDE = SET; // Update DMA request enabled
Dma1Ch5Init (buffer);
// 3. NVIC
NVIC_EnableIRQ (DMA1_CH4_5_6_7_DMA2_CH3_4_5_IRQn);
TIM1.CR1.R |= 1u; // enable TIM1 (překladač bohužel bere poslední bit jako half, registr to neunese)
DMA1.CCR5.R |= 1u; // enable DMA (dtto)
}
// Přerušení od DMA
extern "C" void DMA1_CH4_5_6_7_DMA2_CH3_4_5_IRQHandler (void) {
DMA1_Type::ISR_DEF status (DMA1.ISR);
DMA1.IFCR.R = status.R; // clear flags
if (!PcmDmaInstance) return;
if (status.B.HTIF5 != RESET) PcmDmaInstance->send(false);
else if (status.B.TCIF5 != RESET) PcmDmaInstance->send(true);
}