I recently purchased a Nano 33 BLE and I'm trying to use the RTC but I'm having some troubles.
I was thinking of using the RTCZero library, because my board is supposed to be supported:
Compatibility
This library is compatible with the samd architecture so you should be able to use it on the following Arduino boards:
Arduino MKR FOX 1200
Arduino MKR GSM 1400
...
...
Arduino Nano 33 BLE
Arduino Nano 33 IoT
Arduino Zero
Portenta H7
The problem is that when I include the library by using
#include <RTCZero.h>
I have an error message and cannot compile:
WARNING: library RTCZero claims to run on samd architecture(s) and may be incompatible with your current board which runs on mbed architecture(s).
[... excluded for privacy...]/src/RTCZero.h:32:26: error: 'RTC_MODE2_MASK_SEL_OFF_Val' was not declared in this scope
MATCH_OFF = RTC_MODE2_MASK_SEL_OFF_Val, // Never
I have the same error for a lot of other values defined in RTCZero.h.
Am I using the right library ? Am I including the library correctly ?
As the message said, the RTCZero library is only compatible with the boards of the SAMD architecture (e.g., Nano 33 IoT, MKR Boards, Zero). Your Nano 33 BLE board has the "mbed" architecture, and so is not compatible with the RTCZero library.
Unfortunately, there is a bug in the code that automatically generates these reference pages which causes it to think that the Nano 33 BLE has the samd architecture rather than mbed.
The Arduino Nano 33 BLE uses the nRF52840 inside the NINA-B306 module. The nRF52840 has a build in RTC peripheral and the NINA datasheet suggest the module has a separate clock crystal build in.
What do you want to do with the RTC? Do you care about the RTC specifically or do you just want the date and time? The Arduino Nano 33 BLE uses mbedOS which has built in date and time support. Whether this uses the RTC will need some investigation.
I have an example sketch for a BLE current time service which make use of the mbedOS functions. It allows to set the time via BLE and updates the current time service every second. If that is what you are looking for, I am happy to share. Let me know.
If you are looking for something else please provide some more specific information.
The first is simply setting the time of the device, and access it through BLE with a Current Time Service. I will gladly take you up on your sketch, because I have no idea how to use mbedOS functions.
I am also interested in setting up actions to do at a certain date and time, like an alarm. For example: at 06:00 on Mondays, do such and such every minute for 35 minutes. So I don't need "extreme" precision, but if there is already the necessary abstractions to use timers and/or something for the date and time, that would be great.
Here is the example. This shows you how to setup the time in mbedOS and then update the BLE characteristic accordingly. When you use the EFR Connect app you can set the time.
The time characteristic update is simplified. It only checks every second using millis. This could be improved by increasing the interval and then remembering the last second to only update when the second changes.
I run the sketch for about one day now and the time was off by about two seconds.
/*
This example creates a BLE peripheral with a Current Time Service.
The circuit:
- Arduino Nano 33 BLE or BLE Sense
You can use a generic BLE central app, like LightBlue (iOS and Android) or
nRF Connect (Android), to interact with the services and characteristics
created in this sketch.
The EFR Connect App from Silicon Labs (iOS) can decode and write the currentTimeService.
This example code is in the public domain.
*/
#include <ArduinoBLE.h>
#include <mbed.h>
//----------------------------------------------------------------------------------------------------------------------
// BLE UUIDs
//----------------------------------------------------------------------------------------------------------------------
#define BLE_UUID_CURRENT_TIME_SERVICE "1805"
#define BLE_UUID_DATE_TIME "2A08"
//----------------------------------------------------------------------------------------------------------------------
// BLE Date Time
//----------------------------------------------------------------------------------------------------------------------
typedef struct __attribute__( ( packed ) )
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
} date_time_t;
union date_time_data
{
struct __attribute__( ( packed ) )
{
date_time_t dateTime;
};
uint8_t bytes[ sizeof( date_time_t ) ];
};
union date_time_data dateTimeData;
//----------------------------------------------------------------------------------------------------------------------
// BLE
//----------------------------------------------------------------------------------------------------------------------
#define BLE_DEVICE_NAME "Arduino Nano 33 BLE"
#define BLE_LOCAL_NAME "Arduino Nano 33 BLE"
BLEService currentTimeService( BLE_UUID_CURRENT_TIME_SERVICE );
BLECharacteristic dateTimeCharacteristic( BLE_UUID_DATE_TIME, BLERead | BLEWrite | BLENotify, sizeof dateTimeData.bytes );
//----------------------------------------------------------------------------------------------------------------------
// I/O and App
//----------------------------------------------------------------------------------------------------------------------
#define BLE_LED_PIN LED_BUILTIN
bool timeUpdated = false;
void setup()
{
Serial.begin( 9600 );
// while ( !Serial );
pinMode( BLE_LED_PIN, OUTPUT );
setupTime();
if ( !setupBleMode() )
{
Serial.println( F( "Failed to initialize BLE!" ) );
while ( 1 );
}
else
{
Serial.println( F( "BLE initialized. Waiting for clients to connect." ) );
}
}
void loop()
{
timeTask();
bleTask();
}
bool setupBleMode()
{
if ( !BLE.begin() )
{
return false;
}
// set advertised local name and service UUID
BLE.setDeviceName( BLE_DEVICE_NAME );
BLE.setLocalName( BLE_LOCAL_NAME );
BLE.setAdvertisedService( currentTimeService );
// add characteristics
currentTimeService.addCharacteristic( dateTimeCharacteristic );
// add service
BLE.addService( currentTimeService );
// set the initial value for the characeristics
dateTimeCharacteristic.writeValue( dateTimeData.bytes, sizeof dateTimeData.bytes );
// set BLE event handlers
BLE.setEventHandler( BLEConnected, blePeripheralConnectHandler );
BLE.setEventHandler( BLEDisconnected, blePeripheralDisconnectHandler );
// set service and characteristic specific event handlers
dateTimeCharacteristic.setEventHandler( BLEWritten, bleCharacteristicWrittenHandler );
// start advertising
BLE.advertise();
return true;
}
void bleTask()
{
#define BLE_UPDATE_INTERVAL 10
static uint32_t previousMillis = 0;
uint32_t currentMillis = millis();
if ( currentMillis - previousMillis >= BLE_UPDATE_INTERVAL )
{
previousMillis = currentMillis;
BLE.poll();
}
if ( timeUpdated )
{
timeUpdated = false;
dateTimeCharacteristic.writeValue( dateTimeData.bytes, sizeof dateTimeData.bytes );
}
}
void bleCharacteristicWrittenHandler( BLEDevice central, BLECharacteristic bleCharacteristic )
{
if ( bleCharacteristic.uuid() == ( const char* ) BLE_UUID_DATE_TIME )
{
dateTimeCharacteristic.readValue( dateTimeData.bytes, sizeof dateTimeData.bytes );
setTime( dateTimeData.dateTime );
}
}
void blePeripheralConnectHandler( BLEDevice central )
{
digitalWrite( BLE_LED_PIN, HIGH );
Serial.print( F( "Connected to central: " ) );
Serial.println( central.address() );
}
void blePeripheralDisconnectHandler( BLEDevice central )
{
digitalWrite( BLE_LED_PIN, LOW );
Serial.print( F( "Disconnected from central: " ) );
Serial.println( central.address() );
}
void timeTask()
{
#define TIME_UPDATE_INTERVAL 1000
static uint32_t previousMillis = 0;
unsigned long currentMillis = millis();
if ( currentMillis - previousMillis < TIME_UPDATE_INTERVAL )
{
return;
}
previousMillis = currentMillis;
time_t currentTime = time( NULL );
struct tm * now = localtime( ¤tTime );
dateTimeData.dateTime.year = now->tm_year + 1900;
dateTimeData.dateTime.month = now->tm_mon + 1;
dateTimeData.dateTime.day = now->tm_mday;
dateTimeData.dateTime.hours = now->tm_hour;
dateTimeData.dateTime.minutes = now->tm_min;
dateTimeData.dateTime.seconds = now->tm_sec;
timeUpdated = true;
}
void setupTime( void )
{
date_time_t dateTime = { 2021, 5, 27, 0, 0 , 0 };
setTime( dateTime );
}
void setTime( date_time_t time )
{
struct tm setTime;
setTime.tm_mon = time.month - 1; // month are from (0 - 11)
setTime.tm_year = time.year - 1900; // years since 1900
setTime.tm_mday = time.day; // day of month (0 - 31)
setTime.tm_hour = time.hours; // hour (0 - 23)
setTime.tm_min = time.minutes; // minutes (0 - 59)
setTime.tm_sec = time.seconds; // seconds (0 - 59)
set_time( mktime( &setTime ) );
}
Regarding alarms:
the RTC peripheral seems to have some compare register that could be used for creating events
these compare registers may be used by mbedOS already
maybe mbedOS does not use the RTC
I think the most flexible solution would be a software implementation for the alarms e.g.,
array of alarms
alarm would be a struct of day, time and some flags
every minute the sketch would run through the array and compare the current time with each element and create the actions you want
the array can be filled by using a second characteristic of the same type as current time but one additional number characteristic can be used to select which entry gets read/written
Hey there, I'm using an Arduino Nano 2040 Connect and was checking out your code. It does work up to the point where the time should update, i.e. it's always 11:59:59PM. Do you have an idea how to solve this? I also can read and write using EFR Connect but when reading after writing some date, the date will again be 1.1.1970.
The issue seems to come from the time functions in mbedOS. I suspect this has not been integrated yet. The RP2040 has a RTC peripheral so it should be possible to do this.
We should create a new post in the Nano RP2040 Connect sub forum to allow others to help. Could you be so kind and do that? I will look into this a bit further and add the information I can find there.