Weather station part 2: The radio link


As mentioned in the previous post I’m hoping to put together a weather monitoring system. It will consist of an outstation in the garden which will be solar powered. The outstation will send data over a radio link to a base station located indoors. This post outlines the radio link code and setup.

The outstation radio wiring

The figure above shows the connections between the outstation MCU, the BMP180 pressure/temperature sensor and the NRF905 radio module. There are lots of connections to the radio module and I’m not sure they are all strictly necessary at the moment but for now they stay.
The NRF905 can transmit at a number of different frequencies. After some trial and error I decided to go with a frequency in the 433 ISM band as it seemed to work best (the NRF905 is on a breakout board which already has inductors and capacitors in the antenna circuit which I suspect were tuned for this band). The actual module is supplied from (link). Overall I found this module much easier to use than the NRF24L01.
The code for the radio link is available on github over here. This code transmits an counter value once per second at maximum power (10mW). This current consumption while transmittiing is quite high (about 29mA) but this current burst is pretty short lived. Early indications are that the range is sufficient for my purposes though I may fiddle with the antenna later to see how far it can be pushed.
A (messy) prototype is shown in the photo below
You may notice the ST-Link debugger salvaged from a Nucleo board attached to the target. This debugger was reflashed with the Segger/J-Link firmware and behaved very well.

The base station

The base station consists of an STM32L011 Nucleo board attached to an NRF905 module. A photo is shown below (wiring details in the code only for the moment)
The Nucleo outputs any data it receives over its built-in USB/Serial converter. This is displayed on the host PC.
One problem arose with the STM32L011’s SPI interface which is covered in its errata sheet. There is a timing problem with the SPI pins and ST provide a simple fix for this (which I found out about after two days of head scratching :). Code for the base station is available here

Next post

The next post will deal with the issue of power consumption on the outstation. This needs to be kept as low as possible if the solar power cells I salvaged from cheap garden LED lights are to work out.

Weather station part 1: Pressure and temperature


I’ve decided to try to put together a solar powered wireless weather station this summer. It will consist of two parts: an outstation comprising of a pressure/temperature sensor attached to an STM32F030 MCU; all powered by a cheap solar panel and a rechargeable battery. The MCU will use an NRF905 radio module to send data back to a base station within the house which will display it on screen. Power consumption in the outstation will have to be kept to a minimum.
The base station will consist of an STM32L011 Nucleo board and an NRF905 module. It will interface to the host PC using the built-in UART.

The pressure/temperature sensor

About a year ago I bought a BMP180+HMC5983 module from The BMP180 component is a very sensitive atmospheric pressure and temperature sensor with an I2C interface. The HMC5983 is a digital magnetometer may have a future role to play in the weather station.

The outstation MCU

I have previously posted a description of how to mount the STM32F030 TSSOP-20 MCU on a breadboard friendly breakout board. These MCU’s can be configured to consume very little energy. I had several of these lying around so the seemed the logical choice.


The image above shows the wiring involved. The bmp180 module has built-in pull-up resistors so its quite simple. The code on the other hand is quite complicated. The BMP180 has a very strange conversion routine that takes the sensor outputs and converts them to pressure (in Pascals) and temperature (in degrees C x 10). The measurement results are output via the UART TX pin on PA9. I connected this to the host PC using a USB/Serial converter.
The code can be found here. It includes a lot of debugging code that was useful during development. This is very much version 0.1 as it does not take power consumption into account in any way. That will be the subject of a future post.

Interrupt driven display driver for the Arduino nano


There are a number of 7 segment display available on the Internet. Some of them use 74595 shift registers to control them. These require the display to be refreshed continuously as the LED’s are multiplexed across a number of digital output pins. I bought one from (link) though I see they are now out of stock. With a bit of fiddling I came up with the following interrupt driven code to drive it.

The PWM system is used to generate a periodic interrupt on digital output 3. Arduino allows you to attach an interrupt to this pin which works even if the pin is a PWM output. This is done in the setup function. The interrupt handler is set to RefreshDisplay.

The RefreshDisplay function copies the contents of the global array DisplayMemory to the 74595 shift registers in the the display module. One digit is written for each interrupt. After 8 interrupts, all digits have been updated and the process starts over.

The main loop calls on the DisplayNumber function whose job is to take a apart the supplied number into each of its individual digits. The digits are converted to 7-segment LED codes which are stored in DisplayMemory.
The display is connected to the ICSP header of an Arduino nano as shown. The clock and data pins are driven by software.

int SCKPin = 13;
int DIOPin = 11;
int RCKPin = 12;
int DisplayMemory[8];
void setup()
// Establish periodic interrupt on digital pin 3 so that RefreshDisplay
// is called regularly
long Count=0;
void loop()
const char LED_Codes[]={ 0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10010000 };

void DisplayNumber(long Number)
  int Digit;
  for (Digit=0;Digit<8;Digit++)
    DisplayDigit(7-Digit,Number % 10);
    Number = Number / 10;
void DisplayDigit(int DigitNumber,int Digit)
void RefreshDisplay()
  static  int Digit=1;
  static int Index=0;
  Digit = Digit << 1;  
  if (Index > 7)
    Index = 0;
    Digit = 1;

void SendByte(int Byte)
  int Bit;
  for (Bit = 0; Bit < 8; Bit++)
    if (Byte & 0x80)
    Byte = Byte << 1;

A very low cost STM32F030 dev board

Aliexpress have begun shipping a low cost breakout/development board for the STM32F030. The board can be programmed using ISP and a USB/UART interface as shown below. The boards cost varies but I got mine for 1.58 Euro.
I had previously worked on some suitable examples which can be found over here.
These examples are built using a Makefile however I have found that the following script is a lot easier to work with (just make sure your PATH environment variable includes the directory where the arm compiler programs and utilities are stored).

arm-none-eabi-gcc -static -mthumb -g -mcpu=cortex-m0 *.c -T linker_script.ld -o main.elf -nostartfiles 
arm-none-eabi-objcopy -g -O binary main.elf main.bin
arm-none-eabi-objcopy -g -O ihex main.elf main.hex

You then program the chip by linking the Boot0 pin and 3v3 with the jumper, hit reset and enter the following:

stm32flash -w main.hex /dev/ttyUSB0

To run your program, move the jumper so that it links Boot0 to GND and hit reset.
The USB/UART interface appeared as /dev/ttyUSB0 on my system, yours may vary (on Windows it will be something like COM3)
stm32flash can be downloaded from a number of sources. On Ubuntu it can be installed with

sudo apt-get install stm32flash

The ARM cross compiler suite can be downloaded from

Aliexpress link to the board.

Interactive SPI

The SPI protocol can be tricky enough to get working especially if you are unsure of the MCU you are using and/or the peripheral.  Logic analyzers can help but can also be expensive.  With the help of the following Energia MSP430G2553 code and a dumb terminal serial application program (on your PC) you can interact live with an SPI peripheral and hopefully come to grips with its operation.

The peripheral can be wired as follows:

Launchpad                   Peripheral
P1_0------------------------SS (slave select or CE)

Check the peripheral power requirements first and don’t connect a 5V peripheral directly to a 3.3V MSP430

The program presents the user with a simple menu:

Please select from one of the following:
0: SS Low
1: SS High
2: Write byte
3: Read byte

If you choose 0 or 1, SS is raised or lowered as appropriate and the menu recycles. If you choose 2 you see this (I entered the value ‘a9’ (not case sensitive))

Please select from one of the following:
0: SS Low
1: SS High
2: Write byte
3: Read byte
Enter a 2 character hex value: a9
Out : A9
In : 0

If you choose 3 you will see something like this:

Please select from one of the following:
0: SS Low
1: SS High
2: Write byte
3: Read byte
In : 0

The code is shown below. You will probably need to check out which SPI modes and byte ordering suit you. Also, the SPI interface is running at the very low speed of 125kHz. This was deliberate as it reduces the risk of data errors on shaky test leads and may help debugging. You can of course change this. The divider is divided into 16MHz to give an SPI data rate. This is very definitely version 0.1 and changes are likely in the future when I do some real testing.

 * SPI protocol tester using the MSP430G2553 G2 Launchpad
 * This program allows you manage an SPI bus,write and read data
 * using a serial dumb terminal application
 * The program makes use of the Energia Serial and SPI libraries
 * Serial interface : 9600,n,8,1
 * SPI library reference :
#include <SPI.h>

// Will use P1_0 as SS pin as there is a handy LED there on the launchpad
#define SS_Pin  P1_0

int getUserCommand();
int getInteger(String Prompt);
void setup() {
  // put your setup code here, to run once:
  // Default SPI configuration : feel free to change!
  // Set up the SS Pin and make it HIGH initially (low wakes up a slave)
  SPI.setDataMode(SPI_MODE0); // can choose modes 0,1,2,3
  SPI.setBitOrder(MSBFIRST);  // can be MSBFIRST or LSBFIRST
  SPI.setClockDivider(128);   // assuming a system clock of 16MHz this gives an 
                              // SPI speed of 125kHz - deliberately slow to be more forgiving and
                              // to make signals easier to see with a scope of logic analyser
  // Serial communications to host setup
int TXByte,RXByte;
void loop() {
  // put your main code here, to run repeatedly: 
  switch (getUserCommand())
    case 0 : {
      // Command 0 : drop SS pin down
    case 1 : {
      // Command 1 : raise SS pin up
    case 2 : {
      // Command 2 : send a byte
      TXByte = getInteger("Enter a value to transmit: ");
      RXByte = SPI.transfer(TXByte);
      Serial.print("Out : ");
      Serial.print("In : ");
    case 3 : {
      // Command 3 : read a byte (send a dummy byte out)
      RXByte = SPI.transfer(0x00);
      Serial.print("In : ");
    default : {
      Serial.println("Invalid choice");
int showMenu(String Menu[],int MenuItemCount)
  Serial.println("Please select from one of the following:");
  for (int item=0; item < MenuItemCount; item++)
    Serial.print(": ");
  return - '0'; // assuming a numeric choice is made - convert to decimal from ascii

int getUserCommand()
  String Menu[4];
  Menu[0]="SS Low";
  Menu[1]="SS High";
  Menu[2]="Write byte";
  Menu[3]="Read byte";
  return showMenu(Menu,4);
int HexDigitToDecimal(char Digit)
  if ( (Digit >= '0') && (Digit <= '9') )
    return Digit - '0';
  Digit = Digit | 32; // enforce lower case
  if ( (Digit >= 'a') && (Digit <= 'f') )
    return Digit - 'a' + 10;
  return 0;
int getInteger(String Prompt)
  char HexString[3];
  int ReturnValue = 0;
  Serial.print("Enter a 2 character hex value: ");
  ReturnValue = HexDigitToDecimal(HexString[0]);
  ReturnValue = ReturnValue << 4;
  ReturnValue += HexDigitToDecimal(HexString[1]);
  return ReturnValue;

Let your code do the wiring


The image above shows two implementations of the same gaming system (ArcadeSlam). The display has a parallel data interface and the left hand version maps this interface to the 8 bits of a single I/O port on the MSP430 MCU.  A simple write to the port data register is sufficient to write a byte to the display.  From a programming perspective this is easy but, as you can see, the wiring is a little complex.

The version on the right makes use of the connections within the breadboard to connect the display data interface to the MSP430.  This greatly simplifies the wiring however it pushes this complexity back into the code.  The wiring looks like this:


The display data interface is spread across Ports 1 and 2.  Not only that, the bits are in reverse order.  Reversing bits at run-time represents a performance hit so, a lookup table was generated and the writing of the data bytes goes from this (for the left hand version)

P2OUT = data;


P1OUT &=0xc1;
P2OUT &=0xf8;
if (b)
{ // only write out bits if b is non zero to save time
P1OUT |= reverse_bits[ (b >> 3) ] >> 2;
P2OUT |= reverse_bits[ (b & 0x7) ] >> 5;

The lookup table reverse_bits was produced using the following python script (only a 5 bit table was necessary)

# Output the specified range of numbers with their
# bits reversed as a lookup table suitable for C
print "const uint8_t reverse_bits[]={ \\"
for n in range(32):
print int('{:08b}'.format(n)[::-1], 2),",\\"
print "};"

Performance is not obviously affected by this wiring change and full code can be downloaded over here on github.

More information can also be found on

Low pass filtering using the STML432 Nucleo

This example uses a 4th order Butterworth low pass filter that was designed in GNU Octave.  The sampling rate was set to 200kHz and the cut-off frequency was set to 20kHz.  The filter output at 20kHz is shown below and, as expected, shows an attenuation of 0.7 (approx the square root of 2).


Various attempts were made to optimize the performance of the filter.  The execution time was measured by flipping an output bit either side of the filter code.  An oscilloscope trace of this output is below.


As can be seen, the execution time is 1.78 microseconds. This is pretty quick given that floating point numbers are being used.  I found that my attempts to manually improve the performance made no significant difference compared to what the compiler’s optimizer could do.  I also found that gcc’s -O2 optimization setting produced a faster filter than -O3.  The filter shuffles data in the input and output delay lines.  This may be considered less  than optimal but, given that the order of the filter is low, it probably would make little difference to use circular buffers (and manage buffer state etc).

Code can be downloaded here on Github and should be easily compiled on Linux/Windows/Mac