Code used for Sensor Expo 2016 - Balloon Game. More details can be found here: https://github.com/ROHMUSDC/ROHM-SensorExpo2016-Pressure-Sensor-Demo/

Dependencies:   BLE_API mbed nRF51822

Fork of Nordic_UART_TEMPLATE_ROHM_SHLD1Update by ROHMUSDC

ROHM Balloon Game Demo Code featured at Sensors Expo 2016

This code was written to be used with the Nordic Semiconductor nRF51-DK.

This Code allows the user to configure two known pressure distances and save pressure readings onto the application. Then it will automatically extrapolate these values and allow the user to see the height of the board. When connected to a balloon, greater heights can be achieved and the board will return the current height of the board.

Additional information about the ROHM MultiSensor Shield Board can be found at the following link: https://github.com/ROHMUSDC/ROHM-SensorExpo2016-Pressure-Sensor-Demo/

For code example for the ROHM SENSORSHLD0-EVK-101, please see the following link: https://developer.mbed.org/teams/ROHMUSDC/code/ROHMSensorShield_BALOONGAME/

Operation

See Github Repositoy for additional information on how to operate this demo application.

Supported ROHM Sensor Devices

  • BM1383GLV Pressure Sensor

Questions/Feedback

Please feel free to let us know any questions/feedback/comments/concerns on the ROHM shield implementation by contacting the following e-mail:

main.cpp

Committer:
kbahar3
Date:
2015-08-13
Revision:
4:eabae2996ecc
Parent:
3:c3ee9d663fb8
Child:
5:d39ffc5638a3

File content as of revision 4:eabae2996ecc:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
 /*
 *  Added Functions for ROHM's Multi-Sensor Shield Board
 *  Supports the following Sensor Devices
 *      > BDE0600G Temperature Sensor
 *      > BM1383GLV Pressure Sensor
 *      > BU52014 Hall Sensor
 *      > ML8511 UV Sensor
 *      > RPR-0521 ALS/PROX Sensor
 *      > BH1745NUC Color Sensor
 *      > KMX62 Accel/Mag Sensor
 *      > KX122 Accel Sensor
 *      > KXG03 Gyro (Currently Unavailable as IC hasn't docked yet)
 *
 *  New Code: 
 *      Added a Section in "Main" to act as initialization
 *      Added to the "Periodic Callback" to read sensor data and return to Phone/Host
 */ 
 

//#define AnalogALS   //BH1620    //Change 0: Remove this completely
#define AnalogTemp  //BDE0600
#define AnalogUV    //ML8511
#define HallSensor  //BU52011    //Change 1: Change to use GPIO for BU52014
#define RPR0521     //RPR0521    //Change 2: Remove This and add in the RPR-0521
#define KMX62                    //Change 3: Add Code For BH1745, KX022, BM1383GLV, KMX62
                                
//Devices To Add
// PRessure Sensor
// Accel Only - KX122
// Check Functions for KMX62
// Color Sensor

// Gyro last...


#include "mbed.h"
#include "BLEDevice.h"
#include "UARTService.h"
#include "nrf_temp.h"
#include "I2C.h"

#define MAX_REPLY_LEN           (UARTService::BLE_UART_SERVICE_MAX_DATA_LEN)    //Actually equal to 20
#define SENSOR_READ_INTERVAL_S  (10.0F) 
#define ADV_INTERVAL_MS         (1000UL)
#define UART_BAUD_RATE          (19200UL)
#define DEVICE_NAME             ("DEMO SENSOR") // This can be read AFTER connecting to the device.
#define SHORT_NAME              ("ROHMKRIS")    // Keep this short: max 8 chars if a 128bit UUID is also advertised.

#define DEBUG(...)              { m_serial_port.printf(__VA_ARGS__); }

// Function Prototypes
void PBTrigger();   //Interrupt function for PB4

// Global Variables
BLEDevice   m_ble;
Serial      m_serial_port(p9, p11);  // TX pin, RX pin
DigitalOut  m_cmd_led(LED1);
DigitalOut  m_error_led(LED2);
UARTService *m_uart_service_ptr;
DigitalIn   testButton(p20);
InterruptIn sw4Press(p20);
I2C         i2c(p30,p7);

//Sensor Variables
/*
AnalogIn    BH1620_ALS(p1);     //No Analog ALS on the shield
uint16_t    BH1620_ALS_value;
float       BH1620_output;
*/

AnalogIn    BDE0600_Temp(p3);   //p2 on the prior evk, p3 on the shield
uint16_t    BDE0600_Temp_value;
float       BDE0600_output;

AnalogIn    ML8511_UV(p5);      //p3 on prior EVK, p5 on the shield
uint16_t    ML8511_UV_value;
float       ML8511_output;

DigitalIn   Hall_GPIO0(p14);    //
DigitalIn   Hall_GPIO1(p15);    //
int         Hall_Return1;
int         Hall_Return0;

bool        RepStart = true;
bool        NoRepStart = false;

#ifdef RPR0521
int         RPR0521_addr_w = 0x70;          //7bit addr = 0x38, with write bit 0
int         RPR0521_addr_r = 0x71;          //7bit addr = 0x38, with read bit 1

char        RPR0521_ModeControl[2] = {0x41, 0xE6};  
char        RPR0521_ALSPSControl[2] = {0x42, 0x03};
char        RPR0521_Persist[2] = {0x43, 0x20};
char        RPR0521_Addr_ReadData = 0x44;
char        RPR0521_Content_ReadData[6];

int         RPR0521_PS_RAWOUT = 0;
float       RPR0521_PS_OUT = 0;
int         RPR0521_ALS_D0_RAWOUT = 0;
int         RPR0521_ALS_D1_RAWOUT = 0;
float       RPR0521_ALS_DataRatio = 0;
float       RPR0521_ALS_OUT = 0;
#endif

#ifdef KMX62
int         KMX62_addr_w = 0x1C;          //7bit addr = 0x38, with write bit 0
int         KMX62_addr_r = 0x1D;          //7bit addr = 0x38, with read bit 1

char        KMX62_CNTL2[2] = {0x3A, 0x5F};
char        KMX62_Addr_Accel_ReadData = 0x0A;
char        KMX62_Content_Accel_ReadData[6];
char        KMX62_Addr_Mag_ReadData = 0x10;
char        KMX62_Content_Mag_ReadData[6];

int         MEMS_Accel_Xout = 0;
int         MEMS_Accel_Yout = 0;
int         MEMS_Accel_Zout = 0;
float       MEMS_Accel_Conv_Xout = 0;
float       MEMS_Accel_Conv_Yout = 0;
float       MEMS_Accel_Conv_Zout = 0;
int         MEMS_Mag_Xout = 0;
int         MEMS_Mag_Yout = 0;
int         MEMS_Mag_Zout = 0;
float       MEMS_Mag_Conv_Xout = 0;
float       MEMS_Mag_Conv_Yout = 0;
float       MEMS_Mag_Conv_Zout = 0;
#endif

/**
 * This callback is used whenever a disconnection occurs.
 */
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    switch (reason) {
    case Gap::REMOTE_USER_TERMINATED_CONNECTION:
        DEBUG("Disconnected (REMOTE_USER_TERMINATED_CONNECTION)\n\r");
        break;
    case Gap::LOCAL_HOST_TERMINATED_CONNECTION:
        DEBUG("Disconnected (LOCAL_HOST_TERMINATED_CONNECTION)\n\r");
        break;
    case Gap::CONN_INTERVAL_UNACCEPTABLE:
        DEBUG("Disconnected (CONN_INTERVAL_UNACCEPTABLE)\n\r");
        break;
    }

    DEBUG("Restarting the advertising process\n\r");
    m_ble.startAdvertising();
}


/**
 * This callback is used whenever the host writes data to one of our GATT characteristics.
 */
void dataWrittenCallback(const GattCharacteristicWriteCBParams *params)
{
    // Ensure that initialization is finished and the host has written to the TX characteristic.
    if ((m_uart_service_ptr != NULL) && (params->charHandle == m_uart_service_ptr->getTXCharacteristicHandle())) {
        uint8_t  buf[MAX_REPLY_LEN];
        uint32_t len = 0;

        if (1 == params->len) {
            switch (params->data[0]) {
            case '0':
                m_cmd_led = m_cmd_led ^ 1;
                len = snprintf((char*) buf, MAX_REPLY_LEN, "OK... LED ON");
                break;
            case '1':
                m_cmd_led = m_cmd_led ^ 1;
                len = snprintf((char*) buf, MAX_REPLY_LEN, "OK... LED OFF");
                break;
            case 'a':
                //len = snprintf((char*) buf, MAX_REPLY_LEN, "ALSRaw = %d", BH1620_ALS_value);
                break;
            case 'b':
                //len = snprintf((char*) buf, MAX_REPLY_LEN, "ALS = %.2f lx", BH1620_output);
                break;
            default:
                len = snprintf((char*) buf, MAX_REPLY_LEN, "ERROR");
                break;
            }
        }
        else
        {
            len = snprintf((char*) buf, MAX_REPLY_LEN, "ERROR");
        }

        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);

        DEBUG("%d bytes received from host\n\r", params->len);
    }
}


/**
 * This callback is used whenever a write to a GATT characteristic causes data to be sent to the host.
 */
void dataSentCallback(unsigned count)
{
    // NOTE: The count always seems to be 1 regardless of data.
    DEBUG("%d bytes sent to host\n\r", count);
}


/**
 * This callback is scheduled to be called periodically via a low-priority interrupt.
 */
void periodicCallback(void)
{
    uint8_t  buf[MAX_REPLY_LEN];
    uint32_t len = 0;
    

/*    
#ifdef AnalogALS
    if (m_ble.getGapState().connected) {
        BH1620_ALS_value = BH1620_ALS.read_u16();
        BH1620_output = (float)BH1620_ALS_value * 1.543;
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "ALS = %.2f lx", BH1620_output);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
#endif
*/

#ifdef AnalogTemp
    if (m_ble.getGapState().connected) {
        BDE0600_Temp_value = BDE0600_Temp.read_u16();
        BDE0600_output = (float)BDE0600_Temp_value * 0.00283; //(value * (2.9V/1024))
        BDE0600_output = (BDE0600_output-1.753)/(-0.01068) + 30;
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "Temp = %.2f C", BDE0600_output);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
#endif

#ifdef AnalogUV
    if (m_ble.getGapState().connected) {
        ML8511_UV_value = ML8511_UV.read_u16();
        ML8511_output = (float)ML8511_UV_value * 0.00283; //(value * (2.9V/1024))   //Note to self: when playing with this, a negative value is seen... Honestly, I think this has to do with my ADC converstion...
        ML8511_output = (ML8511_output-2.2)/(0.129) + 15;                           // Added +5 to the offset so when inside (aka, no UV, readings show 0)... this is the wrong approach... and the readings don't make sense... Fix this.
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "UV = %.1f mW/cm2", ML8511_output);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
#endif

#ifdef HallSensor
    if (m_ble.getGapState().connected) {
        Hall_Return0 = Hall_GPIO0;
        Hall_Return1 = Hall_GPIO1;
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "H0 = %d, H1 = %d", Hall_Return0, Hall_Return1);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
#endif

#ifdef DigitalALS
    if (m_ble.getGapState().connected) {
        i2c.read(ALS_addr_r, ALS_ReturnData_raw, 2);
        ALS_Return = (ALS_ReturnData_raw[0]<<8) | ALS_ReturnData_raw[1];
        ALS_Return = ALS_Return/1.2;
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "DALS= %0.2f lx", ALS_Return);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
#endif

#ifdef RPR0521
    if (m_ble.getGapState().connected) {
        
        i2c.write(RPR0521_addr_w, &RPR0521_Addr_ReadData, 1, RepStart);
        i2c.read(RPR0521_addr_r, &RPR0521_Content_ReadData[0], 6, NoRepStart);
        
        RPR0521_PS_RAWOUT = (RPR0521_Content_ReadData[1]<<8) | (RPR0521_Content_ReadData[0]);
        RPR0521_ALS_D0_RAWOUT = (RPR0521_Content_ReadData[3]<<8) | (RPR0521_Content_ReadData[2]);
        RPR0521_ALS_D1_RAWOUT = (RPR0521_Content_ReadData[5]<<8) | (RPR0521_Content_ReadData[4]);
        RPR0521_ALS_DataRatio = (float)RPR0521_ALS_D1_RAWOUT / (float)RPR0521_ALS_D0_RAWOUT;
         
        if(RPR0521_ALS_DataRatio < 0.595){
            RPR0521_ALS_OUT = (1.682*(float)RPR0521_ALS_D0_RAWOUT - 1.877*(float)RPR0521_ALS_D1_RAWOUT);
        }
        else if(RPR0521_ALS_DataRatio < 1.015){
            RPR0521_ALS_OUT = (0.644*(float)RPR0521_ALS_D0_RAWOUT - 0.132*(float)RPR0521_ALS_D1_RAWOUT);
        }
        else if(RPR0521_ALS_DataRatio < 1.352){
            RPR0521_ALS_OUT = (0.756*(float)RPR0521_ALS_D0_RAWOUT - 0.243*(float)RPR0521_ALS_D1_RAWOUT);
        }
        else if(RPR0521_ALS_DataRatio < 3.053){
            RPR0521_ALS_OUT = (0.766*(float)RPR0521_ALS_D0_RAWOUT - 0.25*(float)RPR0521_ALS_D1_RAWOUT);
        }
        else{
            RPR0521_ALS_OUT = 0;
        }
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "DALS= %0.2f lx", RPR0521_ALS_OUT);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
#endif

#ifdef KMX62
    if (m_ble.getGapState().connected) {
        //Read Accel Portion from the IC
        i2c.write(KMX62_addr_w, &KMX62_Addr_Accel_ReadData, 1, RepStart);
        i2c.read(KMX62_addr_r, &KMX62_Content_Accel_ReadData[0], 6, NoRepStart);

        //Note: The highbyte and low byte return a 14bit value, dropping the two LSB in the Low byte.
        //      However, because we need the signed value, we will adjust the value when converting to "g"
        MEMS_Accel_Xout = (KMX62_Content_Accel_ReadData[1]<<8) | (KMX62_Content_Accel_ReadData[0]);
        MEMS_Accel_Yout = (KMX62_Content_Accel_ReadData[3]<<8) | (KMX62_Content_Accel_ReadData[2]);
        MEMS_Accel_Zout = (KMX62_Content_Accel_ReadData[5]<<8) | (KMX62_Content_Accel_ReadData[4]);
          
        //Note: Conversion to G is as follows:
        //      Axis_ValueInG = MEMS_Accel_axis / 1024
        //      However, since we did not remove the LSB previously, we need to divide by 4 again
        //      Thus, we will divide the output by 4095 (1024*4) to convert and cancel out the LSB
        MEMS_Accel_Conv_Xout = (float)MEMS_Accel_Xout/4096/2;
        MEMS_Accel_Conv_Yout = (float)MEMS_Accel_Yout/4096/2;
        MEMS_Accel_Conv_Zout = (float)MEMS_Accel_Zout/4096/2;

        //Read MAg portion from the IC
        i2c.write(KMX62_addr_w, &KMX62_Addr_Mag_ReadData, 1, RepStart);
        i2c.read(KMX62_addr_r, &KMX62_Content_Mag_ReadData[0], 6, NoRepStart);

        //Note: The highbyte and low byte return a 14bit value, dropping the two LSB in the Low byte.
        //      However, because we need the signed value, we will adjust the value when converting to "g"
        MEMS_Mag_Xout = (KMX62_Content_Mag_ReadData[1]<<8) | (KMX62_Content_Mag_ReadData[0]);
        MEMS_Mag_Yout = (KMX62_Content_Mag_ReadData[3]<<8) | (KMX62_Content_Mag_ReadData[2]);
        MEMS_Mag_Zout = (KMX62_Content_Mag_ReadData[5]<<8) | (KMX62_Content_Mag_ReadData[4]);
        
        //Note: Conversion to G is as follows:
        //      Axis_ValueInG = MEMS_Accel_axis / 1024
        //      However, since we did not remove the LSB previously, we need to divide by 4 again
        //      Thus, we will divide the output by 4095 (1024*4) to convert and cancel out the LSB
        MEMS_Mag_Conv_Xout = (float)MEMS_Mag_Xout*0.146;
        MEMS_Mag_Conv_Yout = (float)MEMS_Mag_Yout*0.146;
        MEMS_Mag_Conv_Zout = (float)MEMS_Mag_Zout*0.146;

        len = snprintf((char*) buf, MAX_REPLY_LEN, "KMX61SensorData:");
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);

        len = snprintf((char*) buf, MAX_REPLY_LEN, " AccX= %0.2f g", MEMS_Accel_Conv_Xout);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, " AccY= %0.2f g", MEMS_Accel_Conv_Yout);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, " AccZ= %0.2f g", MEMS_Accel_Conv_Zout);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, " MagX= %0.2f g", MEMS_Mag_Conv_Xout);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, " MagY= %0.2f g", MEMS_Mag_Conv_Yout);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, " MagZ= %0.2f g", MEMS_Mag_Conv_Zout);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        wait_ms(1000);
    }
#endif

    if (m_ble.getGapState().connected) {
        len = snprintf((char*) buf, MAX_REPLY_LEN, "               ");         //Print and Extra Line to show new data
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
    }
}


void error(ble_error_t err, uint32_t line)
{
    m_error_led = 1;
    DEBUG("Error %d on line number %d\n\r", err, line);
}

void PBTrigger()
{
    uint8_t  buf[MAX_REPLY_LEN];
    uint32_t len = 0;
    
    m_cmd_led = !m_cmd_led;
    
    
    if (m_ble.getGapState().connected) {
        /*
        BH1620_ALS_value = BH1620_ALS.read_u16();
        BH1620_output = (float)BH1620_ALS_value * 1.543;
        
        len = snprintf((char*) buf, MAX_REPLY_LEN, "ALS = %.2f lx", BH1620_output);
        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
        */
    }
}

int main(void)
{
    ble_error_t err;
    Ticker      ticker;

    m_serial_port.baud(UART_BAUD_RATE);

    DEBUG("Initialising...\n\r");

    m_cmd_led      = 0;
    m_error_led    = 0;
    //BH1620_ALS_value    = 0;

    ticker.attach(periodicCallback, SENSOR_READ_INTERVAL_S);

    sw4Press.fall(&PBTrigger);

#ifdef RPR0521
  // 1. Mode Control (0x41), write (0xC6): ALS EN, PS EN, 100ms measurement for ALS and PS, PS_PULSE=1
  // 2. ALS_PS_CONTROL (0x42), write (0x03): LED Current = 200mA
  // 3. PERSIST (0x43), write (0x20): PS Gain x4  
    i2c.write(RPR0521_addr_w, &RPR0521_ModeControl[0], 2, false);
    i2c.write(RPR0521_addr_w, &RPR0521_ALSPSControl[0], 2, false);
    i2c.write(RPR0521_addr_w, &RPR0521_Persist[0], 2, false);
#endif

#ifdef KMX62
  // 1. CNTL2 (0x3A), write (0x5F): 4g, Max RES, EN temp mag and accel
    i2c.write(KMX62_addr_w, &KMX62_CNTL2[0], 2, false);
#endif

//Start BTLE Initialization Section
    m_ble.init();
    m_ble.onDisconnection(disconnectionCallback);
    m_ble.onDataWritten(dataWrittenCallback);
    m_ble.onDataSent(dataSentCallback);

    // Set the TX power in dBm units.
    // Possible values (in decreasing order): 4, 0, -4, -8, -12, -16, -20.
    err = m_ble.setTxPower(4);
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    // Setup advertising (GAP stuff).
    err = m_ble.setDeviceName(DEVICE_NAME);
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    err = m_ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    m_ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);

    err = m_ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                                (const uint8_t *)SHORT_NAME,
                                                (sizeof(SHORT_NAME) - 1));
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    err = m_ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                                (const uint8_t *)UARTServiceUUID_reversed,
                                                sizeof(UARTServiceUUID_reversed));
    if (BLE_ERROR_NONE != err) {
        error(err, __LINE__);
    }

    m_ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADV_INTERVAL_MS));
    m_ble.startAdvertising();

    // Create a UARTService object (GATT stuff).
    UARTService uartService(m_ble);
    m_uart_service_ptr = &uartService;

    while (true) {
        m_ble.waitForEvent();
    }
}