Introduction
The previous two posts on this topic dealt with the BMP180 pressure/temperature sensor and the NRF905 radio transceiver separately. This post brings it all together and shows how energy consumption was reduced to prolong battery life. The original plan was to run this from two solar powered garden lights. These lights come with coin cell size NiMh batteries and a simple charging circuit. After a bit of fiddling I decided to put this to one side having concluded that the internal resistance of the coin cells was quite high resulting in a large voltage dip during transmission. Furthermore the capacity of the batteries is so small (40mAh printed on the case) and the quality so poor that they were unable to power the station through the night. For the moment I have switched to a pair of rechargeable 1300mAh AA batteries that are charged externally. I may revisit the solar power option later and replace the tiny NiMh batteries with some decent AA or AAA ones.
Reducing power consumption
The three main power consuming elements in the weather station are:
(1) BMP180 pressure/temperature sensor module
(2) NRF905 radio transceiver
(3) STM32F030 MCU
According to the datasheet, the BMP180 has an idle current of 5uA and an active current of up to 650uA. This device is mounted on a breakout board which has a voltage regulator (XC6206) with a quiescent current consumption of 3uA. A MHC5983 magnetometer is also on the board with a quiescent current of 2uA and an active current of 100uA. The total quiescent for this board should be the sum of these : around 10uA. Only the BMP180 is used so the peak current should get to around 650uA.
The NRF905 is powered down when not in use. The datashseet states that its current consumption should get down to 2.5uA when powered down, 32uA when in standby and 20mA when transmitting at +6dBm.
The STM32F030 is put in to deep sleep mode between transmissions. The LSI clock and RTC are left running and periodically wake the system up. It is a little difficult to determine what the current consumption should be in this mode. According to the datasheet, the current consumption should be between 2 and 5 uA. The power consumption of the RTC is of the order of 1uA according to ST literature. During active mode at 8MHz with code executing from flash, the current consumption should be around 4mA.
Adding all of the standby currents up we get to about 10 + 2.5 + 5 + 1 = 18.5uA.
Active mode current flow should be dominated by the STM32F030 and the NRF905. I would expect active mode currents of 5mA with no radio transmission and 25mA during transmission.
The main program loop is as follows:
while(1) { Int2String(readTemperature(),&Msg[0]); Msg[10]=','; Int2String(readPressure(),&Msg[11]); TxPacket(Msg,0x20); low_power_mode(); // Sleep and wait for RTC interrupt resume_from_low_power(); }
This transmits a packet with the following format:
0000000233,0000099804
This is interpreted as a temperature of 23.3 C and a pressure of 998.04 milibars
The RTC is configured to wake system once per minute (the weather does not change that quickly)
Low power mode is entered and exited with the following two functions:
void low_power_mode() { PwrLow(); // Put NRF905 into low power mode // Turn off GPIO B,A and F RCC_AHBENR &= ~(BIT17+BIT18+BIT22); RCC_APB1ENR &= ~BIT21; // Turn off clock for I2C1 RCC_APB2ENR &= ~BIT12; // turn off SPI1 RCC_CFGR |= 0xf0; // drop bus speed by a factor of 512 cpu_sleep(); // stop cpu } void resume_from_low_power() { RCC_CFGR &= ~0xf0; // speed up to 8MHz // Turn on GPIO B,A and F RCC_AHBENR |= BIT18+BIT17+BIT22; RCC_APB1ENR |= BIT21; // Turn on clock for I2C1 RCC_APB2ENR |= BIT12; // turn on SPI1 PwrHigh(); // power up the radio }
Entering low power mode, the code shuts down the NRF905, disables clocks to the I/O port, I2C and SPI peripherals, slows the peripheral bus clock and stops the CPU. Resuming from low power reverses these steps. The CPU can be placed in shallow or deep sleep modes depending upon the setting of bit 2 in the system control register. The code below enables deep sleep mode which stops the CPU clock and powers down flash memory.
SCR |= BIT2; // enable Deep Sleep mode
On receipt of an RTC interrupt, the CPU exits sleep mode and resumes execution.
Results
The measured quiescent current was a lot higher than expected; around 170uA @ 3.6V and 90uA at 2.4V. Why is this so much higher? Perhaps passive components on the breakout boards such as pull-down or pull-up resistors are raising the levels. All of the peripherals on the STM32F030 may not be powered off. A current drain of 90uA at 2.4V should allow the station to idle on 1300mAh for more than a year and I felt that this was probably good enough for now. The actual run time is likely to be a lot lower than this due to self discharge in the battery and the energy used during the brief transmission interval. I’ll see how it goes with an extended test.
The active mode current is lower than expected. The MCU current just before transmission is about 3mA. It would seem that the radio is only drawing (19-3) = 16mA during transmission. The datasheet suggests that this level of current should be typically 20mA. During experimentation I found that the current levels during transmission were consistently less than suggested by the datasheet – maybe the datasheet typical values are a little overstated.
Looking at the graph, the 5mA (max) region consists of three approx equal length periods: I2C read of temperature, I2C read of pressure and SPI transfer to NRF905. The NRF905 data packet consists of a preamble (10 bits), address (32 bits), data packet (32 bytes) and a CRC field (16 bits). In total this is 538 bits. The data rate if 50kbps which means the transmission time should be 10.76ms. This agrees with the graph.
Debugging issues
I developed this code using my ST-Link V2 debugger salvaged from a Nucleo board and reflashed with J-Link firmware. OpenOCD and GDB allowed me to debug and download code. A problem arises when the CPU is in a deep sleep : OpenOCD can not talk to it in this mode. It complains and times-out repeatedly. Occasionally, it catches the CPU when its awake allowing you halt it and to download code. If the sleep interval is long (e.g. a minute or more) this can be quite frustrating. There is a way around this however. If you pull the Boot0 pin high and power cycle the MCU it will boot to ISP mode. Openocd & GDB can happily attach to this allowing you to download fresh code. When download is complete, set Boot0 to zero and power cycle once more to run your code. You don’t need to stop OpenOCD or GDB when you do this power cycle (I just pulled a wire from the breadboard and put it back again)
Radio range
The NRF905 radio modules were supplied with some short antennas which seemed too short for 433MHz. I found that replacing them with quarter wave length wires slightly improved signal range. I settled on a power output level of 6dBm as it gave me an (urban) range of about 100m – enough for my needs. The radio module seemed to misbehave at the higher power level of +10dBm. This could be as a result of the breakout board or perhaps poor supply regulation. Running it a +6dBm produced stable results.
Code download
You can download the code for the weather station over here on github: https://github.com/fduignan/Weatherstation1
One thought on “Weather station part 3: putting it all together”