RTC on Arduino Nano RP2040 Connect?

Hey there, I'm using an Arduino Nano 2040 Connect and was checking out @Klaus_K code in this thread: RTC on Arduino Nano 33 BLE?. 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.

If you need help for the Arduino Nano 33 BLE please check out his answer in this thread: RTC on Arduino Nano 33 BLE?

@Klaus_K code example

/*
  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 ) );
}

Some mbed OS documentation mentioned one could use mktime, time and localtime to set date and time. This works fine with the Arduino Nano 33 BLE.

I tested this on the Arduino RP2040 Connect and the Raspberry Pi Pico (using Arduino mbed OS). The functions can be called but do not seem to set the time and the time also does not increment.

There is a file mbed_rtc_time.h that contains the prototype for the set_time function. The file can be found:

C:\Users\UserName\AppData\Local\Arduino15\packages\arduino\hardware\mbed_nano\2.1.0\cores\arduino\mbed\platform\include\platform

I could not locate the mbed_rtc_time.cpp which should contain the actual implementation. However the object of that file seems to be in the libmbed.a file which can be found here:

C:\Users\UserName\AppData\Local\Arduino15\packages\arduino\hardware\mbed_nano\2.1.0\variants\NANO_RP2040_CONNECT\libs

I could not find the sources for this file. Can anyone points us to the sources of this file? This seems to be the place where all the mbed OS functions are implemented with the device specific functions.

In theory, there would be a file rtc_api.c in This directory of the modifed MBed source
However, there is no such file, and there is a comment on the MBed Pull request that explicitly says that the RTC is not yet supported.

So I think we're left to conclude that although MBed has RTC calls, they are not yet "connected" to the rp2040 hardware.

Okay so could I use a different library or do I have to wait for MBed to connect RTC?

That is up to you. If you want to finish a project you can add an external RTC. If you are just experimenting with the board, try some other stuff for now.

You could use a different library, if you can find one. The rp2040 doesn't have any "resource protection", so at least in theory it doesn't NEED to specifically be an MBed-aware library...

Note that the rp2040 RTC doesn't have a battery back-up like some chips, so I'm not sure how useful it is.

It looks like the Raspberry Pi SDK has some functions for using the RTC:

// Start on Friday 5th of June 2020 15:45:00
datetime_t t = {
  .year = 2020,
  .month = 06,
  .day = 05,
  .dotw = 5, // 0 is Sunday, so 5 is Friday .hour = 15,
  .min   = 45,
  .sec   = 00
};

void setup() {
  :
// Start the RTC
  rtc_init();
  rtc_set_datetime(&t);
}

void loop() {
  :
// Print the time
  while (true) {
    rtc_get_datetime(&t);
    datetime_to_str(datetime_str, sizeof(datetime_buf), &t);
    printf("\r%s", datetime_str);
    sleep_ms(100);
    :
  }
}

(may require digging up how to include the appropriate definitions. Or they might already be included.)

Or, the rp2040 datasheet has some bare-metal examples of how to manipulate the RTC.