Parsa Karami`s Blog

an Enthusiastic Windows Delevoper

Adding RTC module to RPI in Windows10Iot

744 days ago on August 11, 2017   |   Parsa Karami on Universal Windows App   |   1346
     Adding RTC module to RPI in Windows10Iot     

The time and date is the one of important that always must be work properly in order to develope reliable and trustworthy application, in this post i wnat to show you how can add and install missing Real Time Clock (RTC) to Raspberry Pi board with Microsoft Windows 10 Iot Core os.

The time and date is the one of important that always must be work properly in order to develope reliable and trustworthy application, in this post i wnat to show you how can add and install missing Real Time Clock (RTC) to Raspberry Pi board with Microsoft Windows 10 Iot Core os.

If you don`t know how can install windows 10 iot core on raspberry pi and other same mini-computer like qualcomm dragonboard, intel minno board max, intel jule and other same boards, following this Link to find out how can you do it. at this point i assumed you have a raspberry pi with windows 10 iot core os if you have it this is time to get dive into title.

For first step we must buy a RTC module, in this example i choose DS3231 module but you can choose others, you can buy it from online store like amazon with this Link, after buying RTC module you must connect it thorugh the I2C port in order to communicate module with your application. you can see the module and ports below you must connect this post to I2C serial port in RPi.Add-Missing-RTC-in-Windows-Iot-DS3231-RTC-module

There is four pin needed to comuunicate, the first one is GND (call Ground) that represent the ground connection the second one is VCC it prepare required voltage for module working, in this module the required voltage is 3.3V. and the two remaining pin is SDA and SCL and these are used for communicating with application. if you don`t know how I2C work clearly you should read about it for more details in this Link.

Refering to Wikipedia you can see the below description:
The I2C bus was designed by Philips in the early '80s to allow easy communication between components which reside on the same circuit board. Philips Semiconductors migrated to NXP in 2006. The name I2C translates into “Inter IC”. Sometimes the bus is called IIC or I²C bus.

Now see the following Raspberry Pi pin map image for finding what port must be connected to what pin.

Add-Missing-RTC-in-Windows-Iot-Raspberry-Pi-Pinout

Let`s start from VCC, see the first row of raspberry pi pins and connect vcc to first pin that specified with yellow color, then connect the GND or ground port to the 5th pin number from the left in the first row, after do that connect the SDA to second port from left in the first row and connect the SCL to next one. now the module successfuly connected to raspberry pi and it`s ready for use. for using I2C serial port in UWP application that you want run it on windows iot you must add reference to Windows IoT Extensions for UWP to your project, after that add the below namespace in order to use I2cController and I2cConnectionSettings class.

     using Windows.Devices.I2c;

I think there are two little tips that you must know for communicating and getting or setting a true result from RTC module when you try to connect to module and when you try to get or set datetime to module. the first tip is each module that connect throgh the I2c serial port need bus Address for connecting, in this module the bus Address is (0x68) and you must send it as an argument to the constructor of I2cConnectionSettings class. the second tip is in this module the year calculate from 2000 and when you get the date from module, if module return 17 at the last buffer index it means the year is 2017. when you request time from module the return value of module is an array with 8 items. all the items return from module and send to module must in BCD format for using module in simpler way i write two function that convert BcdToDec and DecToBcd you can see it.

     private byte DecToBcd(byte val)
     {
          return Convert.ToByte((val / 10 * 16) + (val % 10));
     }

     private byte BcdToDec(byte val)
     {
          return Convert.ToByte((val / 16 * 10) + (val % 16));
     }

After get the return value from module the first item at zero index represent the Secend in time, the next one represent the Minute in time, the next one represent the Hour in time, the next one represent the Day of the week in date, the next one represent the Day of the month in date, the next one represent the Month in date and the last one represent the Year after 2000 in date. you can see the ReadDateTime() method that request date and time from module.for requesting date and time you must write 0x00 command to module and after that read data from module like below.

      public async Task<DateTime> ReadDateTime()
      {
           I2cController i2c = await I2cController.GetDefaultAsync();
           I2cConnectionSettings setting = new I2cConnectionSettings(0x68);
           setting.BusSpeed = I2cBusSpeed.StandardMode;
           var device = i2c.GetDevice(setting);
           byte[] writeBuf = { 0x00 };
           device.Write(writeBuf);
           byte[] buffer = new byte[7];
           device.Read(buffer);
           byte second = BcdToDec((byte)(buffer[0] & 0x7f));
           byte minute = BcdToDec(buffer[1]);
           byte hour = BcdToDec((byte)(buffer[2] & 0x3f));
           byte dayOfWeek = BcdToDec(buffer[3]);
           byte dayOfMonth = BcdToDec(buffer[4]);
           byte month = BcdToDec(buffer[5]);
           int year = 2000 + BcdToDec(buffer[6]);
           DateTime dt = new DateTime(year, month, dayOfMonth, hour, minute, second);
           device.Dispose();
           return dt;
      }

And also you can your custome date and time to module with WriteDateTime() method.

     public async Task WriteDateTime(DateTime dateTime)
     {
          I2cController i2c = await I2cController.GetDefaultAsync();
          I2cConnectionSettings setting = new I2cConnectionSettings(0x68);
          setting.BusSpeed = I2cBusSpeed.StandardMode;
          int year = int.Parse(dateTime.Year.ToString().Substring(2, 2));
 
          var device = i2c.GetDevice(setting);
          byte[] writeBuffer = new byte[8];
          writeBuffer[0] = 0x00;
          writeBuffer[1] = DecToBcd(Convert.ToByte(0));
          writeBuffer[2] = DecToBcd(Convert.ToByte(dateTime.Minute));
          writeBuffer[3] = DecToBcd(Convert.ToByte(dateTime.Hour));
          writeBuffer[4] = DecToBcd(Convert.ToByte(dateTime.DayOfWeek));
          writeBuffer[5] = DecToBcd(Convert.ToByte(dateTime.Day));
          writeBuffer[6] = DecToBcd(Convert.ToByte(dateTime.Month));
          writeBuffer[7] = DecToBcd(Convert.ToByte(year));
          device.Write(writeBuffer);
          device.Dispose();
     }

I use Singleton Pattern for using RTC module in my app in order to prevent concurrency confilic during reading from module or writing to module. you can use my class and code and get it from Github with this Link