Quelltext /~heha/mb-iwp/Antriebe/Linak-Servo/hea-fw-230331.zip/caliper.cpp

#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
}
Vorgefundene Kodierung: UTF-80