ECG data acquisition with Analog device frontend and Redbear nano BLE

Dependencies:   BLE_API mbed nRF51822

Fork of BLENano_SimpleControls by RedBearLab

Reference Design

2 channel EKG with Redbear BLE reference and Analog Device amplifier to generate RAW EKG data fed into Medtrics MaaS service . Medtrics API can consumer raw input with given parameters of ADC sample frequency and scaling factor

Specification

  • Application Processor: nRF51822/BLE , Analog frontend: AD8232 /
  • Input Analog Voltage = 3.3V
  • 10 bit ADC input range = (0-1023) or scaling factor= 3.22mV/unit (this is ADC resolution)
  • ADC sample frequency (BLE pull rate) = 250Hz (4ms per sample)

/media/uploads/pkweitai/ble_-3-.jpg Reference IOS and Android app will be online soon!

main.cpp

Committer:
RedBearLab
Date:
2014-10-31
Revision:
0:be2e4095513a
Child:
1:81a97eb70d3d

File content as of revision 0:be2e4095513a:


#include "mbed.h"
#include "BLEDevice.h"
#include "Servo.h"


#define BLE_UUID_TXRX_SERVICE            0x0000 /**< The UUID of the Nordic UART Service. */
#define BLE_UUID_TX_CHARACTERISTIC       0x0002 /**< The UUID of the TX Characteristic. */
#define BLE_UUIDS_RX_CHARACTERISTIC      0x0003 /**< The UUID of the RX Characteristic. */

#define TXRX_BUF_LEN                     20

#define DIGITAL_OUT_PIN                  P0_9       //TXD
#define DIGITAL_IN_PIN                   P0_10      //CTS
#define PWM_PIN                          P0_11      //RXD
#define SERVO_PIN                        P0_8       //RTS
#define ANALOG_IN_PIN                    P0_4       //P04

BLEDevice  ble;

DigitalOut      LED_SET(DIGITAL_OUT_PIN);
DigitalIn       BUTTON(DIGITAL_IN_PIN);
PwmOut          PWM(PWM_PIN);
AnalogIn        ANALOG(ANALOG_IN_PIN);
Servo           MYSERVO(SERVO_PIN);

//Serial pc(USBTX, USBRX);

static uint8_t analog_enabled = 0;
static uint8_t old_state = 0;

// The Nordic UART Service
static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_tx_uuid[]   = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_rx_uuid[]   = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};


uint8_t txPayload[TXRX_BUF_LEN] = {0,};
uint8_t rxPayload[TXRX_BUF_LEN] = {0,};

//static uint8_t rx_buf[TXRX_BUF_LEN];
//static uint8_t rx_len=0;


GattCharacteristic  txCharacteristic (uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
                                      
GattCharacteristic  rxCharacteristic (uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
                                      
GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};

GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));



void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    //pc.printf("Disconnected \r\n");
    //pc.printf("Restart advertising \r\n");
    ble.startAdvertising();
}

void WrittenHandler(const GattCharacteristicWriteCBParams *Handler)
{   
    uint8_t buf[TXRX_BUF_LEN];
    uint16_t bytesRead;
    
    if (Handler->charHandle == txCharacteristic.getValueAttribute().getHandle()) 
    {
        ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead);
        memset(txPayload, 0, TXRX_BUF_LEN);
        memcpy(txPayload, buf, TXRX_BUF_LEN);       
        
        //for(index=0; index<bytesRead; index++)
            //pc.putc(buf[index]);
            
        if(buf[0] == 0x01)
        {
            if(buf[1] == 0x01)
                LED_SET = 1;
            else
                LED_SET = 0;    
        }
        else if(buf[0] == 0xA0)
        {
            if(buf[1] == 0x01)
                analog_enabled = 1;
            else
                analog_enabled = 0;
        }
        else if(buf[0] == 0x02)
        {
            float value = (float)buf[1]/255;
            PWM = value;
        }
        else if(buf[0] == 0x03)
        {
            MYSERVO.write(buf[1]);
        }
        else if(buf[0] == 0x04)
        {
            analog_enabled = 0;
            PWM = 0;
            MYSERVO.write(0);
            LED_SET = 0;
            old_state = 0;    
        }

    }
}
/*
void uartCB(void)
{   
    while(pc.readable())    
    {
        rx_buf[rx_len++] = pc.getc();    
        if(rx_len>=20 || rx_buf[rx_len-1]=='\0' || rx_buf[rx_len-1]=='\n')
        {
            ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), rx_buf, rx_len); 
            pc.printf("RecHandler \r\n");
            pc.printf("Length: ");
            pc.putc(rx_len);
            pc.printf("\r\n");
            rx_len = 0;
            break;
        }
    }
}
*/
void m_status_check_handle(void)
{   
    uint8_t buf[3];
    if (analog_enabled)  // if analog reading enabled
    {
        // Read and send out
        float s = ANALOG;
        uint16_t value = s*1024; 
        buf[0] = (0x0B);
        buf[1] = (value >> 8);
        buf[2] = (value);
        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); 
    }
    
    // If digital in changes, report the state
    if (BUTTON != old_state)
    {
        old_state = BUTTON;
        
        if (BUTTON == 1)
        {
            buf[0] = (0x0A);
            buf[1] = (0x01);
            buf[2] = (0x00);    
            ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); 
        }
        else
        {
            buf[0] = (0x0A);
            buf[1] = (0x00);
            buf[2] = (0x00);
           ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); 
        }
    }
}


int main(void)
{   
    Ticker ticker;
    ticker.attach_us(m_status_check_handle, 200000);
    
    ble.init();
    ble.onDisconnection(disconnectionCallback);
    ble.onDataWritten(WrittenHandler);  
    
    //pc.baud(9600);
    //pc.printf("SimpleChat Init \r\n");

    //pc.attach( uartCB , pc.RxIrq);
    
    // setup advertising 
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                    (const uint8_t *)"Biscuit", sizeof("Biscuit") - 1);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                    (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
    // 100ms; in multiples of 0.625ms. 
    ble.setAdvertisingInterval(160);

    ble.addService(uartService);
    
    ble.startAdvertising(); 
    
    //pc.printf("Advertising Start \r\n");
    
    while(1)
    {
        ble.waitForEvent(); 
    }
}