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