I’ve noticed on the Concerto ADC that the sample rate they claim (up to 2.88MSPS) is only the conversion rate and not the whole true conversion time (i.e. sample time + conversion time). Do they claim this due to having 2 sample-and-hold circuits?
-Jason
Ricky,
Here is a modified adc_soc_C28 file with my analog initialization. Could you take a look to see if it is correct. My intent is to convert all available inputs sequentially using the interrupt scheme you used for triggering on EOC6 and EOC14. Instead of the while loops, I have established interrupt service. I am confused about the PieVectTable.ADCINT1= &adc1_isr. I tried to duplicate this with ADCINT2 but it didn't work. Along with this is the PieCtrlRegs.PIEIER1.bit.INTx1. How should this be done for ADCINT2?
Thanks for you help.
Pat
//###########################################################################
// FILE: adc_soc_c28.c
// TITLE: ADC1 Start-Of-Conversion (SOC) Example Program.
//
//! \addtogroup control_example_list
//! <h1> ADC1 Start of Conversion (adc_soc)</h1>
//!
//! This ADC example uses ePWM1 to generate two periodic and
//! simultaneous SOCs to the ADC. Two channels are converted,
//! ADC1A0 and ADC1A2, triggered by EPWM1SOCA and EPWM1SOCB
//! respectively.
//! Note that because ADC SOC0 has a higher priority by default
//! than SOC1, channel 0 conversion will take precedence over
//! channel 1 conversion.
//! - EPWM1SOCA triggers SOC0
//! - EPMM1SOCB triggers SOC1
//! - EOC1 triggers ADCINT1 after ADC result register is latched
//! New EPWM compare registers CMPC and CMPD are used to control
//! SOCA and SOCB
//! \b Watch \b Variables \n
//! - Voltage1[10] - Last 10 ADCRESULT0 values
//! - Voltage2[10] - Last 10 ADCRESULT1 values
//! - ConversionCount - Current result number 0-9
//! - LoopCount - Idle loop counter
// $TI Release: F28M35x Support Library v110 $
// $Release Date: December 12, 2011 $
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#include <string.h>
#define DUTY_CYCLE 500
#define PERIOD 1000
// Prototype statements for functions found within this file.
interrupt void adc1_isr( void );
void ConfigAdc1( void );
void ConfigAdc2( void );
//void ConfigEpwm1( void );
// Global variables used in this example:
Uint16 LoopCount;
Uint16 ChannelCount;
Uint16 ConversionCount;
#define ADC_usDELAY 1000L
Uint32 VoltageSum[16];
Uint16 Vavg[16];
main()
{
// unsigned short analoginit;
// Step 1. Initialize System Control for Control and Analog Subsytems
// Enable Peripheral Clocks
// This example function is found in the F28M35x_SysCtrl.c file.
InitSysCtrl();
// If project is linked into flash, copy critical code sections to RAM.
#ifdef _FLASH
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif
EDIS;
// Step 2. Initialize GPIO:
// This example function is found in the F28M35x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio(); // Skipped for this example
EALLOW;
GpioG1CtrlRegs.GPBDIR.bit.GPIO32 = 1; // Set as output
GpioG1CtrlRegs.GPBMUX1.bit.GPIO32 = 3; // Select EPWM1SOCA as driving source
GpioG1CtrlRegs.GPBDIR.bit.GPIO33 = 1; // Set as output
GpioG1CtrlRegs.GPBMUX1.bit.GPIO33 = 3; // Select EPWM1SOCB as driving source
// 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 register
PieVectTable.ADCINT1 = &adc1_isr;
// PieVectTable.ADCINT2 = &adc2_isr; ?????????????????????????????????????????
EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4. Initialize all the Device Peripherals:
// This function is found in F28M35x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
InitAdc1(); // For this example, init the ADC
InitAdc2();
// Step 5. User specific code, enable interrupts:
// Enable ADCINT1 in PIE
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable INT 1.1 in the PIE
IER |= M_INT1; // Enable CPU Interrupt 1
// ADCINT2 in PIE ???????????????????????????????????????????????????????????????
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
// Configure ADC and EPWM1 sub-modules
ConfigAdc1();
ConfigAdc2();
LoopCount = 0;
ChannelCount = 0;
// Wait for ADC interrupt
for(;;)
LoopCount++;
if (LoopCount %1000)
VoltageSum[0] += 0;
}
interrupt void adc1_isr( void )
// int i;
VoltageSum[0] = Adc1Result.ADCRESULT0;
VoltageSum[1] = Adc1Result.ADCRESULT1;
VoltageSum[2] = Adc1Result.ADCRESULT2;
VoltageSum[3] = Adc1Result.ADCRESULT3;
VoltageSum[4] = Adc1Result.ADCRESULT4;
VoltageSum[5] = Adc1Result.ADCRESULT5;
VoltageSum[6] = Adc1Result.ADCRESULT6;
Adc1Regs.ADCINTFLGCLR.bit.ADCINT1 = 1; //Clear ADCINT1 flag reinitialize
// for next SOC
Adc2Regs.ADCINTFLGCLR.bit.ADCINT1 = 1; //Clear ADCINT1 flag reinitialize
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE
return;
interrupt void adc2_isr( void )
VoltageSum[7] = Adc2Result.ADCRESULT0;
VoltageSum[8] = Adc2Result.ADCRESULT1;
VoltageSum[9] = Adc2Result.ADCRESULT2;
VoltageSum[10] = Adc2Result.ADCRESULT3;
VoltageSum[11] = Adc2Result.ADCRESULT4;
VoltageSum[12] = Adc2Result.ADCRESULT5;
VoltageSum[13] = Adc2Result.ADCRESULT6;
VoltageSum[14] = Adc2Result.ADCRESULT7;
void ConfigAdc1( void )
// Configure ADC
Adc1Regs.ADCCTL2.bit.ADCNONOVERLAP = 1; // Set ADC to non-overlap mode
Adc1Regs.ADCCTL1.bit.INTPULSEPOS = 1; // EOC trips after conversion result is latched
Adc1Regs.INTSEL1N2.bit.INT1E = 1; // Enabled ADCINT1
Adc1Regs.INTSEL1N2.bit.INT1CONT = 0; // Disable ADCINT1 Continuous mode
Adc1Regs.INTSEL1N2.bit.INT1SEL = 1; // setup EOC1 to trigger ADCINT1
// Select ADC input channels
Adc1Regs.ADCSOC0CTL.bit.CHSEL = 0; // set SOC0 channel select to ADC1A0
Adc1Regs.ADCSOC1CTL.bit.CHSEL = 2; // set SOC1 channel select to ADC1A2
Adc1Regs.ADCSOC2CTL.bit.CHSEL = 3; // set SOC2 channel select to ADC1A3
Adc1Regs.ADCSOC3CTL.bit.CHSEL = 4; // set SOC3 channel select to ADC1A4
Adc1Regs.ADCSOC4CTL.bit.CHSEL = 6; // set SOC4 channel select to ADC1A6
Adc1Regs.ADCSOC5CTL.bit.CHSEL = 7; // set SOC5 channel select to ADC1A7
Adc1Regs.ADCSOC6CTL.bit.CHSEL = 12; // set SOC6 channel select to ADC1B4
// Setup ADCINT1 and ADCINT2 trigger source
Adc1Regs.INTSEL1N2.bit.INT1SEL = 6; //EOC6 triggers ADCINT1
Adc1Regs.INTSEL1N2.bit.INT2SEL = 14; //EOC14 triggers ADCINT2
// Setup each SOC's ADCINT trigger source
Adc1Regs.ADCINTSOCSEL1.bit.SOC0 = 2; //ADCINT2 starts SOC0-7
Adc1Regs.ADCINTSOCSEL1.bit.SOC1 = 2;
Adc1Regs.ADCINTSOCSEL1.bit.SOC2 = 2;
Adc1Regs.ADCINTSOCSEL1.bit.SOC3 = 2;
Adc1Regs.ADCINTSOCSEL1.bit.SOC4 = 2;
Adc1Regs.ADCINTSOCSEL1.bit.SOC5 = 2;
// Set S/H window of 7 ADC clock cycles
Adc1Regs.ADCSOC0CTL.bit.ACQPS = 6; // S/H = ACQPS + 1
Adc1Regs.ADCSOC1CTL.bit.ACQPS = 6;
Adc1Regs.ADCSOC2CTL.bit.ACQPS = 6;
Adc1Regs.ADCSOC3CTL.bit.ACQPS = 6;
Adc1Regs.ADCSOC4CTL.bit.ACQPS = 6;
Adc1Regs.ADCSOC5CTL.bit.ACQPS = 6;
void ConfigAdc2( void )
Adc2Regs.ADCCTL2.bit.ADCNONOVERLAP = 1; // Set ADC to non-overlap mode
Adc2Regs.ADCCTL1.bit.INTPULSEPOS = 1; // EOC trips after conversion result is latched
Adc2Regs.INTSEL1N2.bit.INT2E = 1; // Enabled ADCINT1
Adc2Regs.INTSEL1N2.bit.INT1CONT = 0; // Disable ADCINT1 Continuous mode
Adc2Regs.INTSEL1N2.bit.INT1SEL = 1; // setup EOC1 to trigger ADCINT1
Adc2Regs.ADCSOC0CTL.bit.CHSEL = 0; // set SOC0 channel select to ADC2A0
Adc2Regs.ADCSOC1CTL.bit.CHSEL = 2; // set SOC1 channel select to ADC2A2
Adc2Regs.ADCSOC2CTL.bit.CHSEL = 3; // set SOC0 channel select to ADC2A3
Adc2Regs.ADCSOC3CTL.bit.CHSEL = 4; // set SOC1 channel select to ADC2A4
Adc2Regs.ADCSOC4CTL.bit.CHSEL = 6; // set SOC0 channel select to ADC2A6
Adc2Regs.ADCSOC5CTL.bit.CHSEL = 7; // set SOC1 channel select to ADC2A7
Adc2Regs.ADCSOC6CTL.bit.CHSEL = 8; // set SOC0 channel select to ADC2B0
Adc2Regs.ADCSOC7CTL.bit.CHSEL = 12; // set SOC1 channel select to ADC2B4
Adc2Regs.INTSEL1N2.bit.INT1SEL = 6; //EOC6 triggers ADCINT1
Adc2Regs.INTSEL1N2.bit.INT2SEL = 14; //EOC14 triggers ADCINT2
Adc2Regs.ADCINTSOCSEL1.bit.SOC0 = 2; //ADCINT2 starts SOC0-7
Adc2Regs.ADCINTSOCSEL1.bit.SOC1 = 2;
Adc2Regs.ADCINTSOCSEL1.bit.SOC2 = 2;
Adc2Regs.ADCINTSOCSEL1.bit.SOC3 = 2;
Adc2Regs.ADCINTSOCSEL1.bit.SOC4 = 2;
Adc2Regs.ADCINTSOCSEL1.bit.SOC5 = 2;
Adc2Regs.ADCINTSOCSEL1.bit.SOC6 = 2;
Adc2Regs.ADCINTSOCSEL1.bit.SOC7 = 2;
DELAY_US(ADC_usDELAY); // Delay before converting ADC1
Adc2Regs.ADCSOC0CTL.bit.ACQPS = 6; // S/H = ACQPS + 1
Adc2Regs.ADCSOC1CTL.bit.ACQPS = 6;
Adc2Regs.ADCSOC2CTL.bit.ACQPS = 6;
Adc2Regs.ADCSOC3CTL.bit.ACQPS = 6;
Adc2Regs.ADCSOC4CTL.bit.ACQPS = 6;
Adc2Regs.ADCSOC5CTL.bit.ACQPS = 6;
Adc2Regs.ADCSOC6CTL.bit.ACQPS = 6;
Adc2Regs.ADCSOC7CTL.bit.ACQPS = 6;
I solved the adc2_isr problem (missing prototype) and have tried a PIE setup for adc2 (PieCtrlRegs.PIEIER1.bit.INTx2 = 1; IER |=M_INT2;), but still cannot read any analog inputs. All I get are bogus constant values that remain if I remove the analog inputs. I have tried the other ADC examples as well, have tried introducing delays,etc. Nothing seems to work. I would be happy if someone had an example of successfully reading just one analog input showing all the setup required.
Thanks for any help.
Pat,
The adc_soc example should work if you use it straight from controlSUITE. The example samples channels 0 and 2 on ADC1. I know you said you already used the example, but if it doesn't work than there could be a board issue. Make sure you use the setup_m3 project for the M3.
Regards,
Ricky
Thanks for your response. Since that last entry, I have been able to determine that my problem with ADC1 is caused by the HAL_API that is used for the PLC example software. I have communicated that to the PLC team and am waiting for a reply. The problem is that the HAL initialization seems to destroy the ADC1 result register refresh capability, such that ADC1 will only refresh with a power cycle. Although this is not directly related to the adc_soc_example, the problem first arose when I tried to add the adc_soc task with extensions for additional adc channels to the example PHY code uses ADC1_B0 only but it affects all of ADC1 channels).
Thanks,