Step 2b: Hardware - HT Sensor

 

The code for this step is found here.

 

Just an aside, to copy a project in Simplicity Studio right-click in the Project Explorer and choose Import -> MCU Project. Type the existing project name in the dialog, click through the second screen, and type the new name in the third. Then look at the new project in the Explorer window to make sure all linked files exist and check the project's Properties for the build configuration and settings (we seem to have two versions of GCC, and the first one, GNU ARM 4.9.3, is old and won't compile the program).

 

A recap of our progress: We've created a program that runs in the ZWave Application framework. To an empty project we had to add code from the SDK to initialize and boot the devkit board, which needs some small interactions with the framework to get versions. We then added code to start an event handler in the framework, which pulled in many operating system functions as well as ZWave functionality, which we've disabled or removed for the moment until we're done with the hardware. We've added support for buttons and LEDs which brought in another large batch of include files and driver code. Much of the complexity in the build comes from pieces that are scattered throughout the SDK, so we end up with long include paths and many linked source files.

 

Now we'll access the humidity-temperature (HT) sensor on the devkit board. Communication is done over an I2C bus. According to the sensor's datasheet, its address on the bus is 0x80. There are 16 command bytes to read the sensor, operate the heater, and read product identification bytes. The commands we need are

READ_H_HOLD

0xE5

READ_T_HOLD

0xE3

READ_T_AFTER_H

0xE0

READ_ID2_BYTE1

0xFC

READ_ID2_BYTE2

0xC9

It is slightly more efficient to read both the humidity and temperature together (READ_T_AFTER_H).

 

We use I2CSPM_Transfer() to execute a command. It goes in a loop where we wait while the return value is i2cTransferInProgress, or give up after a fixed number of attempts (2). The function takes an I2C_TransferSeq_TypeDef data structure, defined in platform/emlib/inc/em_i2c.h, which has the destination address, a flag specifying read and/or write operation, and two byte array pointers plus length specifications, one (buf[0]) for writing and the other (buf[1]) for reading.

 

To read the sensor in our function read_HT() the write buffer will contain one byte, the command, and the read buffer must have two. Assuming the read is successful the final return value will be i2cTransferDone and we can convert the read buffer into values following the formulas in the datasheet:

RH = ((read_byte0 << 8) + (read_byte1 & 0xfc)) - 6000

T = ((((read_byte0 << 8) + (read_byte1 & 0xfc)) * 21965) >> 13) - 46850

The humidity is in milli-percent and must be clipped to the range 0 t/m 100,000. Temperature is in milli-degrees and the formula in the datasheet can overflow 32 bits, so we've scaled constants down by 8.

 

To read the product information in verify_sensor() the write buffer will contain two bytes to hold 0xFC and 0xC9, and the read buffer must have eight. The first byte returned will be 0x15 for the Si7021 sensor.

 

In setup_i2c() we define the pin layout and clocks for the bus by filling in an I2CSPM_Init_TypeDef structure and passing it in a call to I2CSPM_Init(). None of the i2cspmconfig.h files under $⁠{SDK}/hardware/kit/SLW* has a setup that matches the description in UG381, the devkit spec, so we have to do it ourselves: SCL on PC10 (I2C0_SCL#14) which unpacks to Port C, pin 10, location 14; and SDA on PC11 (I2C0_SDA#16), or Port C, pin 11, location 16. Setup finishes by calling verify_sensor() to check that we can talk to it.

 

Using the I2C bus means including the header file i2cspm.h in our application, so we must

  1. Add $⁠{SDK}/hardware/kit/common/drivers to the C/C++ Include list.

  2. Link $⁠{SDK}/platform/emlib/src/em_i2c.c to hw/.

  3. Link $⁠{SDK}/hardware/kit/common/drivers/i2cspm.c to hw/.

  4. Create a file src/i2cspmconfig.h which has one define, I2CSPM_TRANSFER_TIMEOUT 3000000.

The last file is needed because the devkit board SLWSTK6050A doesn't have an entry under $⁠{SDK}/hardware/kit.

 

We enable the sensor with GPIO pin PD15, but this also enables the LCD. That spec requires a periodic pulse on PD13 to avoid damaging the display. We'll use the software timer to meet the datasheet requirements of > 1 Hz, 50% duty cycle pulse, toggling PD13 on and off for 250 ms each. The LCD spec also says to keep DISP_SCS on pin PD14 low during EXTCOMIN, so we clear the pin. In the application we add two functions, setup_lcd() which initializes the pins and starts the timer with callback toggle_extcomin().

 

We can now properly implement sensor reads in our button press event handler. The timer placeholders in simulate_ht() get replaced by LED toggles and sensor reads, with the results printed to the UART console. Data logging is done by setting the global number of samples and letting the LCD timer do a sensor read once per sampling interval for TSAMPLE seconds. The values are cached in global arrays in anticipation of the next step, and are also sent to the UART console.

console trace of logging run

Console trace of the start of a logging run.

 

This version of our application contains these functions:

function

role

description

handle_event

button press

read sensor or start logging

handle_dummy

placeholder

empty ZWave command handler

setup_i2c

sensor read

prepare I2C bus

i2c_strerror

sensor read

string version of I2C status code

verify_sensor

sensor read

confirm HT sensor present

read_HT

sensor read

read humidity and/or temperature

setup_lcd

LCD driver

prepare refresh timer

toggle_extcomin

LCD driver, logger

refresh device, log sensor readings

ApplicationInit

ZAF

pre-task system setup

ApplicationTask

ZAF

post-task setup and event loop

Transport_ApplicationCommandHandlerEx

ZAF

empty ZWave command handler

 

The project's file list has added two files under hw/ and one under src/.

hw/

src/

ZAF_AppUtil/

ZAF_CC/

 

config_app.h

ZAF_TSE.c

 

 

HTSensor1.c

ZW_TransportEndpoint.c

 

 

i2cspmconfig.h

 

 

linked within Simplicity Studio

em_i2c.c

 

application_properties.c

 

em_letimer.c

 

AppTimer.c

 

gpiointerrupt.c

 

board_indicator.c

 

i2cspm.c

 

board.c

 

startup_zgm13.S

 

ZAF_command_class_utils.c

 

system_zgm13.c

 

zaf_event_helper.c

 

 

 

ZAF_uart_utils.c

 

 

 

ZW_TransportMulticast.c

 

 

 

ZW_TransportSecProtocol.c

 

 

Our last hardware change is to use the LCD to display the humidity and temperature, rather than having to rely on the debug console.