Honza T. / Mbed 2 deprecated EXAMPLE_Nucleo_InternalTempSensor

Dependencies:   TextLCD_improved mbed

main.cpp

Committer:
dzoni
Date:
2015-12-12
Revision:
1:99b0d902bfd6
Parent:
0:4127c73008a9
Child:
4:be36f1d1babe

File content as of revision 1:99b0d902bfd6:

#include "mbed.h"
#include "stm32f411xe.h"
#include "TextLCD.h"

/*
Reading the temperature
To use the sensor:
3.     Select ADC1_IN16 or ADC1_IN18 input channel. 
4.     Select a sampling time greater than the minimum sampling time specified in the datasheet.
5.     Set the TSVREFE bit in the ADC_CCR register to wake up the temperature sensor from power down mode
6.     Start the ADC conversion by setting the SWSTART bit (or by external trigger)
7.     Read the resulting VSENSE data in the ADC data register
8.     Calculate the temperature using the following formula: Temperature (in °C) = {(VSENSE – V25) / Avg_Slope} + 25
Where:
    – V25 = VSENSE value for 25° C
    – Avg_Slope = average slope of the temperature vs. VSENSE curve (given in mV/°C or μV/°C)

    Refer to the datasheet’s electrical characteristics section for the actual values of V25and Avg_Slope.
 
The TSVREFE bit must be set to enable the conversion of both internal channels: the ADC1_IN16 or ADC1_IN18 (temperature sensor) and the ADC1_IN17 (VREFINT). 

The sensor has a startup time after waking from power down mode before it can output VSENSE at the correct level.
The ADC also has a startup time after power-on, so to minimize the delay, the ADON and TSVREFE bits should be set at the same time.
The temperature sensor output voltage changes linearly with temperature.
The offset of this linear function depends on each chip due to process variation (up to 45 °C from one chip to another).
The internal temperature sensor is more suit ed for applications that detect temperature variations instead of absolute temperatures.
If accurate temperature reading is required, an external temperature sensor should be used.

SINGLE Conversion:

START
    CONT = 0
    ADC_CR2.SWSTART = 

COMPLETED
    16bit data in ADC_DR
    EOC Flag is set
    If JEOCIE bit is set then interrupt generated
    ADC Stops
    
ADC_SR (Status Register)
    - EOC (0x02): Cleared upon reading ADC_DR
    
ADC_CR1 (Control Register 1)
    - RES [1:0]: Resolution
        00  12bit
        01  10bit
        10  8bit
        11  6bit

ADC_CR2 (Control Register 2)
    - SWSTART (ADON must be set to 1): Start conversion on regular channels
    - ADON: A/D Convertor on/off
    - CONT: Continuous conversion
    
ADC_DR (Data Register)

ADC_CCR (Common Control Register)
    - TSVREFE (): Temperature Sensor and Vrefint enable
        VBATE must be disabled to measure temperature
    - VBATE (): Vbat enable

ADC1_SQR1
    - L - počet převod; u regular
        0 = 1 převod

ADC_SQR3
    - nejnižších 5 bitů je první převod
    
ADC_Typedef
ADC_Common_TypeDef

RCC_TypeDef (APB2ENR)

ADC_BASE
ADC1_BASE

ADC
ADC1

 */

void initADCTemp() {
    //enable ADC1 clock
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_ADC1EN);

    // Zapnout ADC
    SET_BIT(ADC1->CR2, ADC_CR2_ADON);
    CLEAR_BIT(ADC1->CR2, ADC_CR2_CONT);
    
    // Zapnout Temp sensor
    CLEAR_BIT(ADC->CCR, ADC_CCR_VBATE);
    SET_BIT(ADC->CCR, ADC_CCR_TSVREFE);
    
    CLEAR_BIT(ADC1->CR1, ADC_CR1_RES);
}

uint16_t getADCTemp() {
    // Set channel
    ADC1->SQR1 &= ~ADC_SQR1_L;  // Count = 1
    ADC1->SQR3 |= ADC_SQR3_SQ1 & 18;

    // Start conversion
    SET_BIT(ADC1->CR2, ADC_CR2_SWSTART);
    
    // Wait for completion
    while (!READ_BIT(ADC1->SR, ADC_SR_EOC))
        ;
        
    // Return result
    return READ_REG(ADC1->DR);
}
     
            
int main() {
    const float     V25 = 943.3212f;// when V25=1.41V at ref 3.3V (0,76V)
    const float     Avg_Slope = 3.1030303f; //when avg_slope=4.3mV/C at ref 3.3V  (2.5mV/C)
    const uint16_t  bufferSize = 4;

    float       temp;
    uint16_t    i;
    uint16_t    uiCnt = 0;

    TextLCD lcd(PA_8, PA_7, PA_9, PA_1, PB_5, PA_10, TextLCD::LCD16x2);

    initADCTemp();
        
    while (true) {
        for (i = 0, temp = 0.0f; i < bufferSize; i++) {
            temp += ((float)getADCTemp() - V25) / Avg_Slope + 48.2f;
            wait_us(1000);
        }
        temp /= (float)bufferSize;
     
        lcd.cls();
        lcd.printf("Teplota: % 4u s", uiCnt);
        uiCnt += 1;
        lcd.locate(0, 1);    
        lcd.printf("% 3.1f%cC", temp, 0xdf);
        wait_us(1000000);
    }
}