Part Number: F28M35H52C
Tool/software: TI C/C++ Compiler
I have a C28 program running based off the adc_soc example that uses ePWM and has code as follows but at present it's only running ADC1
void main(void)
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F28M35x_SysCtrl.c file.
InitSysCtrl();
#ifdef _FLASH
// Copy time critical code and Flash setup code to RAM
// This includes the following functions: InitFlash();
// The RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart
// symbols are created by the linker. Refer to the device .cmd file.
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
// Call Flash Initialization to setup flash waitstates
// This function must reside in RAM
InitFlash();
#endif
// Step 2. Initialize GPIO:
// Initialize GPIO
InitGpio(); // set the GPIO to it's default state.
EALLOW;
GpioG1CtrlRegs.GPADIR.bit.GPIO29 = 1; //set PE5_GPIO29 as output TM - this is for the direct-wired LED I added to my PCB
EDIS;
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F28M35x_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in F28M35x_DefaultIsr.c.
// This function is found in F28M35x_PieVect.c.
InitPieVectTable();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.ADCINT1 = &adc1_isr; // TM from adc_soc_c28.c, points to local isr code that is run after ADC conversion
EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4. Initialize the Device Peripheral. This function can be
// found in F28M35x_CpuTimers.c
//# InitCpuTimers(); // TM initialize the Cpu Timers (not using timers so disabled)
InitAdc1(); // TM initialize ADC1 (need to add ADC2 when we get that far)
// Enable ADCINT1 in PIE
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable INT 1.1 in the PIE
IER |= M_INT1; // Enable CPU Interrupt 1
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
LoopCount = 0; // TM not sure if we need this
ConversionCount = 0; // TM not sure if we need this
// Configure ADC
EALLOW;
Adc1Regs.ADCCTL2.bit.ADCNONOVERLAP = 1; // Enable non-overlap mode i.e.
// conversion and future
// sampling events don't overlap
Adc1Regs.ADCCTL1.bit.INTPULSEPOS = 1; // ADCINT1 trips after AdcResults latch
Adc1Regs.INTSEL1N2.bit.INT1E = 1; // Enabled ADCINT1
Adc1Regs.INTSEL1N2.bit.INT1CONT = 0; // Disable ADCINT1 Continuous mode
Adc1Regs.INTSEL1N2.bit.INT1SEL = 0; // setup EOC0 to trigger ADCINT1 to fire
Adc1Regs.ADCSOC0CTL.bit.CHSEL = 2; // set SOC0 channel select to ADC1A2 ### Current SS
Adc1Regs.ADCSOC1CTL.bit.CHSEL = 3; // set SOC1 channel select to ADC1A3 ### Fault Current
AnalogSysctrlRegs.TRIG1SEL.all = 5; // Assigning EPWM1SOCA to ADC TRIGGER 1 of the ADC module
Adc1Regs.ADCSOC0CTL.bit.TRIGSEL = 5; // Set SOC0 start trigger to ADC Trigger 1(EPWM1 SOCA) of the adc
Adc1Regs.ADCSOC1CTL.bit.TRIGSEL = 5; // set SOC1 start trigger to ADC Trigger 1(EPWM1 SOCA) of the adc
Adc1Regs.ADCSOC0CTL.bit.ACQPS = 6; // set SOC0 S/H Window to 7 ADC Clock Cycles, (6 ACQPS + 1)
Adc1Regs.ADCSOC1CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC Clock Cycles, (6 ACQPS + 1)
EDIS;
//// Assumes ePWM1 clock is already enabled in InitSysCtrl();
//Set event triggers (SOCA) for ADC SOC1
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group
EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTRU_CMPA; // Select SOC from CMPA on
// upcount
EPwm1Regs.ETPS.bit.SOCAPRD = 3; // Generate pulse on every 3rd
// event
// Time-base registers
EPwm1Regs.TBPRD = PERIOD; // Set timer period, PWM
// frequency = 1 / period
EPwm1Regs.TBPHS.all = 0; // Time-Base Phase Register
EPwm1Regs.TBCTR = 0; // Time-Base Counter Register
EPwm1Regs.TBCTL.bit.PRDLD = TB_IMMEDIATE; // Set Immediate load
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count-up mode: used for
// asymmetric PWM
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Setup shadow register load on ZERO
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // load on CTR=Zero
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // load on CTR=Zero
// Set Compare values
EPwm1Regs.CMPA.half.CMPA = DUTY_CYCLE_A; // Set duty 50% initially
EPwm1Regs.CMPB = DUTY_CYCLE_B; // Set duty 50% initially
// Set actions
EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Set PWM2A on Zero
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM2A on event A, up
// count
EPwm1Regs.AQCTLB.bit.ZRO = AQ_CLEAR; // Set PWM2B on Zero
EPwm1Regs.AQCTLB.bit.CBU = AQ_SET; // Clear PWM2B on event B, up
// count
// Step 6. IDLE loop. Just sit and loop forever (optional):
for(;;) ;
} // end of main
__interrupt void adc1_isr(void)
{
// TM I believe these occur after ADC conversions have taken place
GpioG1DataRegs.GPASET.bit.GPIO29 = 1; // LED on as we enter the ADC ISR
myVoltsArray[myIndex] = Adc1Result.ADCRESULT0; // TM set Volts array element from ADC result 0
myAmpsArray[myIndex] = Adc1Result.ADCRESULT1; // TM temp set Amps array element from ADC result 1
myIndex++;
if (myIndex > 10) { // TM, 10 was 12607, made smaller for testing
myIndex = 0;
}
// If 10 conversions have been logged, start over
if(ConversionCount == 9)
{
ConversionCount = 0;
}
else ConversionCount++;
GpioG1DataRegs.GPACLEAR.bit.GPIO29 = 1; // LED off as we exit the ADC ISR
Adc1Regs.ADCINTFLGCLR.bit.ADCINT1 = 1; //Clear ADCINT1 flag reinitialize
// for next SOC
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE
return;
}
I want to perform simultaneous conversions on ADC1INA2 and ADC2INA2 21,600 times per second and then grab those results and store them in my circular array buffer. I've been reading about simultaneous sampling mode in the reference manual (spruh22h.pdf) but it's not clear to me how the results come back - I think I can just set ADC1INA2 and ADC2INA2 to be triggered by the ePWM signal but do I need 2 ISRs to grab the results?
This is further complicated by the requirement that, if the ADC1INA2 value maxes out, I need to substitute a reading from ADC1INA3 (which is reading the same source at a ten times less sensitive scale) so what I really want is to change the source of the ADC1INAx value if the reading goes above (and then below) a set value). Another way to solve this might be to always take the ADC1INA2 and ADC2INA2 readings and then immediately follow up with an ADC1INA3 reading (which will come < 1uS later but that's OK); in this approach, I would test the ADC1INA2 value and if it were maxed out, I'd simply use the ADC1INA3 value divided by ten and stored in my results array.
Note that I am taking 12 bit results and storing them in 16 bit registers so if I'm storing the second result x10, it will still fit into the 16 bit results array - in this way I capture values for an overcurrent.