Tutorial: Creating a new sensor demo

Nuts to bolts: hardware, firmware and gui development exercise.
Questions? - yeagerd yeagerd maintains this page.

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
// Power off sensor and adc
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.
  • First, provide parsing and identifier information to the MyTag class
  • Second, generate a new handler method in this class. Ex, see HandleAccelTagStats
  • Third, edit the HandleTagReceived function to call your handler method upon seeing your sensor
  • Fourth, edit timerUpdateGUI to display your data on the GUI.
  • Do not add GUI code to the handler method, this can cause instability on some computers.

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 * Vsense / Vdd
The equation to calculate Vsense = Vdd * 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 * 200 C / (0.183 V - 1.299 V) = 182.8
The temp T = Vsense * 200 C / (0.183 V - 1.299 V) + 182.8

You'll notice there is some curvature, resulting in an error of about -2.5C when it should read 0C.
This can be fixed by using the CSV table of lookup values that is provided on the manufacturer website.



The last modification was made by - yeagerd yeagerd on Apr 26, 2012 9:28 am