cancel
Showing results for 
Search instead for 
Did you mean: 

Temperature sensor in stm32f4-discovery problems

salahuddinash
Associate II
Posted on May 04, 2014 at 09:41

Hi everyone, 

I'm trying to read temperature from temperature sensor in stm32f4-discovery kit 

I've configured ADC1 and then read converted value and do some math on it 

now when debugging it goes to

hard fault

 

why ?? I don't know

and if there're other notes on this code ?? 

<b>

/*

 *In this project I need to read the temperature sensor, convert it into digital and 

 *send this reading to be displayed on the PC (RealTerm)using USART.

 */

 

#include ''stm32f4_discovery.h''

 

/**************************************************************************************/

void delay(uint32_t);

void RCC_Configuration(void)

{

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

}

 

/**************************************************************************************/

 

 

void ADC_Configuration(void)

{

/*

* In stm32f4-discovery kit, the temperature sensor is connected to ADC1_IN16

*/

  ADC_CommonInitTypeDef ADC_CommonInitStruct;

  ADC_InitTypeDef ADC_InitStruct;

 

ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;

ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;

ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;

ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;

ADC_CommonInit(&ADC_CommonInitStruct);

ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;

ADC_InitStruct.ADC_ScanConvMode = DISABLE;

ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;

ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;

ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStruct.ADC_NbrOfConversion = 1;

ADC_Init(ADC1, &ADC_InitStruct);

//The next statement configures the ADC1 channel, rank and sample time

ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 1, ADC_SampleTime_144Cycles);  //ADC_Channel_TempSensor = ADC_Channel_16

/* Then we enable the internal temperature sensor

* Bit 23 TSVREFE: Temperature sensor and VREFINT enable

* This bit is set and cleared by software to enable/disable the temperature sensor and the 

   * VREFINT channel.

* ADC->CCR |= (uint32_t)ADC_CCR_TSVREFE;

*/

ADC_TempSensorVrefintCmd(ENABLE);

//The next statement enables ADC1

ADC_Cmd(ADC1, ENABLE);

}

 

/**************************************************************************************/

 

#define BUFFERSIZE 128

uint16_t ADCConvertedValues[BUFFERSIZE]; //an array to hold the converted values

 

int main(void)

{

  static volatile float TemperatureValue = 0;

  RCC_Configuration();

 

  ADC_Configuration();

 

  STM_EVAL_LEDInit(LED3); // Configure LEDs to monitor program status 

 

  STM_EVAL_LEDOn(LED3); // Turn LED3 on 

 

  while(1) // Don't want to exit

  {

    ADC_SoftwareStartConv(ADC1); //Start the conversion

while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)

; //Processing the conversion

/*

* To calculate the temperature we follow this formula

* Temperature (in C) = {(Vsense - V25)/(Avg_Slope)}+25 

* Vsense = 0.76V, Avg_Slope = 2.5mV

* Temperature = 

*/

TemperatureValue = ADC_GetConversionValue(ADC1); //Return the converted data

TemperatureValue *= 3300;

TemperatureValue /= 0xfff; //Reading in mV

TemperatureValue /= (float)1000.0; //Reading in Volts

TemperatureValue -= (float)0.760; // Subtract the reference voltage at 25°C

TemperatureValue /= (float).0025; // Divide by slope 2.5mV

TemperatureValue += (float)25.0; // Add the 25°C

 

    /* Toggle LED3 and delay */

    STM_EVAL_LEDToggle(LED3);

delay(3*1000000);

  }

}

//delay function

void delay(uint32_t cnt)

{

while(cnt-->0);

}

</b>

Thanks a lot for your time
7 REPLIES 7
Posted on May 04, 2014 at 10:32

Hard to say without looking more deeply into the project construction, I might guess it's an issue with enabling the FPU, and code in SystemInit() to do that, or set defines for the project via ''Use FPU'' or some such. If not enabled FPU instructions will Hard Fault, a Divide by Zero might also, but can't see one here.

Analyze the Hard Fault to determine the instruction, registers, and processor context when it occurred.

Also be aware that the STM32F4-DISCO is running at 3V, and you can represent floats as say 1000.0f you don't need to cast.

TemperatureValue *= 3300;

TemperatureValue /= 0xfff; //Reading in mV

TemperatureValue /= (float)1000.0; //Reading in Volts

Could be done as

TemperatureValue *= (3.0f / 4096.0f); // 3V over 12-bit range, Reading in Volts
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
salahuddinash
Associate II
Posted on May 04, 2014 at 11:02

Thanks for your reply

 

 

I might guess it's an issue with enabling the FPU, and code in SystemInit() to do that, or set defines for the project via ''Use FPU'' or some such. If not enabled FPU instructions will Hard Fault

I think it's some issues with FPU cause the hard fault happens during the mathematical operations on the measured value.

How can I enable FPU?

Analyze the Hard Fault to determine the instruction, registers, and processor context when it occurred.

I don't know any thing about analyzing the hard fault. would you please explain in more details

Also be aware that the STM32F4-DISCO is running at 3V, and you can represent floats as say 1000.0f you don't need to cast.

TemperatureValue *= 3300;

TemperatureValue /= 0xfff; //Reading in mV

TemperatureValue /= (float)1000.0; //Reading in Volts

Could be done as

TemperatureValue *= (3.0f / 4096.0f); // 3V over 12-bit range, Reading in Volts

Honestly I don't understand the purpose of these math operations ?? 

I've copied and pasted a ready code from some blog and modified it but I don't know why do we have to multiply with 3300 and divide by 0xfff then divide by 1000

 

And how would 3V(the kit is running at) affect my code?
Posted on May 04, 2014 at 13:37

Ok this has devolved into a much more fundamental ''how does this work'' problem.

So the board runs a 3V, it affects your code because the voltage going to VREF+, the reference voltage for the ADC/DAC, defines the maximal range of measurements.

The measurements are 12-bit, this means a range 0..4095 represents DC to VREF. There are 2N ''steps''.

In order to convert the ADC number into a voltage you must use math the SCALE the number space from one set of units to another, so units of VREF/4096 to Volts or Millivolts

Why 3300, well that's a representation of 3.3V in mV

Why mV, well because the code you lifted used INTEGERs, and in order to retain any useful precision you'd want that integer to represent mV rather than V (0,1,2,3 optimistically)

Why f(x) = (x * 3300) / 4096, this is that scaling thing, we multiply by the primary conversion value to maintain the accuracy of the integer, we are using a 32-bit variable, with a 12-bit range, and 3.3V VREF, and finally the division gets us the scale of the 12-bit ADC (2N). I think that 4096 is a better representation than 4095, the difference will be fractional at best, and the binary math for 4096 is much easier (X >> 12)
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on May 04, 2014 at 13:49

As you've decided to use floating point, and voltage, the math representation becomes simpler, but more complicated for the CPU.

The scaling can be done with constants, these can be folded, and you can use multiplies which are computationally more efficient than divides.

To get from units of VREF/4096 to VOLTS, we can multiple the 12-bit value by (3.0f / 4096.0f), the compiler will fold these constants into 0.000732421875f

For the Hard Fault check out some of the handlers described by Joseph Yiu, in his Cortex books, and on the net. These can print out the processor state. You can examine the failing code through a disassembly of the running code, either in the debugger, or as a listing file of the code.

For Keil there is a ''Use FPU'' check box in one of the target panes, in SystemInit() within system_stm32f4xx.c there is code to enable the FPU based on compiler set defines. The example/template projects for the part should have all this set up properly, examine those, as if you set up a project from scratch you might have missed something critical. All I can see is the code you pasted, which doesn't look like it should fault from a cursory analysis.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
salahuddinash
Associate II
Posted on May 04, 2014 at 22:44

For Keil there is a ''Use FPU'' check box in one of the target panes, 

 

Ok, the ''Use FPU'' option is checked in project options

in SystemInit() within system_stm32f4xx.c there is code to enable the FPU based on compiler set defines. 

SystemInit() with in system_stm32f4xx.c .. here's the code found and I can't find anything related to FPU enabling

<b>

void SystemInit(void)

{

  /* Reset the RCC clock configuration to the default reset state ------------*/

  /* Set HSION bit */

  RCC->CR |= (uint32_t)0x00000001;

  /* Reset CFGR register */

  RCC->CFGR = 0x00000000;

  /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset PLLCFGR register */

  RCC->PLLCFGR = 0x24003010;

  /* Reset HSEBYP bit */

  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Disable all interrupts */

  RCC->CIR = 0x00000000;

#ifdef DATA_IN_ExtSRAM

  SystemInit_ExtMemCtl(); 

#endif /* DATA_IN_ExtSRAM */

         

  /* Configure the System clock source, PLL Multiplier and Divider factors, 

     AHB/APBx prescalers and Flash settings ----------------------------------*/

  SetSysClock();

  /* Configure the Vector Table location add offset address ------------------*/

#ifdef VECT_TAB_SRAM

  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */

#else

  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */

#endif

}

</b>

The example/template projects for the part should have all this set up properly, examine those, as if you set up a project from scratch you might have missed something critical. 

I'm modifying an example and not beginning from scratch.. 

Here's the deassembly of the portion of code causes the hard fault 

<b>

   108:     TemperatureValue *= (3.0f / 4096.0f); // 3V over 12-bit range, Reading in Volts 

0x080009D8 6820            LDR           r0,[r4,#0x00]

0x080009DA EDDF0A1E  VLDR          s1,[pc,#0x78]

0x080009DE EE000A10    VMOV          s0,r0

0x080009E2 EEB80A40    VCVT.F32.U32  s0,s0

0x080009E6 EE200A20     VMUL.F32      s0,s0,s1

0x080009EA EEBC0AC0   VCVT.U32.F32  s0,s0

0x080009EE EE100A10     VMOV          r0,s0

0x080009F2 6020               STR           r0,[r4,#0x00]

</b>

specifically the red line causes the hard fault

So what ??
Posted on May 05, 2014 at 00:36

STM32F4xx_DSP_StdPeriph_Lib_V1.3.0\Project\STM32F4xx_StdPeriph_Templates\system_stm32f4xx.c

void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 
10
*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
...

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
salahuddinash
Associate II
Posted on May 05, 2014 at 01:36

Ok, I've reloaded this file instead of the one I had in my project but the problem still the same, Hard Fault

I'm sorry for bothering but I don't know what to do