cancel
Showing results for 
Search instead for 
Did you mean: 

Incorrect readings from STM32F407's internal temperature sensor when rank is changed.

AdityaUbarhande
Associate

Hi All,
I was experimenting with the inbuilt temperature sensor on STM32F4 DISCOVERY board. The sensor is connected to ADC1_IN16 (16th channel of ADC1).

I wrote a basic C program (attached below) and was able to get the sensor working perfectly fine.

(I have configured 3 of the 4 on-board LEDs to change color as the temperature varies, this is why you would see the GPIO config part as well)

 

 

    #include<stdint.h>
    #include<stdio.h>
    int main(void)
    {	
        //Variable Definitions
        uint32_t* GPIO_MODER = (uint32_t*)0x40020C00;
        uint32_t* GPIO_ODR = (uint32_t*)0x40020C14;
     
        uint32_t* RCC_CLK_AHB1 = (uint32_t*)0x40023830;
        uint32_t* RCC_CLK_APB2 = (uint32_t*)0x40023844;
     
        uint32_t* ADC_CR2 = (uint32_t*)0x40012008;
        uint32_t* ADC_SQR3 = (uint32_t*)0x40012034;
        uint32_t* ADC_SQR1 = (uint32_t*)0x4001202C;
        uint32_t* ADC_CCR = (uint32_t*)0x40012304;
        uint32_t* ADC_DR = (uint32_t*)0x4001204C;
        uint32_t* ADC_STAT = (uint32_t*)0x40012000;
        uint32_t* ADC_SMPR = (uint32_t*)0x4001200C;
     
        
        //Clock enable for GPIOD and ADC
        *RCC_CLK_AHB1 |= (1 << 3);	//Enable GPIOD clock
        *RCC_CLK_APB2 |= (1 << 8);	//Enable ADC clock
     
        //GPIO mode set (LEDs set to OUTPUT)
        *GPIO_MODER |= (1 << 30);
        *GPIO_MODER |= (1 << 28);
        *GPIO_MODER |= (1 << 26);
        *GPIO_MODER |= (1 << 24);
     
         //ADC Configuration
     
        *ADC_SQR1 |= (16 << 15);	//Set 16th sequence for Channel 16
        *ADC_SQR1 |= (15 << 20);	//Configure the 'L' section 
        *ADC_SMPR |= (7 << 18);	//Set Sample Rate to Maximum. (480)
        *ADC_CR2 |= (1 << 0);	//Set ADON bit
        *ADC_CCR |= (1 << 23);	//Enable Temperature Sensor
        	
        while(1)
        {
            *ADC_CR2 |= (1 << 30);		//Start Conversion
    	    while(!(*ADC_STAT & (1 << 4)));	//Wait for conversion to start
    	    while (!(*ADC_STAT & (1 << 1)));     // Wait for EOC flag
     
            uint16_t Vsense =  (uint16_t)*ADC_DR; //Read ADC output data
    	    double voltage, celsius;
     
            voltage = (double)Vsense/4095*3.3;
    	    celsius = (double)(((voltage - 0.76) / 0.0025) + 25);
     
            printf("\nTemperature is: %.2f", celsius);  //Print the temperature 
     
            if(celsius < 57.5) //For low temperature, turn blue LED on
    	    {
    		*GPIO_ODR &= ~(1 << 13);
    		*GPIO_ODR &= ~(1 << 14);
    		*GPIO_ODR |= (1 << 15);
    	    }
    	    else if(celsius < 68 && celsius > 58)//For medium temp, turn orange LED on
    	    {
    		*GPIO_ODR &= ~(1 << 15);
    		*GPIO_ODR &= ~(1 << 14);
    		*GPIO_ODR |= (1 << 13);
    	    }
    	    else if(celsius > 65)  //For high temperature, turn red LED on
    	    {
    		*GPIO_ODR &= ~(1 << 15);
    		*GPIO_ODR &= ~(1 << 13);
    		*GPIO_ODR |= (1 << 14);
    	    } 
        }
    }

 

 

Here is what I found!

In my first code (not the one shared above), I set the rank/priority/sequence of Channel 16 to '1' using the ADC_SQR3 Register. And the temperature sensor worked perfectly fine!

But when I change the rank/priority/sequence to something that is NOT '1' (so 2, 3 or even 16), the temperature sensor does not work properly and I get garbage data in the ADC_DR (ADC Data Register). So the code shared above won't work because it sets the sequence of channel 16 to 16th sequence/rank/priority using ADC_SQR1 (see line number 33)

Why is this happening? Why does changing the rank/priority/sequence of channel 16 disturb the functioning of the code?

P.S. In the ADC_SQR1 there is a "bit-space" named "L[3:0]" (screenshot attached). I believe this bit-space stands for the "number of conversions you wish to make". This bit-space was set to 2 when I selected the rank/priority/sequence to be 2 and 16 when I made the priority 16. So I don't think the configuration of 'L' might be the issue. But please do let me know if my understanding is wrong.

1.png

 

 
 

 

P.P.S: Please let me know what is the correct technical term for rank/priority/sequence? I see different words used at different places. Some articles refer to it as rank, so as priorities and the reference manual refers to it as sequence.

 

Regards,

Aditya Ubarhande

1 REPLY 1
RomainR.
ST Employee

Hi @AdityaUbarhande 

In your case, you use ADC1 with only the Temperatur Sensor (internal channel 16).

So, you only have one conversion sequence, specifically the first ADC_SQR3 -> SQ1[4:0].

You do not need to configure the other sequences in ADC_SQR1 or ADC_SQR2 . Refer to RM0090 rev 21 in section 13.3.10 Discontinuous mode - Regular group.

I propose the following code which will allow you to convert the Temperature sensor in Regular mode, 1st sequence with a sampling time of 480 fADC cycles.

 

//ADC Configuration
*ADC_CR2 |= (1 << 10);         // EOCS = 1: End of Regular conversion selection
*ADC_SMPR1 |= (7 << 18);       // SMP16[2:0] = 0b111
*ADC_SQR3 |= (1 << 4);         // SQ1|4:0] = 0b10000 Channel 16 is 1st conversion in regular sequence
*ADC_CCR |= (1 << 23);         // TSVREFE = 1 Enable TSensor
*ADC_CR2 |= (1 << 0);          // ADON = 1, ADC On

  while (1)
  {
    *ADC_CR2 |= (1 << 30);              // SWSTART Start conversion of regular channels
    while (!(*ADC_STAT & (1 << 1)));    // Poll for ADC_SR EOC = 1

    uint16_t Vsense =  (uint16_t)*ADC_DR; //Read ADC output data
    double voltage, celsius;

    voltage = (double)Vsense/4095*3.3;
    celsius = (double)(((voltage - 0.76) / 0.0025) + 25);
  }

Let me know if it help you to better understand?

Best regards

Romain,

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.