Universal Wireless Sensor Node

The Universal Wireless Sensor Node reference design is based on the STM32L412KBT6 ARM microcontroller. Under the guidance of the microcontroller’s firmware, the reference design hardware can perform tasks such as:

  • Switch Disposition (Remote and Local/Open or Closed)
  • Remote and Local Temperature Reporting
  • Remote and Local Humidity Reporting
  • Remote and Local Relay Control
  • Remote and Local Motion Detection
  • Remote and Local Hazardous Gas Detection

As a wireless platform, the Universal Wireless Sensor Node can accommodate a wide variety of radio modules that operate in the low-power unlicensed bands including:

  • 433MHz Transmitters/Receivers/Transceivers
  • 915MHz Transmitters/Receivers/Transceivers
  • 2.4GHz Transmitters/Receivers/Transceivers
  • Bluetooth Radio Modules
  • MURS (Multi-Use Radio Service) Transmitters/Receivers/Transceivers

Lemos International offers radio modules in each of the aforementioned categories. Here are a couple of examples:

  • BiM2-433-64-5V (433MHz)
  • BiM3A-914-64 (915MHz)

The MURS alternative can be advantageous as MURS radio devices also operate in unlicensed bands and can emit a maximum of 2 watts of transmit power. Coupled with the right antenna, MURS offers a long-range radio link that can be used for remote control, remote monitoring and voice applications. Consult the LEMOS International MURS Wireless Sensor Node reference design for more information on MURS radio deployment.

The key to the flexibility of the LEMOS Universal Wireless Sensor Node design is its ability to interface to all of the popular sensor types.  Digital and analog I/O pins that are not being used to interface to sensors can be used to sense contacts or drive relays and LED indicators. The STM32L4 microcontroller is capable of communicating with external devices using I2C, SPI and asynchronous protocols.

Many of today’s crop of sensors utilize I2C (Inter-Integrated Circuit), which is a 2-wire serial protocol that uses data stream addressing that is sometimes based on installing an address jumper on the sensor hardware I/O pins. Data stream addressing simply means that the I2C device responds to an address that is transmitted on the I2C physical communications interface. I2C was invented by Philips, which is now known as NXP. The I2C signals (SDA and SDL) are located on connector J5.

Some sensors communicate to the host microcontroller using SPI (Serial Peripheral Interface).  SPI is a 3-wire high-speed serial interface whose nodes are selected by the host microcontroller using a Slave Select pin. SPI was invented by Motorola. The SPI signals (MOSI, MISO, SCK. CS) are located on connector J4.

More often than not, the 3-wire asynchronous interface (TXD, RXD and GND) is used by the guest radio module. Data flowing over the RF link is relayed to the host microcontroller over this interface. The asynchronous interface is located on connector J5.

The I2C and SPI protocols are also widely used to communicate with memory and display devices. The Universal Wireless Sensor Node reference design takes advantage of the STM32L4’s SPI interface and includes a SPI-driven 25AA256 EEPROM.

Although the I2C, SPI and 3-wire asynchronous protocols do the job in most cases, there are exceptions. For instance, the DS18B20 temperature sensor communicates with the host microcontroller using the 1-Wire protocol. The 1-Wire protocol is a precision-timed half-duplex serial communications method that is made up physically of a single wire and a ground connection. It is the responsibility of the host microcontroller to deliver the microsecond timing needed to generate the precise 1-Wire signal pulses that make up the 1-Wire protocol. The Universal Wireless Sensor Node reference design includes provisions to physically connect to and communicate with a 1-Wire slave device. The DQ signal referenced on terminal block J3 in the schematic represents the 1-Wire signal line.

Since the 1-Wire protocol is half-duplex (cannot transmit and receive as the same time), we need a software mechanism to “turn” the wire around.  In other words, the master 1-Wire device must be able to use the DQ signal as an input or an output.  Here’s the code to make that happen:

void dqOutput(void)

{

LL_GPIO_SetPinMode(DQ_GPIO_Port, DQ_Pin, LL_GPIO_MODE_OUTPUT);

LL_GPIO_SetPinSpeed(DQ_GPIO_Port, DQ_Pin, LL_GPIO_SPEED_FREQ_LOW);

LL_GPIO_SetPinOutputType(DQ_GPIO_Port, DQ_Pin, LL_GPIO_OUTPUT_PUSHPULL);

LL_GPIO_SetPinPull(DQ_GPIO_Port, DQ_Pin, LL_GPIO_PULL_NO);

}

void dqInput(void)

{

LL_GPIO_SetPinMode(DQ_GPIO_Port, DQ_Pin, LL_GPIO_MODE_INPUT);

LL_GPIO_SetPinPull(DQ_GPIO_Port, DQ_Pin, LL_GPIO_PULL_NO);

}

The 1-Wire protocol dictates the pulse sequence that defines a reset sequence. The 1-Wire reset sequence is used to force any slave devices to generate a return pulse.  The 1-Wire reset code looks like this:

uint8_t owReset(void)

{

uint32_t rc;

dqOutput();

LL_GPIO_ResetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(500);

LL_GPIO_SetOutputPin(DQ_GPIO_Port, DQ_Pin);

dqInput();

DWT_Delay(70);

rc = LL_GPIO_IsInputPinSet(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(410);

return rc;

}

The following function locates devices on a 1-Wire domain:

void FindDevices(void)

{

uint8_t m;

if(!owReset()) //Begins when a device is detected

{

if(First()) //Begins when at least one device is found

{

numROMs=0;

do{

numROMs++;

for(m=0;m<8;m++)

{

FoundROM[numROMs][m]=ROM[m]; //Identifies ROM number on found device

}

printf(“ROM CODE = %02X%02X%02X%02X%02X%02X%02X%02X\r\n”,

FoundROM[1][7],FoundROM[1][6],FoundROM[1][5],FoundROM[1][4],

FoundROM[1][3],FoundROM[1][2],FoundROM[1][1],FoundROM[1][0]);

}while (Next()&&(numROMs<10)); //Continues until no additional devices are found

}

}

}

Once a 1-Wire slave device is detected, the master must be able to send and receive bits from the slave device. The difference between sending a 1 bit and a 0 bit is timing of the pulses within a data bit window. You can get an idea of the microsecond timing that differentiates a 1 and 0 bit from the code:

void owWriteBit(uint8_t bit)

{

dqOutput();

if(bit)

{

LL_GPIO_ResetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(6);

LL_GPIO_SetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(64);

}

else

{

LL_GPIO_ResetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(60);

LL_GPIO_SetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(10);

}

}

Receiving a bit also relies on precise timing. In the case of receiving a bit, we poll the DQ signal at a certain point inside the bit window and return the result (1 or 0):

uint8_t owReadBit(void)

{

uint8_t result;

dqOutput();

LL_GPIO_ResetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(6);

LL_GPIO_SetOutputPin(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(9);

dqInput();

result = LL_GPIO_IsInputPinSet(DQ_GPIO_Port, DQ_Pin);

DWT_Delay(55);

return result;

}

Once the code is established to read and write bits, we can read and write bytes by simply calling the bit read/write functions repeatedly.  Here’s how we write a byte:

void owWriteByte(uint8_t data)

{

uint8_t loop;

for(loop = 0; loop < 8; loop++)

{

owWriteBit(data & 0x01);

data >>= 1;

}

}

Here’s how we read a byte:

uint8_t owReadByte(void)

{

uint8_t loop;

uint8_t result=0;

for (loop = 0; loop < 8; loop++)

{

result >>= 1;

if (owReadBit())

result |= 0x80;

}

return result;

}

With the basic 1-Wire functions in place, it’s makes things a bit less difficult when it come to accomplishing the task of reading the temperature sensed by the 1-Wire slave sensor:

void Read_Temperature(void)

{

uint8_t get[10];

uint16_t tempC;//,tempF;

float ftempC,ftempF;

uint8_t k;

owReset();

owWriteByte(0xCC); //Skip ROM

owWriteByte(0x44); // Start Conversion

HAL_Delay(850);

owReset();

owWriteByte(0xCC); // Skip ROM

owWriteByte(0xBE); // Read Scratch Pad

for (k=0;k<9;k++)

{

get[k]=owReadByte();

}

//printf(“\r\nScratchPAD DATA = %02X%02X%02X%02X%02X%02X%02X%02X%02X\r\n”,get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);

tempC = make16(get[1],get[0]);

ftempC = tempC * 0.0625;

printf(“\r\nLEMOS International\r\n”);

printf( “TempC= %3.2f degrees C\r\n”, ftempC ); // print temp. C

 

ftempF = ((ftempC * 9)/5) + 32;

printf( “TempF= %3.2f degrees F\r\n”, ftempF ); // print temp. F

}

The full set of 1-Wire software functions that run on the Universal Wireless Sensor Node are available from LEMOS International (www.lemosint.com).
Download Schematic