/******************************************************************************
* (c) Copyright 2011 Biricha Digital Power Limited
* DATEI : main.c
* AUTOR : Dr. A. Shirsavar / Dr. C. Hossack
* PROJEKT : Piccolo A DPCM
* Zielsystem : MCU C2802x
* ERSTELLUNGSDATUM : 14.11.2011
* COPYRIGHT : Copyright Biricha Digital Power Limited 2011
* Alle Rechte vorbehalten. Eine vollständige oder teilweise Vervielfältigung
* ist untersagt, sofern keine ausdrückliche schriftliche
* Genehmigung des Inhabers der Urheberrechte vorliegt.
* BESCHREIBUNG :
*
* In diesem Projekt wird die spitzenstromgeführte Regelung eines BDP-105-Abwärtswandler-Boards
* mit einem Mikrocontroller Piccolo A von Texas Instruments vorgeführt.
*
* Auf der MCU wird ein 2p2z-Controller (2 Pole, 2 Nullstellen) ausgeführt und es wird ein Anstiegsausgleich
* zur Beseitigung von subharmonischen Schwingungen realisiert. Der Komparator 2 der Piccolo-MCU wird zur Erkennung
* des Spitzenstrom-Sollwerts verwendet.
*
* Die Phasen- und Verstärkungsreserve der digitalen Stromversorgungseinheit wurden mit einem
* Frequenzantwort-Analysator gemessen:
*
* Phasenreserve = 65°
* Durchtrittsfrequenz = 10 kHz
* Schaltfrequenz = 200 kHz
*
* WICHTIG: Das Board BDP-105 sollte an Port 1 der Tochterkarte angeschlossen werden.
* Der Schaltstrom IL muss an den nicht-invertierenden Pin des Komparators
* der Piccolo-MCU angeschlossen werden. Diese Verbindung ist auf der Tochterkarte nicht implementiert.
* Daher muss eine Verbindungsleitung vom IL-Pin der Tochterkarte
* (d. h. A/D-Wandler-Pin B0) zum nicht-invertierenden Pin des Komparators 2 (d. h. A/D-Wandler-Pin A4) verlegt werden.
* Fragen Sie einen Referenten nach einer Verbindungsleitung und richten Sie die Verbindung ein.
*
* LINKS
* file:///C:/tidcs/c28/CSL_C2802x/v100/doc/CSL_C2802x.pdf
******************************************************************************/
/****************************** ABSCHNITT MIT #include-DIREKTIVEN *****************************/
typedef unsigned int Uint16;
typedef unsigned long Uint32;
#include "DSP2802x_Comp.h"
#include "DSP2802x_EPwm.h"
#include "csl.h"
/**************************** ABSCHNITT MIT DEKLARATIONEN ***************************/
/* Einrichten der Koeffizienten für den 2p2z-Controller des Abwärtswandlers BDP-105
* mit einer Schaltfrequenz von 200 kHz und einer Durchtrittsfrequenz von 10 kHz
*/
#define K (54.3563)
#define REF (_IQ15toF(2048))
#define MIN_DUTY 0
#define MAX_DUTY 65535
#define A1 +1.8069498069
#define A2 -0.8069498069
#define B0 +1.1409584360
#define B1 +0.0695049698
#define B2 -1.0714534663
#define PERIOD_NS 5000 /*Unsere Periodendauer in ns für fs = 200kHz*/
/************************** ABSCHNITT NACH DEKLARATIONEN ************************/
/* Datenabgleich mit Speicher vor Instanziierung eines 2p2z-Controllers. */
#pragma DATA_ALIGN ( MyCntrl , 64 );
/* Dadurch wird ein 2p2z-Controller namens MyCntrl deklariert*/
CNTRL_2p2zData MyCntrl;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// GLOBAL VARIABLES
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
uint16_t slope;
/******************************************************************************
* FUNKTION : IsrAdc
* BESCHREIBUNG :
* Dieser Interrupt wird aufgerufen, wenn die Ablaufsteuerung des A/D-Wandlers das Abtasten beendet hat.
******************************************************************************/
interrupt void IsrAdc( void )
{
/* Setzen des GPIO-Pins 12, der mit Testpin TZ auf der Hardware verbunden ist*/
GPIO_set( GPIO_12);
/* Bestätigen der Gruppe und des Interrupts ADC SEQ. Reaktivierung der A/D-Wandler-Interrupts -Int1*/
ADC_ackInt( ADC_INT_1 );
/* Mit diesen drei Zeilen wird der A/D-Wandler gelesen, der 2p2z-Controller aufgerufen und dann
* der Lastzyklus entsprechend aktualisiert.
*/
MyCntrl.Fdbk.m_Int = ADC_getValue(ADC_MOD_1);
CNTRL_2p2z(&MyCntrl);
/* Speist den „anfänglichen" geforderten Stromwert (vom 2p2z-Controller)
* in den D/A-Wandler des Komparators, d. h. den geforderten Strom, bevor
* der Anstiegsausgleich am invertierenden Pin des auf dem Board integrierten
* Komparators 2 anliegt. Der Anfangswert des D/A-Wandlers wird später vom Zähler des Anstiegsausgleichs-Algorithmus
* des D/A-Wandlers aktualisiert.
*/
CMP_setRampMax( CMP_MOD_2, MyCntrl.Out.m_Int );
/* Löschen von GPIO-Pin 12*/
GPIO_clr( GPIO_12);
/* Einrichten des Softstarts*/
CNTRL_2p2zSoftStartUpdate(&MyCntrl);
}
/******************************************************************************
* FUNKTION : main
* BESCHREIBUNG :
*
******************************************************************************/
void main( void )
{
/* Initialisieren von MCU, A/D-Wandler und GPIO12*/
SYS_init();
ADC_init();
GPIO_config( GPIO_12, GPIO_DIR_OUT, false );
/* Setzen von PWM_MOD_1 auf fs = 200 kHz. „PWM1 Ch A" wird für das Schalten
* des Wandlers verwendet. „PWM1 Ch B" wird für Timing-Zwecke verwendet. Später mehr
* dazu.
*/
PWM_config( PWM_MOD_1, PWM_nsToTicks(PERIOD_NS), PWM_COUNT_UP );
PWM_pin( PWM_MOD_1, PWM_CH_A, GPIO_NON_INVERT );
PWM_pin( PWM_MOD_1, PWM_CH_B, GPIO_NON_INVERT );
/* Für eine digitale, stromgeführte Regelung wird die Last von PWM-Kanal A typischerweise auf 100 % gesetzt.
* Anschließend wird die zyklische Auslösefunktion dazu verwendet, den PWM-Pin auf Low-Pegel zu setzen,
* sobald der Strom den geforderten Spitzenwert erreicht. Aus Sicherheitsgründen haben wir hier allerdings
* die maximale Last auf 60 % gesetzt, d. h. wenn Ihr Regelalgorithmus fehlschlägt, wird der PWM
* nach 60 % zurückgesetzt, statt 100 % zu halten.
*/
PWM_setDutyA(PWM_MOD_1, PWM_nsToTicks(PERIOD_NS)*0.6 );
/* PWM1-Kanal A wird für die PWM-Ansteuerung des MOSFETs verwendet. Daher müssen
* die Abtastung, die Umwandlung, die A/D-Wandler-Interrupt-Eingabe, der 2p2z-Controller, der Verstärkungswert, der D/A-Wandler und
* der Komparator noch eingerichtet werden, bevor PWM1-Kanal A in den High-Pegel wechselt. Somit wird also
* der PWM1-Kanal B für das Starten des Abtastvorgangs verwendet. Die fallende Flanke
* von PWM1-Kanal B wird für das Starten des Abtastvorgangs verwendet.
* Danach folgen alle relevanten Berechnungen. Daher sollte die Last von Kanal B so gesetzt werden, dass
* alle Abtastvorgänge und Berechnungen abgeschlossen werden, noch bevor der PWM1-Kanal A in den High-Pegel wechselt.
* Hierfür wurden mit dem Oszilloskop 2,45 µs gemessen.
*
* <---PERIOD_NS-->
* ___ ___
* PWM A: _______| |___________| |___________|
*
* PERIOD_NS-2450
* ________<-----> ________
* PWM B: _______| |______| |______|
* ^ ^
* Hier löst PWM B den ADC SOC aus^ ^ Hier startet PWM B den CLA-Anstiegsausgleich
* Diese fallende Flanke muss so für den nächsten
* angepasst werden, Zyklus
* dass alle Berechnungen abgeschlossen sind,
* bevor der nächste Zyklus beginnt
* (d. h. vor der nächsten ansteigenden Flanke).
*/
/* Mit dieser Funktion wird der PWM1-Kanal B so eingerichtet, dass Berechnungen
* genau vor der Anstiegsflanke PWM B abgeschlossen sind. PERIOD_NS ist die Periodendauer
* und hier auf 5000 ns gesetzt. Daher setzen wir die Impulsbreite hier auf (5000–2450) ns.
*/
PWM_setDutyB(PWM_MOD_1, PWM_nsToTicks( PERIOD_NS-2500 ) );
/* Legt „PWM Mod1" so fest, dass die A/D-Wandlung immer dann beginnt,
* wenn der Timebase-Zähler von PWM1-Kanal B mit der Last von Kanal B übereinstimmt, d. h. wenn die fallende Flanke
* von PWM-Kanal B ADC SoC auslöst, wie oben beschrieben.
*/
PWM_setAdcSoc( PWM_MOD_1, PWM_CH_B, PWM_INT_CMPB_UP );
/* Legt „PWM Mod1" so fest, dass ein Interrupt für jeden PWM-Zyklus erzeugt wird,
* sobald der Timebase-Zähler = 0. Die „0" anstelle einer ISR-Funktion bedeutet,
* dass ein Interrupt erzeugt wird, aber nicht zur ISR-Funktion gewechselt wird.
* Der CLA erkennt diesen Interrupt und führt stattdessen den CLA-Code aus. Zu guter Letzt
* gibt PWM_INT_PRD_1 an, dass ein Interrupt in jedem Zyklus erzeugt werden soll
* statt in jedem zweiten Zyklus.
*/
PWM_setCallback(PWM_MOD_1, 0, PWM_INT_ZERO, PWM_INT_PRD_1 );
/* Speist das Ausgangssignal von Komparator Mod2 in PWM Mod1
* und aktiviert das Austasten durch Setzen des digitalen Compare-Ereignisses
* PWM_DCEVT zum richtigen Zeitpunkt. Hier wird PWM_DCEVT später zum Auslösen von
* PWM verwendet.
* Der Eingang zum Austastblock ist nicht-invertierend und mit „true" ist sichergestellt,
* dass der Ausgang nicht mit dem Timebase-Takt des PWM
* synchronisiert wird.
*/
PWM_configBlanking( PWM_MOD_1, PWM_CMP_COMP2, GPIO_NON_INVERT, true );
/* Setzen der Dauer des Austastfensters auf 420 ns*/
PWM_setBlankingWindow( PWM_MOD_1, PWM_nsToTicks(420) );
/* setzt die relevanten Auslösezonen: D. h. wenn PWM_DCEVT eintritt,
* wird PWM1-Kanal A zyklisch gelöscht, aber es gibt keine Auswirkungen auf PWM1-Kanal B.
* PWM_DCEVT wurde in PWM_configBlanking() eingerichtet.
*/
PWM_setTripZone( PWM_MOD_1, PWM_DCEVT, PWM_TPZ_CYCLE_BY_CYCLE );
PWM_setTripState( PWM_MOD_1, PWM_CH_A, GPIO_CLR );
PWM_setTripState( PWM_MOD_1, PWM_CH_B, GPIO_NO_ACTION );
/* Konfigurieren des A/D-Wandlers für das Abtasten von Vo, wenn dieser von der fallenden Flanke von PWM1-Kanal B ausgelöst wird
*/
ADC_config( ADC_MOD_1, ADC_SH_WIDTH_7, ADC_CH_B2, ADC_TRIG_EPWM1_SOCB );
/* Wenn Umwandlung abgeschlossen, Interrupt aufrufen und zu „IsrAdc" wechseln.*/
ADC_setCallback( ADC_MOD_1, IsrAdc, ADC_INT_1 );
/* Initialisieren der 2p2z-Regelstruktur (2 Pole, 2 Nullstellen)*/
CNTRL_2p2zInit(&MyCntrl
,_IQ15(REF)
,_IQ26(A1),_IQ26(A2)
,_IQ26(B0),_IQ26(B1),_IQ26(B2)
,_IQ23(K),MIN_DUTY,MAX_DUTY
);
/* Konfigurieren des Komparators Mod2 ohne Qualifizierungsfenster,
* d. h. asynchron. Der Komparatorausgang ist nicht-invertierend und der invertierende
* Eingang des Komparators ist an den internen D/A-Wandler angebunden.
*/
CMP_config( CMP_MOD_2, CMP_ASYNC, GPIO_NON_INVERT, CMP_DAC );
/* Zähler-Submodul des D/A-Wandlers wird konfiguriert
* Dadurch wird ein Anstieg auf dem Stromreferenzsignal anhand einer
* digitalen Treppenkurve erzeugt.
*/
CMP_rampConfig( CMP_MOD_2, PWM_MOD_1 );
decval = CMP_calcRampDec( CMP_mVtoRampValue(124), PWM_freqToTicks(200000) );
CMP_setRampDec( CMP_MOD_2, decval );
/* Einrichten eines 500-ms-Softstarts*/
CNTRL_2p2zSoftStartConfig(&MyCntrl, 500, PERIOD_NS );
/* Aktivieren globaler Interrupts und Warten in Leerlaufschleife*/
INT_enableGlobal(true);
while(1)
{
}
}