We use the DC9005 Eterna QuikEval Adapter to connect the mote to an LTC2984 Multi-Sensor High Accuracy Digital Temperature Measurement System Demo Board to read a K-type thermocouple.



Introduction

This recipe covers the upcoming DC9005 Eterna QuikEval Adapter - it allows your OCDK application to talk to any of the Linear demo boards that support the DC590B interface.  It does not currently support using the QuikEval GUI tools for driving the demo, but it allows for OCSDK firmware development for a wide variety of linear ICs without having to spin a board.


Figure 1 - The DC9005 

Hardware Connection

In our sample, we use the DC9003 Evaluation Kit mote, connected to a DC9006 Interface board.  The DC9006 provides power for the mote and the target demoboard through the DC9005 adapter, as well as giving us access to JTAG programming, SPI programming (via ESP), and the mote CLI.

In this demo, the DC9005 plugs into a DC2399A  demo circuit which features the LTC2984 24-Bit Precision Digital Temperature Measurement System with EEPROM.  In our example, we use the DC2212A dual thermocouple board - it provides two standard thermocouple connectors with onboard diode cold-junction compensation.

Figure 2 - Setup

Software

Portions of this code was adapted from the Linduino C code included in the LTC2984 Demo Software.

The application consists of a single task appTask, that initializes SPI and configures the LTC2984 to read a K-type thermocouple on connector J2, then polls the temperature every 10s.  The temperature data is printed on the mote's CLI, and sent to the manager in the same OAP format (see the SmartMesh IP Tools Guide for details) as is used in the TempMonitor SmartMesh SDK Python application.  The sample application also has a CLI command to read the "postage stamp" personality I2C EEPROM found on DC590B-compatible demo circuits. 

Open the SPI Device

The datasheet states that the LTC2984 expects CPHA = 1, and CPOL = 1. However, the part also accepts CPHA=0 and CPOL=0, which is the default

// open the SPI device 
dnErr = dn_open(
                  DN_SPI_DEV_ID,
                  &app_v.spiOpenArgs,
                  sizeof(app_v.spiOpenArgs)
);
ASSERT(dnErr == DN_ERR_NONE);

Open the I2C Device

The DC9005 has a pin that is used to select which bus, I2C or SPI, that will be used to communicate with the target IC.  Since all DC590B cards come with an I2C EEPROM that contains device information that is used by QuikEval, we open the I2C. We can simultaneously read the personality EEPROM and the sensor regardless of which bus is selected.

//===== open the I2C device for reading the personality EEPROM
if(app_v.fI2cOpen == CLOSED){
    dnErr = i2cOpen();
    app_v.fI2cOpen = OPEN;
}

// ===== open the BUS_SELECT pin
dnErr = gpioSetMode(BUS_SELECT, DN_IOCTL_GPIO_CFG_OUTPUT, NULL, PIN_LOW);
if (dnErr != DN_ERR_NONE){
      dnm_ucli_printf("bus pin open err=%d\r\n", dnErr);
}

dnErr = gpioWrite(BUS_SELECT, BUS_SPI);
if (dnErr != DN_ERR_NONE){
      dnm_ucli_printf("bus pin write err=%d\r\n", dnErr);
}

OAP Temperature Data

We define a number of structs to carry OAP data - these are packed in order to avoid unexpected padding. 

PACKED_START

typedef struct{
   INT8U      control;
   INT8U      id;
}oap_header_t;

typedef struct{   
   INT8U      tag;
   INT8U      length;
   INT8U      value;
}oap_channel_t;

typedef struct{
   INT64S     sec;
   INT32S     usec;   
}packet_utc_t;      // IAR doesn't pack dn_utc_time_t into the oap_temp_notification_t properly

typedef struct{   
   oap_header_t    header;
   INT8U           command;
   INT8U           type;
   oap_channel_t   channel;
   packet_utc_t    timestamp;
   INT32U          rate; //ms
   INT8U           num_samples;
   INT8U           sample_size; //bits
   INT16S          temperature;
}oap_temp_notification_t;
 

Taking a Temperature Measurement

Each measurement consists of the following steps:

// -- Set global config register
rwByte(CONFIG_REG, MEM_WRITE, TEMP_UNIT__C | REJECTION__50_60_HZ);
// -- Set delay between conversions
rwByte(MUX_REG, MEM_WRITE, 0);
//----- Channel 1: Assign Type K Thermocouple -----
channel_assignment_data = SENSOR_TYPE__TYPE_K_THERMOCOUPLE | TC_COLD_JUNCTION_CH__2 | TC_SINGLE_ENDED |
                             TC_OPEN_CKT_DETECT__YES | TC_OPEN_CKT_DETECT_CURRENT__10UA;

assignChannel(CH_1, channel_assignment_data);
//----- Channel 2: Diode reference -----
channel_assignment_data = SENSOR_TYPE__OFF_CHIP_DIODE | DIODE_SINGLE_ENDED | DIODE_NUM_READINGS__2 |
                             DIODE_AVERAGING_OFF | DIODE_CURRENT__20UA_80UA_160UA | (0x100C49 << DIODE_IDEALITY_FACTOR_LSB);

assignChannel(CH_2, channel_assignment_data);
convertChannel(CH_1); 
OSTimeDly(500);  // wait 500 ms for conversion to complete instead of polling
rwByte(STATUS_REG, MEM_READ, 0);
rawTemperature = getRawResults(READ_CH_BASE, CH_1);   
if(rawTemperature & 0x800000){  // mask off sign bit
    temperature = (INT16S)(rawTemperature & 0x7FFFFF)  >> 10;
    temperature *= (INT16S)-1;
}   
else {
    temperature = (INT16S)(rawTemperature >> 10);
}

dnm_ucli_printf("Channel=%d, Temperature Result = %d.%u\r\n", CH_1, temperature, rawTemperature & 0x3FF);
app_v.oap_temp.temperature = htons(temperature);

// Send an OAP temperature packet
app_v.oap_temp.header.control = UNACKNOWLEDGED | REQUEST | NOSYNC;

if (firstPacket) {
    app_v.oap_temp.header.control |= SYNC;
    firstPacket = 0;
}

app_v.oap_temp.header.id = (SESSIONID<<4) + report_ctr;
report_ctr++;

if (report_ctr > 15) {
    report_ctr=0;
}   

// packet timestamp
dn_getNetworkTime(&asn, &utc);
app_v.oap_temp.timestamp.sec = htonl(utc.sec);
app_v.oap_temp.timestamp.usec = htons(utc.usec);

memcpy(&pkToSend->locSendTo.payload, &app_v.oap_temp, sizeof(app_v.oap_temp));

// send the packet
dnErr = dnm_loc_sendtoCmd(pkToSend, sizeof(oap_temp_notification_t), &rc);
ASSERT (dnErr == DN_ERR_NONE);      

OSTimeDly(10*SECOND);
}


LTC2984 Helper Functions

Several helper functions are provided in LTP2983_support_functions.c to handle low-level interaction with the chip:  

Links

DC2212A Thermocouple Board

Source code: