2024-03-09 11:10:52 +01:00
|
|
|
#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;
|
2024-03-09 12:20:35 +01:00
|
|
|
const GpioClass de (GpioPortA, 12);
|
|
|
|
de << true; // použitý hardware používá jako budič sluchátek 75176 (RS485), nutno vybavit
|
2024-03-09 11:10:52 +01:00
|
|
|
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 {
|
2024-03-09 12:20:35 +01:00
|
|
|
//r.B.DTG = 48u; // dead: 1 us
|
2024-03-09 11:10:52 +01:00
|
|
|
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);
|
|
|
|
}
|