Previous posts showed how to use a TC74 temperature sensor with an STM32 microcontroller and how to handle communication errors . Since typically the temperature is not a value that changes rapidly, it is not essential to take multiple measurements with a high sampling rate, even if the I2C protocol is rather quick. For this reason, the TC74 sensor has a very low power standby mode when it not needed. The TC74 has an internal analog to digital converter which saves the value on an internal register. What is more this converter has a typical sampling rate of 8 samples per second. In standby mode this ADC is switched off. Concerning the power consumption, the information on the datasheet is a bit confusing. The datasheet provides a current consumption of 200uA in operating mode and 5uA in standby mode, which is a very significant difference. However, consumption in normal mode is measured for Vdd of 5.5V, whereas consumption in standby mode for Vdd of 3.3V. Based on my measurements of 2 TC74 operating in 3V, standby mode: 4uA, operating mode: 170uA. So indeed, the power saving is significant and should be used in low power applications. As it was analyzed, the TC74 has an 8-bit register which stores the temperature value. It has a second register (address 0x01), called the configuration register which has two bits. The first one (bit 7) enables the standby mode, whereas the second one (bit 6) shows when the sensor is ready to transmit the first data after entering operating operating. So the sequence to read the temperature using low power consumption is the following:
- Wake up
- Wait for the data to be ready (either using a delay or be polling the data ready bit of the config register
- Get temperature
- Sleep
After a wake up instruction, the TC74 needs about 300ms to transmit the first data. So in my implementation, a timer is used to wait for 500ms after a wake up instruction, get temperature and sleep the sensor and wait for 5s until the temperature is measured again. First of all, the TC74_Read_Temperature() function needs to be modified in order to read the 0x00 register (temperature) or the 0x01 register (configuration).
int TC74_Read_Register(uint8_t TC74address, uint8_t reg)
{
int8_t data1, data2;
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0)
{
return -127;
}
if(I2C_write(I2C1, reg)>0)
return -127;
if(I2C_stop(I2C1)==1)
return -127;
if(I2C_start(I2C1, TC74address, I2C_Direction_Receiver)>0)
{
return -127;
}
data1 = I2C_read_ack(I2C1);
data2 = I2C_read_nack(I2C1);
return data1;
}
We need to have a status variable which will show whether the TC74 is in operating or standby mode.
typedef enum {TC74_SLEEPING, TC74_WAITING} TC74_statetypedef;
TC74_statetypedef Temp_read_status=TC74_SLEEPING;
Two new functions are added, one that wakes up the sensor and another one that sends the instruction to enter standby mode.
int TC74_WakeUp(uint8_t TC74address)
{
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0)
{
return -127;
}
if(I2C_write(I2C1, 0x01)>0)
return -127;
if(I2C_write(I2C1, 0x00)>0)
return -127;
if(I2C_stop(I2C1)==1)
return -127;
return 0;
}
int TC74_Sleep(uint8_t TC74address)
{
if(I2C_start(I2C1, TC74address, I2C_Direction_Transmitter)>0)
{
return -127;
}
if(I2C_write(I2C1, 0x01)>0)
return -127;
if(I2C_write(I2C1, 0x80)>0)
return -127;
if(I2C_stop(I2C1)==1)
return -127; return 0;
}
After that we need to initialize a timer, TIM6 for the current example. The APB1 peripheral clock is 32MHz for the STM32L152.
void TIM6_Config(void)
{
TIM_TimeBaseInitTypeDef timerInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
timerInitStructure.TIM_Prescaler=1000;
timerInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
timerInitStructure.TIM_Period=32000;
timerInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM6, &timerInitStructure);
TIM_Cmd(TIM6, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
}
The interrupt handler routine of TIM6 is:
void TIM6_IRQHandler(void)
{
if (TIM_GetFlagStatus(TIM6, TIM_IT_Update)!=RESET)
{
TIM_Cmd(TIM6, DISABLE);
if (Temp_read_status==TC74_SLEEPING)
{
TC74_WakeUp(TC74_ADDRESS);
TIM6->PSC = 5000;
Temp_read_status=TC74_WAITING;
}
else
{
Temperature=TC74_Read_Register(TC74_ADDRESS,0x00);
TC74_Sleep(TC74_ADDRESS);
TIM6->PSC = 500;
Temp_read_status=TC74_SLEEPING;
}
TIM6->CNT=0;
TIM_Cmd(TIM6, ENABLE);
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}
}
The full project to read the temperature from the TC74 sensor with error handling and standby mode can be found on my Github page.