#include "Settings.h"
#include <cstring>
#include "regdef2.h"
// ************************************************************************
// Scaling factors to bring all current feedbacks to normal scale
// matching with shunt based measurement
// With shunt, 1.0pu current == 9.945A
// LEM, 1.0pu current == 12A
// SDFM, 0.8906pu current == 12.5A
// ************************************************************************
// Achtung!! Das Delfino-Board hat 3 V Referenzspannung, nicht 2,5 V!
const float LEM_TO_SHUNT = 1.206637; // (12.0/9.945)
// ADC Related defines
namespace nsADC{
const float PU_SCALE_FACTOR = 0.000244140625; //1/2^12
const float PU_PPB_SCALE_FACTOR = 0.000488281250; //1/2^11
inline float IFB_SV() {return AdcaResultRegs.ADCRESULT0*PU_SCALE_FACTOR;}
inline float IFB_SW() {return AdcbResultRegs.ADCRESULT0*PU_SCALE_FACTOR;}
inline float IFB_SV_PPB() {return (int)AdcaResultRegs.ADCPPB1RESULT.all*PU_PPB_SCALE_FACTOR;}
inline float IFB_SW_PPB() {return (int)AdcbResultRegs.ADCPPB1RESULT.all*PU_PPB_SCALE_FACTOR;}
inline float R_SIN() {return AdcdResultRegs.ADCRESULT0*PU_SCALE_FACTOR;}
inline float R_COS() {return AdccResultRegs.ADCRESULT0*PU_SCALE_FACTOR;}
inline float R_SIN_PPB() {return (int)AdcdResultRegs.ADCPPB1RESULT.all*PU_PPB_SCALE_FACTOR;}
inline float R_COS_PPB() {return (int)AdccResultRegs.ADCPPB1RESULT.all*PU_PPB_SCALE_FACTOR;}
inline float IFB_LEMV() {return AdcaResultRegs.ADCRESULT1*PU_SCALE_FACTOR;}
inline float IFB_LEMW() {return AdcbResultRegs.ADCRESULT1*PU_SCALE_FACTOR;}
inline float IFB_LEMV_PPB() {return (int)AdcaResultRegs.ADCPPB2RESULT.all*PU_PPB_SCALE_FACTOR;}
inline float IFB_LEMW_PPB() {return (int)AdcbResultRegs.ADCPPB2RESULT.all*PU_PPB_SCALE_FACTOR;}
}
// Offset calibration routine is run to calibrate for any offsets on the opamps
static struct{
float Rsin, // offset in resolver sine fbk channel @ no excitation
Rcos, // offset in resolver cos fbk channel @ no excitation
shntV, // offset in shunt current V fbk channel @ 0A
shntW, // offset in shunt current W fbk channel @ 0A
lemV, // offset in LEM current V fbk channel @ 0A
lemW; // offset in LEM current W fbk channel @ 0A
}offset;
void Currentsense::resetADCoffset() {
std::memset(&offset,0,sizeof offset);
}
void Currentsense::integrateADCoffset(float K2) {
float K1=1-K2;
if (SENSES & bit(SHUNT_CURRENT_SENSE)) {
offset.shntV = K1*offset.shntV + K2*nsADC::IFB_SV(); //Phase A offset
offset.shntW = K1*offset.shntW + K2*nsADC::IFB_SW(); //Phase B offset
}
if (SENSES & bit(LEM_CURRENT_SENSE)) {
offset.lemV = K1*offset.lemV + K2*nsADC::IFB_LEMV();
offset.lemW = K1*offset.lemW + K2*nsADC::IFB_LEMW();
}
if (ENCODERS & bit(SINCOS_ENCODER)) {
offset.Rsin = K1*offset.Rsin + K2*nsADC::R_SIN();
offset.Rcos = K1*offset.Rcos + K2*nsADC::R_COS();
}
}
void Currentsense::setADCoffsetregs() {
EALLOW;
if (SENSES & bit(SHUNT_CURRENT_SENSE)) {
AdcaRegs.ADCPPB1OFFREF = (offset.shntV*4096); // setting shunt Iu offset
AdcbRegs.ADCPPB1OFFREF = (offset.shntW*4096); // setting shunt Iv offset
}
if (ENCODERS & bit(SINCOS_ENCODER)) {
AdccRegs.ADCPPB1OFFREF = (offset.Rcos*4096); // setting encoder cos in offset
AdcdRegs.ADCPPB1OFFREF = (offset.Rsin*4096); // setting encoder sin in offset
}
if (SENSES & bit(LEM_CURRENT_SENSE)) {
AdcaRegs.ADCPPB2OFFREF = (offset.lemV*4096); // setting LEM Iv offset
AdcbRegs.ADCPPB2OFFREF = (offset.lemW*4096); // setting LEM Iw offset
}
EDIS;
}
void Currentsense::readShunt() {
As = nsADC::IFB_SV_PPB();
Bs = nsADC::IFB_SW_PPB();
Cs = -As -Bs;
}
void Currentsense::readLEM() {
As = nsADC::IFB_LEMV_PPB() * LEM_TO_SHUNT;
Bs = nsADC::IFB_LEMW_PPB() * LEM_TO_SHUNT;
Cs = -As -Bs;
}
RAMFUNC void adcGetSinCos(float sincos[2]) {
sincos[0] = nsADC::R_SIN_PPB();
sincos[1] = nsADC::R_COS_PPB();
}
static void configureADC() {
//Write ADC configurations and power up the ADC for both ADC A
for (int i=0; i<4; i++) {
volatile ADC_REGSA®s=AdcRegsA[i];
// External REFERENCE must be provided
regs.CTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
regs.CTL2.bit.RESOLUTION = 0; // 12 bit
regs.CTL2.bit.SIGNALMODE = 0; // SIGNAL_SINGLE
//Set pulse positions to late
regs.CTL1.bit.INTPULSEPOS = 1;
//power up the ADC
regs.CTL1.bit.ADCPWDNZ = 1;
}
//delay for > 1ms to allow ADC time to power up
for (unsigned i = 0; i < 1000; i++) asm(" RPT#255 || NOP");
}
// Objektorientierter Nachbau von F2837xD_TempSensorConv.c
static struct TempSensor{
float slope; // Steilheit (aus OTP-ROM)
float offset; // Offset (aus OTP-ROM)
float scaleFactor; // Vorskalierung des A/D-Wertes bei Referenzspannung != 2,5 V
void init();
float getTempC(int16_t adcvalue);
TempSensor(float Uref):slope(5196.0/32768),offset(1788),scaleFactor(Uref/2.5) {}
}tempsensor(3.0);
//for pre-production devices, use these static values for slope and offset
//need to remember VREFHI voltage so that sensor readings can be scaled
//to match 2.5V values used for calibration data.
void TempSensor::init() {
AnalogSubsysRegs.TSNSCTL.all = 1;
// DELAY_US(1000);
//check the device revision
if(DevCfgRegs.REVID >= 3) {
//for production devices (Rev. C), pull the slope and offset from OTP
slope = (*(int(*)())0x7036E)()/32768.0; // geheimnisvolle Funktion liefert Q15-Format
offset = (*(int(*)())0x70372)(); // geheimnisvolle Funktion liefert Integer
}
}
//This function uses the reference data stored in OTP to convert the raw temperature
//sensor reading into degrees C
float TempSensor::getTempC(int16 adcvalue) {
return (scaleFactor*adcvalue-offset)*slope;
}
float Adc::myGetTemperatureC(int16_t adcvalue) {return tempsensor.getTempC(adcvalue);}
static void configAdcChannels() {
tempsensor.init();
//Select the channels to convert and end of conversion flag
// Analog signals that are sampled
// SOC 0 1 2 3 4 5
// Adca: A13 A1 A2 A3 A4 A5
// Adcb: 14 15 B2 B3 B4 B5
// Adcc: A0/12 A0/12 C2 C3 C4 C5
// Adcd: D0-D1 D2-D3 D4-D5 (asynchron)
static const uint16_t chsel[6]={
0x0CED,0x2CF1,0x4222,0x0333,0x2444,0x4555}; // Nibbles für A/D-Wandler d..a
for (int i=0; i<4; i++) {
volatile ADC_REGSA®s=AdcRegsA[i];
// regs.BURSTCTL.bits.BURSTEN = 1;
// regs.BURSTCTL.bits.BURSTSIZE = 6-1;
// regs.BURSTCTL.bits.BURSTTRIGSEL = 5; // trigger on ePWM1 SOCA/C
for (int j=0; j<6; j++) {
regs.SOCCTL[j].bit.CHSEL = chsel[j]>>(i<<2);
regs.SOCCTL[j].bit.ACQPS = 30; // sample window in SYSCLK cycles
regs.SOCCTL[j].bit.TRIGSEL = 5; // trigger on ePWM1 SOCA/C
}
regs.rsvd5[3]=0x7000; // geheimnisvoll!!
}
AdcdRegsA.CTL2.bit.SIGNALMODE = 1; // differenziell
AdcdRegsA.CTL2.bit.RESOLUTION = 1; // 16 Bit
// AdcdRegsA.BURSTCTL.bits.BURSTSIZE = 3-1;
// Weil LemV2 = B4 (=Adcb Eingang 4) als einziges Stromsignal
// kein Komparator-Modul CMPSS hat, hier einen digitalen Komparator ansetzen
AdcbRegsA.PPB[0].CONFIG.all = 4; // dem SOC4 zuordnen
AdcbRegsA.PPB[0].TRIPHI.all = 0xFF0; // noch nicht auslösen
AdcbRegsA.PPB[0].TRIPLO.all = 0x010; // noch nicht auslösen
}
static void linkPwm2Adc(volatile EPWM_REGS®s) {
regs.ETSEL.bit.SOCASEL = ET_CTR_PRD; // Select SOC from counter at ctr = 0
regs.ETPS.bit.SOCAPRD = ET_1ST; // Generate pulse on 1st even
regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
}
void Adc::InitAll() {
configureADC();
configAdcChannels();
linkPwm2Adc(EPwm1Regs);
}
Detected encoding: ASCII (7 bit) | 8
|