RTC on Arduino Nano 33 BLE?

Hello everybody.

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 ?

Any pointers would be appreciated,

Thanks

Hi @furnost. The library reference page is wrong.

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.

Hopefully that bug will be fixed soon.

Hi @pert
Thanks for clarifying things !

Is there another library that I can use or is there no RTC on the Nano 33 BLE ? If so, do you know about a model that supports RTC and BLE ?

Thanks

Welcome to the forum.

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.

Hi @Klaus_K
I am interested multiple things:

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.

Would this be possible using mbedOS functions ?

Thanks!

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( &currentTime );

  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
1 Like

Thanks @Klaus_K for this complete example. I will look into it in more details.

I'm also thinking of using this "NRF52_MBED_TimerInterrupt Library". Maybe the combination of the two will be the best way of achieving what I want.

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.

1 Like

Awesome thanks. I created a new thread here: RTC on Arduino Nano RP2040 Connect?