#include "hea.h"
namespace caliper{
static uint32_t dmabuf[2]; // ab der Mitte von dmabuf[0] genutzt
// <inline> für schnelle Interrupt-Abarbeitung
static inline void dma_spi_rearm() {
DMA1_Channel2->CCR = 1<<10 // 16 Bit Speicher
|1<<8 // 16 Bit Peripherie (Seite 742: „must be accessed in words or half-words“)
|1<<7 // Speicher-Inkrement
|1<<5 // Auto-Reload (für CNDTR)
|1<<1 // Interrupt bei voller Transferlänge
|1<<0; // Freigabe
SPI1->CR1 = SPI_CR1_DFF // 16 Bit
|SPI_CR1_LSBFIRST // LSB zuerst
|SPI_CR1_RXONLY // Nichts senden
|SPI_CR1_SSM // Software-Slave-Select, SSI = 0
|SPI_CR1_SPE // aktivieren
|SPI_CR1_CPOL // Takt = H in Ruhe durch Invertierung
|SPI_CR1_CPHA; // Datenübernahme bei zweiter (steigender) Flanke
SPI1->CR2 = SPI_CR2_RXDMAEN;
}
static void dma_spi_arm() {
DMA1_Channel2->CPAR = uint32_t(&SPI1->DR);
DMA1_Channel2->CMAR = uint32_t(dmabuf)+2;
DMA1_Channel2->CNDTR = 3; // 48 Bit = 3 Halbwörter
dma_spi_rearm();
}
//ISR: Prüft ob eine Pause bei der SPI-Datenübertragung vorliegt: Dann Daten gültig
//Dauer: 0,9 µs ≈ 65 Takte (elend viel!)
static void tim_end() {
// debug::isrstart();
TIM4->SR = 0; // Interrupt bestätigen
BB_BIT(SPI1->CR1,8)=1; // Slave-Select High (nur das setzt den Bitzähler zurück!)
if (!(SPI1->SR&SPI_SR_RXNE)) { // kein weiteres Halbwort eingetrudelt?
repI.ms = dmabuf[1]>>11; // gültige Daten liefern
BB_BIT(repI.flags,5) = 1; // gültig markieren und Push-Nachricht
};
dma_spi_rearm(); // Neustart veranlassen
// debug::isrend();
}
//ISR: DMA (6 Byte) fertig: DMA beenden und Timer4 im Einzelschuss starten
//Dauer: 150 ns ≈ 11 Takte
static void dma_end() {
// debug::isrstart();
DMA1_Channel2->CCR = 0; // DMA Halt
DMA1->IFCR = DMA_IFCR_CGIF2; // Alle Arten von DMA-Interrupts Kanal 2 bestätigen
TIM4->CR1 = TIM_CR1_OPM|TIM_CR1_CEN; // Etwas warten und nachsehen ob alles in Ordnung ist
// debug::isrend();
}
// Die Portpins und RCC sind bereits initialisiert!
void init() {
TIM4->PSC = 72-1; // Takt = 1 MHz
TIM4->ARR = 200-1; // 200 µs Wartezeit
TIM4->DIER= TIM_DIER_UIE; // Interrupt bei „Update“ = CNT==ARR -> CNT==0
vtbl[16+TIM4_IRQn]=tim_end;
NVIC_EnableIRQ(TIM4_IRQn);
vtbl[16+DMA1_Channel2_IRQn]=dma_end;
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
//SPI1 ist fest mit DMA1C2 verknüpft!
dma_spi_arm();
}
}//namespace
void pwm::init() {
auto&t=*TIM2;
t.PSC = 0;
t.ARR = 0xFFF; // 12 Bit für PWM-Frequenz 72 MHz/4096 ≈ 17,6 kHz
t.CCR4 = 0x800;
t.CCMR2 = 6<<12|1<<11; // PWM-Modus für OC4 mit Preload-Modus
t.CCER = TIM_CCER_CC4E; // OC4 aktivieren
t.EGR = TIM_EGR_UG;
t.CR1 = TIM_CR1_CEN; // Timer2 starten, startet PWM-Ausgabe
}
Detected encoding: UTF-8 | 0
|