Second part of the series Writing Bluetooth LE firmware the easy way blog. This second part shows how to read and advertise the environment sensor data (BME280 using Motsai Neblina module and BME680 using breakout board). Still with only a few lines of code. See blog page here.
Complete code bellow advertise Temperature, Pressure, Humidity data from #BME680 & #BME280.
#define DEVICE_NAME "EnvSensorTag" /**< Name of device. Will be included in the advertising data. */ #ifdef NEBLINA_MODULE #define TPH_BME280 #else #define TPH_BME680 #endif #ifdef NRF52 // Use timer to update data // NOTE : RTC timer 0 used by radio, RTC Timer 1 used by SDK // Only RTC timer 2 is usable with Softdevice for nRF52, not avail on nRF51 // //#define USE_TIMER_UPDATE #endif #define APP_ADV_INTERVAL MSEC_TO_UNITS(200, UNIT_0_625_MS) /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */ #ifdef USE_TIMER_UPDATE // Use timer to update date #define APP_ADV_TIMEOUT_IN_SECONDS 0 /**< The advertising timeout (in units of seconds). */ #else // Use advertisement timeout to update data #define APP_ADV_TIMEOUT_IN_SECONDS 1 /**< The advertising timeout (in units of seconds). */ #endif void TimerHandler(Timer *pTimer, uint32_t Evt); uint8_t g_AdvDataBuff[9] = { BLEADV_MANDATA_TYPE_TPH, }; BLEADV_MANDATA &g_AdvData = *(BLEADV_MANDATA*)g_AdvDataBuff; // Evironmental Sensor Data to advertise BLEADV_MANDATA_TPHSENSOR &g_TPHData = *(BLEADV_MANDATA_TPHSENSOR *)g_AdvData.Data; BLEADV_MANDATA_GASSENSOR &g_GasData = *(BLEADV_MANDATA_GASSENSOR *)g_AdvData.Data; const static TIMER_CFG s_TimerCfg = { .DevNo = 1, .ClkSrc = TIMER_CLKSRC_DEFAULT, .Freq = 0, // 0 => Default highest frequency .IntPrio = APP_IRQ_PRIORITY_LOW, .EvtHandler = TimerHandler }; TimerLFnRF5x g_Timer; const BLEAPP_CFG s_BleAppCfg = { { // Clock config nrf_clock_lf_cfg_t #ifdef IMM_NRF51822 NRF_CLOCK_LF_SRC_RC, // Source RC 1, 1, 0 #else NRF_CLOCK_LF_SRC_XTAL, // Source 32KHz XTAL 0, 0, NRF_CLOCK_LF_ACCURACY_20_PPM #endif }, 0, // Number of central link 0, // Number of peripheral link BLEAPP_MODE_NOCONNECT, // Connectionless beacon type DEVICE_NAME, // Device name ISYST_BLUETOOTH_ID, // PnP Bluetooth/USB vendor id 1, // PnP Product ID 0, // Pnp prod version false, // Enable device information service (DIS) NULL, (uint8_t*)&g_AdvDataBuff, // Manufacture specific data to advertise sizeof(g_AdvDataBuff), // Length of manufacture specific data BLEAPP_SECTYPE_NONE, // Secure connection type BLEAPP_SECEXCHG_NONE, // Security key exchange NULL, // Service uuids to advertise 0, // Total number of uuids APP_ADV_INTERVAL, // Advertising interval in msec APP_ADV_TIMEOUT_IN_SECONDS, // Advertising timeout in sec 100, // Slow advertising interval, if > 0, fallback to // slow interval on adv timeout and advertise until connected 0, 0, -1, // Led port nuber -1, // Led pin number 0, // Tx power NULL // RTOS Softdevice handler }; // Motsai Neblina V2 module uses SPI interface #ifdef NEBLINA_MODULE static const IOPINCFG gsSpiBoschPin[] = { {SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_PINOP, IOPINDIR_OUTPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, {SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_PINOP, IOPINDIR_INPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, {SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_PINOP, IOPINDIR_OUTPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, {BME280_CS_PORT, BME280_CS_PIN, BME280_CS_PINOP, IOPINDIR_OUTPUT, IOPINRES_PULLUP, IOPINTYPE_NORMAL}, }; static const SPICFG s_SpiCfg = { SPI_DEVNO, SPIMODE_MASTER, gsSpiBoschPin, sizeof( gsSpiBoschPin ) / sizeof( IOPINCFG ), 8000000, // Speed in Hz 8, // Data Size 5, // Max retries SPIDATABIT_MSB, SPIDATAPHASE_SECOND_CLK, // Data phase SPICLKPOL_LOW, // clock polarity SPICSEL_AUTO, 6, //APP_IRQ_PRIORITY_LOW, // Interrupt priority nullptr }; SPI g_Spi; DeviceIntrf *g_pIntrf = &g_Spi; #else // Configure I2C interface static const I2CCFG s_I2cCfg = { 0, // I2C device number { #if defined(TPH_BME280) || defined(TPH_BME680) {I2C0_SDA_PORT, I2C0_SDA_PIN, I2C0_SDA_PINOP, IOPINDIR_BI, IOPINRES_NONE, IOPINTYPE_NORMAL}, {I2C0_SCL_PORT, I2C0_SCL_PIN, I2C0_SCL_PINOP, IOPINDIR_OUTPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, #else // Custom board with MS8607 {0, 4, 0, IOPINDIR_BI, IOPINRES_NONE, IOPINTYPE_NORMAL}, {0, 3, 0, IOPINDIR_OUTPUT, IOPINRES_NONE, IOPINTYPE_NORMAL}, #endif }, 100000, // Rate I2CMODE_MASTER, 0, // Slave address 5, // Retry 7, // Interrupt prio NULL // Event callback }; // I2C interface instance I2C g_I2c; DeviceIntrf *g_pIntrf = &g_I2c; #endif // Configure environmental sensor static TPHSENSOR_CFG s_TphSensorCfg = { #ifdef NEBLINA_MODULE 0, // SPI CS index 0 connected to BME280 #else BME680_I2C_DEV_ADDR0, // I2C device address #endif SENSOR_OPMODE_SINGLE, 100, // Sampling frequency in Hz 1, 1, 1, 1 }; // Environmental sensor instance TphgBme680 g_Bme680Sensor; TphBme280 g_Bme280Sensor; TphMS8607 g_MS8607Sensor; #ifdef TPH_BME280 TphSensor &g_TphSensor = g_Bme280Sensor; #elif defined(TPH_BME680) TphSensor &g_TphSensor = g_Bme680Sensor; #else TphSensor &g_TphSensor = g_MS8607Sensor; #endif void ReadPTHData() { TPHSENSOR_DATA data; g_TphSensor.Read(data); g_TphSensor.StartSampling(); g_AdvData.Type = BLEADV_MANDATA_TYPE_TPH; // NOTE : M0 does not access unaligned data // use local 4 bytes align stack variable then mem copy // skip timestamp as advertising pack is limited in size memcpy(&g_TPHData, ((uint8_t*)&data) + 4, sizeof(BLEADV_MANDATA_TPHSENSOR)); // Update advertisement data BleAppAdvManDataSet(g_AdvDataBuff, sizeof(g_AdvDataBuff)); } void TimerHandler(Timer *pTimer, uint32_t Evt) { if (Evt & TIMER_EVT_TRIGGER(0)) { ReadPTHData(); } } void BlePeriphEvtUserHandler(ble_evt_t * p_ble_evt) { #ifndef USE_TIMER_UPDATE if (p_ble_evt->header.evt_id == BLE_GAP_EVT_TIMEOUT) { // Update environmental sensor data every time advertisement timeout // for re-advertisement ReadPTHData(); } #endif } void HardwareInit() { // Set this only if nRF is power at 2V or more nrf_power_dcdcen_set(true); // Initialize I2C #ifdef NEBLINA_MODULE g_Spi.Init(s_SpiCfg); #else g_I2c.Init(s_I2cCfg); #endif // Inititalize sensor g_TphSensor.Init(s_TphSensorCfg, g_pIntrf, NULL); g_TphSensor.StartSampling(); // Update sensor data TPHSENSOR_DATA tphdata; g_TphSensor.Read(tphdata); g_AdvData.Type = BLEADV_MANDATA_TYPE_TPH; // Do memcpy to adv data. Due to byte alignment, cannot read directly into // adv data memcpy(g_AdvData.Data, ((uint8_t*)&tphdata) + 4, sizeof(BLEADV_MANDATA_TPHSENSOR)); #ifdef USE_TIMER_UPDATE // Only with SDK14 g_Timer.Init(s_TimerCfg); uint64_t period = g_Timer.EnableTimerTrigger(0, 500UL, TIMER_TRIG_TYPE_CONTINUOUS); #endif } int main() { HardwareInit(); BleAppInit((const BLEAPP_CFG *)&s_BleAppCfg, true); BleAppRun(); return 0; }
In this advanced and digital age there are many types and formats of CVs submitted to companies but those technical papers will be addressed to well-organized and well-documented companies because without these qualities your text will not be considered by anyone. Hire and find best experts here for CV making. Nobody will not take your CV for granted and will be considered by those companies.