Wednesday, 12 November 2014

Smartwatch Part-1 (Real Time Clock)

Hi guys, It's been a long time since my last post. Actually I was busy in making my smartwatch project. Guess what I have already interfaced and written the drivers for the RTC, Display, IMU. And I have successfully created a clock displaying date and time on the display. I will guide you on how to build this smartwatch yourself through a series of blog post. So keep watching and happy learning.


The SMART Things

So let's get started. First I will let you know what all things I am using for this smartwatch. Here is a list along with the link where you can get these things cheapest in India. For outsiders I think Sparkfun, Adafruit, eBay, Amazon etc will be good place to search for.
  1. Tiva C Launchpad.
  2. DS1307 Real Time Clock
  3. GY-521 Inertial Measurement Unit (IMU)
  4. Nokia 5110 LCD (The cheapest monochrome display in market).
  5. HMC5883L Triple Axis Magnetometer. (For the digital Compass)
  6. Code Composer Studio (Sorry I am not going to use Energia!! )
For now I have only these few stuffs. I will keep on adding features as I continue building it.

 Getting CCS

  • Getting CCS for your Tiva C Launchpad is simple. 
  • Just click on the link provided above. 
  • Click on "Get Software" button beside SW-EK-TM4C123GXL. This is the entire software package including the drivers required to program your device.
  • Register for a myTI account and fill up the required details.
  • You will get a download link. Download software.
  • Extract the file. From EK-TM4C123GXL-CCS-786\Tools\CCS\CCS5.4.0.00091_win32 run ccs_setup_5.4.0.00091.exe (It will take a while..... around 45 minutes)
  • Install only the components required or the entire thing if you are not worried about the space required.
  • Now from EK-TM4C123GXL-CCS-786\TivaWare install SW-EK-TM4C123GXL-2.1.0.12573.exe
  • A tip: Try to install the software in the default directory coz CCS installations can often be nasty.
  • Check out this pdf if you are facing any problem installing.

The CLOCK is Ticking!!

Lets start with the RTC. DS1307 is a really popular and really efficient Real Time Clock. It can be accessed and controlled by I2C protocol. It is a good practice to study the datasheet first if you are working with a device from scratch. It gives you the freedom to develop your own drivers for the device. You can check out the datasheet here. You can find the register addresses of the device in the datasheet. You only need to concentrate on that portion.

If you are a total noob like me and you are working with I2C for the first time then this is a good place to start. You don't need to know each and every details of I2C, only an overview will be sufficient since we will be using the peripheral drivers provided in the Tivaware software package provided by TI.

The Brain

You may ask "Hey why the hell are you not using Arduino ?". I will answer "Hey why don't you go and play with the kids". Oh come on, the world has seen a lot of arduino. Let's try something different. Let's create a device from scratch. Let's not hide behind the abstractions of arduino, lets dig in and see how things work from inside out. So controversies apart lets talk about the microcontroller that we are going to use. It is an ARM Cortex M4 controller by Texas Instrument and it is named TM4CGH6PM. Based on this controller they built a development board called the Tiva C Launchpad to make our job easier. It has I2C, SSI, UART and a whole lot of processing power that will be more than enough for our smart watch.
 
Tiva C Launchpad Pin Out

Setting up Code Composer Studio (CCS)

This is a very tricky part. Since CCS is based on the Eclipse IDE it is a bit tricky to get things to work the first time. But don't worry because TI has provided some example projects for us to get things started easily.
  • Open CCS and follow the steps in this pdf.
  • If you are not in a mood to read the pdf just go to Project->Import Existing CCS Eclipse Project
  • Click on "Select search-directory" and browse to C:\ti\TivaWare_C_Series-2.1.0.12573\examples\boards\ek-tm4c123gxl or the drive where you have installed.
  • Click "Select all" and then Finish.
Now you will be having all your projects on the Project Explorer panel like this.
Now open the hello project and delete the hello.c file by right clicking and clicking on delete, because we are going to use this project as our base since it is already preconfigured by TI. Now right-click on your project and go to New-> Source file. Then create RTC.c.


Now you are ready to do all the coding stuff.

Wire it UP

Now that you have got your softwares ready let's wire up the circuit. The connections are with respect to the pinout diagram given above. Sorry I didn't get a Fritzing part for this board.

Let's get your hands Dirty

Copy the following code in your blank C file.
//include files  
 #include <stdarg.h>  
 #include <stdbool.h>  
 #include <stdint.h>  
 #include "inc/hw_i2c.h"  
 #include "inc/hw_memmap.h"  
 #include "inc/hw_types.h"  
 #include "inc/hw_gpio.h"  
 #include "driverlib/i2c.h"  
 #include "driverlib/sysctl.h"  
 #include "driverlib/gpio.h"  
 #include "driverlib/pin_map.h"  
 #include "driverlib/uart.h"  
 #include "utils/uartstdio.h"  
 //Defines for DS1307  
 #define SLAVE_ADDRESS 0x68  
 #define SEC 0x00  
 #define MIN 0x01  
 #define HRS 0x02  
 #define DAY 0x03  
 #define DATE 0x04  
 #define MONTH 0x05  
 #define YEAR 0x06  
 #define CNTRL 0x07  
 //initialize I2C module 0  
 //Slightly modified version of TI's example code  
 void InitI2C0(void)  
 {  
   //enable I2C module 0  
   SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);  
   //reset module  
   SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);  
   //enable GPIO peripheral that contains I2C 0  
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);  
   // Configure the pin muxing for I2C0 functions on port B2 and B3.  
   GPIOPinConfigure(GPIO_PB2_I2C0SCL);  
   GPIOPinConfigure(GPIO_PB3_I2C0SDA);  
   //GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);  
   //GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);  
   //GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_DIR_MODE_HW);  
   //GPIODirModeSet(GPIO_PORTB_BASE, GPIO_PIN_3, GPIO_DIR_MODE_HW);  
   // Select the I2C function for these pins.  
   GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);  
   GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);  
   // Enable and initialize the I2C0 master module. Use the system clock for  
   // the I2C0 module. The last parameter sets the I2C data transfer rate.  
   // If false the data rate is set to 100kbps and if true the data rate will  
   // be set to 400kbps.  
   I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);  
   //clear I2C FIFOs  
   HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;  
 }  
 //sends an I2C command to the specified slave  
 void I2CSend(uint8_t slave_addr, uint8_t num_of_args, ...)  
 {  
   // Tell the master module what address it will place on the bus when  
   // communicating with the slave.  
   I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);  
   //stores list of variable number of arguments  
   va_list vargs;  
   //specifies the va_list to "open" and the last fixed argument  
   //so vargs knows where to start looking  
   va_start(vargs, num_of_args);  
   //put data to be sent into FIFO  
   I2CMasterDataPut(I2C0_BASE, va_arg(vargs, uint32_t));  
   //if there is only one argument, we only need to use the  
   //single send I2C function  
   if(num_of_args == 1)  
   {  
     //Initiate send of data from the MCU  
     I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);  
     // Wait until MCU is done transferring.  
     while(I2CMasterBusy(I2C0_BASE));  
     //"close" variable argument list  
     va_end(vargs);  
   }  
   //otherwise, we start transmission of multiple bytes on the  
   //I2C bus  
   else  
   {  
     //Initiate send of data from the MCU  
     I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);  
     // Wait until MCU is done transferring.  
     while(I2CMasterBusy(I2C0_BASE));  
     //send num_of_args-2 pieces of data, using the  
     //BURST_SEND_CONT command of the I2C module  
     unsigned char i;  
     for(i = 1; i < (num_of_args - 1); i++)  
     {  
       //put next piece of data into I2C FIFO  
       I2CMasterDataPut(I2C0_BASE, va_arg(vargs, uint32_t));  
       //send next data that was just placed into FIFO  
       I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);  
       // Wait until MCU is done transferring.  
       while(I2CMasterBusy(I2C0_BASE));  
     }  
     //put last piece of data into I2C FIFO  
     I2CMasterDataPut(I2C0_BASE, va_arg(vargs, uint32_t));  
     //send next data that was just placed into FIFO  
     I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);  
     // Wait until MCU is done transferring.  
     while(I2CMasterBusy(I2C0_BASE));  
     //"close" variable args list  
     va_end(vargs);  
   }  
 }  
 //read specified register on slave device  
 uint32_t I2CReceive(uint32_t slave_addr, uint8_t reg)  
 {  
   //specify that we are writing (a register address) to the  
   //slave device  
   I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);  
   //specify register to be read  
   I2CMasterDataPut(I2C0_BASE, reg);  
   //send control byte and register address byte to slave device  
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);  
   //wait for MCU to finish transaction  
   while(I2CMasterBusy(I2C0_BASE));  
   //specify that we are going to read from slave device  
   I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, true);  
   //send control byte and read from the register we  
   //specified  
   I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);  
   //wait for MCU to finish transaction  
   while(I2CMasterBusy(I2C0_BASE));  
   //return data pulled from the specified register  
   return I2CMasterDataGet(I2C0_BASE);  
 }  
 unsigned char dec2bcd(unsigned char val)  
 {  
      return (((val / 10) << 4) | (val % 10));  
 }  
 // convert BCD to binary  
 unsigned char bcd2dec(unsigned char val)  
 {  
  return (((val & 0xF0) >> 4) * 10) + (val & 0x0F);  
 }  
 //Set Time  
 void SetTimeDate(unsigned char sec, unsigned char min, unsigned char hour,unsigned char day, unsigned char date, unsigned char month,unsigned char year)  
 {  
      I2CSend(SLAVE_ADDRESS,8,SEC,dec2bcd(sec),dec2bcd(min),dec2bcd(hour),dec2bcd(day),dec2bcd(date),dec2bcd(month),dec2bcd(year));  
 }  
 /*/Set Date  
 void SetDate(unsigned char day, unsigned char date, unsigned char month,unsigned char year)  
 {  
      I2CSend(SLAVE_ADDRESS,9,0x00,DAY,dec2bcd(day),DATE,dec2bcd(date),MONTH,dec2bcd(month),YEAR,dec2bcd(year));  
 }*/  
 //Get Time and Date  
 unsigned char GetClock(unsigned char reg)  
 {  
      unsigned char clockData = I2CReceive(SLAVE_ADDRESS,reg);  
      return bcd2dec(clockData);  
 }  
 void ConfigureUART(void)  
 {  
   //  
   // Enable the GPIO Peripheral used by the UART.  
   //  
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);  
   //  
   // Enable UART0  
   //  
   SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);  
   //  
   // Configure GPIO Pins for UART mode.  
   //  
   GPIOPinConfigure(GPIO_PA0_U0RX);  
   GPIOPinConfigure(GPIO_PA1_U0TX);  
   GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);  
   //  
   // Use the internal 16MHz oscillator as the UART clock source.  
   //  
   UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);  
   //  
   // Initialize the UART for console I/O.  
   //  
   UARTStdioConfig(0, 115200, 16000000);  
 }  
 void main(void)  
 {  
      // Set the clocking to run directly from the external crystal/oscillator.  
        SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_INT | SYSCTL_XTAL_16MHZ);  
        //initialize I2C module 0  
        InitI2C0();  
        ConfigureUART();  
        SetTimeDate(30,32,8,4,5,11,14);  
        unsigned char sec,min,hour,day,date,month,year;  
        while(1)  
        {  
             sec = GetClock(SEC);  
             min = GetClock(MIN);  
             hour = GetClock(HRS);  
             day = GetClock(DAY);  
             date = GetClock(DATE);  
             month = GetClock(MONTH);  
             year = GetClock(YEAR);  
             SysCtlDelay(SysCtlClockGet()/10*3);  
             UARTprintf("%02d:%02d:%02d \n%02d %02d/%02d/%02d\n",hour,min,sec,day,date,month,year);  
        }  
 } 
I have commented each and every line for better understanding of the code. One tip that I would like to share with you guys is that the steps for configuring any peripheral device are as follows
  • Enable the peripheral
  • Reset the peripheral
  • Enable the GPIO with which the peripheral is multiplexed.
  • Configure the GPIO to use those peripheral pins.
  • Configure GPIO pin type.
  • Initialize the peripheral.
The Peripheral Driver Library User Manual would be the right place to know about the APIs. TI has also provided some pretty good examples to get started. If you want to build a product from scratch you have to do the hard work guys. Believe me this may sound a bit complicated to you but I had no idea about these things a week back. I studied all the datasheets and the user manuals and some blogs in the TI community to get started and then things started to flow.
Reading datasheets is a very good habit if you want to take control of the product that you are building.


What's the TIME bro ??

Now that you have understood how the RTC works and written your first code. It is time to chr=eck out the time.
  • Now click on the little hammer(build) icon on the top of the CCS window. This will build and compile your program and check for errors. Hopefully you wont have any errors if you have followed my steps.
  • Now that your code is error free click on the little bug(debug) icon beside the hammer icon.
 
  • This will take you to the debug screen where you can dump your code to the controller and debug all the variables, registers etc.
 
  • Now obviously you would like to check the time. So go on and open up a serial monitor like Putty and open the serial port to which your controller is connected and set it to baud rate 115200 and click open.
  • You can check which COM port your device is connected by right-clicking on Computer click on Manage and go to Device Manage. Under Device Manager click on the triangle beside Ports to see which COM port your controller is connected.
 
  • You can see a window like this showing the time every one second.
So go on and tweak the program according to your own need and display time in your own format. You can also dispaly names of the day and month instead of just numbers.

Happy coding and keep watching my blog for more updates on smartwatch.

P.S. - Next we will work with Nokia 5110 LCD to display time there. Excited??

8 comments:

  1. Sounak,
    I have a problem, I can't read or even alter the Master Data Register @ address 0x4002 0008

    Hope you can shed light.

    Thanks,

    ReplyDelete
  2. hello sir .... i have found four error while building my project in the code composer studio.the errors are following
    1.#10010 errors encountered during linking
    2.#10234-d unresolved symbols remain
    3.unresolved symbols uartstudioconfig, first referenced in

    ReplyDelete
  3. the only way to not encounter those problem is to make your own library. I did make my own library by reading the reference manual

    ReplyDelete
  4. Students can learn practical lessons and techniques used to design, implement, integrate and test software used for advanced embedded systems Corporate training in Embedded Systems | embedded systems training institute in bangalore

    ReplyDelete
  5. It is safe to say that you are searching for paid applications for nothing? How might you complete it? Here is it: Appvn Download for PC. Appvn Download for PC will help you to download applications, eBooks, diversions, ringtones, funnies, backdrops, music, screensavers, and so on. All these stuff can be downloaded for nothing. Appvn Download for PC can be effortlessly dealt with by everybody. You can search for various applications that suit your decision. You can download Appvn for PC on Windows 10, Windows 8, Windows 7 or Windows XP for utilizing the premium applications for nothing.

    ReplyDelete