CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

[Debug] PIC -- RTC -- EEPROM

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
domdom



Joined: 06 Sep 2006
Posts: 29

View user's profile Send private message

[Debug] PIC -- RTC -- EEPROM
PostPosted: Mon Mar 12, 2007 3:27 am     Reply with quote

I am trying to program the PIC which connecting to RTC and eeprom with I2C (4.7K pull up resistor).

but i cannot get anything in my hyperterminal.

below is my main code:
Code:

#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)

#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOPUT,NOBROWNOUT
#use delay(clock=20000000)
#endif

#define RTC_SDA  PIN_C4
#define RTC_SCL  PIN_C3
#define EEPROM_SDA  PIN_C4
#define EEPROM_SCL  PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL, FORCE_HW)

#include <stdio.h>
#include <ds1307.c>
#include <24256>

#use rs232(baud =19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,stream=,bits=8)


void main(void)
{
   BYTE data;
   BYTE data2;
   long int addr;
   init_ext_eeprom();


   delay_ms(50);

   init_ds1307();          // initial DS1307


   data = 12;
   data2 = 12;
   addr = 5;


   write_ext_eeprom(addr,data);

}
   printf("write ad.\%02Lu data \%02u", addr, data);
   delay_ms(50);



   while (1)
   {
   data2 = read_ext_eeprom(addr);
   printf("Read  ad.\%02Lu data \%02u", addr, data2);
   delay_ms(1000);
}

}





ds1307 driver

Code:


////////////////////////////////////////////////////////////////////////////////
///                               DS1307.C                                   ///
///                     Driver for Real Time Clock                           ///
///                                                                          ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
///                 used when PIC loses power and DS1307 run from 3V BAT     ///
///               - Disable squarewave output                                ///
///                                                                          ///
/// ds1307_set_date_time(day,mth,year,dow,hour,min,sec)  Set the date/time   ///
///                                                                          ///
/// ds1307_get_date(day,mth,year,dow)               Get the date             ///
///                                                                          ///
/// ds1307_get_time(hr,min,sec)                     Get the time             ///
///                                                                          ///
////////////////////////////////////////////////////////////////////////////////

//#define RTC_SDA  PIN_C4
//#define RTC_SCL  PIN_C3

//#use i2c(master, sda=RTC_SDA, scl=RTC_SCL, FORCE_HW)

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
   BYTE seconds = 0;

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_start();
   i2c_write(0xD1);      // RD from RTC
   seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
   i2c_stop();
   seconds &= 0x7F;

   delay_us(3);

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_write(bin2bcd(seconds));     // Start oscillator with current "seconds value
   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x07);      // Control Register
   i2c_write(0x80);     // Disable squarewave output pin
   i2c_stop();

}

void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
  sec &= 0x7F;
  hr &= 0x3F;

  i2c_start();
  i2c_write(0xD0);            // I2C write address
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_write(bin2bcd(sec));      // REG 0
  i2c_write(bin2bcd(min));      // REG 1
  i2c_write(bin2bcd(hr));      // REG 2
  i2c_write(bin2bcd(dow));      // REG 3
  i2c_write(bin2bcd(day));      // REG 4
  i2c_write(bin2bcd(mth));      // REG 5
  i2c_write(bin2bcd(year));      // REG 6
  i2c_write(0x80);            // REG 7 - Disable squarewave output pin
  i2c_stop();
}

void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x03);            // Start at REG 3 - Day of week
  i2c_start();
  i2c_write(0xD1);
  dow  = bcd2bin(i2c_read() & 0x7f);   // REG 3
  day  = bcd2bin(i2c_read() & 0x3f);   // REG 4
  mth  = bcd2bin(i2c_read() & 0x1f);   // REG 5
  year = bcd2bin(i2c_read(0));            // REG 6
  i2c_stop();
}

void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_start();
  i2c_write(0xD1);
  sec = bcd2bin(i2c_read() & 0x7f);
  min = bcd2bin(i2c_read() & 0x7f);
  hr  = bcd2bin(i2c_read(0) & 0x3f);
  i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE retval;

  temp = binary_value;
  retval = 0;

  while(1)
  {
    // Get the tens digit by doing multiple subtraction
    // of 10 from the binary value.
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else // Get the ones digit by adding the remainder.
    {
      retval += temp;
      break;
    }
  }

  return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
  BYTE temp;

  temp = bcd_value;
  // Shifting upper digit right by 1 is same as multiplying by 8.
  temp >>= 1;
  // Isolate the bits for the upper digit.
  temp &= 0x78;

  // Now return: (Tens * 8) + (Tens * 2) + Ones

  return(temp + (temp >> 2) + (bcd_value & 0x0f));
}



lastly is eeprom24256 driver
Code:

///////////////////////////////////////////////////////////////////////////
////   Library for a 24LC256 serial EEPROM                             ////
////                                                                   ////
////   init_ext_eeprom();    Call before the other functions are used  ////
////                                                                   ////
////   write_ext_eeprom(a, d);  Write the byte d to the address a      ////
////                                                                   ////
////   d = read_ext_eeprom(a);   Read the byte d from the address a    ////
////                                                                   ////
////   The main program may define eeprom_sda                          ////
////   and eeprom_scl to override the defaults below.                  ////
////                                                                   ////



#ifndef EEPROM_SDA

#define EEPROM_SDA  PIN_C4
#define EEPROM_SCL  PIN_C3

#endif

#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL)

#define EEPROM_ADDRESS long int
#define EEPROM_SIZE   512000

void init_ext_eeprom()
{
   output_float(EEPROM_SCL);
   output_float(EEPROM_SDA);

}


void write_ext_eeprom(long int address, BYTE data)
{
   short int status;
   i2c_start();
   i2c_write(0xa0);
   i2c_write(address>>8);
   i2c_write(address);
   i2c_write(data);
   i2c_stop();
   i2c_start();
   status=i2c_write(0xa0);
   while(status==1)
   {
   i2c_start();
   status=i2c_write(0xa0);
   }
}


BYTE read_ext_eeprom(long int address) {
   BYTE data;
   i2c_start();
   i2c_write(0xa0);
   i2c_write(address>>8);
   i2c_write(address);
   i2c_start();
   i2c_write(0xa1);
   data=i2c_read(0);
   i2c_stop();
   return(data);
}



appreciate if someone can help me to find out what goes wrong in my code
KaraMuraT



Joined: 16 May 2006
Posts: 65
Location: Ankara/Turkey

View user's profile Send private message Send e-mail

PostPosted: Mon Mar 12, 2007 3:55 am     Reply with quote

My suggestions are:

You are using two I2C init lines. Lower it to one and dont use FORCE_HW. Try it after making everthing work. In fact I guess FORCE_HW is important if you use your PIC just as slave.

Then try adding "stream= ANYSTRING" identifier in your #use RS232 line and change your printf(XXXX) functions to fprintf(ANYSTRING,XXXX)


And an advice about debugging process. Take everthing one by one where the problem starts. You're saying "I can not see anything in Hyper terminal"... Means you can have possible RS232 problems. Try to solve RS232 issues with simple steps like sending a simple string to it.

One last advice. I recommend you to use another program for communication. You can download Docklight (www.docklight.de - free version exists) and see what happens. You can see the traffic and send anything you want, but can not record the communication and send files with free version.
_________________
/// KMT
/// www.muratursavas.com
domdom



Joined: 06 Sep 2006
Posts: 29

View user's profile Send private message

PostPosted: Mon Mar 12, 2007 11:00 am     Reply with quote

Ya. When i debugging the software, i usually add a subroutine to see which line is giving me problem.

for instant:

Code:

#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)

#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOPUT,NOBROWNOUT
#use delay(clock=20000000)
#endif

#define RTC_SDA  PIN_C4
#define RTC_SCL  PIN_C3
#define EEPROM_SDA  PIN_C4
#define EEPROM_SCL  PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL, FORCE_HW)

#include <stdio.h>
#include <ds1307.c>
#include <24256>

#use rs232(baud =19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,stream=,bits=8)


void main(void)
{
   BYTE data;
   BYTE data2;
   long int addr;
   init_ext_eeprom();


   delay_ms(50);

   init_ds1307();          // initial DS1307


   data = 12;
   data2 = 12;
   addr = 5;


   write_ext_eeprom(addr,data);
[color=red]     [b]while(1)
{

      output_bit(PIN_B1,0);
      Output_bit(PIN_B2,0);
      delay_ms(1000);

      output_bit(PIN_B1,1);
      Output_bit(PIN_B2,1);
      delay_ms(1000);
}[/b][/color]
printf("write ad.\%02Lu data \%02u", addr, data);
   delay_ms(50);



   while (1)
   {
   data2 = read_ext_eeprom(addr);
   printf("Read  ad.\%02Lu data \%02u", addr, data2);
   delay_ms(1000);
}

}



the red colour subroutine which i use to test every single line, i found that the command after write_ext_eeprom() is not running.

I tried my hyperterminal. There is no problem. I tested with a simple program to printf a few sentences in hyperterminal. It works.
KaraMuraT



Joined: 16 May 2006
Posts: 65
Location: Ankara/Turkey

View user's profile Send private message Send e-mail

PostPosted: Tue Mar 13, 2007 12:33 am     Reply with quote

Did you try to remove additional I2C init line and the FORCE_HW statement. I advice you to download datasheet of eeprom and check the serial communication section.

Just comment this line

"// #use i2c(master, sda=RTC_SDA, scl=RTC_SCL, FORCE_HW)"

because you're initiating I2C in this line already

"#include <ds1307.c>"

Also I see a "#include <24256> " line. Do you have such file? it's not a defined driver.
_________________
/// KMT
/// www.muratursavas.com
KaraMuraT



Joined: 16 May 2006
Posts: 65
Location: Ankara/Turkey

View user's profile Send private message Send e-mail

PostPosted: Tue Mar 13, 2007 12:51 am     Reply with quote

Did you connected the address pins to the ground? A0, A1 and A2... if not, this driver will not work. it's just implemented for I2C address "10100000 = 0xA0"


Does it respond anything or the program does stop responding?
_________________
/// KMT
/// www.muratursavas.com
domdom



Joined: 06 Sep 2006
Posts: 29

View user's profile Send private message

PostPosted: Tue Mar 13, 2007 11:46 pm     Reply with quote

it's working...(remove the force Hw)

But can i know why the force hw causing the problem?


Anyway, thanks KMT
KaraMuraT



Joined: 16 May 2006
Posts: 65
Location: Ankara/Turkey

View user's profile Send private message Send e-mail

PostPosted: Wed Mar 14, 2007 1:41 am     Reply with quote

Lots of PIC's have I2C (MSSP) errata on silicon. And they still exist in new line of products (Nanowatt series). It took my precious one month to find out the error is caused by an errata. I don't know why they are not correcting it.

I'm glad you didn't loose this time. Your welcome...
_________________
/// KMT
/// www.muratursavas.com
domdom



Joined: 06 Sep 2006
Posts: 29

View user's profile Send private message

PostPosted: Wed Mar 14, 2007 1:55 am     Reply with quote

Another question(sorry if I am too stupid)

I am writing subroutine:

1. My clock is displaying(running) on my screen( using hyperterminal).
2. PIC write a data(12) to ext eeprom addr(5)
3. Display the time PIC write the data to eeprom
4. PIC read back the data(12) from same addr(5)
5. Display the time PIC read from eeprom


below subroutine is my clock which displaying on my screen(it works):


Code:

   ds1307_set_date_time(23,7,6,1,18,47,00);   
    while(1)
    {
   
   ds1307_get_time(hr,min,sec);
   printf("\f Time:");
   putc((hr/10) + 0x30);
   
   putc((hr%10) + 0x30);
   printf(":");
   putc((min/10) + 0x30);
   putc((min%10) + 0x30);
   printf(":");
   putc((sec/10) + 0x30);
   putc((sec%10) + 0x30);
   printf("  \n");

   
   delay_ms(1000);


But i no idea how to write sub for remaining parts. Can you show me some idea?
KaraMuraT



Joined: 16 May 2006
Posts: 65
Location: Ankara/Turkey

View user's profile Send private message Send e-mail

PostPosted: Wed Mar 14, 2007 2:38 am     Reply with quote

Linus Torvalds has a famous word.

"If you have more than 3 indents, you're already screwed!"...

First of all I advice you write your codes in modules and use always indents...

For example your code. Most probably you'll try to write everything in "main.c" and as plain text (not using indents). It's not a problem if your code consists about 50-100 lines. But think about 5000 , 10K lines. This will be an absolute mess.

My Advices:

* Use user friendly names for your main functions. They will include the low level functions.

* Try to use separate files for every module. For example use a file like rtc.c for your real time codes, use eeprom.c for your eeprom codes. And than write human friendly functions. Like "ReadEepromData(unsigned int address) or "ReadTime()". And seperated files helps you to use files again easily. This will help you to create your own library.

* Use global variables for your var's that always used and must exist all the time. But if you need them for just this function, use them locally. This will help you about RAM optimising.

* But this may cause stack problems if you use too many function chains. Always be aware about your worst stack usage. You can take the info from "*.sta" file which is generated at the compilation time.


if I were you, I would write your code as:

main.c

Code:
.
.
/// Your definitions codes etc
.
.

/// Remember to define your global variables before the additional module s
#include "rtc.c"

void main(void)
{
  ds1307_set_date_time(23,7,6,1,18,47,00);

  while(1)
  {
      ReadTime();

      DisplayTime();

      delay_ms(1000);
  }
}


rtc.c:

Code:


void ReadTime()
{
   ds1307_get_time(&hr, &min, &sec);        /// hr, min, sec must be global and notice the address operator
}


void DisplayTime()
{
   printf("\f Time:");
   putc((hr/10) + 0x30);
   
   putc((hr%10) + 0x30);
   printf(":");
   putc((min/10) + 0x30);
   putc((min%10) + 0x30);
   printf(":");
   putc((sec/10) + 0x30);
   putc((sec%10) + 0x30);
   printf("  \n");
}

_________________
/// KMT
/// www.muratursavas.com
domdom



Joined: 06 Sep 2006
Posts: 29

View user's profile Send private message

PostPosted: Thu Mar 15, 2007 7:08 pm     Reply with quote

Hi KMT,

I search the forum and found that you worked bootloader before. Do you have the working code?

Pic use : 16f877a

Basically all i need to implement the bootloader are just include 3 files?

#include bootloader.h , #include bootloader.c, and my main application code?

Appreciate if you can teach me
KaraMuraT



Joined: 16 May 2006
Posts: 65
Location: Ankara/Turkey

View user's profile Send private message Send e-mail

PostPosted: Fri Mar 16, 2007 12:44 am     Reply with quote

you can read lots of topics in here about bootloaders. But let me help you about the basic concept.

You don't have 3 include files. including means just separating project into different files for easy management or library purposes. Bootloading is a bit different.

For bootloading process you need 2 different projects. But they will share something about hardware.

Think about the PIC's ROM(flash) starting from address 0x0000 to 0x4000. This is a ROM area of 16F877. PIC needs a reserved area. This area is from 0x0000 to 0x0023 and includes interrupt maps and some hardware related things that I don't know yet. If you use a programmer, your programs starts from 0x0000 as reset point of the program and includes a reserved area for hardware related things to 0x0023 and continues to write from 0x0024 to it's final address.

The concept is: You have a small program which is named as bootloader, programmed via a programmer. Stays at the rom from 0x0024 to it's size. usually it's not bigger than 0x07FF.

As you can see you still have a space from 0x0800 to 0x4000. That space will hold your application code.

Your application code is a different project not written in bootlader code. You make it as you make before but with a difference. You have to change it's start point at the ROM. If you don't do that, you'll overwrite your bootloader code. It does not matter you're using RS232 or a different communcation standart.

CCS has a built in feature called "#build" to do this. it states programs start point with "reset=" statement and also includes a statement as "interrupt=". interrupt is usually "reset+0x0008".

If a bootloader starts up, tries to get application code wherever you want (RS232, I2C, USB etc). If receive starts, writes it to the rest freespace. and if it finishes writing passes the PIC control to application via simply jumping to application address reset point (start).

I'm sure you have read lots of "interrupts does not work, they stop working" topics in here. That because interrupts need special attention in bootloading concept.

PIC is calling interrpupts not software related. It jumps directly to a hardware location and its fixed. Ant the location belongs to bootloader. That's why you see a interrupt vector re-assignment codes with "#org" statement. If application calls an interrupt, PIC jumps to an area between "0x0008 and 0x0023", not to the area states as inthe application program "#build .... interrrupt=0x0808". You need to redirect PIC to your application interrupts. and there you have your codes as like this :

Code:

#org 0x0008, 0x0023
void isr_relocate(void)
{
   #asm
     GOTO  0x0808    // else jump to application ISR

     NOP                           // Just filling memory
     NOP
     NOP
     NOP
     NOP
     NOP

     GOTO   0x0823 // else jump to application ISR
   #endasm
   
}


This #org statement puts following function specifically at the location between 0x0008 and 0x0023. as you can see, GOTO is redirecting the process to application interrupt points.

Ckielstra's bootloader (you should see at my topics) as also a function. It's capable to use interrupts in bootloader. The code above can not process any bootloading interrupts. It just redirects to the application.

One last word. At compilation time you have to take care to your final code size. your limit is not %100. Your limit is (%100 - bootloader size).
_________________
/// KMT
/// www.muratursavas.com
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group