Source file: /~heha/ewa/Reluktanzmotor/maweig-Motor-200831.zip/main.cpp

/*	High-Speed-Motorsteuerung für 2 Motoren im Maschinensatz.
	Davon 1 Reluktanzmotor.
Kodierung: UTF-8 _mit_ BOM, Tabweite: 8, Einrückung: 2
Nur _mit_ BOM transkodiert der Compiler L-Strings korrekt in UTF-16.
Controller:	TMS320F28379D (1 CPU pro Motor)
Board:		LaunchPad + externe Mess- und Leistungselektronik
Autor:		Henrik Haftmann, für Maximilian Weigelt (Login: maweig)

PROBLEME:
* SDFM ungetestet
* Wacklige Programmstruktur, ungeklärt warum es bei manchen Kompilationen
  (gestern) hängt; kein Interrupt von EPWM11.

==== Controller-Peripherie und zugeordnete CPU (1 oder 2) ====
  Interrupts
	1		1,2	(war mal: Resolver)
	3		1,2	MotorControl
	4		1	COM-Port über FT2232H
	5		1,2	(COM-Port über Pfostenleiste und Optokoppler)
	6		1,2	(war mal: Endat und BissC)
  PWM (Pulsweitenmodulator)
	ePWM1-3		1	PWMs für 3 Phasen
	ePWM4-6		2	PWMs für 3 Phasen
	ePWM7			frei (keine Ausgänge verfügbar)
	ePWM8+9		1	Taktgenerator (20 MHz) für ΣΔ-Stromsensoren AMC1204
	ePWM10			frei (beide Ausgänge verfügbar)
	ePWM11		1	Motorsteuer-ISR (10 kHz) + ΣΔ-Synchronisation
	ePWM12			frei (nur Ausgang A verfügbar)
  CAP (Capture/Compare)		(ohne Interesse)

  QEP (Quadratur-Encoder)
	eQEP1		1	Encoder für Motor 1
	eQEP2		2	Encoder für Motor 2 (falls Kupplung des Maschinensatzes versagt)
	eQEP3			(nicht verfügbar)

  SDFM (ΣΔ-Filter-Modul)
	ΣΔ1_CD1		1	Strom 1 U AMC1204
	ΣΔ1_CD2			Strom 1 V
	ΣΔ1_CD3			(nicht verfügbar)
	ΣΔ1_CD4			(nicht verfügbar)
	ΣΔ2_CD1		2	Strom 2 U
	ΣΔ2_CD2			Strom 2 V
	ΣΔ2_CD3			Zwischenkreisspannung oder Strom 2 W
	ΣΔ2_CD4			(nicht verfügbar)

  SPI (Serial Peripheral Interface, Symbol ⇔)
	SPI_A			(beißt sich mit ΣΔ2_CD3)
	SPI_B		1	externer ΣΔ-Dezimierer AMC1210
	SPI_C			(nur auf J9 verfügbar)
  SCI (Asynchron-serielle Schnittstelle)
	SCI_A		1	via FT2232H
	SCI_B		1	(ungenutzt / Debug CPU1)
	SCI_C		2	(ungenutzt / Debug CPU2)
	SCI_D			(ohne Interesse)
  I²C (Inter-IC-Bus)		(ohne Interesse)
  BSP (Buffered Serial Port)	(ohne Interesse)
  CAN (Controller Area Network)	(ohne Interesse)
  USB (Useless Serial Bus)	(nicht verfügbar, nur 12 Mbit/s)
  uPP (Parallelport)		(nicht verfügbar)
  EMIF (External Memory)	(nicht verfügbar + ohne Interesse)

  ADC (Analog-Digital-Wandler) und CMPSS (Komparatoren)
	ADC_A	A13	1	Temperatursensor
		A1		cos 2 (ohne SINCOS 2: D/A-Wandler)
		A2/C1+		LemU 1
		A3		UfbU 1
		A4/C2+		LemU 2
		A5		UfbU 2
	ADC_B	14/C4+	1	sin 1 (ADCIN14) (ohne SINCOS 1: Zwischenkreisspannung?)
		15		sin 2 (ADCIN15) (ohne SINCOS 2: Drehzahl/-Momentvorgabe)
		B2/C3+		LemV 1
		B3		UfbV 1
		B4		LemV 2 (kein Komparator!)
		B5		UfbV 2
	ADC_C	??		frei
		A0/12	1	cos 1 (ohne SINCOS 1: D/A-Wandler)
		C2/C6+		LemW 1
		C3		UfbW 1
		C4/C5+		LemW 2
		C5		UfbW 2
	ADC_D	D4-D5		frei (SMA-Buchsen + Instrumentationsverstärker)
		D0/C7+ - D1	frei (J21-1) - (J21-3)
		D2/C8+ - D3	frei (J21-5) - (J21-7)
	Alle Hi-Referenzen = 2,5 V, alle Lo-Referenzen = 00
	  Das heißt alle negativ werdenden Analogspannungen müssen
	  auf halbe Referenzspannung angehoben werden (Offset).
	  16 Bit geht nur differenziell.
	  Umschaltung nicht innerhalb eines Bursts möglich.
	  Daher läuft ADC_D asynchron zu den drei anderen A/D-Wandlern.
	Ströme werden zuletzt gemessen, um möglichst aktuell zu sein.

  DAC (Digital-Analog-Wandler)
	DacA			(beißt sich mit AdcA0)
	DacB			(beißt sich mit AdcA1)
	DacC			(nicht verfügbar)

  sonstiges
	rote LED	1	GPIO34
	blaue LED	1	GPIO31
	grüne LED	leuchtet immer (3P3)
	COMx (FT2232H)	1	GPIO42 (TxD), GPIO43 (RxD)
	CAN an J12	1	GPIO12 (Tx), GPIO17 (Rx)
  Die LEDs auf der FT232-Seite können nicht vom Controller aus gesteuert werden.

==== Launchpad-Pins ====
(oberes Stiftleistenpaar):
╔═══════╤═══════╦═══════╤═══════╗	╔═══════╤═══════╦═══════╤═══════╗
║	│    3P3║5P	│	║	║PWM1A	│     P0║00	│	║
║	│    P32║00	│	║	║PWM1B	│     P1║P61	│ΣΔ2_C3	║
║(RxD)b	│    P19║Adc14	│sin	║	║PWM2A	│     P2║P123	│ΣΔ1_C1	║
║(TxD)b	│    P18║AdcC3	│UfbW	║	║PWM2B	│     P3║P122	│ΣΔ1_D1	║
║	│    P67║AdcB3	│UfbV	║	║PWM3A	│     P4║RST	│	║
║	│   P111║AdcA3	│UfbU	║	║PWM3B	│     P5║P58	│(MOSI)	║
║ΣΔ2_D3	│    P60║AdcC2	│LemW	║	║tripI	│    P24║P59	│(MISO)	║
║	│    P22║AdcB2	│LemV	║	║ΣΔCout	│    P16║P124	│ΣΔ1_C2	║
║	│   P105║AdcA2	│LemU	║	║PwmDAC1│ (P159)║P125	│ΣΔ1_D2	║
║	│   P104║AdcA0	│cos	║	║PwmDAC2│ (P160)║P29	│	║
╚═══════╧═══════╩═══════╧═══════╝	╚═══════╧═══════╩═══════╧═══════╝

(unteres Stiftleistenpaar):
╔═══════╤═══════╦═══════╤═══════╗	╔═══════╤═══════╦═══════╤═══════╗
║	│    3P3║5P	│	║	║PWM4A	│     P6║00	│	║
║	│    P95║00	│	║	║PWM4B	│     P7║P66	│⇔CS	║
║(RxD)c	│   P139║Adc15	│sin	║	║PWM5A	│     P8║P131	│ΣΔ2_C1	║
║(TxD)c	│    P56║AdcC5	│UfbW	║	║PWM5B	│     P9║P130	│ΣΔ2_D1	║
║	│    P97║AdcB5	│UfbV	║	║PWM6A	│    P10║RST	│	║
║	│    P94║AdcA5	│UfbU	║	║PWM6B	│    P11║P63	│⇔MOSI	║
║⇔SCK	│    P65║AdcC4	│LemW	║	║tripI	│    P14║P64	│⇔MISO	║
║	│    P52║AdcB4	│LemV	║	║ΣΔCout	│    P15║P26	│ΣΔ2_C2	║
║	│    P41║AdcA4	│LemU	║	║PwmDAC3│ (P161)║P27	│ΣΔ2_D2	║
║	│    P40║AdcA1	│cos	║	║PwmDAC4│ (P162)║P25	│	║
╚═══════╧═══════╩═══════╧═══════╝	╚═══════╧═══════╩═══════╧═══════╝

(Encoder 5V:)	QEP_B			QEP_A
		╔═══════╤═══════╗	╔═══════╤═══════╗
		║A	│P54	║	║A	│P20	║
		║B	│P55	║	║B	│P21	║
		║I	│P57	║	║I	│P99	║
		║5P	│	║	║5P	│	║
		║00	│	║	║00	│	║
		╚═══════╧═══════╝	╚═══════╧═══════╝

Verschaltung:
P0 = PWM1A -> Phase A High-Side-Treiber, Low = aktiv (treibt Zwischenkreisspannung)
P1 = PWM1B -> Phase A  Low-Side-Treiber, Low = aktiv (treibt 0 V)
P2 = PWM2A -> Phase B High-Side-Treiber, Low = aktiv (treibt Zwischenkreisspannung)
P3 = PWM2B -> Phase B  Low-Side-Treiber, Low = aktiv (treibt 0 V)
P4 = PWM3A -> Phase C High-Side-Treiber, Low = aktiv (treibt Zwischenkreisspannung)
P5 = PWM3B -> Phase C  Low-Side-Treiber, Low = aktiv (treibt 0 V)
…TODO
*/

#include "Settings.h"
#include "regdef2.h"	// Registerdefinitionen mit Arrays

Comport com0(SciaRegs);

//=============================================================================
//	B - TASK (executed every 200 µs ≙ 5 kHz = F_CPU/40000)
//=============================================================================
static void B() { 	// Toggle GPIO-34
#ifdef CPU1
  static int LedCnt1;
  if (++LedCnt1==200) {	// 200 µs × 200 = 40 ms ≙ 25 Hz
    LedCnt1 = 0;
    GpioDataRegsA.doTOGGLE(34);
//    GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;  // LED blinking (12.5 Hz)
  }
  static int terminaltick;
  if (++terminaltick==1000) {	// 200 ms
    terminaltick = 0;
    Terminal::Update();
  }
#endif
}

// THE BACKGROUND TASK: On overflow of each of the three CPU timer, do something.
// Otherwise, sleeping CPU would be nice to save power.
static void loop() {
  if (CpuTimer0Regs.TCR.bit.TIF==1) {
    CpuTimer0Regs.TCR.bit.TIF = 1;	// clear flag
    Trip::Check();	// A - TASK (executed every 50 µs ≙ 20 kHz = F_CPU/10000)
  }
  if (CpuTimer1Regs.TCR.bit.TIF==1) {
    CpuTimer1Regs.TCR.bit.TIF = 1;	// clear flag
    B();
  }
}

void configGpio(uint8_t pin, unsigned settings) {
  GpioCtrlRegsA[pin>>5].orBits(pin&31,settings);
}
// settings:	[3:0]	mux
//		[7:4]	csel
//		[9:8]	qsel
//		[10]	dir_out
//		[11]	pullup_on
//		[12]	inv
//		[13]	open_drain
//		[14]	lock
void GPIO_CTRL_REGSA::orBits(uint8_t pin, unsigned settings) volatile{
  orMUX(pin,settings&15); settings>>=4;
  orCSEL(pin,settings&15); settings>>=4;
  orQSEL(pin,settings&3); settings>>=2;
  if (settings&1) orDIR(pin); settings>>=1;
  if (settings&1) orPUD(pin); settings>>=1;
  if (settings&1) orINV(pin); settings>>=1;
  if (settings&1) orODR(pin); settings>>=1;
  if (settings&1) orLOCK(pin);
}

void configPwm(volatile EPWM_REGS&regs, Uint16 period, Uint16 slave_phase) {
	// Time Base SubModule Registers
  TBCTL_REG tbctl = {0};
  tbctl.bit.CTRMODE = TB_COUNT_UP;	// 00: Aufwärts
  if (slave_phase) tbctl.bit.PHSEN = TB_ENABLE;	// 1: Phasensynchronisierung erlauben
  else tbctl.bit.SYNCOSEL = TB_CTR_ZERO;	// 01: sync "down-stream" when counter == 0
  tbctl.bit.FREE_SOFT = 0b10;			// 1x: Continue running at emulation events
  regs.TBCTL.all = tbctl.all;
  regs.TBPRD = period-1;	// PWM frequency = 1 / period
	// Action Qualifier SubModule Registers
  AQCTLA_REG aqctla = {0};
  aqctla.bit.ZRO = AQ_SET;	// setzen bei Null
  aqctla.bit.CAU = AQ_CLEAR;	// löschen bei Erreichen des Compare-Wertes -> Normale PWM
  regs.AQCTLA.all = aqctla.all;
  regs.TBPHS.bit.TBPHS = slave_phase;
}

static void configDac(volatile DAC_REGS&regs) {
  regs.DACCTL.bit.DACREFSEL  = 1;	// Referenzspannung
  regs.DACOUTEN.bit.DACOUTEN = 1;	//Enable DAC output
  regs.DACVALS.bit.DACVALS   = 1024;
}

static void configDac() {	// SETUP DACS
  configDac(DacaRegs);
  DacaRegs.DACCTL.bit.LOADMODE = 1;	// enable value change only on sync signal
  DacaRegs.DACCTL.bit.SYNCSEL  = 0;	// sync from pwm 1
  configDac(DacbRegs);
  configDac(DaccRegs);
}

static void calOffsets() {
  Currentsense::resetADCoffset();
  Currentsense::resetSDFMoffset();
  for (int Counter=0; Counter<20000; ) {
    if (EPwm11Regs.ETFLG.bit.INT==1) {
      EPwm11Regs.ETCLR.bit.INT=1;
      if (++Counter>1000) {
        const float K2 = 0.001999;	// Offset filter coefficient: T/(T+0.05);
        Currentsense::integrateSDFMoffset(K2);
        Currentsense::integrateADCoffset(K2);
      }
    }
  }
  Currentsense::setADCoffsetregs();
}

/*********************
 ** Hier geht's los **
 *********************/
void main() {
  SysInit::InitAll();
  configGpioOut(31);		// GPIO31 für blaue LED auf Ausgang
  GpioDataRegsA.doSET(31);	// erstmal AUS
  configGpioOut(34);		// GPIO34 für rote LED auf Ausgang
  // erstmal EIN
// Timing sync for background loops
// Timer period definitions found in device specific PeripheralHeaderIncludes.h
  CpuTimer0Regs.PRD.all = 10000;	// A tasks
  CpuTimer1Regs.PRD.all = 40000;	// B tasks

	// *****************************************
	// Inverter PWM configuration
	// ****************************************
  SyncSocRegs.SYNCSELECT.bit.EPWM4SYNCIN = 0;	//EPwm1SyncOut
  EPwm4Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
  SyncSocRegs.SYNCSELECT.bit.EPWM10SYNCIN = 0;	//EPwm1Sync Out
  EPwm10Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
  Comport::InitAll();
  com0.init(BRR(12000000));	// 12 MBaud ergibt BRR = 1
  com0.send(L"\e[H\e[JStart...");	// synchron; String passt komplett in die Sendewarteschlange (16 Zeichen)
  Adc::InitAll();
  configDac();
  initMotorControl();
  initSigmaDelta();
  PosEnc::InitAll();
  Amc1210::InitAll();
  Trip::InitAll();
  CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;	// jetzt erst legen alle PWM-Module los
  EDIS;
  com0.send(L"\e[1;33mOffsetkalibrierung\e[m...");
  calOffsets();
// ISR Mapping
  EALLOW;
  EPwm11Regs.ETCLR.bit.INT=1;
  asm(" push IER");
  asm(" pop DBGIER");	// All interrupts allowed while real-time debugging
  asm(" clrc INTM,DBGM");	// enable interrupts and debug interrupts
  EDIS;
  com0.send(L"\e[1;32mSchleife\e[m\r\n");
//  - IDLE loop. Just loop forever
  for(;;) loop();	// (Arduino-like)
}
Detected encoding: ASCII (7 bit)8