Jump to: navigation, search

I2C Bus for MP02

Introduction

Adding an I2C bus capability to the MP2 allows the use of a wide range of hardware modules such as Real Time Clock and various sensor devices including Temperature, Humidity, Voltage and Current.

To provide an I2C bus, two spare GPIO pins are used along with several driver and utility software modules.

The MP02 has a 'Router' connector on the main board which is used to accommodate a range of daughter boards such as the FXS telephony board. The required GPIO lines are available on this connector, along with power lines, making it easy to connect a I2C module.

This article describes describes how to fit a DS3231 I2C module to the MP02 as an example. This module is readily available for under $10 and provides a precision Real Time Clock, a 4kB Flash memory and also measures temperature.

Setting up the I2C Bus

In order to use GPIO lines for the I2C bus, it is necessary to install several additional packages, specifically 'kmod-i2c-core', 'kmod-i2c-gpio-custom' and 'i2c-tools.

If building the firmware, run 'make menuconfig' and select the packages in 'Kernel modules / I2C Support' as follows:

 <*> kmod-i2c-core................................ I2C support
 ---   kmod-i2c-algo-bit........... I2C bit-banging interfaces
 ---   kmod-i2c-gpio................ GPIO-based bitbanging I2C
 <*>   kmod-i2c-gpio-custom...... Custom GPIO-based I2C device

In 'Utilities', select the 'i2c-tools package:

  <*> i2c-tools............................................ I2C tools for Linux


If adding the packages to existing firmware, use opkg as follows:

 > opkg update
 > opkg install i2c-tools
 > opkg install kmod-i2c-core
 > opkg install kmod-i2c-gpio-custom


To create the I2C bus using particular GPIO lines it is necessary to pass the GPIO numbers to the kernel module as follows.

At run time, to create I2C Bus 0 (/dev/i2c-0) using GPIO-19 for SDA and GPIO-21 for SCL, run the command:

 # insmod i2c-gpio-custom bus0=0,  19,  21


To set this up automatically at boot time, edit the file '/etc/modules.d/99-i2c-gpio-custom' to contain the following:

  i2c-gpio-custom bus0=0,  19,  21,  200   rtc-ds3231

When the I2C bus is set up, you should see it appear in '/dev' as 'i2c-0'.

Note that nominated GPIO lines must be available for use or the kernel module will fail to install, with an error message at the command line or in the 'dmesg' output.

On devices other than the MP2, you may have to use different GPIO lines depending on which lines are available.

Connecting to the I2C Bus Lines

The MP2 has a 'Router' connector on the main PCB which is used to plug in various daughter boards such as the FXS telephony board. The power and signal lines required for the I2C bus appear on this connector as follows:

 Gnd             Pin 4
 Vcc  3.3V       Pin 1
 SDA  GPIO-19    Pin 6
 SCL  GPIO-21    Pin 8

The photo below shows a DS3231 RTC modules mounted in the MP2 and wired to the Router connector.

Accessing the I2C Module Data

To check that the DS3231 RTC module has been successfully connected to the I2C Bus 0, you can use the 'i2cdetect' command as follows:

 # i2cdetect   -y   0
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 
 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
 70: -- -- -- -- -- -- -- --                         

This shows that there are two devices connected to the I2C bus, one at address '57' (the memory' and one at '68' (the RTC'

 Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]
      i2cdetect -F I2CBUS
      i2cdetect -l

To list the data from the RTC, use the 'i2cdump' command as follows:

 # i2cdump  -y  0  0x68
 No size specified (using byte-data access)
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
 00: 36 50 16 01 03 04 17 00 00 12 80 05 13 00 00 89    6P?????..????..?
 10: 00 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00    .#..............

To select just the first 15 locations, specify the required range as follows:

   # i2cdump  -y  -r 0-15  0  0x68
 
 Usage: i2cdump [-f] [-y] [-r first-last] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]
   I2CBUS is an integer or an I2C bus name
   ADDRESS is an integer (0x03 - 0x77)
   MODE is one of:
     b (byte, default)
     w (word)
     W (word on even register addresses)
     s (SMBus block)
     i (I2C block)
     c (consecutive byte)
     Append p for SMBus PEC

The data bytes in the first seven locations represent the time as follows:

 ss mm hh dd DD MM YY

So the time and date in the above example output is: 16:50:36 03/04/2017 Note: dd in location '3' is the day of the week.

For full details of all the data, see the DS3231 data sheet below.

To read or write a single location, use the 'i2cget' and 'i2cset' commands as follows:

 # i2cget  -y  0  0x68  1  b
   0x13
 
 # i2cset  -y  0  0x68  1 23 b
 
 Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
 Usage: i2cset [-f] [-y] [-m MASK] [-r] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]


References

https://datasheets.maximintegrated.com/en/ds/DS3231.pdf

http://linux-adm5120.sourceforge.net/openwrt/i2c/

http://www.pragti.ch/kippycam/2012/08/15/Adding-an-I2C-interface-to-the-TL-WR703N/

https://www.cyberciti.biz/faq/linux-unix-formatting-dates-for-display/


Sample Code

Get the temperature from the DS3231 module.

 #! /bin/sh
 # Get temp data from RTC and convert to dec
   T1=$(i2cget -y 0 0x68 0x11)
   t1=$(($T1))
 # Get fractional temp data from RTC and convert
   T2=$(i2cget -y 0 0x68 0x12)
   case $T2 in
     0x00) t2=".0";;
     0x40) t2=".25";;
     0x80) t2=".5";;
     0xc0) t2=".75";;
   esac
   echo "$t1$t2"


Set the RTC from the system time

 #! /bin/sh
 # Get the system date string and format it.
   DATE=$(date +"0x%S 0x%M 0x%H 00 0x%d 0x%m 0x%y")
 # Write to sequential register locations in the RTC
   i2cset -y  0 0x68 0  $DATE i

Set the system time from the RTC

 #! /bin/sh
 # Get the RTC sequential data bytes 0 to 6 
   str=$(i2cdump -y -r 0-6 0 0x68 b | grep "00:" | cut -d : -f2 | cut -c 2-21)
 # Split into fields
   ss=$(echo $str | cut -d " " -f1)
   mm=$(echo $str | cut -d " " -f2)
   hh=$(echo $str | cut -d " " -f3)
   DD=$(echo $str | cut -d " " -f5)
   MM=$(echo $str | cut -d " " -f6)
   YY=$(echo $str | cut -d " " -f7)
 # Set the system date
   date -s "$YY$MM$DD$hh$mm.$ss" > /dev/null


DS3231 RTC Module in MP2