This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

F28335 ADC Setup for PMSM Sensorless

Other Parts Discussed in Thread: CONTROLSUITE

I've modified the HVPM_Sensorless_2833x project provided with controlSUITE in the HVMotorCtrl+PfcKit_v2.1 folder to work with a Semikron SKAI2-LV device.  I'm having trouble understanding if I have the ADC's setup correctly.  I've combed through the documentation and SPRU812A to try to understand what is coded and if it is performing what I need done.

 

First, let me walk through the code I have.

 

HVPM_Sensorless.c:

...

// Default ADC initialization

int ChSel[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

int TrigSel[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

int ACQPS[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

...

void main(void) {

...

// Initialize ADC for Semikron SKAI2-LV

ChSel[0] = 0;   // ChSelect: ADC A0 -> CS_AnalL1; Analog Value from Current Sensor Leg-U

ChSel[1] = 8;   // ChSelect: ADC B0 -> CS_AnalL3; Analog value from Current Sensor Leg-W

ChSel[2] = 2;   // ChSelect: ADC A2 -> PM_AnaUL1; Phase Voltage U

ChSel[3] = 3;   // ChSelect: ADC A3 -> PM_AnaUL2; Phase Voltage V

ChSel[4] = 4;   // ChSelect: ADC A4 -> PM_AnaUL3; Phase Voltage W

ChSel[5] = 9;   // ChSelect: ADC B1 -> PM_Ana_UDcl; Analog Voltage value from DC-Link

ChSel[6] = 10;  // ChSelect: ADC B2 -> Battery_Voltage; Analog value UCC_IN voltage

ChSel[7] = 1;   // ChSelect: ADC A1 -> 1V5P_REF; 1.5V Reference voltage for the current sensors

ChSel[8] = 11;  // ChSelect: ADC B3 -> DCB_Temp_Inverter; Analog value from DCB temperature sensor

ChSel[9] = 12;  // ChSelect: ADC B4 -> Motor_Temp_Inverter; Analog value from motor temperature sensor

ChSel[10] = 5;  // ChSelect: ADC A5 -> GPxO_AnalGpxo1; Analog value from current sensor of GPxO1

ChSel[11] = 6;  // ChSelect: ADC A6 -> GPxO_AnalGpxo2; Analog value from current sensor of GPxO2

ChSel[12] = 7;  // ChSelect: ADC A7 -> GPxO_AnalGpxo3; Analog value from current sensor of GPxO3

ChSel[13] = 13; // ChSelect: ADC B5 -> GPAI_AnaUPot1; Analog value from GPAI1

ChSel[14] = 14; // ChSelect: ADC B6 -> GPAI_AnaUPot2; Analog value from GPAI2

ChSel[15] = 15; // ChSelect: ADC B7 -> GPAI_AnaUPot3; Analog value from GPAI3

 

// Initialize ADC module

ADC_MACRO_INIT(ChSel, TrigSel, ACQPS)

 

...

}

 

The ADC_MACRO_INIT definition is located in the file f2833xileg_vdc.h.  In this file, the ChSel was originally only a 1x8 array, which I now have as a 1x16.  As such, the code for the ADC_MACRO_INIT looks like the following:

 

/* ==================================================================================

File name: F2833XILEG_VDC.H

Target    : TMS320F2833X family

===================================================================================*/

 

#ifndef __F2833XILEG_VDC_H__

#define __F2833XILEG_VDC_H__

 

/*------------------------------------------------------------------------------

ADC Initialization Macro Definition

------------------------------------------------------------------------------*/

 

extern void DSP28x_usDelay(unsigned long Count);

extern void ADC_cal();

#define CPU_CLOCK_SPEED     15.000L   // 10.000L for a 100MHz CPU clock speed

#define ADC_usDELAY 50000L

#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_CLOCK_SPEED) - 9.0L) / 5.0L)

 

#define ADC_MACRO_INIT(ChSel,Trigsel,ACQPS)                                                                                                   \

                                                                                                                                                                                      \

                EALLOW;                                                                                                                                                      \

                SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;                                                                                                \

                ADC_cal();                                                                                                                                                     \

                EDIS;                                                                                                                                                             \

                                                                                                                                                                                       \

                AdcRegs.ADCTRL3.all = 0x00E0; /* Power up bandgap/reference/ADC circuits*/                                      \

                DELAY_US(ADC_usDELAY);         /* Delay before converting ADC channels*/                                           \

                                                                                                                                                                                       \

               AdcRegs.ADCTRL1.bit.ACQ_PS = ACQPS[0];                                                                                             \

                AdcRegs.ADCTRL1.bit.CPS = 1;                                                                                                                   \

                AdcRegs.ADCTRL3.bit.ADCCLKPS = 0;                                                                                                      \

                AdcRegs.ADCTRL1.bit.SEQ_CASC = 0;       /* 0x0 Dual Sequencer Mode, 0x1 Cascaded Mode*/           \

                AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x0;                                                                                            \

                AdcRegs.ADCTRL2.bit.RST_SEQ1 = 0x1;                                                                                                    \

                AdcRegs.ADCTRL2.bit.RST_SEQ2 = 0x1;                                                                                                    \

                AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1=0x1; /* enable SOC from EPWMA trigger*/                        \

                                                                                                                                                                                       \

                                                                                                                                                                                       \

                AdcRegs.ADCCHSELSEQ1.bit.CONV00 = ChSel[0];                                                                                  \

                AdcRegs.ADCCHSELSEQ1.bit.CONV01 = ChSel[1];                                                                                  \

                AdcRegs.ADCCHSELSEQ1.bit.CONV02 = ChSel[2];                                                                                  \

                AdcRegs.ADCCHSELSEQ1.bit.CONV03 = ChSel[3];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV04 = ChSel[4];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV05 = ChSel[5];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV06 = ChSel[6];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV07 = ChSel[7];                                                                                  \

                                                                                                                                                                                      \

                AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 7;                                                                                          \

                EDIS;                                                                                                                                                             \

                                                                                                                                                                                      \

                /* Set up Event Trigger with CNT_zero enable for Time-base of EPWM1 */                                                \

                EPwm1Regs.ETSEL.bit.SOCAEN = 1;     /* Enable SOCA */                                                                      \

                EPwm1Regs.ETSEL.bit.SOCASEL = 2;   /* Enable period event for SOCA */                                            \

                EPwm1Regs.ETPS.bit.SOCAPRD = 1;     /* Generate SOCA on the 1st event */                                        \

                EPwm1Regs.ETCLR.bit.SOCA = 1;          /* Clear SOCA flag */

 

 

#endif // __F2833XILEG_VDC_H__

 

What I would like to occur, would be for the ADC sequence to rundown through all 16 channels. To that effect, I believe that I would need to have modified the code in the following sections:

 

                …

                AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;       /* 0x0 Dual Sequencer Mode, 0x1 Cascaded Mode*/          \

                …

                AdcRegs.ADCCHSELSEQ1.bit.CONV00 = ChSel[0];                                                                                  \

                AdcRegs.ADCCHSELSEQ1.bit.CONV01 = ChSel[1];                                                                                  \

                AdcRegs.ADCCHSELSEQ1.bit.CONV02 = ChSel[2];                                                                                  \

                AdcRegs.ADCCHSELSEQ1.bit.CONV03 = ChSel[3];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV04 = ChSel[4];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV05 = ChSel[5];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV06 = ChSel[6];                                                                                  \

                AdcRegs.ADCCHSELSEQ2.bit.CONV07 = ChSel[7];                                                                                  \

                AdcRegs.ADCCHSELSEQ3.bit.CONV08 = ChSel[8];                                                                                  \

                AdcRegs.ADCCHSELSEQ3.bit.CONV09 = ChSel[9];                                                                                  \

                AdcRegs.ADCCHSELSEQ3.bit.CONV10 = ChSel[10];                                                                                \

                AdcRegs.ADCCHSELSEQ3.bit.CONV11 = ChSel[11];                                                                                \

                AdcRegs.ADCCHSELSEQ4.bit.CONV12 = ChSel[12];                                                                                \

                AdcRegs.ADCCHSELSEQ4.bit.CONV13 = ChSel[13];                                                                                \

                AdcRegs.ADCCHSELSEQ4.bit.CONV14 = ChSel[14];                                                                                \

                AdcRegs.ADCCHSELSEQ4.bit.CONV15 = ChSel[15];                                                                                \

                                                                                                                                                                                      \

                AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 15;                                                                                        \

 

Do I have the right idea?

 

The first six (6) measurements I really need all at the same time, but as that’s not possible, I have to settle for either a Hold & Sample (H/S) where the A & B inputs are Held and then sequentially sampled, or I have to cascade the whole arrangement. Can anyone suggest a better way or am I on the right path?

  • Hi Tim,

    You can't directly sample 6 samples all at the same time, but you can sample in the order 6-5-4-3-2-1-1-2-3-4-5-6 and then average like channels to get results whose average time are all in the same place. You can use this with fully sequential mode or grouped into pairs to be simultaneously sampled. Otherwise you just need to sample them sequentially and assume the ADC is fast enough that the samples are close enough to the same time.

    Instead of 6 samples, we typically see someone trying to sample 3 voltages or currents from a 3 phase motor at the same time, but the ADC can only do 2 simultaneous conversions. In this case, you can order them as: 3 then (1 + 2 simultaneously ) then 3 again, and then average the two channel 3 results to get 3 "simultaneous" conversions.

    This is from a purely ADC perspective; someone from TI with a better systems understanding of Motor control + PFC may be able to give you a more specific answer.
  • Thanks Devin.

    I agree, this ADC cannot do 6 simultaneous conversions. Truly, it can only do 1 conversion at a time, but it can hold an A-channel and B-channel (do they have to be the same? eg. A1 & B1...or can they be different? A1 & B4?) and then sample the hold values that were taken at the same time.

    I had thought about the method you proposed, concerning the 6-5-4...4-5-6 averaging, though I thought I could only sample 16 values in sequential mode. I assume that I would have to reset the ADC or something to put a new sequence based on a different SOC trigger and such?

    Also, I'm unfamiliar with the method of transitioning back and forth from simultaneous to sequential. How would one go about performing such a feat? (aka, could you please post an example?)

    I'm fine with sampling in sequence for the moment, I don't believe my currents or voltages will be swinging that much just yet. I am a bit confused with the examples in general in the document I referenced.

    Do you or anyone know how I should setup the code from what I have concerning my original questions?
  • Hi Tim,

    Yeah, for the 6-5-4...4-5-6 methodology, this would take 12 of 16 ADCRESULT registers. If this makes you have more than 16 total samples to process each trigger, they you would have to use some method of breaking the conversions into multiple sequences, which could get messy.

    For simultaneous sampling, this must be the same channel numbers...e.g. A1/B1 or A5/B5. The process is essentially the same as sequential sampling mode, but each channel select results in 2 voltages being captured, and then sequentially resolved into a digital value. So the ADC might sample A1 and B1, then convert A1, then convert B1, then sample A5 and B5, then convert A5, then convert B5...etc. To enable this, you set the SMODE bit in ADCCTRL3 (this is global to the ADC). You can read about the various control bits in spru812a.

    If you want to scan through 16 channels, I think the approach you were taking of cascading the sequencers and setting all the channel selects to all the channels is fine.
  • Thanks again Devin.

    I think you nailed my questions. Specifically, when operating in simultaneous mode, the channel numbers are taken as the binary equivalent of 0-7 (000-111), with the MSB in the 4-bit channel selection being ignored; A (=0) or B (=1). Therefore, the A and B channels are sampled/held at the same time, and then converted in the order of the A-channel followed by the B-channel.

    For my application, I think it would be best to perform a sequential operation on all 16 channels in the order I've listed from my initial post. The order, therefore, is now more hardware dependent on what connections are made to which inputs. As I do not have control of the hardware, this is something to consider as part of some redesign suggestions to Semikron.

    On the other hand, simultaneous mode would create the following sequential pattern, and might be worth considering:

    ChSel[0] = 0; // ChSelect: ADC A0 -> CS_AnalL1; Analog Value from Current Sensor Leg-U
    ChSel[1] = 8; // ChSelect: ADC B0 -> CS_AnalL3; Analog value from Current Sensor Leg-W
    ChSel[2] = 2; // ChSelect: ADC A2 -> PM_AnaUL1; Phase Voltage U
    ChSel[3] = 10; // ChSelect: ADC B2 -> Battery_Voltage; Analog value UCC_IN voltage
    ChSel[4] = 3; // ChSelect: ADC A3 -> PM_AnaUL2; Phase Voltage V
    ChSel[5] = 11; // ChSelect: ADC B3 -> DCB_Temp_Inverter; Analog value from DCB temperature sensor
    ChSel[6] = 4; // ChSelect: ADC A4 -> PM_AnaUL3; Phase Voltage W
    ChSel[7] = 12; // ChSelect: ADC B4 -> Motor_Temp_Inverter; Analog value from motor temperature sensor
    ChSel[8] = 9; // ChSelect: ADC B1 -> PM_Ana_UDcl; Analog Voltage value from DC-Link
    ChSel[9] = 1; // ChSelect: ADC A1 -> 1V5P_REF; 1.5V Reference voltage for the current sensors
    ChSel[10] = 5; // ChSelect: ADC A5 -> GPxO_AnalGpxo1; Analog value from current sensor of GPxO1
    ChSel[11] = 13; // ChSelect: ADC B5 -> GPAI_AnaUPot1; Analog value from GPAI1
    ChSel[12] = 6; // ChSelect: ADC A6 -> GPxO_AnalGpxo2; Analog value from current sensor of GPxO2
    ChSel[13] = 14; // ChSelect: ADC B6 -> GPAI_AnaUPot2; Analog value from GPAI2
    ChSel[14] = 7; // ChSelect: ADC A7 -> GPxO_AnalGpxo3; Analog value from current sensor of GPxO3
    ChSel[15] = 15; // ChSelect: ADC B7 -> GPAI_AnaUPot3; Analog value from GPAI3


    Thank you again,
    Tim, PE
  • Hi Tim,

    Sounds good - feel free to start a new thread if you run into additional difficulties.

    I will also point out that if you are using purely sequential mode, then you should have the flexibility in SW to sample in whatever order you want, so which channels are connected to what HW shouldn't matter much. However, if you are using simultaneous sampling, you do need the HW designers to place the signals to be sampled on appropriate channel pairs (but you can still sample the channel pairs in any order).