LIS3DH & BLE broadcast example for VTT Node V3 & mbed

Dependencies:   BLE_API TMP_nrf51 mbed nRF51822

main.cpp

Committer:
jejuho
Date:
2015-12-08
Revision:
0:de3e4a57ebe0
Child:
1:bd7fd35251ab

File content as of revision 0:de3e4a57ebe0:

#include "mbed.h"
#include "ble/BLE.h"

#define USE_DFU

#ifdef USE_DFU
#include "DFUService.h"
#endif

#include "AT45.h"
#include "LIS3DH.h"

//interrupt /gpio configuration
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "nrf_soc.h"

//SPI stuff
#define MOSI p8
#define MISO p9
#define SCLK p7
#define CS p2

//#include "app_error.h"
//void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) { }

//const static char     DEVICE_NAME[]        = "BAc0N";
//static const uint16_t uuid16_list[]        = {GattService::UUID_STREAMING_SERVICE};

BLE        ble;

static LIS3DH lis(MOSI, MISO, CS, SCLK);    
                                                                                            
#define LED_0 p20
#define LED_1 p23
//#define LED_2 p24
DigitalOut myled1(LED_0);
DigitalOut myled2(LED_1);
//DigitalOut myled3(LED_2);

//#define UART_TX p17
//#define UART_RX p18
//Serial pc(UART_TX, UART_RX); // tx, rx


/** @brief Function for initializing the GPIO Tasks/Events peripheral.
*/
static void gpiote_init(void)
{
        // Configure accelerometer interrupt pin
    nrf_gpio_cfg_input(3, NRF_GPIO_PIN_PULLDOWN);
        //nrf_gpio_cfg_input(4, NRF_GPIO_PIN_PULLDOWN);
    
    // Configure GPIOTE channel 0 to generate event when MOTION_INTERRUPT_PIN_NUMBER goes from Low to High
    nrf_gpiote_event_config(0, 3, NRF_GPIOTE_POLARITY_LOTOHI);   //accelerometer int1
        //nrf_gpiote_event_config(1, 4, NRF_GPIOTE_POLARITY_LOTOHI);   //accelerometer int2

    // Enable interrupt for NRF_GPIOTE->EVENTS_IN[0] event
    NRF_GPIOTE->INTENSET  = GPIOTE_INTENSET_IN0_Msk;
        //NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN1_Msk;
}

extern "C"
void GPIOTE_IRQHandler(void)
{
    // Event causing the interrupt must be cleared
    NRF_GPIOTE->EVENTS_IN[0]  = 0;
    //NRF_GPIOTE->EVENTS_IN[1]  = 0;
    lis.LIS3DH_ResetInt1Latch();
    
    myled1 = !myled1;
    myled2 = !myled2;
}

void disconnect_input_buffers()
{
    for(uint8_t i = 0; i < 3; i++)
    {
                    NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                        | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
                                        | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                        | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                        | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    }   
    //Omit accelerometer interrupt pins (3&4)
    for(uint8_t i = 5; i < 21; i++)
    {
                    NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                        | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
                                        | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                        | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                        | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    }   
    //Omit I2C pins (21 & 22)
    for(uint8_t i = 23; i < 31; i++)
    {
                    NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                        | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
                                        | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                        | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                        | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    }
}

__packed struct ApplicationData_t {
    uint16_t                    applicationSpecificId; /* An ID used to identify temperature value in the manufacture specific AD data field */
    //TMP_nrf51::tmpSensorValue_t tmpSensorValue;        /* User defined application data */
    int8_t                      accel_temp;
    //uint16_t lis;
    AxesRaw_t                   accel_raw;        
};

void setupApplicationData(ApplicationData_t &appData)
{
    static const uint16_t APP_SPECIFIC_ID_TEST = 0xFEFE;
    appData.applicationSpecificId = APP_SPECIFIC_ID_TEST;
    //appData.tmpSensorValue        = tempSensor.get();
    lis.LIS3DH_GetAccAxesRaw(&appData.accel_raw);
    lis.LIS3DH_GetTempRaw(&appData.accel_temp);
    //uint8_t asdf; 
    //lis.LIS3DH_GetWHO_AM_I(&asdf);
    //uint8_t val = 100;
    //appData.lis = (asdf << 8) | val;
    
    //appData.lis = lis.whoami();
}
 
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    ble.gap().startAdvertising();
}

void senseCallback(void)
{   
    ApplicationData_t appData;  
    setupApplicationData(appData);
    ble.gap().updateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&appData, sizeof(ApplicationData_t));             
}

int main() 
{
    
    //LEDS off
    myled1 = 0;
    myled2 = 0;
    //myled3 = 0;
    
    //Without this setup CS lines of AT45 & LIS3DH are in conflict, causing huge current consumption
    //i.e. both are connected to same SPI interface at the same time
    #if defined(TARGET_NRF51822_NODE_V3_OTA) || defined(TARGET_NRF51822_NODE_V3) || defined(TARGET_NRF51822_NODE_V3_BOOT)   
    DigitalOut LIS_CS_0(CS);
    LIS_CS_0 = 1; //not selected
    
    DigitalOut AT_CS(p5);
    DigitalOut AT_RS(p6);

    AT_CS = 1; //not selected
    AT_RS = 0; //asserted == reset state
    wait_ms(100);
    AT_RS = 1;
    #endif
    
    //Initialize SPI interface
    SPI spi(MOSI, MISO, SCLK); // mosi, miso, sclk
    spi.format(8,3);
    spi.frequency(8000000); 
    //setup AT45 dataflash to powersaving mode
    AT45* flash = new AT45(spi, p5);    
    flash->ultra_deep_power_down(true); 
    
    //Accelerometer interrupt pin configuration
    gpiote_init();  
    
    //Disconnect input buffers to save power
    //disabled for testing
    //disconnect_input_buffers();
    
    //Initialize LIS3DH driver
    lis.InitLIS3DH(LIS3DH_NORMAL, LIS3DH_ODR_100Hz, LIS3DH_FULLSCALE_2);    //Init Acc-sensor
    //lis.LIS3DH_SetTemperature(MEMS_ENABLE);
    //lis.LIS3DH_SetADCAux(MEMS_ENABLE);
    //lis.LIS3DH_SetBDU(MEMS_ENABLE);
    //enable threshold to generate interrupt
    lis.SetLIS3DHActivityDetection(3, LIS3DH_INT_MODE_6D_POSITION, 1);
    //disable...
    //lis.SetLIS3DHActivityDetection(20, LIS3DH_INT_MODE_OR, 0);
    
    // Enable GPIOTE interrupt in Nested Vector Interrupt Controller.
    NVIC_ClearPendingIRQ(GPIOTE_IRQn);
    NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Set << GPIOTE_INTENSET_PORT_Pos;
    NVIC_SetPriority(GPIOTE_IRQn, 1);
    NVIC_EnableIRQ(GPIOTE_IRQn);
    //sd_nvic_EnableIRQ(GPIOTE_IRQn);
    
    //osDelay(osWaitForever); 
    //Was Getting 13.2uA with these settings (flash deep power down).
    //With ultra deep power down 7.8uA... rose back to ~11uA??? Seems to fluctuate. Now getting 9.4... IO issue?
    //Now getting 5.4uA
    
    //device current
    //3.8uA idle (SYSTEM-ON base current with 32 kB RAM enabled.). Executing code from flash memory 4.1uA. From ram 2.4uA
    //32.768 kHz crystal oscillator 0.4uA / 32.768 kHz RC oscillator (32k RCOSC) 1.1uA (kumpi on?)
    //RTC Timer (LFCLK source) 0.1uA
    //==3.8 + (0.4) + 0.1uA + 5*0.1 (digitalout active) = 4.8uA
    
    //(watchdog) 0.1uA
    //GPIO as input = 22uA (Run current with 1 or more GPIOTE active channels in Input mode.)
    //as output 0.1A (Run current with 1 or more GPIOTE active channels in Output mode)
    
    //Peripherals current
    //BMP 180 0.1uA standby, 5uA standard mode, 7uA high resolution mode
    //LIS3DH 0.5uA standby mode, varies a lot in measurement mode
    //Si7021  0.06uA standby mode, 150uA active
    //AT45 Ultra deep power down 0,4uA, deep power down 5uA. Standby 25uA. 11mA active
    //== 0.1uA + 0.5uA + 0.06uA + 0.4uA = 1.06uA
    
    //total should be ~5.86 (or 5.46 depending on whether oscillator is included in system idle current)
    
    //Initialize BLE stuff
    ble.init();
    ble.gap().onDisconnection(disconnectionCallback);
    
    #ifdef USE_DFU
    DFUService dfu(ble);
    #endif
    
    /* Setup advertising. */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER);
    ApplicationData_t appData;
    setupApplicationData(appData);
    //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&appData, sizeof(ApplicationData_t));
    
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    //ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(100); /* 1000ms. */
    ble.gap().startAdvertising();
    
    Ticker ticker;
    ticker.attach(senseCallback, 0.1);
  
    ///Could have main loop here doing something
    while(true) {
        ble.waitForEvent();
   }     
}