Hi everyone,
Looking for some guidance on the following please. I’m 95% there but just can’t tie the pieces together.
I have a XIOA BLE and I’m using arduino ide. I’m looking to build something that works like this.
- Acts as an I2C slave, accepting 11 Bytes packets from another device
- Advertises this data by BLE with an interval of ~10 seconds
- Uses the lowest possible power
All the individual bits are working.
- I can read/write the I2C buffer from external devices on the bus
- BLE advertising is working, reading data from the buffer when updateAdvertisingData() is called
- Low power is working, average of 40uA
The problem is that I can’t tie them together.
When I call updateAdvertisingData() from inside the I2C event handler, the device crashes.
If I try to use a global flag dataUpdated = true; and conditionally check that in a loop, it works however I then lose low power operation, presumably because the cpu stays on, running at 7mA
void loop() {
// Check if data has been updated via I2C
if (dataUpdated) {
updateAdvertisingData();
dataUpdated = false;
}
}
I’m not sure how or where I should call updateAdvertisingData() so that I can keep the device in low power.
Any pointers would be appreciated.
Thanks
#include <bluefruit.h>
#include <Wire.h>
#include "nrf_nvic.h"
#include "nrf_soc.h"
#define I2C_ADDRESS 0x10
volatile bool dataUpdated = false;
volatile uint8_t i2cBuffer[22]; // 22 bytes for 11 integers
void receiveEvent(int howMany) {
if (howMany > sizeof(i2cBuffer)) {
while (Wire.available()) {
Wire.read();
}
return;
}
for (int i = 0; i < howMany && i < sizeof(i2cBuffer); i++) {
i2cBuffer[i] = Wire.read();
}
// Debug print to show received data
Serial.print("Data received: ");
for (int i = 0; i < howMany; i++) {
Serial.print(i2cBuffer[i], HEX);
Serial.print(" ");
}
Serial.println();
// Flag that data has been updated
dataUpdated = true;
}
void requestEvent() {
const uint8_t* bufferPtr = (const uint8_t*)i2cBuffer;
Wire.write(bufferPtr, sizeof(i2cBuffer));
// Debug print to show sent data
Serial.print("Data sent: ");
for (int i = 0; i < sizeof(i2cBuffer); i++) {
Serial.print(bufferPtr[i], HEX);
Serial.print(" ");
}
Serial.println();
}
void updateAdvertisingData() {
Serial.println("Updating advertising data...");
uint8_t msd[25];
msd[0] = 0xFF; // Manufacturer specific data type
msd[1] = 0x00; // Manufacturer ID (low byte)
msd[2] = 0x00; // Manufacturer ID (high byte)
memcpy(&msd[3], (const void*)i2cBuffer, sizeof(i2cBuffer));
// Debug print to show the data to be advertised
Serial.print("Data to be advertised: ");
for (int i = 0; i < sizeof(msd); i++) {
Serial.print(msd[i], HEX);
Serial.print(" ");
}
Serial.println();
Bluefruit.Advertising.clearData();
Bluefruit.Advertising.addData(BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, msd, sizeof(msd));
Bluefruit.ScanResponse.addName();
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(16000, 16000); // Advertising every 10 seconds
Bluefruit.Advertising.setFastTimeout(30); // Fast advertising for 30 seconds
Bluefruit.Advertising.start(0);
// Debug print to show updated advertising data
Serial.print("Advertising data updated: ");
for (int i = 0; i < sizeof(msd); i++) {
Serial.print(msd[i], HEX);
Serial.print(" ");
}
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.println("I2C and BLE Example");
Wire.begin(I2C_ADDRESS);
Wire.setPins(4, 5); // SDA on P0.04, SCL on P0.05
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Serial.println("I2C Slave Initialized");
// Initialize BLE
Bluefruit.begin();
Bluefruit.setName("MY12345");
Bluefruit.autoConnLed(false);
Bluefruit.setTxPower(-4); // Reduce TX power to save energy
// Start advertising with initial data
updateAdvertisingData();
Serial.println("Broadcasting, open your beacon app to test");
// Suspend the loop to save power
suspendLoop();
}
void loop() {
}