/* 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®s, 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®s) {
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
|