2024-10-25 01:51 AM
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.
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
2024-12-03 06:45 AM
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.