Skip navigation

Safe and Sound

12 Posts authored by: mbozdal

Time is running and I am away from home with my kits I don't add additional hardware functionality yet but change the user interface from the previous one. I planned to add RSSI measurements but Ground Operations Centre took all the time. This article is the final one for this design challenge therefore I will explain what I  have done till now and what can be added in the future.

 

Previously, the helmet was sending one data per second. Now, it is sending 100 data pre second. I accomplish this by decreasing the system tick from 100ms to 10ms and task pause from 10 ticks to single tick. 10 times from the system speed and 10 times from the waiting overall data transmission is 100 folded. It can be increased more but it requires a comprehensive timing analysis which can be a future task.

 

Hence, I am not in my town I just grab the MSP432 with sensors and leave the helmet and gate control circuit at home. This is not my first trip during the design challenge and kits travelled Canada before they have arrived so they have seen many places

 

Let's see how the system is working now.

 

 

 

 

Updated

The following video is the final hardware version for the design challenge. Unfortunately, I couldn't carry all parts with me. That is why demonstration above only show acceleration and temperature. You can find the details here Safe & Sound Wearables - Trackable Safety Helmet for Miners #12: Smart Helmet Video Demonstration .

 

Updated

 

I implemented two graphs; one for temperature and one for acceleration. There are also alarm indicators and alarm clear button. The controller can see 10 seconds window graph but also able to see the past data by dragging the cursor.

 

Initial plan and how things have changed

My idea aims to improve the mine safety. It will track the miners, detect possible explosions, and prevent human ignorance while forcing them to wear proper work suit. I planned the following tasks before I started the project. I achieved some, some are failed, and some are impossible to implement with current tech.

 

TASKS

 

1 - As I mentioned above, the main problem is high methane gas concentration. If the air includes 5% to 15% methane it can explode. Because of this, methane concentration must be observed. This should be placed in many areas of the mining area but if we implement the sensor on the helmet, we can see how the concentration change around the workers. How concentration change in a time and place will give important information about the estimating explosions. Methane gas sensors, like Methane CNG Gas Sensor - MQ-4, usually have analogue output and MSP432P401R has 14-bit 1MSPS differential SAR ADC. The first task is connecting an analogue gas sensor to MSP432P401R and process it.

 

2 - Methane concentration is the obvious indicator of the explosion. However, there are other important parameters like pressure and temperature so they should be measured. BOOSTXL-SENSORS  booster pack has an environmental sensor which can measure ambient temperature, pressure, and humidity. This information can be analysed and gas concentration limitation can be changed dynamically.

 

3 - In order to achieve a reliable system, it is required to have a communication link. The main reason is the collected data can be analysed by the central point and if something is wrong warning signal can be activated. It also brings other benefits like if something happens to the worker, he can send an emergency message. The kit includes Bluetooth and Wi-Fi network processors. Bluetooth is not suitable hence it is not supporting meshing (Bluetooth 5 bring this support) and distance is short. Wi-Fi is the better option because it has mesh support and longer range. However, it is still not enough distance, if we imagine the mine area and any explosion can disrupt communication if a link is destroyed. Long-range communication link will be feasible for this application like narrow band communication. The required data rate is not high so Lo-Ra, SigFox, or sub 1GHz long range RF can be preferred. Hence, the mine are under the ground and there may be lots of distractions during the path, this is the hardest part of the project. I will implement the project by Wi-Fi but it should be changed considering the outline of the mine. Implementation will be similar only the RF part and protocol is changing.

 

4 - Another problem is after an explosion it takes long times to reach the miners sometimes it takes months. If we can build a tracking system it will help us to reach them swiftly. Actually, the previous task also cover this topic. If we implement a reliable mesh network, we can use both time of flight (ToF) and received signal strength indicator(RSSI) to track the miners. However, inside the mine, both of these may not give the accurate results. This should be supported by the dead-reckoning. Dead-reckoning can be implemented by using inertia measurement unit (IMU) which includes accelerometer and gyroscope. BOOSTXL-SENSORS  booster pack also includes IMU sensor. Dead-reckoning can be synchronised at the mesh points so accuracy can be increased.

 

5 - Hence, we have IMU sensor for tracking, we can add additional functionality. We can detect the falling of the workers and help them immediately. This looks unnecessary because of the emergency message but if the miner loses the conscious, the automated fall detection can help to find worker immediately.

 

6 - Some people are ignorant and unless you do not push them to wear safety uniform, they don't wear it. In order to be sure helmet is worn, workers should be controlled at the mine access area and helmetless entry shouldn't be allowed. To achieve this RFID-enabled ticket can be placed inside the helmet and gates are opened by the helmet. Bluetooth can also be preferred if the power consumption problem is solved for wearable. With the implementation of the Bluetooth, the helmet can act as a Bluetooth smart key fob and access is denied without the helmet.

 

Challenges and Threats

 

The hardest part of the project is designing a reliable communication network. It is one of the key parts of the project. If a reliable network connection is provided, it will be so easy to implement emergency messaging and make the tracking easier. There are lots of computationally intensive task for the processor to do, I am not sure one processor can handle all of these so multiple processors may be required but this will increase price and size. It is also possible to send the data to the centre and make calculation there and the send back to the result like the idea in the IoT systems. Dead-reckoning can be also challenging if the proper synchronisation and filtering are not done. Processing data (correlation between different variables) will require a comprehensive research for implementing this system into real mine. I may implement an estimated or dummy correlation hence the real data correlation includes different disciplines and measurements inside the real mine.

 

 

The main task was measuring the methane concentration which was failed. Before applying for the design challenge, I just heard about the ATEX but didn't know much about it. I did some research, get comments/help from the Element14 community and it looks like impossible to implement because I couldn't find a small gas sensor which can fit inside a helmet and ATEX approved. The problem gas sensors require a heating element so they require an ex-proof box or could spark an explosion. This was my fault in the planning part and there was nothing much to do. I do implement a temperature sensor and a pressure sensor. Of course, they are not intrinsically safe yet but it is possible to implement.

 

The communication was another important task. The TI https://www.element14.com/community/view-product.jspa?fsku=2535895&nsku=38Y6657&COM=noscriptSimpleLink Wi-Fi CC3100 module BoosterPack works fine but I test it inside a room. I am sure mines has lots of things to block or interfere the Wi-Fi signals. Therefore, it requires testing inside the mine area but unfortunately, I don't have a chance to go inside a mine even I could the design should be approved as intrinsically safe before the tests.

 

The next task was tracking and detecting the faints. I have used an ADXL345 accelerometer which can detect the inactivity and free-fall. I successfully detect and transmit the free-fall and inactivity. I haven't had time to implement dead-reckoning. It is not easy to implement an accurate dead-reckoning. It can be a future work to add an IMU sensor and implement a dead-reckoning with proper filters. RSSI signals also can be used to improve the tracking and decrease the deviation.

 

The final task was to prevent the human ignorance. I think this task has a pretty solid success. If RFID tag is inserted inside the helmet during the manufacturing miners has no choice to access without the helmet. It can be also used for tracking the miners and workload. Hence, a passive tag has inserted the helmet, it doesn't require ATEX certification.

 

 

Software

 

I can divide the software into two parts. One firmware for the MCUs and the other one is the PC program Ground Operation Centre. For MCU programs, I prefer to use TI-RTOS. I hadn't used RTOS before the design challenge. It was a little difficult at first but I think it makes things easier for me for the later changes like increasing the data transmission. My idea was also challenging me and improve myself. I think it was a good intro.

 

The Ground Operation Centre is the backbone of the project. It collects data and shows it a user-friendly interface. I think it requires a database later on for recording all the data for a longer time. It can be integrated into work process and simplifies the things while improving the safety. I have coded the program in C#.

 

You can download the whole project from the following links.

 

Ground Operation Centre : https://drive.google.com/open?id=0B9wed2dhooCNTDJRZVBIV0p3YjQ

MSP-EXP432P401R LaunchPad Firmware: https://drive.google.com/open?id=0B9wed2dhooCNaVJGMVRkdW82OEU

MSP430 Launchpad Firmware: https://drive.google.com/open?id=0B9wed2dhooCNVXhRVUZEdFFlbDA

 

Hardware

 

The main hardware component of the design is MSP-EXP432P401R LaunchPad. It does pretty much everything. I also used the following components in my project.

 

The Wi-Fi boosterpack to send data to Ground Operations Centre Texas Instruments: SimpleLink Wi-Fi CC3100 module BoosterPack

 

Accelerometer Sensor Analog Devices: ADXL345

 

Temperature Sensor: Texas Instruments: TMP102

 

Force Sensitive Resistor: Interlink Electronics: FSR402

 

Gate control has a Texas Instruments: MSP430 Launchpad for controlling the gate and transmitting the data to PC and Texas Instruments: DLP-7970ABP NFC transceiver BoosterPack to read NFC tags.

 

Future Tasks

Dead-reckoning is the main thing I should implement the future version. To improve accuracy, RSSI data will be useful. The design should include some hardware implementations like using fuses and Zenner diodes. It is also required that power analysis of the circuit which is required for the ATEX and also for the battery life.

 

It was honouring and useful for me to take in part in this design challenge. I would like to thank Element14 community for their help. I also want to thank Element14 staff and TI for organising the challenge and providing us this opportunity.

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

Deadline is closing and I need to be faster. This week, I created a circuit board and removed the breadboard. The original plan was to add methane sensor but I couldn't find any portable version for the helmet. Usual gas sensors have a heating element which is dangerous for the mining areas so I skipped that part. Below the video, you can see the demonstration of the smart helmet.

 

 

Some screenshots from the Ground Operations Centre program.

The raw data structure is ##*temperature*accelerometer interrupt*accelerometer data* analogue input*-- . For instance, accelerometer interrupt area shows 131 when there is no interrupt, 139 for the inactivity alarm, and 147 for the freefall alarm. Next, I will modify the user interface and show this data as a user-friendly manner.

 

The Ground Operations Centre can also track the who is accessing the mine area. The NFC tag allows miner who has the smart helmet but if the same tag try to access/exit twice it will give warning as shown below.

Let's put together what hardware components and software I have used.

 

Hardware:

 

The main controller Texas Instruments: MSP-EXP432P401R LaunchPad

The Wi-Fi boosterpack to send data to Ground Operations Centre Texas Instruments: SimpleLink Wi-Fi CC3100 module BoosterPack

Accelerometer Sensor Analog Devices: ADXL345

Temperature Sensor: Texas Instruments: TMP102

Force Sensitive Resistor: Interlink Electronics: FSR402

Gate control has a Texas Instruments: MSP430 Launchpad for controlling the gate and transmitting the data to PC and Texas Instruments: DLP-7970ABP NFC transceiver BoosterPack to read NFC tags.

 

Software:

 

The code for MSP-EXP432P401R LaunchPad

/*
 * Copyright (c) 2015-2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


/*
 *  ======== tcpEchoCC3X00.c ========
 */


#include <driverlib.h>
#include <string.h>
#include <stdbool.h>


/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/runtime/System.h>
#include <xdc/cfg/global.h>


/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>


/* TI-RTOS Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/ADC.h>
#include <ti/drivers/PWM.h>


/* SimpleLink Wi-Fi Host Driver Header files */
#include <simplelink.h>


/* Example/Board Header file */
#include "Board.h"


/* Local Platform Specific Header file */
#include "sockets.h"


#include <stdint.h>


#include "ADXL345.h"






/* Port number for listening for TCP packets */
#define TCPPORT         1000


#define TASKSTACKSIZE   1024


/* IP addressed of server side socket. Should be in long format,
 * E.g: 0xC0A8000A == 192.168.0.10 */
#define IP_ADDR_Server 0xC0A8000A


extern bool smartConfigFlag;
Task_Struct taskWiFiStruct;
Char taskWiFiStack[TASKSTACKSIZE];


Task_Struct taskUARTStruct;
Char taskUARTStack[TASKSTACKSIZE];


Task_Struct taskI2CStruct;
Char taskI2CStack[TASKSTACKSIZE];


Task_Struct taskADXL345Struct;
Char taskADXL345Stack[TASKSTACKSIZE];


Task_Struct taskADCStruct;
Char taskADCStack[TASKSTACKSIZE];


Task_Struct taskPWMStruct;
Char taskPWMStack[512];










/* Globals */


void *netIF;


char connected = 0; // re-connect the AP


volatile char *Mymessage = "elemet14";


uint16_t pressureAdcValue;








// mailbox


typedef struct MsgPWM {
    uint32_t pwm;
} MsgPWM;


/*
 *  ======== echoFxn ========
 *  Task for this function is created statically. See the project's .cfg file.
 */
Void echoFxn(UArg arg0, UArg arg1)
{
    char input;
    UART_Handle uart;
    UART_Params uartParams;
    const char echoPrompt[] = "\fEchoing characters:\r\n";


    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 9600;
    uart = UART_open(Board_UART0, &uartParams);


    if (uart == NULL)
    {
        System_abort("Error opening the UART");
    }


    UART_write(uart, echoPrompt, sizeof(echoPrompt));


    /* Loop forever echoing */
    while (1)
    {
        UART_read(uart, &input, 10);
        Mymessage = &input;
        //UART_write(uart, &input, 10);
        //UART_write(uart, "\n\r", 10);
        Task_sleep(10);
    }
}


/*
 *  ======== I2C readPos Fxn ========
 *  Task for this function is created statically. See the project's .cfg file.
 */
#define TMP102_I2C_ADDR    0x48
#define ADXL345_I2C_ADDR   0x53
#define adxl345_I2C   MSP_EXP432P401R_I2CB0


#define ADXL345_POWER_CTL       0x2D        // Power-Saving Features Control


int temperature;
int interruptData;
char accelerometerData[6];


/*    Reads Num Bytes. Starts from Address Reg to _buff Array        */
//void ADXL345::readFrom(byte address, int num, byte _buff[])
//void ADXL345::writeTo(byte address, byte val)
Void readPos(UArg arg0, UArg arg1)
{
    uint8_t txBuffer[2];
    uint8_t rxBuffer[6];
    I2C_Handle i2c;
    I2C_Params i2cParams;
    I2C_Transaction i2cTransaction;
    char I2CErrorN = 0;
    char i;


    /* Create I2C for usage */
    I2C_Params_init(&i2cParams);
    i2cParams.bitRate = I2C_100kHz;
    i2c = I2C_open(adxl345_I2C, &i2cParams);
    if (i2c == NULL)
    {
        System_abort("Error Initializing I2C\n");
    }
    else
    {
        System_printf("I2C Initialized!\n");
    }


    txBuffer[0] = 0;
    i2cTransaction.slaveAddress = TMP102_I2C_ADDR;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.readCount = 2;


    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[0] = 0x32;
    txBuffer[1] = 0;
    i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.readCount = 2;


    while (1)
    {


        //Read interrupt bits on ADXL345
        i2cTransaction.readCount = 1;
        txBuffer[0] = ADXL345_INT_SOURCE;
        i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
        I2CErrorN = I2C_transfer(i2c, &i2cTransaction);
        interruptData = rxBuffer[0];


        //Read accelerometer data
        i2cTransaction.readCount = 6;
        txBuffer[0] = 0x32;
        i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
        I2CErrorN = I2C_transfer(i2c, &i2cTransaction);
        for(i=0;i<6;i++)
            accelerometerData[i] = rxBuffer[i];


        //Read temperature
        i2cTransaction.readCount = 1;
        txBuffer[0] = 0;
        i2cTransaction.slaveAddress = TMP102_I2C_ADDR;
        I2CErrorN = I2C_transfer(i2c, &i2cTransaction);
        temperature = rxBuffer[0];






        if (I2CErrorN != 1)
        {
            System_printf("I2C Bus fault\n");
            System_flush();
        }


        Task_sleep(10);
    }


    /* Deinitialized I2C */
    I2C_close(i2c);
    System_printf("I2C closed!\n");
    System_flush();


}


/******** activity, inactivity from ADXL345 int source1. Activated via Hwi***/
void ADXL345_int1(unsigned int index)
{
    MsgPWM pMsg;
    /* Clear the GPIO interrupt and toggle an LED */
    GPIO_toggle(Board_LED0);
    pMsg.pwm = 50;
    Mailbox_post(mbPWM, &pMsg, 10);
}


void ADXL345_init(UArg arg0, UArg arg1)
{
    uint8_t txBuffer[2];
    uint8_t rxBuffer[2];
    I2C_Handle i2c;
    I2C_Params i2cParams;
    I2C_Transaction i2cTransaction;


    /* Create I2C for usage */
    I2C_Params_init(&i2cParams);
    i2cParams.bitRate = I2C_100kHz;
    i2c = I2C_open(adxl345_I2C, &i2cParams);
    if (i2c == NULL)
    {
        System_abort("Error Initializing I2C\n");
    }
    else
    {
        System_printf("I2C Initialized!\n");
    }


    /**** ADXL345 TURN ON ***/


    txBuffer[0] = ADXL345_POWER_CTL;  //Wakeup
    txBuffer[1] = 0;
    i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 2;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.readCount = 1;


    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[1] = 16;               // Auto_sleep
    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[1] = 8;               // Measure
    I2C_transfer(i2c, &i2cTransaction);


    /***** Give the range settings *****/
    // Accepted values are 2g, 4g, 8g or 16g - ADXL345_DATA_FORMAT
    // Higher Values = Wider Measurement Range
    // Lower Values = Greater Sensitivity
    /**** Activity Inactivity setting  ***/


    txBuffer[0] = ADXL345_ACT_INACT_CTL;
    txBuffer[1] = 0b01110111;
    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[0] = ADXL345_TIME_INACT; //
    txBuffer[1] = 10;
    I2C_transfer(i2c, &i2cTransaction);


    /**** Activity Threshold  ***/


    txBuffer[0] = ADXL345_THRESH_ACT;
    txBuffer[1] = 75; // 62.5mg per increment    // Activity thresholds (0-255)
    I2C_transfer(i2c, &i2cTransaction);


    /**** Inactivity Threshold  ***/


    txBuffer[0] = ADXL345_THRESH_INACT;
    txBuffer[1] = 18; // 62.5mg per increment    // Inactivity thresholds (0-255)
    I2C_transfer(i2c, &i2cTransaction);


    /**** Free-Fall Threshold and Time ***/


    txBuffer[0] = ADXL345_THRESH_FF;
    txBuffer[1] = 7;  // (5 - 9) recommended - 62.5mg per increment
    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[0] = ADXL345_TIME_FF;
    txBuffer[1] = 30; // (20 - 70) recommended - 5ms per increment
    I2C_transfer(i2c, &i2cTransaction);


    /**** Interrupt setup  ***/


    //Interrupt mapping
    txBuffer[0] = ADXL345_INT_MAP;
    txBuffer[1] = 0; // 0b11110011;  //inactivity and free-fall is int1, activity is int2 ( others are int 2 but disabled)
    I2C_transfer(i2c, &i2cTransaction);


    //Interrupt enable


    txBuffer[0] = ADXL345_INT_ENABLE;
    txBuffer[1] = 0b00011100; //activity, inactivity, and free-fall interrupts are enabled
    I2C_transfer(i2c, &i2cTransaction);


    /* Deinitialized I2C */
    I2C_close(i2c);
    System_printf("I2C closed!\n");
    System_flush();


    /* Construct BIOS objects */
    Task_Params taskParams;


    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskI2CStack;
    Task_construct(&taskI2CStruct, (Task_FuncPtr) readPos, &taskParams, NULL);


}


/*
 *  ======== gpioButtonFxn ========
 *  Callback function for the GPIO interrupt on Board_BUTTON1.
 */
void gpioButtonFxn(unsigned int index)
{
    /* Begin smart config process */
    //smartConfigFlag = true;


    MsgPWM pMsg;
    pMsg.pwm = 0;
    Mailbox_post(mbPWM, &pMsg, 10);




}


int socketHandler = -1;
int status;
char recievedBuff[4];


/*
 *  ======== TCPsend Function ========
 *  It creates socket, send message, receive it
 *  then close the socket
 */
char* str;
Void TCPSend(char *message)
{
    char i;
    while (1)
    {
        if (connected != 1)
        {
            // Open WiFi and await a connection
            netIF = socketsStartUp();


            socketHandler = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


            /*
             * SL_AF_INET indicates using IPv4
             * SL_SOCK_STREAM indicates using TCP
             * IPPROTO_TCP
             */


            connected = 1;


            if (socketHandler == -1)
            {
                System_printf("Error: socket not created.\n");
                connected = 0;
            }


            SlSockAddrIn_t Addr;  // Socket settings
            Addr.sin_family = SL_AF_INET;
            Addr.sin_port = sl_Htons(TCPPORT);
            Addr.sin_addr.s_addr = sl_Htonl(IP_ADDR_Server);


            status = sl_Connect(socketHandler, (SlSockAddr_t *) &Addr,
                                sizeof(SlSockAddrIn_t));
        }


        status = sl_Send(socketHandler, "##*", 3, 0);


        Mymessage = char2str(temperature) ;
        status = sl_Send(socketHandler, Mymessage, 3, 0);
        status = sl_Send(socketHandler, "*", 1, 0);
        Mymessage = char2str(interruptData) ;
        status = sl_Send(socketHandler, Mymessage, 3, 0);
        status = sl_Send(socketHandler, "*", 1, 0);


        for(i =0 ; i<6 ; i++)
        {
            Mymessage = char2str(accelerometerData[i]) ;
            status = sl_Send(socketHandler, Mymessage, 3, 0);


        }
        status = sl_Send(socketHandler, "*", 1, 0);
        Mymessage = int2str(pressureAdcValue) ;
        status = sl_Send(socketHandler, Mymessage, 5, 0);
        status = sl_Send(socketHandler, "*--", 3, 0);


        // sl_Close(socketHandler);


        Task_sleep(10);


    }
    // Close the network - don't do this if other tasks are using it
    //socketsShutDown(netIF);
}




/*
 *  ======== taskAdcSample ========
 *  Open an ADC instance and get a sampling result from a one-shot conversion.
 */


Void taskAdcSample(UArg arg0, UArg arg1)
{
    ADC_Handle   adc0;
    ADC_Params   params;
    ADC_Params_init(&params);
    adc0 = ADC_open(Board_ADC0, &params);


    while (1) {
        Task_sleep(10);
        /* Blocking mode conversion */
        ADC_convert(adc0, &pressureAdcValue);
    }
    // theoretically close the ADC driver. This code is never reached
//    ADC_close(adc0);
//    ADC_close(adc1);
}










/*
 *  ======== pwmLEDFxn ========
 *  Task periodically increments the PWM duty for the on board LED.
 */


Void pwmLEDFxn(UArg arg0, UArg arg1)
{
    PWM_Handle pwm1;
    PWM_Params params;
    uint16_t   pwmPeriod = 2000;      // Period and duty in microseconds


    MsgPWM msg;


    PWM_Params_init(&params);
    params.dutyUnits = PWM_DUTY_US;
    params.dutyValue = 0;
    params.periodUnits = PWM_PERIOD_US;
    params.periodValue = pwmPeriod;
    pwm1 = PWM_open(Board_PWM0, &params);
    if (pwm1 == NULL) {
        System_abort("Board_PWM0 did not open");
    }
    PWM_start(pwm1);




    /* Loop forever incrementing the PWM duty */
    while (1) {
        //Task_sleep(10);
        /* wait for mailbox to be posted by writer() */
        if (Mailbox_pend(mbPWM, &msg, BIOS_WAIT_FOREVER)) {
            PWM_setDuty(pwm1, msg.pwm);
        }
    }
}






/*
 *  ======== main ========
 */
int main(void)
{
    /* Construct BIOS objects */
    Task_Params taskParams;


    /* Call board init functions. */
    Board_initGeneral();
    Board_initGPIO();
    Board_initWiFi();
    Board_initUART();
    Board_initI2C();
    Board_initADC();
    Board_initPWM();






    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskWiFiStack;
    taskParams.priority = 1;
    Task_construct(&taskWiFiStruct, (Task_FuncPtr) TCPSend, &taskParams, NULL);


    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskUARTStack;
    taskParams.instance->name = "echo";
    Task_construct(&taskUARTStruct, (Task_FuncPtr) echoFxn, &taskParams, NULL);




    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskADCStack;
    taskParams.priority = 1;
    Task_construct(&taskADCStruct, (Task_FuncPtr) taskAdcSample, &taskParams, NULL);




    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskADXL345Stack;
    Task_construct(&taskADXL345Struct, (Task_FuncPtr) ADXL345_init, &taskParams,
    NULL);




    /* Construct LED Task thread */
    Task_Params_init(&taskParams);
    taskParams.stackSize = 512;
    taskParams.stack = &taskPWMStack;
    taskParams.arg0 = 50;
    Task_construct(&taskPWMStruct, (Task_FuncPtr)pwmLEDFxn, &taskParams, NULL);




    /* Install Button callback */
    GPIO_setCallback(Board_BUTTON1, gpioButtonFxn);


    /* Enable interrupts */
    GPIO_enableInt(Board_BUTTON1);


    /* Turn on user LED */
    GPIO_write(Board_LED0, Board_LED_ON);


    System_printf("Starting the TCP Echo example for the CC3X00 \n"
                  "System provider is set to SysMin. Halt the target to view"
                  " any SysMin content in ROV.\n");


    /* SysMin will only print to the console when you call flush or exit */
    System_flush();


    /* install Button callback */
    GPIO_setCallback(MSP_EXP432P401R_INT1, ADXL345_int1);


    /* Enable interrupts */
    GPIO_enableInt(MSP_EXP432P401R_INT1);


    /* Start BIOS */
    BIOS_start();


    return (0);
}

 

The code for MSP430 Launchpad

/*
 * File Name: main.c
 *
 * Description: The TRF7970A is an integrated analog front end and
 * data framing system for a 13.56 MHz RFID reader system.
 * Built-in programming options make it suitable for a wide range
 * of applications both in proximity and vicinity RFID systems.
 * The reader is configured by selecting the desired protocol in
 * the control registers. Direct access to all control registers
 * allows fine tuning of various reader parameters as needed.
 *
 *
 * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*
* DESCRIPTION:
* This example detects ISO15693, Type 2, Type 3, Type 4A, Type 4B
* NFC/RFID tags. It then indicates the Tag type through LED's on the
* TRF7970A Booster pack. Information such as tag UID's and block data is
* sent out via a UART at 115200 Baud and can be read on a Computer.
*
* The TRF7970A is an integrated analog front end and
* data framing system for a 13.56 MHz RFID reader system.
* Built-in programming options make it suitable for a wide range
* of applications both in proximity and vicinity RFID systems.
* The reader is configured by selecting the desired protocol in
* the control registers. Direct access to all control registers
* allows fine tuning of various reader parameters as needed.
*
* The TRF7970A is interfaced to a MSP430G2553 through a SPI (serial)
* interface using a hardware USCI. The MCU is the master device and
* initiates all communication with the reader.
*
* The anti-collision procedures (as described in the ISO
* standards 14443A/B and 15693) are implemented in the MCU
* firmware to help the reader detect and communicate with one
* PICC/VICC among several PICCs/VICCs.
*
* AUTHORS:   Josh Wyatt
* Ralph Jacobi
*
* BUILT WITH:
* Code Composer Studio Core Edition Version: 6.0.1.00040
* (c) Copyright Texas Instruments, 2014. All rights reserved.
*****************************************************************/


//===============================================================
// Program with hardware USART and SPI communication        ;
// interface with TRF7970A reader chip.                         ;
//                                                              ;
// PORT1.0 - HEART BEAT LED                                     ;
// PORT1.1 - UART RX                                            ;
// PORT1.2 - UART TX                                            ;
// PORT1.5 - SPI DATACLK                                        ;
// PORT1.6 - SPI MOSI TODO: Remove LED2 Jumper on G2 LaunchPad  ;
// PORT1.7 - SPI MISO                                           ;
//                                                              ;
// PORT2.7 - IRQ (INTERUPT REQUEST from TRF7970A) (XOUT on LP)  ;
// PORT2.1 - SLAVE SELECT                                       ;
// PORT2.2 - TRF7970A ENABLE                                    ;
// PORT2.3 - ISO14443B LED                                      ;
// PORT2.4 - ISO14443A LED                                      ;
// PORT2.5 - ISO15693  LED                                      ;
//===============================================================


#include "nfc_app.h"
#include "trf79xxa.h"


#include <string.h>


#include <stdbool.h>
#include "MSP430.h"         // Processor specific header




void delay_ms(unsigned int ms)
{
    while (ms)
    {
        __delay_cycles(1000);
        ms--;
    }
}




#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
   if (UCA0RXBUF == '1') // '1' received? open the gate
   {
       P1OUT |= 1;


       delay_ms(9000);


       P1OUT &= 0xfe;
   }
   else //Gate is closed
   {
       P1OUT &= 0xfe; // Not necessary for the current program
   }


}


//===============================================================


void main(void)
{
  uint8_t ui8VLOCalibCount;
  char x;


// TODO: Remove LED2 Jumper on G2 LaunchPad if using it, otherwise SPI will not work.


  // Stop the Watchdog timer,
  WDTCTL = WDTPW + WDTHOLD;


  // Select DCO to be 8 MHz
  MCU_initClock();
  MCU_delayMillisecond(10);


  // Calibrate VLO
  MCU_calculateVLOFreq();


  // Set the SPI SS high
  SLAVE_SELECT_PORT_SET;
  SLAVE_SELECT_HIGH;


  // Four millisecond delay between bringing SS high and then EN high per TRF7970A Datasheet
  MCU_delayMillisecond(4);


  // Set TRF Enable Pin high
  TRF_ENABLE_SET;
  TRF_ENABLE;


  // Wait until TRF system clock started
  MCU_delayMillisecond(5);


  // Set up TRF initial settings
  TRF79xxA_initialSettings();
  TRF79xxA_setTrfPowerSetting(TRF79xxA_3V_FULL_POWER);


#ifdef ENABLE_HOST
  // Set up UART
  UART_setup();
#endif


  // Initialize all enabled technology layers
  NFC_init();


  P1DIR |= 0x1;
    P1OUT &= 0xfe;


    UC0IE |= UCA0RXIE; // Enable USCI_A0 RX interrupt




  // Enable global interrupts
  __bis_SR_register(GIE);


  // Enable IRQ Pin
  IRQ_ON;


#ifdef ENABLE_HOST
  UART_putIntroReaderMsg(RFID_READER_FW_VERSION, RFID_READER_FW_DATE);
#endif




  while(1)
  {
  // Poll for NFC tags
  NFC_findTag();




  // VLO drifts with temperature and over time, so it must be periodically recalibrated
  // Calibrate the VLO every 25 passes of the NFC polling routine
  ui8VLOCalibCount++;
  if (ui8VLOCalibCount == 25)
  {
  // Calibrate VLO
  MCU_calculateVLOFreq();
  // Reset Calibration Counter
  ui8VLOCalibCount = 0;
  }
  }
}

 

The Ground Operations Centre: https://drive.google.com/file/d/0B9wed2dhooCNTDJRZVBIV0p3YjQ/view?usp=sharing

 

 

This is a short update for this week. I hope I will write one more and summarise the whole project.

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

In this article, I will demonstrate the Smart Helmet v0.1 I am always on the move so I struggle to find time but slowly going further. Let's summarise what have done up to now. I am using TI-RTOS. I stack the Wi-Fi booster pack to MSP432. Connect ADXL345 accelerometer and TMP102 using I2C interface. Detect free-fall, inactivity, and send all the data to Ground Operations Center over Wi-Fi using TCP/IP protocol. I coded Ground Operations Center using C# and it still needs some modifications. DLP-7970ABP boosterpack is connected to Ground Operations Center via UART interface. It controls the gate and doesn't allow unauthorised access and access without the helmet.

 

In this week, I added a buzzer and pressure sensor. The buzzer is driven by PWM and pressure sensor is read using the analogue input. For pressure, I have used FSR 402 Interlink Electronics. Actually, it is force sensing resistor. It is resistance changes based on the applied force and it is not sensitive but it shows the idea. The code for the ADC? I follow the MSP432 and TI-RTOS: Getting Started Pt. 2 - Add an ADC Sample Task. I create task by code instead of the GUI so the task initialization is as follow

 

    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskADCStack;
    Task_construct(&taskADCStruct, (Task_FuncPtr) taskAdcSample, &taskParams, NULL);

 

I only use the adc0 so I removed the adc1 measurements from the taskADCSample task. pressureAdcValue is where the analogue value is saved. It is then transmitted via Wi-Fi to the Ground Operations Centre with other data. 

 

/*
 *  ======== taskAdcSample ========
 *  Open an ADC instance and get a sampling result from a one-shot conversion.
 */


Void taskAdcSample(UArg arg0, UArg arg1)
{
    ADC_Handle   adc0;
    ADC_Params   params;
    ADC_Params_init(&params);
    adc0 = ADC_open(Board_ADC0, &params);


    while (1) {
        Task_sleep(10);
        /* Blocking mode conversion */
        ADC_convert(adc0, &pressureAdcValue);
    }
    // theoretically close the ADC driver. This code is never reached
//    ADC_close(adc0);
//    ADC_close(adc1);
}

 

The next step is adding PWM for the buzzer. Hence, the buzzer sounds pretty awful, I recognise that I need to add some button control to stop it. It is not for the terrible sound of course. There may be cases where the alarm triggered falsely or the miner inform that he got the warning or some other reasons. So how we will do this? There should be a PWM task but duty cycle will change. At first duty cycle is 0 and if the alarm is triggered it will be something valuable like 50.  If the miner press the button, it should be zero again. It looks like there will be message transfer between the task so the answer is Mailboxes. This project is the first time I use RTOS, I don't know there is a better way but  Mailboxes works pretty well for what I want to do. I get great help from jancumps's article MSP432 and TI-RTOS: PID Library Part 2 - Real World Example.

The PWM task is as shown below. It setup PWM and sets the duty cycle 0. Then, it waits for the message to read from Mailboxes. When a message arrives it change the duty cycle.

 

Void pwmFxn(UArg arg0, UArg arg1)
{
    PWM_Handle pwm1;
    PWM_Params params;
    uint16_t   pwmPeriod = 2000;      // Period and duty in microseconds


    MsgPWM msg;


    PWM_Params_init(&params);
    params.dutyUnits = PWM_DUTY_US;
    params.dutyValue = 0;
    params.periodUnits = PWM_PERIOD_US;
    params.periodValue = pwmPeriod;
    pwm1 = PWM_open(Board_PWM0, &params);
    if (pwm1 == NULL) {
        System_abort("Board_PWM0 did not open");
    }
    PWM_start(pwm1);




    /* Loop forever incrementing the PWM duty */
    while (1) {
        //Task_sleep(10);
        /* wait for mailbox to be posted by writer() */
        if (Mailbox_pend(mbPWM, &msg, BIOS_WAIT_FOREVER)) {
            PWM_setDuty(pwm1, msg.pwm);
        }
    }
}

 

 

Where I change the duty cycle is one in ISR of ADX345 and another one is in ISR of the button press.

 

/******** activity, inactivity from ADXL345 int source1. Activated via Hwi***/
void ADXL345_int1(unsigned int index)
{
    MsgPWM pMsg;
    /* Clear the GPIO interrupt and toggle an LED */
    GPIO_toggle(Board_LED0);
    pMsg.pwm = 50;
    Mailbox_post(mbPWM, &pMsg, 10);
}

 

 

/*
 *  ======== gpioButtonFxn ========
 *  Callback function for the GPIO interrupt on Board_BUTTON1.
 */
void gpioButtonFxn(unsigned int index)
{


    MsgPWM pMsg;
    pMsg.pwm = 0;
    Mailbox_post(mbPWM, &pMsg, 10);


}

 

 

I was planning to make a video to demonstrate the design but it is so messy now. I will prepare a circuit board then put things inside the helmet. Hopefully, I will publish video next week. What I will do next is modify the program and finish the PC side.

WhatsApp Image 2017-06-11 at 18.29.29.jpeg

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

 

This is the full code of the program up to now.

/*
 * Copyright (c) 2015-2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


/*
 *  ======== tcpEchoCC3X00.c ========
 */


#include <driverlib.h>
#include <string.h>
#include <stdbool.h>


/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/runtime/System.h>
#include <xdc/cfg/global.h>


/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>


/* TI-RTOS Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/ADC.h>
#include <ti/drivers/PWM.h>


/* SimpleLink Wi-Fi Host Driver Header files */
#include <simplelink.h>


/* Example/Board Header file */
#include "Board.h"


/* Local Platform Specific Header file */
#include "sockets.h"


#include <stdint.h>


#include "ADXL345.h"






/* Port number for listening for TCP packets */
#define TCPPORT         1000


#define TASKSTACKSIZE   1024


/* IP addressed of server side socket. Should be in long format,
 * E.g: 0xC0A8000A == 192.168.0.10 */
#define IP_ADDR_Server 0xC0A8000A


extern bool smartConfigFlag;
Task_Struct taskWiFiStruct;
Char taskWiFiStack[TASKSTACKSIZE];


Task_Struct taskUARTStruct;
Char taskUARTStack[TASKSTACKSIZE];


Task_Struct taskI2CStruct;
Char taskI2CStack[TASKSTACKSIZE];


Task_Struct taskADXL345Struct;
Char taskADXL345Stack[TASKSTACKSIZE];


Task_Struct taskADCStruct;
Char taskADCStack[TASKSTACKSIZE];


Task_Struct taskPWMStruct;
Char taskPWMStack[512];










/* Globals */


void *netIF;


char connected = 0; // re-connect the AP


volatile char *Mymessage = "elemet14";


uint16_t pressureAdcValue;








// mailbox


typedef struct MsgPWM {
    uint32_t pwm;
} MsgPWM;


/*
 *  ======== echoFxn ========
 *  Task for this function is created statically. See the project's .cfg file.
 */
Void echoFxn(UArg arg0, UArg arg1)
{
    char input;
    UART_Handle uart;
    UART_Params uartParams;
    const char echoPrompt[] = "\fEchoing characters:\r\n";


    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 9600;
    uart = UART_open(Board_UART0, &uartParams);


    if (uart == NULL)
    {
        System_abort("Error opening the UART");
    }


    UART_write(uart, echoPrompt, sizeof(echoPrompt));


    /* Loop forever echoing */
    while (1)
    {
        UART_read(uart, &input, 10);
        Mymessage = &input;
        //UART_write(uart, &input, 10);
        //UART_write(uart, "\n\r", 10);
        Task_sleep(10);
    }
}


/*
 *  ======== I2C readPos Fxn ========
 *  Task for this function is created statically. See the project's .cfg file.
 */
#define TMP102_I2C_ADDR    0x48
#define ADXL345_I2C_ADDR   0x53
#define adxl345_I2C   MSP_EXP432P401R_I2CB0


#define ADXL345_POWER_CTL       0x2D        // Power-Saving Features Control


int temperature;
int interruptData;
char accelerometerData[6];


/*    Reads Num Bytes. Starts from Address Reg to _buff Array        */
//void ADXL345::readFrom(byte address, int num, byte _buff[])
//void ADXL345::writeTo(byte address, byte val)
Void readPos(UArg arg0, UArg arg1)
{
    uint8_t txBuffer[2];
    uint8_t rxBuffer[6];
    I2C_Handle i2c;
    I2C_Params i2cParams;
    I2C_Transaction i2cTransaction;
    char I2CErrorN = 0;
    char i;


    /* Create I2C for usage */
    I2C_Params_init(&i2cParams);
    i2cParams.bitRate = I2C_100kHz;
    i2c = I2C_open(adxl345_I2C, &i2cParams);
    if (i2c == NULL)
    {
        System_abort("Error Initializing I2C\n");
    }
    else
    {
        System_printf("I2C Initialized!\n");
    }


    txBuffer[0] = 0;
    i2cTransaction.slaveAddress = TMP102_I2C_ADDR;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.readCount = 2;


    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[0] = 0x32;
    txBuffer[1] = 0;
    i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.readCount = 2;


    while (1)
    {


        //Read interrupt bits on ADXL345
        i2cTransaction.readCount = 1;
        txBuffer[0] = ADXL345_INT_SOURCE;
        i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
        I2CErrorN = I2C_transfer(i2c, &i2cTransaction);
        interruptData = rxBuffer[0];


        //Read accelerometer data
        i2cTransaction.readCount = 6;
        txBuffer[0] = 0x32;
        i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
        I2CErrorN = I2C_transfer(i2c, &i2cTransaction);
        for(i=0;i<6;i++)
            accelerometerData[i] = rxBuffer[i];


        //Read temperature
        i2cTransaction.readCount = 1;
        txBuffer[0] = 0;
        i2cTransaction.slaveAddress = TMP102_I2C_ADDR;
        I2CErrorN = I2C_transfer(i2c, &i2cTransaction);
        temperature = rxBuffer[0];






        if (I2CErrorN != 1)
        {
            System_printf("I2C Bus fault\n");
            System_flush();
        }


        Task_sleep(10);
    }


    /* Deinitialized I2C */
    I2C_close(i2c);
    System_printf("I2C closed!\n");
    System_flush();


}


/******** activity, inactivity from ADXL345 int source1. Activated via Hwi***/
void ADXL345_int1(unsigned int index)
{
    MsgPWM pMsg;
    /* Clear the GPIO interrupt and toggle an LED */
    GPIO_toggle(Board_LED0);
    pMsg.pwm = 50;
    Mailbox_post(mbPWM, &pMsg, 10);
}


void ADXL345_init(UArg arg0, UArg arg1)
{
    uint8_t txBuffer[2];
    uint8_t rxBuffer[2];
    I2C_Handle i2c;
    I2C_Params i2cParams;
    I2C_Transaction i2cTransaction;


    /* Create I2C for usage */
    I2C_Params_init(&i2cParams);
    i2cParams.bitRate = I2C_100kHz;
    i2c = I2C_open(adxl345_I2C, &i2cParams);
    if (i2c == NULL)
    {
        System_abort("Error Initializing I2C\n");
    }
    else
    {
        System_printf("I2C Initialized!\n");
    }


    /**** ADXL345 TURN ON ***/


    txBuffer[0] = ADXL345_POWER_CTL;  //Wakeup
    txBuffer[1] = 0;
    i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 2;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.readCount = 1;


    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[1] = 16;               // Auto_sleep
    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[1] = 8;               // Measure
    I2C_transfer(i2c, &i2cTransaction);


    /***** Give the range settings *****/
    // Accepted values are 2g, 4g, 8g or 16g - ADXL345_DATA_FORMAT
    // Higher Values = Wider Measurement Range
    // Lower Values = Greater Sensitivity
    /**** Activity Inactivity setting  ***/


    txBuffer[0] = ADXL345_ACT_INACT_CTL;
    txBuffer[1] = 0b01110111;
    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[0] = ADXL345_TIME_INACT; //
    txBuffer[1] = 10;
    I2C_transfer(i2c, &i2cTransaction);


    /**** Activity Threshold  ***/


    txBuffer[0] = ADXL345_THRESH_ACT;
    txBuffer[1] = 75; // 62.5mg per increment    // Activity thresholds (0-255)
    I2C_transfer(i2c, &i2cTransaction);


    /**** Inactivity Threshold  ***/


    txBuffer[0] = ADXL345_THRESH_INACT;
    txBuffer[1] = 20; // 62.5mg per increment    // Inactivity thresholds (0-255)
    I2C_transfer(i2c, &i2cTransaction);


    /**** Free-Fall Threshold and Time ***/


    txBuffer[0] = ADXL345_THRESH_FF;
    txBuffer[1] = 7;  // (5 - 9) recommended - 62.5mg per increment
    I2C_transfer(i2c, &i2cTransaction);


    txBuffer[0] = ADXL345_TIME_FF;
    txBuffer[1] = 30; // (20 - 70) recommended - 5ms per increment
    I2C_transfer(i2c, &i2cTransaction);


    /**** Interrupt setup  ***/


    //Interrupt mapping
    txBuffer[0] = ADXL345_INT_MAP;
    txBuffer[1] = 0; // 0b11110011;  //inactivity and free-fall is int1, activity is int2 ( others are int 2 but disabled)
    I2C_transfer(i2c, &i2cTransaction);


    //Interrupt enable


    txBuffer[0] = ADXL345_INT_ENABLE;
    txBuffer[1] = 0b00011100; //activity, inactivity, and free-fall interrupts are enabled
    I2C_transfer(i2c, &i2cTransaction);


    /* Deinitialized I2C */
    I2C_close(i2c);
    System_printf("I2C closed!\n");
    System_flush();


    /* Construct BIOS objects */
    Task_Params taskParams;


    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskI2CStack;
    Task_construct(&taskI2CStruct, (Task_FuncPtr) readPos, &taskParams, NULL);


}


/*
 *  ======== gpioButtonFxn ========
 *  Callback function for the GPIO interrupt on Board_BUTTON1.
 */
void gpioButtonFxn(unsigned int index)
{
    /* Begin smart config process */
    //smartConfigFlag = true;


    MsgPWM pMsg;
    pMsg.pwm = 0;
    Mailbox_post(mbPWM, &pMsg, 10);


}


int socketHandler = -1;
int status;
char recievedBuff[4];


/*
 *  ======== TCPsend Function ========
 *  It creates socket, send message, receive it
 *  then close the socket
 */
char* str;
Void TCPSend(char *message)
{
    char i;
    while (1)
    {
        if (connected != 1)
        {
            // Open WiFi and await a connection
            netIF = socketsStartUp();


            socketHandler = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


            /*
             * SL_AF_INET indicates using IPv4
             * SL_SOCK_STREAM indicates using TCP
             * IPPROTO_TCP
             */


            connected = 1;


            if (socketHandler == -1)
            {
                System_printf("Error: socket not created.\n");
                connected = 0;
            }


            SlSockAddrIn_t Addr;  // Socket settings
            Addr.sin_family = SL_AF_INET;
            Addr.sin_port = sl_Htons(TCPPORT);
            Addr.sin_addr.s_addr = sl_Htonl(IP_ADDR_Server);


            status = sl_Connect(socketHandler, (SlSockAddr_t *) &Addr,
                                sizeof(SlSockAddrIn_t));
        }


        status = sl_Send(socketHandler, "##*", 3, 0);


        Mymessage = char2str(temperature) ;
        status = sl_Send(socketHandler, Mymessage, 3, 0);
        status = sl_Send(socketHandler, "*", 1, 0);
        Mymessage = char2str(interruptData) ;
        status = sl_Send(socketHandler, Mymessage, 3, 0);
        status = sl_Send(socketHandler, "*", 1, 0);


        for(i =0 ; i<6 ; i++)
        {
            Mymessage = char2str(accelerometerData[i]) ;
            status = sl_Send(socketHandler, Mymessage, 3, 0);


        }
        status = sl_Send(socketHandler, "*", 1, 0);
        Mymessage = int2str(pressureAdcValue) ;
        status = sl_Send(socketHandler, Mymessage, 5, 0);
        status = sl_Send(socketHandler, "*--", 3, 0);


        // sl_Close(socketHandler);


        Task_sleep(10);


    }
    // Close the network - don't do this if other tasks are using it
    //socketsShutDown(netIF);
}




/*
 *  ======== taskAdcSample ========
 *  Open an ADC instance and get a sampling result from a one-shot conversion.
 */


Void taskAdcSample(UArg arg0, UArg arg1)
{
    ADC_Handle   adc0;
    ADC_Params   params;
    ADC_Params_init(&params);
    adc0 = ADC_open(Board_ADC0, &params);


    while (1) {
        Task_sleep(10);
        /* Blocking mode conversion */
        ADC_convert(adc0, &pressureAdcValue);
    }
    // theoretically close the ADC driver. This code is never reached
//    ADC_close(adc0);
//    ADC_close(adc1);
}










/*
 *  ======== pwmFxn ========
 */


Void pwmFxn(UArg arg0, UArg arg1)
{
    PWM_Handle pwm1;
    PWM_Params params;
    uint16_t   pwmPeriod = 2000;      // Period and duty in microseconds


    MsgPWM msg;


    PWM_Params_init(&params);
    params.dutyUnits = PWM_DUTY_US;
    params.dutyValue = 0;
    params.periodUnits = PWM_PERIOD_US;
    params.periodValue = pwmPeriod;
    pwm1 = PWM_open(Board_PWM0, &params);
    if (pwm1 == NULL) {
        System_abort("Board_PWM0 did not open");
    }
    PWM_start(pwm1);




    /* Loop forever incrementing the PWM duty */
    while (1) {
        //Task_sleep(10);
        /* wait for mailbox to be posted by writer() */
        if (Mailbox_pend(mbPWM, &msg, BIOS_WAIT_FOREVER)) {
            PWM_setDuty(pwm1, msg.pwm);
        }
    }
}






/*
 *  ======== main ========
 */
int main(void)
{
    /* Construct BIOS objects */
    Task_Params taskParams;


    /* Call board init functions. */
    Board_initGeneral();
    Board_initGPIO();
    Board_initWiFi();
    Board_initUART();
    Board_initI2C();
    Board_initADC();
    Board_initPWM();






    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskWiFiStack;
    taskParams.priority = 1;
    Task_construct(&taskWiFiStruct, (Task_FuncPtr) TCPSend, &taskParams, NULL);


    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskUARTStack;
    taskParams.instance->name = "echo";
    Task_construct(&taskUARTStruct, (Task_FuncPtr) echoFxn, &taskParams, NULL);




    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskADCStack;
    taskParams.priority = 1;
    Task_construct(&taskADCStruct, (Task_FuncPtr) taskAdcSample, &taskParams, NULL);




    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskADXL345Stack;
    Task_construct(&taskADXL345Struct, (Task_FuncPtr) ADXL345_init, &taskParams,
    NULL);




    /* Construct LED Task thread */
    Task_Params_init(&taskParams);
    taskParams.stackSize = 512;
    taskParams.stack = &taskPWMStack;
    taskParams.arg0 = 50;
    Task_construct(&taskPWMStruct, (Task_FuncPtr)pwmFxn, &taskParams, NULL);




    /* Install Button callback */
    GPIO_setCallback(Board_BUTTON1, gpioButtonFxn);


    /* Enable interrupts */
    GPIO_enableInt(Board_BUTTON1);


    /* Turn on user LED */
    GPIO_write(Board_LED0, Board_LED_ON);


    System_printf("Starting the TCP Echo example for the CC3X00 \n"
                  "System provider is set to SysMin. Halt the target to view"
                  " any SysMin content in ROV.\n");


    /* SysMin will only print to the console when you call flush or exit */
    System_flush();


    /* install Button callback */
    GPIO_setCallback(MSP_EXP432P401R_INT1, ADXL345_int1);


    /* Enable interrupts */
    GPIO_enableInt(MSP_EXP432P401R_INT1);


    /* Start BIOS */
    BIOS_start();


    return (0);
}

After recognising having more than 4 days, I took a deep breath and heading to the working prototype. In the previous article, I have made a simple gate control. In this week I made some additional functionality and will demonstrate it on the video. The idea of this part is not allowing the miner to access mining area without the helmet (or can be any safety clothes) so providing the safety. It also records the access control which makes managing and planning easier.

 

The system is consist of NFC reader and NFC tag. In reality, short range RFDI system will be suitable hence NFC allows a few cms which is very short distance. However, the implementation of the system and how it works is completely the same.

 

Let's see how system works

 

 

I have used the example code here (DLP-7970ABP NFC Transceiver Booster Pack | TI.com ). I made some change on the program. First, RX is not activated by the example code so I need to enable the RX pin to send the gate to open command.

 

    // Modified code
    P1SEL |= BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD
    P1SEL2 |= BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD
    
    // The original Code
    //P1SEL |= BIT2; // P1.2=TXD
    //P1SEL2 |= BIT2; // P1.2=TXD

 

 

After enabling RX, I implemented RX data received interrupt. Therefore, I need to activate the RX interrupt.

 

    UC0IE |= UCA0RXIE; // Enable USCI_A0 RX interrupt

 

Then interrupt service routine to open the gate.

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
   if (UCA0RXBUF == '1') // '1' received? open the gate
   {
       P1OUT |= 1;


       delay_ms(5000);


       P1OUT &= 0xfe;
   }
   else //Gate is closed
   {
       P1OUT &= 0xfe; // Not necessary for the current program 
   }


}

 

In the interrupt service routine program gets the information from the Ground Operations Centre. Ground Operations Centre checks whether this user is inside (it may be fake ID or user throw the helmet back ) or the ID is valid. If the user is allowed to access, it sends "1" to gate control board. If "1" is gotten by the gate control board, it will turn on the LED (open the gate), waits 5 seconds while disabling reading activities and then turn off the LED (close the gate). Using delay inside the interrupt is a terrible idea but in this time it does what I want.

 

Time is running, I will make some changes on the design and shoot videos and demonstrate how the system works.

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

 

Here is the full code.

 

/*
 * File Name: main.c
 *
 * Description: The TRF7970A is an integrated analog front end and
 * data framing system for a 13.56 MHz RFID reader system.
 * Built-in programming options make it suitable for a wide range
 * of applications both in proximity and vicinity RFID systems.
 * The reader is configured by selecting the desired protocol in
 * the control registers. Direct access to all control registers
 * allows fine tuning of various reader parameters as needed.
 *
 *
 * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*
* DESCRIPTION:
* This example detects ISO15693, Type 2, Type 3, Type 4A, Type 4B
* NFC/RFID tags. It then indicates the Tag type through LED's on the
* TRF7970A Booster pack. Information such as tag UID's and block data is
* sent out via a UART at 115200 Baud and can be read on a Computer.
*
* The TRF7970A is an integrated analog front end and
* data framing system for a 13.56 MHz RFID reader system.
* Built-in programming options make it suitable for a wide range
* of applications both in proximity and vicinity RFID systems.
* The reader is configured by selecting the desired protocol in
* the control registers. Direct access to all control registers
* allows fine tuning of various reader parameters as needed.
*
* The TRF7970A is interfaced to a MSP430G2553 through a SPI (serial)
* interface using a hardware USCI. The MCU is the master device and
* initiates all communication with the reader.
*
* The anti-collision procedures (as described in the ISO
* standards 14443A/B and 15693) are implemented in the MCU
* firmware to help the reader detect and communicate with one
* PICC/VICC among several PICCs/VICCs.
*
* AUTHORS:   Josh Wyatt
* Ralph Jacobi
*
* BUILT WITH:
* Code Composer Studio Core Edition Version: 6.0.1.00040
* (c) Copyright Texas Instruments, 2014. All rights reserved.
*****************************************************************/


//===============================================================
// Program with hardware USART and SPI communication        ;
// interface with TRF7970A reader chip.                         ;
//                                                              ;
// PORT1.0 - HEART BEAT LED                                     ;
// PORT1.1 - UART RX                                            ;
// PORT1.2 - UART TX                                            ;
// PORT1.5 - SPI DATACLK                                        ;
// PORT1.6 - SPI MOSI TODO: Remove LED2 Jumper on G2 LaunchPad  ;
// PORT1.7 - SPI MISO                                           ;
//                                                              ;
// PORT2.7 - IRQ (INTERUPT REQUEST from TRF7970A) (XOUT on LP)  ;
// PORT2.1 - SLAVE SELECT                                       ;
// PORT2.2 - TRF7970A ENABLE                                    ;
// PORT2.3 - ISO14443B LED                                      ;
// PORT2.4 - ISO14443A LED                                      ;
// PORT2.5 - ISO15693  LED                                      ;
//===============================================================


#include "nfc_app.h"
#include "trf79xxa.h"


#include <string.h>


#include <stdbool.h>
#include "MSP430.h"         // Processor specific header




void delay_ms(unsigned int ms)
{
    while (ms)
    {
        __delay_cycles(1000);
        ms--;
    }
}




#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
   if (UCA0RXBUF == '1') // '1' received? open the gate
   {
       P1OUT |= 1;


       delay_ms(9000);


       P1OUT &= 0xfe;
   }
   else //Gate is closed
   {
       P1OUT &= 0xfe; // Not necessary for the current program
   }


}


//===============================================================


void main(void)
{
  uint8_t ui8VLOCalibCount;
  char x;


// TODO: Remove LED2 Jumper on G2 LaunchPad if using it, otherwise SPI will not work.


  // Stop the Watchdog timer,
  WDTCTL = WDTPW + WDTHOLD;


  // Select DCO to be 8 MHz
  MCU_initClock();
  MCU_delayMillisecond(10);


  // Calibrate VLO
  MCU_calculateVLOFreq();


  // Set the SPI SS high
  SLAVE_SELECT_PORT_SET;
  SLAVE_SELECT_HIGH;


  // Four millisecond delay between bringing SS high and then EN high per TRF7970A Datasheet
  MCU_delayMillisecond(4);


  // Set TRF Enable Pin high
  TRF_ENABLE_SET;
  TRF_ENABLE;


  // Wait until TRF system clock started
  MCU_delayMillisecond(5);


  // Set up TRF initial settings
  TRF79xxA_initialSettings();
  TRF79xxA_setTrfPowerSetting(TRF79xxA_3V_FULL_POWER);


#ifdef ENABLE_HOST
  // Set up UART
  UART_setup();
#endif


  // Initialize all enabled technology layers
  NFC_init();


  P1DIR |= 0x1;
    P1OUT &= 0xfe;


    UC0IE |= UCA0RXIE; // Enable USCI_A0 RX interrupt




  // Enable global interrupts
  __bis_SR_register(GIE);


  // Enable IRQ Pin
  IRQ_ON;


#ifdef ENABLE_HOST
  UART_putIntroReaderMsg(RFID_READER_FW_VERSION, RFID_READER_FW_DATE);
#endif




  while(1)
  {
  // Poll for NFC tags
  NFC_findTag();




  // VLO drifts with temperature and over time, so it must be periodically recalibrated
  // Calibrate the VLO every 25 passes of the NFC polling routine
  ui8VLOCalibCount++;
  if (ui8VLOCalibCount == 25)
  {
  // Calibrate VLO
  MCU_calculateVLOFreq();
  // Reset Calibration Counter
  ui8VLOCalibCount = 0;
  }
  }
}

Edit: The draft has been published by mistake, therefore, I updated it.

 

I don't know why but it takes so long to implement access control with NFC. I think I put forward it because it is a separate design from the helmet. Hence, I use a passive tag on the helmet, it is only attached to it and no more work on helmet side. The https://www.element14.com/community/view-product.jspa?fsku=2535894&nsku=74X8084&COM=noscriptDLP-7970ABP NFC transceiver BoosterPack  is the key element of this part. It will read the tag and send the data over the serial port (the msp430 board convert serial to USB) to the Ground Operations Centre. The Ground Operations Centre will decide to doors open. It registers the users who access the mining side so if multiple access occurred from a single tag it will deny the access. Following screenshot shows the how the program works.

 

 

The Ground Operations Centre saves the user IDs who has accessed the side. If the user ID from the insider wants to access again it will not allow that user to access. I use sample code for MSP430. This board will be connected to Ground Operations Centre via the serial port. Therefore, I added a serial terminal to C# example. The program gets the data and checks it whether it belongs to a worker who is inside the mine area. If it is, then access is denied. I haven't implemented but there should be also exit gate control which deletes the user ID when they left the mine area. It is the same program but instead of registering user, it will delete. 

 

 

        public void AddDataMethod(String myString)
        {
            //check wheather user is inside 
            if (users.Contains(myString))
            {
                rtbNFC.SelectionColor = System.Drawing.Color.Red;
                myString = "Access Denied: " + myString + " \n\r";
                serialNFC.Write("0");
            }
            else
            {
                rtbNFC.SelectionColor = System.Drawing.Color.Green;
                myString = "Access Successful: " + myString + " \n\r"; ;
                users[minerNo] = txt;
                minerNo++;
                serialNFC.Write("1");
            }


            rtbNFC.AppendText(myString);
        }

 

 

 

I had a huge mistake and I thought the deadline was extended to next month until I have read dougw's latest blog post. Now, I have few days and need to combine all things and show the working prototype. I hope I can shoot a video. I will also add all the codes as an attachment on the next blog.

I didn't have much time so I used Arduino for the sensor board which makes design cumbersome to fit inside a helmet. However, I have some time this week so I created code for MSP432. ADXL345 can be accessible through either an SPI (3- or 4-wire) or I2C digital interface. I prefer I2C because I have used TMP102 temperature sensor which has I2C interface. Using I2C, I don't need to use additional pins. ADXL345 is not very easy to use. It requires some setting before gathering the data. You may ask why I have chosen it, the reason is I have a spare one.

 

I modified the Sparkfun Arduino library for the MSP432 with the minimum setting. First, we need to wake-up accelerometer and tell it to take measurements. This is done sending commands to POWER_CTL register. Second, we need to set the range of the sensor. The range varies from 2g to 16g. The more the range the less the sensitivity. I prefer the sensitivity so set it to 2g which is the default value. I may change this values when I embed the design inside the helmet and take real scenario measurements. 

 

The ADXL345 provides more than x,y,z data. It can provide interrupt for activity, inactivity, freefall and more. To use interrupt we need to set them. ACT_INACT_CTL (value = 01110111) register is control register for activity and inactivity detection.

"Then THRESH_ACT register is eight bits and holds the threshold value for detecting activity. The data format is unsigned, so the magnitude of the activity event is compared with the value in the THRESH_ACT register. The scale factor is 62.5 mg/LSB."

THRESH_INACT register has a similar task which holds the threshold for the inactivity. After setting thresholds, I set the FREE_FALL register which can detect the free-fall.

 

 

ADXL345 has two interrupt pin but eight interrupt sources. Therefore, we need to map the interrupts for the pins. I am using activity, inactivity, free-fall interrupts (maybe data available when my design becomes more clear).

Any bits set to 0 in this register send their respective interrupts to the INT1 pin, whereas bits set to 1 send their respective interrupts to the INT2 pin. All selected interrupts for a given pin are OR’ed.

I will use interrupt pin 1 for the inactivity and free-fall and interrupt pin 2 for the activity (activity is used to double check). Therefore, I need to write 0bxxx100xx (0b11110011).

 

After setting all the values, we need to enable interrupts so we need to send 0b00011100 to INT_ENABLE register.

 

Here is the initialization code for the ADXL345. I coded this as a library file but I2C_transfer function can be only called from inside the task. Therefore following function is a task.

 

void ADXL345_init (UArg arg0, UArg arg1)
{
          uint8_t         txBuffer[2];
          uint8_t         rxBuffer[2];
          I2C_Handle      i2c;
          I2C_Params      i2cParams;
          I2C_Transaction i2cTransaction;




          /* Create I2C for usage */
          I2C_Params_init(&i2cParams);
          i2cParams.bitRate = I2C_100kHz;
          i2c = I2C_open(adxl345_I2C, &i2cParams);
          if (i2c == NULL) {
              System_abort("Error Initializing I2C\n");
          }
          else {
              System_printf("I2C Initialized!\n");
          }


          /**** ADXL345 TURN ON ***/


          txBuffer[0] = ADXL345_POWER_CTL;  //Wakeup
          txBuffer[1] = 0;
          i2cTransaction.slaveAddress = ADXL345_I2C_ADDR;
          i2cTransaction.writeBuf = txBuffer;
          i2cTransaction.writeCount = 2;
          i2cTransaction.readBuf = rxBuffer;
          i2cTransaction.readCount =1;


          I2C_transfer(i2c, &i2cTransaction);


          txBuffer[1] = 16;               // Auto_sleep
          I2C_transfer(i2c, &i2cTransaction);


          txBuffer[1] = 8;               // Measure
          I2C_transfer(i2c, &i2cTransaction);


          /***** Give the range settings *****/
          // Accepted values are 2g, 4g, 8g or 16g - ADXL345_DATA_FORMAT
          // Higher Values = Wider Measurement Range
          // Lower Values = Greater Sensitivity






          /**** Activity Inactivity setting  ***/


          txBuffer[0] = ADXL345_ACT_INACT_CTL;
          txBuffer[1] = 0b01110111;
          I2C_transfer(i2c, &i2cTransaction);


          txBuffer[0] = ADXL345_TIME_INACT; //
          txBuffer[1] = 10;
          I2C_transfer(i2c, &i2cTransaction);


          /**** Activity Threshold  ***/


          txBuffer[0] = ADXL345_THRESH_ACT;
          txBuffer[1] = 75; // 62.5mg per increment    // Activity thresholds (0-255)
          I2C_transfer(i2c, &i2cTransaction);


          /**** Inactivity Threshold  ***/


          txBuffer[0] = ADXL345_THRESH_INACT;
          txBuffer[1] = 20; // 62.5mg per increment    // Inactivity thresholds (0-255)
          I2C_transfer(i2c, &i2cTransaction);


          /**** Free-Fall Threshold and Time ***/


          txBuffer[0] = ADXL345_THRESH_FF;
          txBuffer[1] = 7;  // (5 - 9) recommended - 62.5mg per increment
          I2C_transfer(i2c, &i2cTransaction);


          txBuffer[0] = ADXL345_TIME_FF;
          txBuffer[1] = 30; // (20 - 70) recommended - 5ms per increment
          I2C_transfer(i2c, &i2cTransaction);


          /**** Interrupt setup  ***/


          //Interrupt mapping


          txBuffer[0] = ADXL345_INT_MAP;
          txBuffer[1] = 0; // 0b11110011;  //inactivity and free-fall is int1, activity is int2 ( others are int 2 but disabled)
          I2C_transfer(i2c, &i2cTransaction);


          //Interrupt enable


          txBuffer[0] = ADXL345_INT_ENABLE;
          txBuffer[1] = 0b00011100;  //activity, inactivity, and free-fall interrupts are enabled
          I2C_transfer(i2c, &i2cTransaction);




          /* Deinitialized I2C */
          I2C_close(i2c);
          System_printf("I2C closed!\n");
          System_flush();






          /* Construct BIOS objects */
          Task_Params taskParams;


          Task_Params_init(&taskParams);
          taskParams.stackSize = TASKSTACKSIZE;
          taskParams.stack = &taskI2CStack;
          Task_construct(&taskI2CStruct, (Task_FuncPtr)readPos, &taskParams, NULL);






}

 

 

ADXL345 has the interrupt output so we need to get this on MSP432. It was a little trick to find how interrupts work on TI-RTOS then it becomes very easy. First, MSP_EXP432P401R.c should be configured. I set up the p3.6 pin for the INT1 output of the ADXL345 so I added the following code to gpioConfigs driver. Then give that pin a name inside MSP_EXP432P401R.h.

 

    /* MSP_EXP432P401R_P3.6 */

    GPIOMSP432_P3_6 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING,

 

 

 

MSP_EXP432P401R.c Pin Configuration

GPIO_PinConfig gpioPinConfigs[] = {
    /* Input pins */
    /* MSP_EXP432P401R_S1 */
    GPIOMSP432_P1_1 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_RISING,
    /* MSP_EXP432P401R_S2 */
    GPIOMSP432_P1_4 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_RISING,


    /* MSP_EXP432P401R_P3.6 */
    GPIOMSP432_P3_6 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING,


    /* Output pins */
    /* MSP_EXP432P401R_LED1 */
    GPIOMSP432_P1_0 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW,
    /* MSP_EXP432P401R_LED_RED */
    GPIOMSP432_P2_0 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW,


    /*
     * MSP_EXP432P401R_LED_GREEN & MSP_EXP432P401R_LED_BLUE are used for
     * PWM examples.  Uncomment the following lines if you would like to control
     * the LEDs with the GPIO driver.
     */
    /* MSP_EXP432P401R_LED_GREEN */
    //GPIOMSP432_P2_1 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW,
    /* MSP_EXP432P401R_LED_BLUE */
    //GPIOMSP432_P2_2 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW
};

 

 

MSP_EXP432P401R.h Pin tagging

 

typedef enum MSP_EXP432P401R_GPIOName {
    MSP_EXP432P401R_S1 = 0,
    MSP_EXP432P401R_S2,
    MSP_EXP432P401R_INT1,
    MSP_EXP432P401R_LED1,
    MSP_EXP432P401R_LED_RED,


    /*
     * MSP_EXP432P401R_LED_GREEN & MSP_EXP432P401R_LED_BLUE are used for
     * PWM examples.  Uncomment the following lines if you would like to control
     * the LEDs with the GPIO driver.
     */
    //MSP_EXP432P401R_LED_GREEN,
    //MSP_EXP432P401R_LED_BLUE,


    MSP_EXP432P401R_GPIOCOUNT
} MSP_EXP432P401R_GPIOName;

 

 

Finally, activate the interrupt inside the main function.

 

    /* install Button callback */
    GPIO_setCallback(MSP_EXP432P401R_INT1 , gpioButtonFxn0);


    /* Enable interrupts */
    GPIO_enableInt(MSP_EXP432P401R_INT1 );

 

 

Now the design has the same features with the previous one but Arduino is removed. This make it more compact, cheaper, and more based on MSP432

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

I was absent last two weeks, I hope I will catch up the following weeks In the last post, I have written about the socket programming and wifi boosterpack. The next think I need to hook up the sensor boosterpack but there were problems. Although bare-metal code for sensor boosterpack works, the sample code for the TI-RTOS didn't work. I didn't want to use the bare-metal code because it was pretty long and timing can be a problem if I combine wifi module and some other stuff. Also, I don't have much time so I came up with separating the sensor board and create sensor board with Arduino.

IMG_20170415_210611.jpg

 

 

I have used TMP102 digital temperature sensor and ADXL345 accelerometer. ADXL345 makes things easier because it has an Arduino library wich can detect the inactivity. The code below is getting sensors data and send temperature and activity/inactivity over the serial port. I will connect the serial port to MSP432 and send the data over Wi-Fi boosterpack. I will add a pressure sensor and buzzer to warn the user.

 

I also got the helmet. I hope this week I will do more work and catch up.

 

 

/*  ********************************************* 
 *  SparkFun_ADXL345_Example
 *  Triple Axis Accelerometer Breakout - ADXL345 
 *  Hook Up Guide Example 
 *  
 *  Utilizing Sparkfun's ADXL345 Library
 *  Bildr ADXL345 source file modified to support 
 *  both I2C and SPI Communication
 *  
 *  E.Robert @ SparkFun Electronics
 *  Created: Jul 13, 2016
 *  Updated: Sep 06, 2016
 *  
 *  Development Environment Specifics:
 *  Arduino 1.6.11
 *  
 *  Hardware Specifications:
 *  SparkFun ADXL345
 *  Arduino Uno
 *  *********************************************/


#include <SparkFun_ADXL345.h>  // SparkFun ADXL345 Library
#include <Wire.h>             // Used to establied serial communication on the I2C bus
#include "SparkFunTMP102.h"  // Used to send and recieve specific information from our sensor




/*********** COMMUNICATION SELECTION  for ADXL345 ***********/
/*    Comment Out The One You Are Not Using    */
ADXL345 adxl = ADXL345(10);           // USE FOR SPI COMMUNICATION, ADXL345(CS_PIN);
//ADXL345 adxl = ADXL345();             // USE FOR I2C COMMUNICATION


/****************** INTERRUPT for ADXL345 ******************/
/*      Uncomment If Attaching Interrupt       */
//int interruptPin = 2;                 // Setup pin 2 to be the interrupt pin (for most Arduino Boards)




/*********** Initialize  TMP102 ***********/
TMP102 sensor0(0x48); // Initialize sensor at I2C address 0x48
const int ALERT_PIN = A3;




void TMP102Init()
{
  
  pinMode(ALERT_PIN,INPUT);  // Declare alertPin as an input for TMP102
  sensor0.begin();  // Join I2C bus
  // Initialize sensor0 settings
  // These settings are saved in the sensor, even if it loses power
  
  // set the number of consecutive faults before triggering alarm.
  // 0-3: 0:1 fault, 1:2 faults, 2:4 faults, 3:6 faults.
  sensor0.setFault(0);  // Trigger alarm immediately
  
  // set the polarity of the Alarm. (0:Active LOW, 1:Active HIGH).
  sensor0.setAlertPolarity(1); // Active HIGH
  
  // set the sensor in Comparator Mode (0) or Interrupt Mode (1).
  sensor0.setAlertMode(0); // Comparator Mode.
  
  // set the Conversion Rate (how quickly the sensor gets a new reading)
  //0-3: 0:0.25Hz, 1:1Hz, 2:4Hz, 3:8Hz
  sensor0.setConversionRate(2);
  
  //set Extended Mode.
  //0:12-bit Temperature(-55C to +128C) 1:13-bit Temperature(-55C to +150C)
  sensor0.setExtendedMode(0);


  //set T_HIGH, the upper limit to trigger the alert on
  sensor0.setHighTempF(85.0);  // set T_HIGH in F
  //sensor0.setHighTempC(29.4); // set T_HIGH in C
  
  //set T_LOW, the lower limit to shut turn off the alert
  sensor0.setLowTempF(84.0);  // set T_LOW in F
  //sensor0.setLowTempC(26.67); // set T_LOW in C
  
}




void ADXLInit()
{
  adxl.powerOn();                     // Power on the ADXL345


  adxl.setRangeSetting(16);           // Give the range settings
                                      // Accepted values are 2g, 4g, 8g or 16g
                                      // Higher Values = Wider Measurement Range
                                      // Lower Values = Greater Sensitivity


  adxl.setSpiBit(0);                  // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1
                                      // Default: Set to 1
                                      // SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library 
   
  adxl.setActivityXYZ(1, 0, 0);       // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  adxl.setActivityThreshold(75);      // 62.5mg per increment   // Set activity   // Inactivity thresholds (0-255)

  adxl.setInactivityXYZ(1, 0, 0);     // Set to detect inactivity in all the axes "adxl.setInactivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF)
  adxl.setInactivityThreshold(75);    // 62.5mg per increment   // Set inactivity // Inactivity thresholds (0-255)
  adxl.setTimeInactivity(10);         // How many seconds of no activity is inactive?


  adxl.setTapDetectionOnXYZ(0, 0, 1); // Detect taps in the directions turned ON "adxl.setTapDetectionOnX(X, Y, Z);" (1 == ON, 0 == OFF)

  // Set values for what is considered a TAP and what is a DOUBLE TAP (0-255)
  adxl.setTapThreshold(50);           // 62.5 mg per increment
  adxl.setTapDuration(15);            // 625 μs per increment
  adxl.setDoubleTapLatency(80);       // 1.25 ms per increment
  adxl.setDoubleTapWindow(200);       // 1.25 ms per increment

  // Set values for what is considered FREE FALL (0-255)
  adxl.setFreeFallThreshold(7);       // (5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(30);       // (20 - 70) recommended - 5ms per increment

  // Setting all interupts to take place on INT1 pin
  //adxl.setImportantInterruptMapping(1, 1, 1, 1, 1);     // Sets "adxl.setEveryInterruptMapping(single tap, double tap, free fall, activity, inactivity);" 
                                                        // Accepts only 1 or 2 values for pins INT1 and INT2. This chooses the pin on the ADXL345 to use for Interrupts.
                                                        // This library may have a problem using INT2 pin. Default to INT1 pin.
  
  // Turn on Interrupts for each mode (1 == ON, 0 == OFF)
  adxl.InactivityINT(1);
  adxl.ActivityINT(1);
  adxl.FreeFallINT(1);
  adxl.doubleTapINT(1);
  adxl.singleTapINT(1);
  
//attachInterrupt(digitalPinToInterrupt(interruptPin), ADXL_ISR, RISING);   // Attach Interrupt
}


/******************** SETUP ********************/
void setup(){
  
  Serial.begin(9600);                 // Start the serial terminal


  TMP102Init();
  ADXLInit();


}






/****************** MAIN CODE ******************/
/*     Accelerometer Readings and Interrupt    */
void loop(){


  float temperature;
  boolean alertPinState, alertRegisterState;
  
  // Accelerometer Readings
  int x,y,z;   
  adxl.readAccel(&x, &y, &z);         // Read the accelerometer values and store them in variables declared above x,y,z


  // Output Results to Serial
  /* UNCOMMENT TO VIEW X Y Z ACCELEROMETER VALUES */  
  //Serial.print(x);
  //Serial.print(", ");
  //Serial.print(y);
  //Serial.print(", ");
  //Serial.println(z); 
  
  ADXL_ISR();
  // You may also choose to avoid using interrupts and simply run the functions within ADXL_ISR(); 
  //  and place it within the loop instead.  
  // This may come in handy when it doesn't matter when the action occurs. 






 // Turn sensor on to start temperature measurement.
  // Current consumtion typically ~10uA.
  sensor0.wakeup();


  // read temperature data
  temperature = sensor0.readTempF();
  //temperature = sensor0.readTempC();


  // Check for Alert
  alertPinState = digitalRead(ALERT_PIN); // read the Alert from pin
  alertRegisterState = sensor0.alert();   // read the Alert from register
  
  // Place sensor in sleep mode to save power.
  // Current consumtion typically <0.5uA.
  sensor0.sleep();


  // Print temperature and alarm state
  Serial.print("Temperature: ");
  Serial.print(temperature);
  
 // Serial.print("\tAlert Pin: ");
 // Serial.print(alertPinState);
  
 // Serial.print("\tAlert Register: ");
 // Serial.println(alertRegisterState);
  
  delay(1000);  // Wait 1000ms




}


/********************* ISR *********************/
/* Look for Interrupts and Triggered Action    */
void ADXL_ISR() {
  
  // getInterruptSource clears all triggered actions after returning value
  // Do not call again until you need to recheck for triggered actions
  byte interrupts = adxl.getInterruptSource();
  
  // Free Fall Detection
  if(adxl.triggered(interrupts, ADXL345_FREE_FALL)){
    Serial.println("*** FREE FALL ***");
    //add code here to do when free fall is sensed
  } 
  
  // Inactivity
  if(adxl.triggered(interrupts, ADXL345_INACTIVITY)){
    Serial.println("*** INACTIVITY ***");
     //add code here to do when inactivity is sensed
  }
  
  // Activity
  if(adxl.triggered(interrupts, ADXL345_ACTIVITY)){
    Serial.println("*** ACTIVITY ***"); 
     //add code here to do when activity is sensed
  }
  
  // Double Tap Detection
  if(adxl.triggered(interrupts, ADXL345_DOUBLE_TAP)){
    Serial.println("*** DOUBLE TAP ***");
     //add code here to do when a 2X tap is sensed
  }
  
  // Tap Detection
  if(adxl.triggered(interrupts, ADXL345_SINGLE_TAP)){
    Serial.println("*** TAP ***");
     //add code here to do when a tap is sensed
  } 
}

 

IMG_20170415_210540.jpg

Kits have arrived and hands become dirty The next day after kits have arrived, I plugged wifi boosterpack and use the Tera Term for communication. It worked without any coding. Great Well, not really. I wanted to modify the code but I was stuck because I had never used any RTOS. I could use Energia (which is so like Arduino IDE) examples but I want to learn RTOS. It is challenging myself and learning new skills I went over the online training course and get the basics of the TI-RTOS. I can't say I know the RTOS yet but I start learning maybe after design challenge, I will be knowing RTOS. There are two notes for noobs related to TI-RTOS. First, If you use Task_sleep(10); it doesn't have a constant period. The period is determined by the config user interface as shown below. Therefore Task_sleep(10); will sleep one second (10 * 100 000 us). Second, If you create a software interrupt (or any other task) and want to use them on code interface, you need to include xds/cfg/global.h library.

 

 

I get the glimpse of the TI-RTOS so I moved to programming the wifi boosterpack. The example code under TI-RTOS is configured as a server but I need a client (unless I change the method like reverse RFID). There is User's Guide document ( CC3100/CC3200 SimpleLink™ Wi-Fi® Internet on-a-Chip ) which shows how to configure and use the CC3100 module. Using that guide I have written the following code.

 

Void TCPSetup(char *message)
{
    while(1)
    {
      if(connected == 0)
      {
          // Open WiFi and await a connection
          netIF = socketsStartUp();

          socketHandler = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

          /*
           * SL_AF_INET indicates using IPv4
           * SL_SOCK_STREAM indicates using TCP
           * IPPROTO_TCP
           */

          connected = 1;


          if (socketHandler == -1)
          {
             System_printf("Error: socket not created.\n");
             connected = 0;
          }

          SlSockAddrIn_t Addr;  // Socket settings
          Addr.sin_family = SL_AF_INET;
          Addr.sin_port = sl_Htons(TCPPORT);
          Addr.sin_addr.s_addr = sl_Htonl(IP_ADDR_Server);

          status = sl_Connect(socketHandler, ( SlSockAddr_t *) &Addr, sizeof(SlSockAddrIn_t));
      }


      status = sl_Send(socketHandler, "elemet14", 8, 0 );


     // sl_Close(socketHandler);

      Task_sleep(10);

    }
            // Close the network - don't do this if other tasks are using it
            //socketsShutDown(netIF);

}

 

 

The code (it is a task on TI-RTOS) above connects a network and sends data. It is a task called every second. Next, I need to modify socket library because wifi module is not going to connect to the same access point. Maybe giving the same SSIDs will solve the problem but if they cover the same area it may be a problem. Therefore, my next study will focus on auto connecting the WiFi module and getting the RSSI values.

 

 

On the other hand, I need a server software (Ground Operation Centre ) in order to collect all data and manage the system. I have written simple programs on C# so I prefer it ( while I am writing this, I think about Raspi and Python. Maybe, I can change it). I have written the v0.1 of the Ground Operation Centre program. It is a basic socket program now. However, future versions will include the access control and data collections. You can see a snap of the program here

 

ezgif-1-eae1499308.gif

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

 

 

P.S. Sorry for the code snip I couldn't find the how to activate cursor and shorten the length of the code snip. Lol It is done automatically.

My kits arrived after unexpected Canada trip. I know what was going to arrive but opening the box was still very exciting Here are some photos

 

unbox_1

All the family together

 

IMG_20170318_205043.jpg

Boosterpacks are lying on the A4 paper so this will give you the rough size of the components. I love the NFC tag It is so thin like a stamp. I can stick it on the helmet for entrance control.

 

IMG_20170318_205555.jpg

MSP432 and Wi-Fi boosterback are out of the bag because I will start with them My plan is now getting started with Wi-Fi module and PC program. I hope I can test it tomorrow.

 

My next blog will be related to running up Wi-Fi and connecting it to PC.

 

You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

My safety helmet design can be divided into three categories. The first category is data acquisition from sensors and processing them to predict the potential explosion. The second is tracking the miners and determine their current or immediately pre-accident location. The third one is communication between the workers and ground operations centre(GOC). This week's blog is related to second and third parts because the tracking system is related to the communication system. There was a delay to shipping kits so I haven't started hands on developments. However, I am glad for the delay because the more I do research the more I need time. There are huge details and I may modify my proposal based on my findings.

 

Underground Communication

 

Underground wireless communication can be divided into two categories, primary and secondary communications. Primary communication is for daily communication between miners and ground workers. Leaky feeder and node-based systems are examples of the primary communication systems (PCS). The operating frequency of the PCS starts from very-high-frequency (30 - 300 MHz) band to super-high-frequency band (3 - 30 GHz). Secondary communication uses low frequencies (sub 1MHz) therefore it doesn't have the capacity for the for general communication and requires bigger and heavier antennas. Secondary communication is used during the emergency hence it can propagate through the earth or coal. I will use the PCS for this project hence it requires the plenty data transmission (sensory data for multiple workers).

 

Leaky Feeder Systems

Leaky feeder systems are mainly used in mining areas. They provide two-way communication by using a special type of the coaxial cable. The cable has holes where electromagnetic waves penetrate into or leak out of the coaxial cable. The leaky feeder cable is large transceiver antenna which is established through the tunnels. Hence, the cable can't transmit the obtained signal at infinite length, it requires amplifiers to strengthen the RF signal.

 

 

Leaky feeder coaxial cable showing radio frequency in and out

 

A leaky feeder cable.

Node-Based Systems

Three types of the node-based systems are used in undergrounds; wireless local area network (WLAN), wireless fidelity (Wi-Fi) mesh, and ad hoc mesh. All three use the same standard 802.11b/g. It is open standard so manufacturers can add proprietary features to original WLAN protocol in order to provide the robustness. The ad-hoc mesh network is the most reliable one from them.  It has additional features like using end device as a mesh node, communicating autonomously with any node inside the RF range, and forming a network without dependency on the central server. ZigBee is on of the example of an ad-hoc network.  ZigBee is a good option if the data rate is sufficient. (20 kbit/s (868 MHz band) to 250 kbit/s (2.4 GHz band)).

 

Emslie et al. proposed that mine entries act as waveguides for frequencies in the UHF range and upper frequencies. According to proposal 800 to 1,000 MHz range has the minimum path loss.  (This turns on the light for TI sub - 1 GHz RF communication systems). This indicates that 800 to 1,000 MHz is very effective design for undergrounds.

Figure 2-29. UHF propagation path loss modeling [adapted from Emslie et al. 1975].

 

UHF propagation path loss modeling [adapted from Emslie et al. 1975].

 

 

 

Underground Tracking

 

Traditionally, tracking inside the mine are done manually informing the dispatcher. However, this method is not reliable because a miner can forget (or ignore) to inform dispatcher or the area can be huge therefore it may be impossible to point the exact location. Electronic tracking systems help to solve these problems. There are various methods like RFID tags, node-based systems which measure the signal strength, and dead reckoning. Tracking system needs a communication system with the ground operations centre(GOC) so a node-based system has advantages. If other methods are used, they need a separate communication system.

 

RFID systems are common in shopping malls. The system has a tag (usually passive) and reader. Cheap tags can be embedded to tracked body and when the reader reads the tag, the items or people are located in that area. There is also a reverse-RFID method where the location is tagged and people or items have the readers. Both methods require a communication link either wired or wireless to inform the GOC.

 

My project requires node-based wireless communication system (I will use wi-fi. Although, Wi-Fi can be used inside the mine areas some of them requires sub 1GHz system). Therefore, implementing RFID tracking system is wasting resources. RFID system is simpler to implement but that time system cost will increase. Wi-Fi can be used to track miners based on the received signal strength indicator (RSSI). I haven't checked the CC3100MODBOOST specifications yet, I hope it allows me to get RSSI value. Unfortunately, there may be many reflections and interference. This method requires complicated software algorithm for tracking. Therefore, I am planning to combine dead reckoning with RSSI. Dead reckoning uses accelerometer and gyroscope sensor to get user movement and process it. Dead reckoning doesn't require RF signal but sensor outputs can be noisy which result in error. I hope I can eliminate the errors by using both of them.

 

If you have any suggestion, I look forward to hearing from you.

 

If you want to learn about communication and tracking at underground, you can check the "Advanced Tutorial on Wireless Communication and Electronic Tracking" from The National Institute for Occupational Safety and Health (NIOSH). They have plenty of useful resources.

 

.You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project

In the previous post, I have talked about my proposed project. Hence my project primarily targets to improve the safety of the miners, it has to be ATEX compatible (in Europe) or intrinsically safe (in the USA). It looks like test centres provide their test in accordance with the multiple regulations so you can get the approval with one test for the most part of the world. In this week's blog post, I will talk about some regulations for electronics in explosive areas like mines. I don't have any experiences working in the safety-critical environments so please correct me if there is a mistake. The idea behind the intrinsically safe equipment is preventing the design to release enough energy to create an explosion. This can be done either by ignition or a hot surface. The lesson is that don't spark and don't heat up However, it is not that simple. Let's see some details of the standards.

 

"Simple device is defined 3.12 of the ANSI/ISA-RP 12.6-1987 as any device which will neither generate nor store more than 1.2 volts, 0.1 amps, 25 mW or 20 μJ." Simple devices can be used intrinsically safe and do not need to be approved. Therefore, LEDs, thermocouples may not need an approval. Unfortunately, my design is not in this category because it requires 3.3V or even 5V for sensors This means that this particular design should be tested in accreditated testing laboratories. This is way beyond the aim of the contest and my capabilities (at least for now ). Let's move on some other details. The energy level of any intrinsically safe device should always be below the ignition curve in Figure 1 where operating energy level is 1W or less[1]. Fortunately, my design operates at 5V so my main design consideration is the whole system should be working under 1W. Still, this does not guarantee the intrinsic safety, it is just the necessary step.

 

Ignition Curves

     Figure 1 - Ignition Curve

 

The idea behind the ignition curve is preventing to emit energy to create an ignition. Therefore another two important parameters, capacitance and inductance, play a role. Hence they can store energy, they should not store more than limitations. Let's say we overcome these problems and our system is obeying these rules. Is it intrinsically safe now? No, not yet. We only regulate the first but the most important rule limiting the energy. Another design consideration is fault tolerance. The design also should not exceed these limitations in a case of any fault. The design testing is done for the worst-case scenarios. "The probability of failure is irrelevant and is not considered[2]." Maybe, the fault may occur once in million but that error can cause a catastrophic accident so the design should prevent exceeding limitations and it may require using fuses and Zenner diodes. The PCB design and encapsulation should be designed to prevent the environmental effects such as dust causing the short-circuit.

 

The surface temperature of the design also must be considered. The good design will solve this problem hence the power consumption is limited and the system is shut downed in a faulty condition. This is important because the gas or other substance may combust if the temperature limit is exceeded. If the design is working at the edge, an on-board temperature sensor may be required.

 

In order to prevent sparks, it is better to lock parts of the system to the each other. For example, batteries should be closed by screws so that people will not unplug and plug components inside the mine.

 

 

To summarise, intrinsically safe devices are mainly constrained by their energy consumption and temperature of the device is limited. They also designed to work under the harsh environment such as a dusty place. They are fault tolerant and do not exceed the limitation even the worst-case scenario. Obviously, they do not spark.

 

If we look at the parts of my design, I will use the development board and booster packs. Hence, there are extra components and system will be bulky, a PCB design is required. I am not sure in the given time frame, I can test the working prototype and design a PCB. However, I will limit the system power consumption to 1W and consider the surface temperature. I will also inform you if there is an obvious violation of the regulations in the prototype boards (if I can detect). If you have any suggestion, I look forward to hearing from you.

 

P.S.  I may have errors hence this is my first design for safety critical environments. Please, correct me if there is an error.

        The information above is particularly for portable devices so it does not include the grounding and intrinsically safe barriers,

 

 

References:

1 - Intrinsic Safety Circuit Design

2 - Essential Concepts of Intrinsic Safety

Yesterday, I got an email from element14 which inform that my proposed project is accepted for Safe & Sound design challenge. The aim is "designing a wearable that protects a person from personal and environmental risks, or monitors personal health or protects personal property from theft" and the only requirement is using Texas Instruments’ latest microcontroller.

My project is building a safe working place for the miners. I decided to build this project because, in the 21st century, we still get news miners are missing and the result is usually catastrophic (Gas explosion kills 33 Chinese miners-2016, 9 miners dead and 23 missing after an explosion in Ukrainian coal mine).

The main reason for the coal mine explosions is the methane gas explosions. The gas concentration, temperature, and pressure effect the explosion(Why Do Coal Mines Explode?). In order to prevent explosions, these parameters should be observed carefully. Firstly, the design will measure these parameters.

Even all the measures are taken, the explosion may occur and some miners can be stuck inside the mining area and it may take long times to reach them. In Chilean mine explosion, it took 17 days to find the sign of the miners were alive with the help of dozens of holes drilled by rescue teams (Chilean miners: Where are they now?). The time run against miners' lives. Therefore, if we know where they are exactly, we can reach them faster and increase the possibility of the saving lives. Secondly, the design will track the workers.

Another important feature is preventing human ignorance like not wearing the required safety-uniform, helmet, or mask. By nature, some people don't follow the rules. There should be always a control mechanism to push them to follow rules. It is possible to add RFID or similar technology to inside the helmet so that workers must wear the safety equipment to pass the gates. Thirdly, the design will prevent the unsafe access.

In order to solve these problems, I will design a trackable safety-helmet. This can be also implemented on a safety suit where it is required. Let's see the required tasks to create this design.

 

TASKS

 

1 - As I mentioned above, the main problem is high methane gas concentration. If the air includes 5% to 15% methane it can explode. Because of this, methane concentration must be observed. This should be placed in many areas of the mining area but if we implement the sensor on the helmet, we can see how the concentration change around the workers. How concentration change in a time and place will give important information about the estimating explosions. Methane gas sensors, like Methane CNG Gas Sensor - MQ-4, usually have analogue output and MSP432P401R has 14-bit 1MSPS differential SAR ADC. The first task is connecting an analogue gas sensor to MSP432P401R and process it.

 

2 - Methane concentration is the obvious indicator of the explosion. However, there are other important parameters like pressure and temperature so they should be measured. BOOSTXL-SENSORS  booster pack has an environmental sensor which can measure ambient temperature, pressure, and humidity. This information can be analysed and gas concentration limitation can be changed dynamically.

 

3 - In order to achieve a reliable system, it is required to have a communication link. The main reason is the collected data can be analysed by the central point and if something is wrong warning signal can be activated. It also brings other benefits like if something happens to the worker, he can send an emergency message. The kit includes Bluetooth and Wi-Fi network processors. Bluetooth is not suitable hence it is not supporting meshing (Bluetooth 5 bring this support) and distance is short. Wi-Fi is the better option because it has mesh support and longer range. However, it is still not enough distance, if we imagine the mine area and any explosion can disrupt communication if a link is destroyed. Long-range communication link will be feasible for this application like narrow band communication. The required data rate is not high so Lo-Ra, SigFox, or sub 1GHz long range RF can be preferred. Hence, the mine are under the ground and there may be lots of distractions during the path, this is the hardest part of the project. I will implement the project by Wi-Fi but it should be changed considering the outline of the mine. Implementation will be similar only the RF part and protocol is changing.

 

4 - Another problem is after an explosion it takes long times to reach the miners sometimes it takes months. If we can build a tracking system it will help us to reach them swiftly. Actually, the previous task also cover this topic. If we implement a reliable mesh network, we can use both time of flight (ToF) and received signal strength indicator(RSSI) to track the miners. However, inside the mine, both of these may not give the accurate results. This should be supported by the dead-reckoning. Dead-reckoning can be implemented by using inertia measurement unit (IMU) which includes accelerometer and gyroscope. BOOSTXL-SENSORS  booster pack also includes IMU sensor. Dead-reckoning can be synchronised at the mesh points so accuracy can be increased.

 

5 - Hence, we have IMU sensor for tracking, we can add additional functionality. We can detect the falling of the workers and help them immediately. This looks unnecessary because of the emergency message but if the miner loses the conscious, the automated fall detection can help to find worker immediately.

 

6 - Some people are ignorant and unless you do not push them to wear safety uniform, they don't wear it. In order to be sure helmet is worn, workers should be controlled at the mine access area and helmetless entry shouldn't be allowed. To achieve this RFID-enabled ticket can be placed inside the helmet and gates are opened by the helmet. Bluetooth can also be preferred if the power consumption problem is solved for wearable. With the implementation of the Bluetooth, the helmet can act as a Bluetooth smart key fob and access is denied without the helmet.

 

Challenges and Threats

 

The hardest part of the project is designing a reliable communication network. It is one of the key parts of the project. If a reliable network connection is provided, it will be so easy to implement emergency messaging and make the tracking easier. There are lots of computationally intensive task for the processor to do, I am not sure one processor can handle all of these so multiple processors may be required but this will increase price and size. It is also possible to send the data to the centre and make calculation there and the send back to the result like the idea in the IoT systems. Dead-reckoning can be also challenging if the proper synchronisation and filtering are not done. Processing data (correlation between different variables) will require a comprehensive research for implementing this system into real mine. I may implement an estimated or dummy correlation hence the real data correlation includes different disciplines and measurements inside the real mine.

 

Summary

 

The idea of designing Trackable Safety Helmet for Miners is simple but it requires many challenging tasks. The tasks focused on the safety but additional functionality can be added at a time. If you have any suggestion, I look forward to hearing from you.

 

The key benefits of the project can be summarised as

- Foreseen the possible explosion and warn the workers

- Provide personal safety while not allowing access to work area without helmet

- Detecting fall and warning the others to help

- Tracking worker and in case of the explosion reach them faster

 

Edit: Other blog posts

 

Safe & Sound Wearables - Trackable Safety Helmet for Miners #2: Intrinsic Safety

Safe & Sound Wearables - Trackable Safety Helmet for Miners #3: Communication and Tracking

Safe & Sound Wearables - Trackable Safety Helmet for Miners #4: Unboxing After Canada Trip

Safe & Sound Wearables - Trackable Safety Helmet for Miners #5: Socket Programming and WiFi Boosterpack

Safe & Sound Wearables - Trackable Safety Helmet for Miners #6: Sensor Board

Safe & Sound Wearables - Trackable Safety Helmet for Miners #7: Data from Sensor to PC

Safe & Sound Wearables - Trackable Safety Helmet for Miners #8: ADXL345 Driver for MSP432

Safe & Sound Wearables - Trackable Safety Helmet for Miners #9: Access Control with NFC

Safe & Sound Wearables - Trackable Safety Helmet for Miners #10: Access Control Showcase

Safe & Sound Wearables - Trackable Safety Helmet for Miners #11: Smart Helmet V0.1

Safe & Sound Wearables - Trackable Safety Helmet for Miners #12: Smart Helmet Video Demonstration

Safe & Sound Wearables - Trackable Safety Helmet for Miners #13: Summary