Adding A Sensor

Prequel: Selecting a sensor

1) Sensor allows 1.8V supply voltage

2) Time necessary to make a measurement (power-on time + settling time)

3) Sensor current consumption

4) Do you need amplifiers for the analog sensor? Add this to the current consumption

5) A rough approximation for your energy budget is 1 mA for 1 ms. As long the product of your current settlingtime is less than 1mA*1ms, you should be able to run the sensor without problems. Otherwise, you will need to get creative (and possible add more storage cap to wisp).


Step 1: Wire it up

First, we need to pick some unused pins. See the HW Feature Set page for a description of which pins are available for external devices.

Next, we need to scope out the schematic and pcb layout to see where the pins are. These are located on the Wisp 4.1 DL hardware page. Most likely, we will require a pin to power the sensor, a pin to sense the analog sensor output, and ground.

Finally, we can wire the wisp up to our sensor. A really fancy designer might make a daughterboard that connects directly to the WISP!


Step 2: Get the latest trunk release firmware

Download the latest trunk release. Instructions are here

Copy one of the sensor header files (ex, int_temp_sensor.h) and rename it to reflect your sensor.


Step 2a: Edit the pin definition header file (pinDefWISP4.1DL.h)

By default, all unused pins are set as outputs by the DRIVE_ALL_PINS macro defined in the pinDef header file. It looks like this:

#define DRIVE_ALL_PINS  \

  P1OUT = 0;  \

  P2OUT = 0;  \

  P3OUT = 0;  \

  P1DIR = TEMP_POWER | TX_PIN | RX_EN_PIN | DEBUG_1_4 | LED_POWER | CAP_SENSE; \

  P2DIR = DEBUG_2_3 | CRYSTAL_OUT; \

  P3DIR = CLK_A | VSENSE_POWER | TX_A | RX_A;

Remove the pin you want to use an an ADC input.

The mapping of pins is also in this pinDef header file, so you can quickly find which pin you need to remove from the macro.


Step 2b: Edit the firmware core (hw41_d41.c)

In the source code, find the text “Step 1: pick an application,” → set SENSOR_DATA_IN_ID to 1, others to 0.

Now, near the top of the WISP main code (hw41_D41.c), there is a section “Step 1A: pick a sensor type.” Add a #define for your sensor and set the ACTIVE_SENSOR = your new sensor.

Lastly, find the section that actually includes the sensor header files. It looks like:

#if READ_SENSOR

  #if (ACTIVE_SENSOR == SENSOR_ACCEL_QUICK)

    #include "quick_accel_sensor.h"

  #elif (ACTIVE_SENSOR == SENSOR_ACCEL)

    #include "accel_sensor.h"

  #elif (ACTIVE_SENSOR == SENSOR_INTERNAL_TEMP)

    #include "int_temp_sensor.h"

  #elif (ACTIVE_SENSOR == SENSOR_EXTERNAL_TEMP)

    #error "SENSOR_EXTERNAL_TEMP not yet implemented"

  #elif (ACTIVE_SENSOR == SENSOR_NULL)

    #include "null_sensor.h"

  #elif (ACTIVE_SENSOR == SENSOR_COMM_STATS)

    #error "SENSOR_COMM_STATS not yet implemented"

  #endif

#endif

Add handling for your sensor header file.


Step 2c: Edit your sensor header file

You'll notice the first line in the sensor file defines a type ID.

#define SENSOR_DATA_TYPE_ID       0x0F

The purpose of the type ID is so that the GUI can figure out what type of sensor it is. Some IDs have been used already. The Working with WISP firmware page include information about how the data is formatted in the WISP ID and reserves some sensor type IDs for existing applications. Pick a new type ID.

After the power management code

if(!is_power_good())

  sleep();


we'll need to power on our sensor and wait for it to settle

P__3__OUT |= SENSOR_POWER_PIN;

for(i = 0; i < 1000; i++);


also, you'll need to define SENSOR_POWER_PIN as BITx where x is between 0 and 7 inclusive. This represents port y.x (ex, Port 3.5 → BIT5 in this example)

P3OUT should be changed to the port your sensor is on.

Configure and sample the adc

// Set up ADC for internal temperature sensor

ADC10CTL0 &= ~ENC; // make sure this is off otherwise settings are locked.

ADC10CTL1 = INCH_??? + ADC10DIV_3;

ADC10CTL0 = ADC10SHT_3 + ADC10ON;

// start conversion

ADC10CTL0 |= ENC + ADC10SC;       // Sampling and conversion start

while (ADC10CTL1 & ADC10BUSY);    // wait while ADC finished work


load the sensor data into the ID:

(target + k + 1 ) = (ADC10MEM & 0xff);

grab msb bits and store it 

*(target + k) = (ADC10MEM & 0x0300) » 8; 

and power everything off

ADC10CTL0 &= ~ENC;

ADC10CTL0 &= ~ADC10ON;       // turn adc off

P1OUT &= ~SENSOR_POWER_PIN;


Step 3: Edit the GUI

The LLRP GUI app documentation is here: UsingImpinjLLRP


As a placeholder, the concise instructions are copied here. TODO: add example code snippets.


Addendum 1: Making sense of ADC readings

First, some basic nomenclature so we don't get confused:

Sensor output voltage: Vsense

ADC output code: Dout


WISP has a 10 bit ADC. That means there are 2^10-1 possible output codes, ranging from Dout = 0 to 1023.


These are mapped, linearly onto the range of possible input voltages (as a fraction of the ADC references, which are Vdd and Gnd).

Vsense = 0 → Dout = 0

Vsense = Vdd/2 → Dout = 511

Vsense = Vdd → Dout = 1023


The equation to calculate Dout = 1024


Addendum 2: Scaling of specific sensors

WISP has an external temperature sensor with model # LM94021. Google to get the data sheet.

See the “Typical Transfer Characteristic” (and the table of values later in the data sheet).


We use the lowest gain setting. Thus:

Temp = -50C → Vsense = 1.299V

Temp = 0 → Vsense = 1.034V

Temp = 150C → Vsense = 0.183V


We simply use a linear extrapolation.

The slope S = Temp = 200 C / (0.183 V - 1.299 V) = -179.2 deg C / V

The offset F = -50 - (1.299 V