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

#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&regs=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&regs=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&regs) {
  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