I have been testing the Seeed Studio XIAO boards and I must say they are very interesting, for this post I will review my experience with the XIAO-nRF52840 Sense which Seeed Studio sent two for free but I burned one on the first week of testing, I have some experience with the XIAO-RP240 which also like but haven't used that one as much as this new one.
I decided to open the XIAO that was already burned to see if I could fix it by changing the voltage regulator or replacing any other component if necessary but the components in there are very tiny and for my particular case the MCU also gets damaged so there was no point on trying to fix that board as it would be much cheaper to buy a new one, and also this board it's not quite serviceable as the components are very tiny and the information is as easy to obtain.
The bluetooth examples for the XIAO are the ones created by Adafruit and for the Arduino NANO33 BLE as their board uses the same nRF MCU chip, there are many examples provided by Adafruit and there is also the quick start page by Seeed Studio to get on speed very easily.
I have a couple of Dynamixel motors that are very small which makes them the perfect match with these tiny XIAO boards, the Dynamixel motors are smart servomotors that are digitally controlled by the Dynamixel Protocol that let you know the exact shaft position and the working temperature inside the motor, the voltage supplied to the motor and so much more that results on a lot of data which can be sent out via Bluetooth or as simple to just control the motor wirelessly with a phone app.
To interface the motor with any microcontroller is necessary to add a communication buffer like my Dynamixel Interface that allows you to control the data flow from the microcontroller to the motor and vice-versa.
For me to ensure that the data was correctly being sent from the XIAO to my phone I decided to add an ST7735 80x160 px TFT Display, I used the bb_spi_lcd library as is the one that I used with older projects because is simple and easy to use. In this display I am printing all the data gathered from my Dynamixel library which also works fine with the XIAO-nRF52840 Sense.
I have used the Bluetooth UART Adafruit example to send commands from the phone to the XIAO board using the LightBlue app for iPhone, the commands are in HEX so be sure to properly describe in your Arduino code what command are you expecting to receive. I have used 0x41 for the letter 'A' and so on, but you can also specify the command as a HEX value by using the prefix 0x.
Arduino example code:
/*********************************************************************
This is an example for our nRF52 based Bluefruit LE modules
Pick one up today in the adafruit shop!
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
#include <bluefruit.h>
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
#include <bb_spi_lcd.h>
#include "Dynamixel.h"
#define SPISPEEDHZ 4000000
#define DISPLAY_HEIGHT 80
#define DISPLAY_WIDTH 160
#define BACKGROUND 0xFFFF
#define FONTCOLOR 0xF800
#define MOSI_PIN 10
#define DC_PIN 9
#define SCK_PIN 8
#define RESET_PIN 3
SPILCD lcd;
// BLE Service
BLEDfu bledfu; // OTA DFU service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
int voltage, temperature, position;
char voltageArray[20], temperatureArray[20], positionArray[20];
bool ledIndicator = OFF;
int goalPosition = 1846;
void setup()
{
Serial.begin(115200);
Dynamixel.begin(&Serial1,57600,D5,2);
Dynamixel.profileVelocity(1,1000);
Dynamixel.torqueStatus(1,ON);
Dynamixel.move(1,goalPosition);
spilcdInit(&lcd, LCD_ST7735S_B, FLAGS_INVERT | FLAGS_SWAP_RB, SPISPEEDHZ,-1, DC_PIN, RESET_PIN, -1, -1, MOSI_PIN, SCK_PIN);
spilcdSetOrientation(&lcd, LCD_ORIENTATION_90);
spilcdFill(&lcd, BACKGROUND, DRAW_TO_LCD);
spilcdFill(&lcd, BACKGROUND, DRAW_TO_LCD);
spilcdFill(&lcd, BACKGROUND, DRAW_TO_LCD);
#if CFG_DEBUG
// Blocking wait for connection when debug mode is enabled via IDE
while ( !Serial ) yield();
#endif
Serial.println("Seeed XIAO-nRF52840 BLEUART Example");
Serial.println("---------------------------\n");
// Setup the BLE LED to be enabled on CONNECT
// Note: This is actually the default behavior, but provided
// here in case you want to control this LED manually via PIN 19
Bluefruit.autoConnLed(true);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
Bluefruit.setTxPower(4); // Check bluefruit.h for supported values
//Bluefruit.setName(getMcuUniqueID()); // useful testing with multiple central connections
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// Configure and Start Device Information Service
bledis.setManufacturer("Seeed Studio");
bledis.setModel("XIAO nRF52840");
bledis.begin();
// Configure and Start BLE Uart Service
bleuart.begin();
// Start BLE Battery Service
blebas.begin();
blebas.write(100);
// Set up and start advertising
startAdv();
Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode");
Serial.println("Once connected, enter character(s) that you wish to send");
}
void startAdv(void)
{
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 128-bit uuid
Bluefruit.Advertising.addService(bleuart);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* For recommended advertising interval
* https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void loop()
{
// Forward data from HW Serial to BLEUART
while (Serial.available())
{
// Delay to wait for enough input, since we have a limited transmission buffer
delay(2);
uint8_t buf[64];
int count = Serial.readBytes(buf, sizeof(buf));
bleuart.write( buf, count );
}
// Forward from BLEUART to HW Serial
while ( bleuart.available() )
{
uint8_t ch;
ch = (uint8_t) bleuart.read();
if (ch == 'A'){
goalPosition += 50;
if( goalPosition >= 3800) goalPosition = 3800;
Dynamixel.move(1,goalPosition);
} else if (ch == 'B'){
goalPosition -= 50;
if( goalPosition <= 60) goalPosition = 60;
Dynamixel.move(1,goalPosition);
} else if (ch == 'C'){
goalPosition = 1846;
Dynamixel.move(1,goalPosition);
} else if (ch == 'D'){
if( ledIndicator == ON) ledIndicator = OFF; else ledIndicator = ON;
Dynamixel.ledStatus(1,ledIndicator);
}
Serial.write(ch);
}
voltage = Dynamixel.readVoltage(1);
temperature = Dynamixel.readTemperature(1);
position = Dynamixel.readPosition(1);
sprintf(voltageArray,"%.1fV %dC ", (float(voltage)/10),temperature);
sprintf(positionArray,"%d ",position);
spilcdWriteString(&lcd, 2, 4, (char *)"Dynamixel XIAO", FONTCOLOR, BACKGROUND, FONT_8x8, DRAW_TO_LCD);
spilcdWriteString(&lcd, 2, 16, (char *)"Voltage Temperature", FONTCOLOR, BACKGROUND, FONT_8x8, DRAW_TO_LCD);
spilcdWriteString(&lcd, 2, 28, (char *)voltageArray, FONTCOLOR, BACKGROUND, FONT_16x16, DRAW_TO_LCD);
spilcdWriteString(&lcd, 2, 48, (char *)"Position RAW", FONTCOLOR, BACKGROUND, FONT_8x8, DRAW_TO_LCD);
spilcdWriteString(&lcd, 2, 60, (char *)positionArray, FONTCOLOR, BACKGROUND, FONT_16x16, DRAW_TO_LCD);
}
// callback invoked when central connects
void connect_callback(uint16_t conn_handle)
{
// Get the reference to current connection
BLEConnection* connection = Bluefruit.Connection(conn_handle);
char central_name[32] = { 0 };
connection->getPeerName(central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* Callback invoked when a connection is dropped
* @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.println();
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
Please don't forget to leave your comment below, let me know if you want me to do a different test with this microcontroller or if you wish me to expand more on this code.
Comments