cancel
Showing results for 
Search instead for 
Did you mean: 

[SOLVED] STM32F746 temperature sensor problem

quentin2399
Associate II
Posted on June 27, 2016 at 12:22

Hello,

I'm trying to get temperature from internal sensor of the STM32F7 I'm a begineer and I'm working on a discovery kit directly on mbed. Currently, the functionHAL_ADC_PollForConversion return nothing, because of an infinite loop. I don't understand why ...

#include ''mbed.h''
float temp = 0;
ADC_HandleTypeDef hadc1;
Serial pc(USBTX, USBRX); // tx, rx
void init(){
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV8;
hadc1.Init.Resolution = ADC_RESOLUTION12b;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
HAL_ADC_Init(&hadc1);
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; //ADC_Channel_TempSensor = ADC_Channel_18 on STM32f7xx*/
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_144CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
/* 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;
//The next statement enables ADC1
__HAL_ADC_ENABLE(&hadc1);
pc.printf(''Init done\n'');
}
float getMCUTemperature() {
float temp;
HAL_ADC_Start(&hadc1);
pc.printf(''AAA\n'');
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
pc.printf(''BBB\n'');
HAL_ADC_Stop(&hadc1);
temp = ((HAL_ADC_GetValue(&hadc1))/40)*30;
temp = (temp - 70)/2.5;
temp += 0;
return temp;
} 
int main() {
init();
while(1) {
temp = getMCUTemperature();
pc.printf(''Temp = %f\n'',temp);
wait(1.0); // 1 sec
}
}

I can't use ''ADC_TempSensorVrefintCmd()'' ( undefined function), so, I put directly the

TSVREFE

bit myself.

Does anyone have the same problem ? Best regards, Quentin
8 REPLIES 8
troy1818
Senior
Posted on June 27, 2016 at 12:40

Hi,

These are the instructions (Description of STM32F4xx HAL drivers):

Start the ADC peripheral using HAL_ADC_Start()

Wait for end of conversion using HAL_ADC_PollForConversion(), at this stage usercan specify the value of timeout according to his end application

To read the ADC converted values, use the HAL_ADC_GetValue() function.

Stop the ADC peripheral using HAL_ADC_Stop() 

The reason for ''infinite'' loop is because no conversion is made and you have HAL_MAX_DELAY as argument.

The reason for not getting any conversion could be many. One reason could be that you did not activate the peripheral correctly. For example, did you turn on the clock for the peripheral ?

quentin2399
Associate II
Posted on June 27, 2016 at 13:48

Thank you for your quick response.

These are instructions for the STM32F7xx in ''

stm32f7xx_hal_adc.c

''

:

#)Initialize the ADC low level resources by implementing the HAL_ADC_MspInit():
(##) Enable the ADC interface clock using __HAL_RCC_ADC_CLK_ENABLE()
(##) ADC pins configuration
(+++) Enable the clock for the ADC GPIOs using the following function:
__HAL_RCC_GPIOx_CLK_ENABLE() 
(+++) Configure these ADC pins in analog mode using HAL_GPIO_Init() 
(##) In case of using interrupts (e.g. HAL_ADC_Start_IT())
(+++) Configure the ADC interrupt priority using HAL_NVIC_SetPriority()
(+++) Enable the ADC IRQ handler using HAL_NVIC_EnableIRQ()
(+++) In ADC IRQ handler, call HAL_ADC_IRQHandler()
(##) In case of using DMA to control data transfer (e.g. HAL_ADC_Start_DMA())
(+++) Enable the DMAx interface clock using __HAL_RCC_DMAx_CLK_ENABLE()
(+++) Configure and enable two DMA streams stream for managing data
transfer from peripheral to memory (output stream)
(+++) Associate the initialized DMA handle to the CRYP DMA handle
using __HAL_LINKDMA()
(+++) Configure the priority and enable the NVIC for the transfer complete
interrupt on the two DMA Streams. The output stream should have higher
priority than the input stream.

All my code is here. Indeed, I think the clock isn't turned on. I tried to activate the clock but the functions which I have to use are undefined (like ''

__HAL_RCC_ADC_CLK_ENABLE()'')

Is it normal ?
troy1818
Senior
Posted on June 27, 2016 at 14:23

Strange, they should be defined somewhere in ST HAL layer. Perhaps in stm32f7xx_hal_rcc.h?

quentin2399
Associate II
Posted on June 28, 2016 at 12:53

Apparently, many things changed between STM32F4 and STM32F7 to Enable Clocks.

I tried to activate clock with this code and call it before all, but still the same problem.

static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 288;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 6;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; 
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; 
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
SystemCoreClockUpdate();
}

AvaTar
Lead
Posted on June 28, 2016 at 13:27

Because this is the routine to switch the system (core) clock, and not for the ADC.

Those peripheral clock setup routines are usually implemented in a file name

stm32f7xx_hal_msp.c

.

There is an example project for the temperature sensor in:

($Cube)/\Projects/STM32F769I-Discovery/Examples/ADC

and other ADC examples (for instance) in:

($Cube)/\Projects/STM32F746ZG-Nucleo/Examples/ADC

They are however for ''regular'' toolchains, not mbed. At least they could serve as a guide.

troy1818
Senior
Posted on June 28, 2016 at 15:56

You need to activate the clock for all functionality that you are going to use. For example, if you are using port C GPIOs then you need to activate clock for port C. If you are using ADC 3 then you need to activate that specifically:

__HAL_RCC_ADC3_CLK_ENABLE();

I cannot see that you are activating other than PWR in your example code.

Regards,

Rygelxvi

quentin2399
Associate II
Posted on June 29, 2016 at 11:33

Thank you for your answers.

I don't have

stm32f7xx_hal_msp.c

. And I code directly on mbed on Internet, I don't have any repositories like this. So, I don't need to activate system clock at all ? I tried to activate only ADC1 Clock (used for temperature sensor as explained in the Reference Manual) like this :

__HAL_RCC_ADC1_CLK_ENABLE();

Now, the program isn't stuck in a infinite loop, but the function ''

HAL_ADC_GetValue(&hadc1))''

always return 0 ...

Do I have to activate some GPIO Clocks or something else ?
quentin2399
Associate II
Posted on June 29, 2016 at 12:05

I finally found something which already working.

This link helped me a lot :

https://developer.mbed.org/users/of050966/code/NewKu/docs/ee86970ea7df/InternalTemperature_8cpp_source.html

It's almost fully functionnal. I adapted the code for the conversion, I think it was no good ( always 97 before) New one is here :

#include ''mbed.h''
analogin_t obj;
float temp;
Serial pc(USBTX, USBRX); // tx, rx
DigitalOut myled(LED1);
void temp_init(analogin_t *obj) {
pc.printf(''Init...
'');
obj->adc = (ADCName)16;
// Enable ADC1 clock source.
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
// Enable the ADC
ADC1->CR2 |= ADC_CR2_ADON;
// Enable internal temperature sensor.
ADC->CCR |= ADC_CCR_TSVREFE;
// Set longest sample time just to be safe.
ADC1->SMPR1 |= 0x1c;
pc.printf(''Init Done
'');
}
static inline uint32_t temp_read(analogin_t *obj) {
// Select the appropriate channel
ADC1->SQR3 = (int) obj->adc;
// Start conversion
ADC1->CR2 |= ADC_CR2_SWSTART;
// Wait for conversion to finish
while (!(ADC1->SR & ADC_SR_EOC));
uint32_t data = ADC1->DR;
return data; // 12 bit
}
static inline uint32_t temp_read_u32(analogin_t *obj) {
uint32_t value;
value = temp_read(obj);
return value;
}
uint16_t temperature_read_u16(analogin_t *obj) {
uint32_t value = temp_read_u32(obj);
return (value << 
4
) | ((value >> 8) & 0x000F); // 12 bit
}
float temperature_read(analogin_t *obj) {
uint32_t value = temp_read_u32(obj);
float ret = (value/40)*30;
ret = (ret - 70)/2.5;
ret += 0;
return ret;
}
int main() {
temp_init(&obj);
while(1) {
temp = temperature_read(&obj);
pc.printf(''Temperature = %f C
'',temp);
wait(1.0); // 1 sec
}
}