Tool/software: Code Composer Studio
With reference to the http://e2e.ti.com/support/microcontrollers/other/f/908/t/594823 it still seems unclear how to make a correct setup.
In an application we have ADC0 running at full speed (2MHz) and so also ADC1. ADC1 is only used for the internal temperature measurement.
By using the configuration giving 64 ADC-clocks for sample-hold we get some measurements much lower than expected (range 30-47 degrees C when using heat-gun up till 100 degree C).
We have tried to read out 3-10 consecutive readings (having global interrupt disabled), but still poor readings of temperature.
Only by adding oversampling we are getting useful results: ADCHardwareOversampleConfigure(ADC1_BASE, 64);
This seems strange as this is not logical compared to the errata.
Any good explanation ? and have we missed something ?
The code is shown below:
Initialisation:
//
// Set the clock for both ADCs (ADC1_BASE sets the clock for both ADCs)
// ADC_CLOCK_DIVIDER == 30 -> set the ADC clock to 16MHz corresponding to 1Msp/s
// ADC_CLOCK_DIVIDER == 15 -> set the ADC clock to 32MHz corresponding to 2Msp/s
//
ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, ADC_CLOCK_DIVIDER);
//------------------------
//
// Initialize the internal ADC1 peripheral used for internal chip temperature measurement.
// The temperature measurement is done in the -in another function - see below.
//
//
// Set the sequencer number
//
uint32_t g_uisequencernum = 3;
static void ADC1Init(void)
{
//
// The ADC1 peripheral must be enabled for use.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
//
// Wait for the ADC1 peripheral to be ready.
//
while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC1))
{}
//
//set the auto avergage to 64.
//
ADCHardwareOversampleConfigure(ADC1_BASE, 64);
//
// Make sure ADC1 sample sequencer is disabled before configuring it.
//
MAP_ADCSequenceDisable(ADC1_BASE, g_uisequencernum);
//
// Enable sample sequence with a processor signal trigger.
//
MAP_ADCSequenceConfigure(ADC1_BASE, g_uisequencernum, ADC_TRIGGER_PROCESSOR, 0);
//
// Configure step 0 on sequence.
//
//MAP_ADCSequenceStepConfigure(ADC1_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END| ADC_CTL_SHOLD_16);
/*
* Set up the ADC sequencer for temperature reading
*
* ADC_CTL_TS : Temperature sensor select
* ADC_CTL_IE : Interrupt enable
* ADC_CTL_SHOLD_16 : Sample and hold 16 ADC clocks
* ADC_CTL_END : Sequence end select
*
*/
MAP_ADCSequenceStepConfigure(ADC1_BASE, g_uisequencernum, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_SHOLD_64 | ADC_CTL_END);
//
// Since sample sequence is now configured, it must be enabled.
//
MAP_ADCSequenceEnable(ADC1_BASE, g_uisequencernum);
//
// Clear the interrupt status flag. This is done to make sure the
// interrupt flag is cleared before we sample.
//
MAP_ADCIntClear(ADC1_BASE, ADCIntClear);
return;
}
Function for reading out the temperature:
{
uint32_t ui32Temperature = 0; // used for reading values from the adc
int32_t i32Temperature = 0; // used for calculating the actual temperature
uint8_t i = 3;
#if defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1)
// If platform is TM4C129
/*uint32_t n;
taskENTER_CRITICAL(); //<----- Enter critical section !
IntMasterDisable(); //<----- Disable interrupts !
for(n=0;n<1000;n++)
{
MAP_ADCIntStatus(ADC1_BASE, 3, false);
}*/
//while(!MAP_ADCIntStatus(ADC1_BASE, 3, false)) {} // Wait for conversion to be completed, there could still be some samples left in the ping-pong queue initiated by the normal sample mode.
for (i=3; i>0; i--) //run 3 loops to meet setling time of temperature sensor internally (see errata: www.ti.com/.../spmz850c.pdf)
{
// See TivaWare example in: <tivaware>/examples/peripherals/adc/temperature_sensor.c
MAP_ADCProcessorTrigger(ADC1_BASE, g_uisequencernum); // Trigger the ADC conversion.
while(!MAP_ADCIntStatus(ADC1_BASE, g_uisequencernum, false)) {} // Wait for conversion to be completed.
MAP_ADCIntClear(ADC1_BASE, g_uisequencernum); // Clear the ADC interrupt flag.
MAP_ADCSequenceDataGet(ADC1_BASE, g_uisequencernum, &ui32Temperature); // Read ADC Value.
i32Temperature = (int32_t)ui32Temperature;
}
/*IntMasterEnable(); //<----- Enable interrupts !
taskEXIT_CRITICAL(); //<----- Exit critical section !*/
i32Temperature = (1475-(i32Temperature*2475)/4096)/10; // Use non-calibrated conversion provided in the data sheet.
#else
// If platform is LM3S9D92
for (i=3; i>0; i--) //run 3 loops to meet setling time of temperature sensor internally (see errata)
{
ADCIntClear(ADC0_BASE, g_uisequencernum); //clear any old interrupts
ADCProcessorTrigger(ADC0_BASE, g_uisequencernum); //Initiate the next adc-temperature conversion
while(!ADCIntStatus(ADC0_BASE, g_uisequencernum, false)) {} // Wait until the sample sequence has completed.
ADCSequenceDataGet(ADC0_BASE, g_uisequencernum, &ui32Temperature);
i32Temperature = (int32_t)ui32Temperature;
}
i32Temperature = 147-((i32Temperature*225)/1024); // calculate in celcius
#endif
pushinteger(int32_t)i32Temperature;
return 1;
}