LIS3DH & BLE broadcast example for VTT Node V3 & mbed
Dependencies: BLE_API TMP_nrf51 mbed nRF51822
main.cpp@1:bd7fd35251ab, 2016-01-25 (annotated)
- Committer:
- jejuho
- Date:
- Mon Jan 25 13:27:15 2016 +0000
- Revision:
- 1:bd7fd35251ab
- Parent:
- 0:de3e4a57ebe0
Initial version.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jejuho | 1:bd7fd35251ab | 1 | /** |
jejuho | 1:bd7fd35251ab | 2 | * LIS3DH & BLE broadcast example for VTT Node V3 & mbed |
jejuho | 1:bd7fd35251ab | 3 | * broadcasts accelerometer xyz values. |
jejuho | 1:bd7fd35251ab | 4 | * Also generates LIS3DH interrupt on position change and lights up leds based on that interrupt. |
jejuho | 1:bd7fd35251ab | 5 | * As a bonus, read temperature values from SOC and transmit those as well. |
jejuho | 1:bd7fd35251ab | 6 | * Juho Eskeli, VTT |
jejuho | 1:bd7fd35251ab | 7 | */ |
jejuho | 1:bd7fd35251ab | 8 | |
jejuho | 1:bd7fd35251ab | 9 | |
jejuho | 1:bd7fd35251ab | 10 | #include "NodeV3PinNames.h" //This should come before mbed.h to override pin configuration |
jejuho | 0:de3e4a57ebe0 | 11 | #include "mbed.h" |
jejuho | 0:de3e4a57ebe0 | 12 | #include "ble/BLE.h" |
jejuho | 0:de3e4a57ebe0 | 13 | |
jejuho | 0:de3e4a57ebe0 | 14 | #define USE_DFU |
jejuho | 0:de3e4a57ebe0 | 15 | |
jejuho | 0:de3e4a57ebe0 | 16 | #ifdef USE_DFU |
jejuho | 0:de3e4a57ebe0 | 17 | #include "DFUService.h" |
jejuho | 0:de3e4a57ebe0 | 18 | #endif |
jejuho | 0:de3e4a57ebe0 | 19 | |
jejuho | 0:de3e4a57ebe0 | 20 | #include "AT45.h" |
jejuho | 0:de3e4a57ebe0 | 21 | #include "LIS3DH.h" |
jejuho | 1:bd7fd35251ab | 22 | #include "TMP_nrf51.h" |
jejuho | 0:de3e4a57ebe0 | 23 | |
jejuho | 0:de3e4a57ebe0 | 24 | //interrupt /gpio configuration |
jejuho | 0:de3e4a57ebe0 | 25 | #include "nrf_gpio.h" |
jejuho | 0:de3e4a57ebe0 | 26 | #include "nrf_gpiote.h" |
jejuho | 0:de3e4a57ebe0 | 27 | #include "nrf_soc.h" |
jejuho | 0:de3e4a57ebe0 | 28 | |
jejuho | 0:de3e4a57ebe0 | 29 | //const static char DEVICE_NAME[] = "BAc0N"; |
jejuho | 0:de3e4a57ebe0 | 30 | //static const uint16_t uuid16_list[] = {GattService::UUID_STREAMING_SERVICE}; |
jejuho | 0:de3e4a57ebe0 | 31 | |
jejuho | 0:de3e4a57ebe0 | 32 | BLE ble; |
jejuho | 0:de3e4a57ebe0 | 33 | |
jejuho | 1:bd7fd35251ab | 34 | #define MOSI SPI_PSELMOSI0 |
jejuho | 1:bd7fd35251ab | 35 | #define MISO SPI_PSELMISO0 |
jejuho | 1:bd7fd35251ab | 36 | #define CS SPI_PSELSS0 |
jejuho | 1:bd7fd35251ab | 37 | #define SCLK SPI_PSELSCK0 |
jejuho | 0:de3e4a57ebe0 | 38 | static LIS3DH lis(MOSI, MISO, CS, SCLK); |
jejuho | 1:bd7fd35251ab | 39 | static TMP_nrf51 tempSensor; |
jejuho | 0:de3e4a57ebe0 | 40 | |
jejuho | 1:bd7fd35251ab | 41 | DigitalOut myled1(LED1); |
jejuho | 1:bd7fd35251ab | 42 | DigitalOut myled2(LED2); |
jejuho | 0:de3e4a57ebe0 | 43 | |
jejuho | 1:bd7fd35251ab | 44 | DigitalOut LIS_CS_0(CS); //LIS3DH CS |
jejuho | 1:bd7fd35251ab | 45 | DigitalOut AT_CS(p5); //Dataflash CS |
jejuho | 1:bd7fd35251ab | 46 | DigitalOut AT_RS(p6); //Dataflash reset |
jejuho | 0:de3e4a57ebe0 | 47 | |
jejuho | 0:de3e4a57ebe0 | 48 | /** @brief Function for initializing the GPIO Tasks/Events peripheral. |
jejuho | 0:de3e4a57ebe0 | 49 | */ |
jejuho | 0:de3e4a57ebe0 | 50 | static void gpiote_init(void) |
jejuho | 0:de3e4a57ebe0 | 51 | { |
jejuho | 1:bd7fd35251ab | 52 | // Configure accelerometer interrupt pin |
jejuho | 0:de3e4a57ebe0 | 53 | nrf_gpio_cfg_input(3, NRF_GPIO_PIN_PULLDOWN); |
jejuho | 0:de3e4a57ebe0 | 54 | //nrf_gpio_cfg_input(4, NRF_GPIO_PIN_PULLDOWN); |
jejuho | 0:de3e4a57ebe0 | 55 | |
jejuho | 0:de3e4a57ebe0 | 56 | // Configure GPIOTE channel 0 to generate event when MOTION_INTERRUPT_PIN_NUMBER goes from Low to High |
jejuho | 0:de3e4a57ebe0 | 57 | nrf_gpiote_event_config(0, 3, NRF_GPIOTE_POLARITY_LOTOHI); //accelerometer int1 |
jejuho | 0:de3e4a57ebe0 | 58 | //nrf_gpiote_event_config(1, 4, NRF_GPIOTE_POLARITY_LOTOHI); //accelerometer int2 |
jejuho | 0:de3e4a57ebe0 | 59 | |
jejuho | 0:de3e4a57ebe0 | 60 | // Enable interrupt for NRF_GPIOTE->EVENTS_IN[0] event |
jejuho | 0:de3e4a57ebe0 | 61 | NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Msk; |
jejuho | 1:bd7fd35251ab | 62 | //NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN1_Msk; |
jejuho | 0:de3e4a57ebe0 | 63 | } |
jejuho | 0:de3e4a57ebe0 | 64 | |
jejuho | 0:de3e4a57ebe0 | 65 | extern "C" |
jejuho | 0:de3e4a57ebe0 | 66 | void GPIOTE_IRQHandler(void) |
jejuho | 0:de3e4a57ebe0 | 67 | { |
jejuho | 0:de3e4a57ebe0 | 68 | // Event causing the interrupt must be cleared |
jejuho | 0:de3e4a57ebe0 | 69 | NRF_GPIOTE->EVENTS_IN[0] = 0; |
jejuho | 0:de3e4a57ebe0 | 70 | //NRF_GPIOTE->EVENTS_IN[1] = 0; |
jejuho | 0:de3e4a57ebe0 | 71 | lis.LIS3DH_ResetInt1Latch(); |
jejuho | 0:de3e4a57ebe0 | 72 | |
jejuho | 0:de3e4a57ebe0 | 73 | myled1 = !myled1; |
jejuho | 0:de3e4a57ebe0 | 74 | myled2 = !myled2; |
jejuho | 0:de3e4a57ebe0 | 75 | } |
jejuho | 0:de3e4a57ebe0 | 76 | |
jejuho | 0:de3e4a57ebe0 | 77 | void disconnect_input_buffers() |
jejuho | 0:de3e4a57ebe0 | 78 | { |
jejuho | 0:de3e4a57ebe0 | 79 | for(uint8_t i = 0; i < 3; i++) |
jejuho | 0:de3e4a57ebe0 | 80 | { |
jejuho | 0:de3e4a57ebe0 | 81 | NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) |
jejuho | 0:de3e4a57ebe0 | 82 | | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
jejuho | 0:de3e4a57ebe0 | 83 | | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
jejuho | 0:de3e4a57ebe0 | 84 | | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
jejuho | 0:de3e4a57ebe0 | 85 | | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
jejuho | 0:de3e4a57ebe0 | 86 | } |
jejuho | 0:de3e4a57ebe0 | 87 | //Omit accelerometer interrupt pins (3&4) |
jejuho | 0:de3e4a57ebe0 | 88 | for(uint8_t i = 5; i < 21; i++) |
jejuho | 0:de3e4a57ebe0 | 89 | { |
jejuho | 0:de3e4a57ebe0 | 90 | NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) |
jejuho | 0:de3e4a57ebe0 | 91 | | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
jejuho | 0:de3e4a57ebe0 | 92 | | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
jejuho | 0:de3e4a57ebe0 | 93 | | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
jejuho | 0:de3e4a57ebe0 | 94 | | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
jejuho | 0:de3e4a57ebe0 | 95 | } |
jejuho | 0:de3e4a57ebe0 | 96 | //Omit I2C pins (21 & 22) |
jejuho | 0:de3e4a57ebe0 | 97 | for(uint8_t i = 23; i < 31; i++) |
jejuho | 0:de3e4a57ebe0 | 98 | { |
jejuho | 0:de3e4a57ebe0 | 99 | NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) |
jejuho | 0:de3e4a57ebe0 | 100 | | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
jejuho | 0:de3e4a57ebe0 | 101 | | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
jejuho | 0:de3e4a57ebe0 | 102 | | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
jejuho | 0:de3e4a57ebe0 | 103 | | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); |
jejuho | 0:de3e4a57ebe0 | 104 | } |
jejuho | 0:de3e4a57ebe0 | 105 | } |
jejuho | 0:de3e4a57ebe0 | 106 | |
jejuho | 0:de3e4a57ebe0 | 107 | __packed struct ApplicationData_t { |
jejuho | 0:de3e4a57ebe0 | 108 | uint16_t applicationSpecificId; /* An ID used to identify temperature value in the manufacture specific AD data field */ |
jejuho | 1:bd7fd35251ab | 109 | TMP_nrf51::tmpSensorValue_t tmpSensorValue; /* User defined application data */ |
jejuho | 1:bd7fd35251ab | 110 | int8_t accel_temp; |
jejuho | 0:de3e4a57ebe0 | 111 | AxesRaw_t accel_raw; |
jejuho | 0:de3e4a57ebe0 | 112 | }; |
jejuho | 0:de3e4a57ebe0 | 113 | |
jejuho | 0:de3e4a57ebe0 | 114 | void setupApplicationData(ApplicationData_t &appData) |
jejuho | 0:de3e4a57ebe0 | 115 | { |
jejuho | 0:de3e4a57ebe0 | 116 | static const uint16_t APP_SPECIFIC_ID_TEST = 0xFEFE; |
jejuho | 0:de3e4a57ebe0 | 117 | appData.applicationSpecificId = APP_SPECIFIC_ID_TEST; |
jejuho | 1:bd7fd35251ab | 118 | appData.tmpSensorValue = tempSensor.get(); |
jejuho | 0:de3e4a57ebe0 | 119 | lis.LIS3DH_GetAccAxesRaw(&appData.accel_raw); |
jejuho | 1:bd7fd35251ab | 120 | lis.LIS3DH_GetTempRaw(&appData.accel_temp); |
jejuho | 0:de3e4a57ebe0 | 121 | } |
jejuho | 0:de3e4a57ebe0 | 122 | |
jejuho | 0:de3e4a57ebe0 | 123 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) |
jejuho | 0:de3e4a57ebe0 | 124 | { |
jejuho | 0:de3e4a57ebe0 | 125 | ble.gap().startAdvertising(); |
jejuho | 0:de3e4a57ebe0 | 126 | } |
jejuho | 0:de3e4a57ebe0 | 127 | |
jejuho | 0:de3e4a57ebe0 | 128 | void senseCallback(void) |
jejuho | 0:de3e4a57ebe0 | 129 | { |
jejuho | 0:de3e4a57ebe0 | 130 | ApplicationData_t appData; |
jejuho | 0:de3e4a57ebe0 | 131 | setupApplicationData(appData); |
jejuho | 0:de3e4a57ebe0 | 132 | ble.gap().updateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&appData, sizeof(ApplicationData_t)); |
jejuho | 0:de3e4a57ebe0 | 133 | } |
jejuho | 0:de3e4a57ebe0 | 134 | |
jejuho | 1:bd7fd35251ab | 135 | void setup_CS_LIS3DH() |
jejuho | 0:de3e4a57ebe0 | 136 | { |
jejuho | 1:bd7fd35251ab | 137 | //Without this setup CS lines of AT45 & LIS3DH are in conflict, causing huge current consumption |
jejuho | 0:de3e4a57ebe0 | 138 | LIS_CS_0 = 1; //not selected |
jejuho | 0:de3e4a57ebe0 | 139 | AT_CS = 1; //not selected |
jejuho | 0:de3e4a57ebe0 | 140 | AT_RS = 0; //asserted == reset state |
jejuho | 0:de3e4a57ebe0 | 141 | wait_ms(100); |
jejuho | 0:de3e4a57ebe0 | 142 | AT_RS = 1; |
jejuho | 1:bd7fd35251ab | 143 | } |
jejuho | 1:bd7fd35251ab | 144 | |
jejuho | 1:bd7fd35251ab | 145 | int main() |
jejuho | 1:bd7fd35251ab | 146 | { |
jejuho | 1:bd7fd35251ab | 147 | //LEDS off |
jejuho | 1:bd7fd35251ab | 148 | myled1 = 0; |
jejuho | 1:bd7fd35251ab | 149 | myled2 = 0; |
jejuho | 1:bd7fd35251ab | 150 | |
jejuho | 1:bd7fd35251ab | 151 | setup_CS_LIS3DH(); |
jejuho | 0:de3e4a57ebe0 | 152 | |
jejuho | 0:de3e4a57ebe0 | 153 | //Initialize SPI interface |
jejuho | 0:de3e4a57ebe0 | 154 | SPI spi(MOSI, MISO, SCLK); // mosi, miso, sclk |
jejuho | 0:de3e4a57ebe0 | 155 | spi.format(8,3); |
jejuho | 0:de3e4a57ebe0 | 156 | spi.frequency(8000000); |
jejuho | 0:de3e4a57ebe0 | 157 | //setup AT45 dataflash to powersaving mode |
jejuho | 0:de3e4a57ebe0 | 158 | AT45* flash = new AT45(spi, p5); |
jejuho | 0:de3e4a57ebe0 | 159 | flash->ultra_deep_power_down(true); |
jejuho | 0:de3e4a57ebe0 | 160 | |
jejuho | 0:de3e4a57ebe0 | 161 | //Accelerometer interrupt pin configuration |
jejuho | 0:de3e4a57ebe0 | 162 | gpiote_init(); |
jejuho | 0:de3e4a57ebe0 | 163 | |
jejuho | 0:de3e4a57ebe0 | 164 | //Disconnect input buffers to save power |
jejuho | 1:bd7fd35251ab | 165 | disconnect_input_buffers(); |
jejuho | 0:de3e4a57ebe0 | 166 | |
jejuho | 0:de3e4a57ebe0 | 167 | //Initialize LIS3DH driver |
jejuho | 0:de3e4a57ebe0 | 168 | lis.InitLIS3DH(LIS3DH_NORMAL, LIS3DH_ODR_100Hz, LIS3DH_FULLSCALE_2); //Init Acc-sensor |
jejuho | 0:de3e4a57ebe0 | 169 | //enable threshold to generate interrupt |
jejuho | 1:bd7fd35251ab | 170 | lis.SetLIS3DHActivityDetection(3, LIS3DH_INT_MODE_6D_POSITION, 1); |
jejuho | 0:de3e4a57ebe0 | 171 | |
jejuho | 0:de3e4a57ebe0 | 172 | // Enable GPIOTE interrupt in Nested Vector Interrupt Controller. |
jejuho | 0:de3e4a57ebe0 | 173 | NVIC_ClearPendingIRQ(GPIOTE_IRQn); |
jejuho | 0:de3e4a57ebe0 | 174 | NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Set << GPIOTE_INTENSET_PORT_Pos; |
jejuho | 0:de3e4a57ebe0 | 175 | NVIC_SetPriority(GPIOTE_IRQn, 1); |
jejuho | 0:de3e4a57ebe0 | 176 | NVIC_EnableIRQ(GPIOTE_IRQn); |
jejuho | 1:bd7fd35251ab | 177 | //sd_nvic_EnableIRQ(GPIOTE_IRQn); |
jejuho | 0:de3e4a57ebe0 | 178 | |
jejuho | 0:de3e4a57ebe0 | 179 | //Initialize BLE stuff |
jejuho | 0:de3e4a57ebe0 | 180 | ble.init(); |
jejuho | 0:de3e4a57ebe0 | 181 | ble.gap().onDisconnection(disconnectionCallback); |
jejuho | 0:de3e4a57ebe0 | 182 | |
jejuho | 0:de3e4a57ebe0 | 183 | #ifdef USE_DFU |
jejuho | 0:de3e4a57ebe0 | 184 | DFUService dfu(ble); |
jejuho | 0:de3e4a57ebe0 | 185 | #endif |
jejuho | 0:de3e4a57ebe0 | 186 | |
jejuho | 0:de3e4a57ebe0 | 187 | /* Setup advertising. */ |
jejuho | 0:de3e4a57ebe0 | 188 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
jejuho | 0:de3e4a57ebe0 | 189 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER); |
jejuho | 0:de3e4a57ebe0 | 190 | ApplicationData_t appData; |
jejuho | 0:de3e4a57ebe0 | 191 | setupApplicationData(appData); |
jejuho | 0:de3e4a57ebe0 | 192 | //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
jejuho | 0:de3e4a57ebe0 | 193 | //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
jejuho | 0:de3e4a57ebe0 | 194 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&appData, sizeof(ApplicationData_t)); |
jejuho | 0:de3e4a57ebe0 | 195 | |
jejuho | 0:de3e4a57ebe0 | 196 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
jejuho | 0:de3e4a57ebe0 | 197 | //ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); |
jejuho | 0:de3e4a57ebe0 | 198 | ble.gap().setAdvertisingInterval(100); /* 1000ms. */ |
jejuho | 0:de3e4a57ebe0 | 199 | ble.gap().startAdvertising(); |
jejuho | 0:de3e4a57ebe0 | 200 | |
jejuho | 0:de3e4a57ebe0 | 201 | Ticker ticker; |
jejuho | 0:de3e4a57ebe0 | 202 | ticker.attach(senseCallback, 0.1); |
jejuho | 0:de3e4a57ebe0 | 203 | |
jejuho | 0:de3e4a57ebe0 | 204 | ///Could have main loop here doing something |
jejuho | 0:de3e4a57ebe0 | 205 | while(true) { |
jejuho | 0:de3e4a57ebe0 | 206 | ble.waitForEvent(); |
jejuho | 0:de3e4a57ebe0 | 207 | } |
jejuho | 0:de3e4a57ebe0 | 208 | } |
jejuho | 0:de3e4a57ebe0 | 209 |