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

Can't get DS1306 alarm to operate

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



Joined: 18 Feb 2004
Posts: 16
Location: UK

View user's profile Send private message

Can't get DS1306 alarm to operate
PostPosted: Wed Mar 08, 2006 5:55 am     Reply with quote

Hello.

I have produced the following code to test using the DS1306 RTC as an alarm to trigger an interrupt. The device is using the SPI port and communication appears to work well enough (i.e. I can read and write all of the memory addresses) but I can't seem to get the interrupt pin INT1 (pin 6) on the DS1306 to activate. I was wondering whether there was anything blatently obvious that I have missed that would make it work.

Thanks in advance,

Simon.

main.c

Code:
//  PIC Code for the Autonomous Water Sampling System timer circuit.
//  By Simon Ayers
//  Software version 0.01 (08/02/2006)
//

#include <18F252.h>
#include <math.h>
#include <ds1306.c>
#use delay(clock=8192000)
#fuses HS, NOWDT, NOPROTECT, NOBROWNOUT
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#include <useful.h>

int1 rb_pin = 0;

#INT_EXT1
void ext1_isr()
{
   rb_pin = 1;
}

void main()
{
   int8 hour, minute, second, day, date, month, year, control;
   char str[10], c;
   enable_interrupts(INT_EXT1);
   ext_int_edge(1, L_TO_H);
   disable_interrupts(global);
   rb_pin = 0;
   output_float(PIN_B1);
   //output_a(0);
   //output_b(0);
   //output_c(0);
   ds1306_init();
   ds1306_writebyte(0x8F, 0x00);
   delay_us(10);
   ds1306_writebyte(0x8F, 0x02);
   control = ds1306_readbyte(0x0F);
   printf("Control byte value is %X\r\n", control);
  /* printf("enter hour (0 - 23).\r\n");
   hour = getnumber(str);
   printf("enter minute (0 - 60).\r\n");
   minute = getnumber(str);
   printf("enter second (0 - 60).\r\n");
   second = getnumber(str);
   printf("enter day (1=monday, 2=tuesday, etc).\r\n");
   day = getnumber(str);
   printf("enter day of month (1 - 31).\r\n");
   date = getnumber(str);
   printf("enter month (1 - 12).\r\n");
   month = getnumber(str);
   printf("enter year 20XX (0 - 99).\r\n");
   year = getnumber(str);*/

   ds1306_settime_24hr(15, 20, 15);
   ds1306_setdate(4, 23, 2, 6);
   ds1306_setalarm1_24hr(15, 22, 00, 4);
   enable_interrupts(global);
   printf("Press 't' to retrieve the time and 'd' to retrieve the date.\r\n");
   while(rb_pin == 0)
   {
      c = getc();
      if ((c == 't') || (c == 'T'))
      {
         second = bcd2bin(ds1306_readbyte(0x00));
         minute = bcd2bin(ds1306_readbyte(0x01));
         hour = bcd2bin(ds1306_readbyte(0x02));
         printf("Time = ");
         if (hour < 10)
            printf("0%d:", hour);
         else
            printf("%d:", hour);
         if (minute < 10)
            printf("0%d:", minute);
         else
            printf("%d:", minute);
         if (second < 10)
            printf("0%d", second);
         else
            printf("%d", second);
         printf("\r\n");
      }
    c = getc();
      if ((c == 'a') || (c == 'A'))
      {
         second = bcd2bin(ds1306_readbyte(0x0B));
         minute = bcd2bin(ds1306_readbyte(0x0C));
         hour = bcd2bin(ds1306_readbyte(0x0D));
         printf("Alarm time = ");
         if (hour < 10)
            printf("0%d:", hour);
         else
            printf("%d:", hour);
         if (minute < 10)
            printf("0%d:", minute);
         else
            printf("%d:", minute);
         if (second < 10)
            printf("0%d", second);
         else
            printf("%d", second);
         printf("\r\n");
      }

      if ((c == 'd') || (c == 'D'))
      {
         day = bcd2bin(ds1306_readbyte(0x03));
         date = bcd2bin(ds1306_readbyte(0x04));
         month = bcd2bin(ds1306_readbyte(0x05));
         year = bcd2bin(ds1306_readbyte(0x06));
         printf("Date = ");
         switch(day)
         {
            case 1:  printf("Monday");
                     break;
            case 2:  printf("Tuesday");
                     break;
            case 3:  printf("Wednesday");
                     break;
            case 4:  printf("Thursday");
                     break;
            case 5:  printf("Friday");
                     break;
            case 6:  printf("Saturday");
                     break;
            case 7:  printf("Sunday");
                     break;
         }
         printf(", ");
         if (date < 10)
            printf("0%d/", date);
         else
            printf("%d/", date);
         if (month < 10)
            printf("0%d/", month);
         else
            printf("%d/", month);
         if (year < 10)
            printf("0%d", year);
         else
            printf("%d", year);
         printf("\r\n");

      }
   }
   printf("\r\nInterrupt activated.  ");
   second = bcd2bin(ds1306_readbyte(0x00));
   minute = bcd2bin(ds1306_readbyte(0x01));
   hour = bcd2bin(ds1306_readbyte(0x02));
   printf("Time = ");
   if (hour < 10)
      printf("0%d:", hour);
   else
      printf("%d:", hour);
   if (minute < 10)
      printf("0%d:", minute);
   else
      printf("%d:", minute);
   if (second < 10)
      printf("0%d", second);
   else
      printf("%d", second);
   printf("\r\n");
}


ds1306.c

Code:
//  Drivers for the DS1306 Real-Time Clock chip running in SPI mode.
//  Simon Ayers - 08/02/2006
//
//  ds1306_init();  Call before the other functions are used.
//
//  ds1306_writebyte(addr, data);  Write a single byte to address addr
//
//  data = ds1306_readbyte(addr);  Read a single byte from address addr
//
//  ds1306_settime_12hr(hour, minute, second, ampm);
//    - Set the RTC time when in 12hr mode (ampm = 1 when PM)
//
//  ds1306_settime_24hr(hour, minute, second);
//    - Set the RTC time when in 24hr mode
//
//  ds1306_setdate(day, date, month, year);
//    - day = 1-7 (1 = monday, 7 = sunday), date = 1-31, month 1-12, year = 0-99
//
//  ds1306_setalarm0_12hr(hour, minute, second, ampm, day, mask)
//    - sets alarm 0 when in 12hr mode (ampm = 1 when PM)
//    - mask (datasheet page 7) msb = seconds, lsb = days
//
//  ds1306_setalarm0_24hr(hour, minute, second, day, mask);  As above but 24hr
//
//  ds1306_setalarm1_12hr(hour, minute, second, ampm, day, mask): as ...alarm0_12hr
//
//  ds1306_setalarm1_24hr(hour, minute, second, day, mask);  As above but 24hr
//


#define DS1306_CE     PIN_B2
#define DS1306_DO     PIN_C5
#define DS1306_DI     PIN_C4
#define DS1306_CLK    PIN_C3

char bin2bcd(char binary_value)
{
   char temp;
   char 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);
}

//--------------------------------------------------------------
// This function converts an 8 bit BCD value to
// an 8 bit binary value.
// The input range must be from 00 to 99.

char bcd2bin(char bcd_value)
{
   char 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));

}


void ds1306_init()
{
   short int i;

   output_low(DS1306_DO);
   output_low(DS1306_CLK);
   output_low(DS1306_CE);
   i=input(DS1306_DI);

   //setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);

   return;
}

void ds1306_writebyte(int8 addr, int8 data)
{
   output_high(DS1306_CE);
   spi_write(addr);
   spi_write(data);
   output_low(DS1306_CE);
}

int8 ds1306_readbyte(int8 addr)
{
   int8 data;
   output_high(DS1306_CE);
   spi_write(addr);
   data = spi_read(0);
   output_low(DS1306_CE);
   return data;
}

void ds1306_settime_12hr(int8 hour, int8 minute, int8 second, int1 ampm)
{
   /*hour = hour & 0x1F;
   hour += (ampm * 0x20);
   hour += 0x40;

   minute = minute & 0x7F;
   second = second & 0x7F;*/

   output_high(DS1306_CE);
   spi_write(0x80);
   spi_write(bin2bcd(second));
   spi_write(bin2bcd(minute));
   spi_write(bin2bcd(hour));
   output_low(DS1306_CE);

   return;
}

void ds1306_settime_24hr(int8 hour, int8 minute, int8 second)
{
   /*hour = hour & 0x3F;
   minute = minute & 0x7F;
   second = second & 0x7F;*/

   output_high(DS1306_CE);
   spi_write(0x80);
   spi_write(bin2bcd(second));
   spi_write(bin2bcd(minute));
   spi_write(bin2bcd(hour));
   output_low(DS1306_CE);

   return;
}

void ds1306_setdate(int8 day, int8 date, int8 month, int8 year)
{
   /*day = day & 0x07;
   date = date & 0x3F;
   month = month & 0x3F;
   year = year & 0x7F;*/

   output_high(DS1306_CE);
   spi_write(0x83);
   spi_write(bin2bcd(day));
   spi_write(bin2bcd(date));
   spi_write(bin2bcd(month));
   spi_write(bin2bcd(year));
   output_low(DS1306_CE);

   return;
}

void ds1306_setalarm0_12hr(int8 hour, int8 minute, int8 second, int1 ampm, int8 day, int8 mask)
{
   /*hour = hour & 0x1F;
   hour += (ampm * 0x20);
   hour += 0x40;

   minute = minute & 0x7F;
   second = second & 0x7F;
   day = day &0x07;

   second += (mask & 0x08);
   minute += (mask & 0x04);
   hour += (mask & 0x02);
   day += (mask & 0x01);*/

   output_high(DS1306_CE);
   spi_write(0x87);
   spi_write(bin2bcd(second));
   spi_write(bin2bcd(minute));
   spi_write(bin2bcd(hour));
   spi_write(bin2bcd(day));
   output_low(DS1306_CE);

   return;
}

void ds1306_setalarm0_24hr(int8 hour, int8 minute, int8 second, int8 day)
{
   /*hour = hour & 0x3F;
   minute = minute & 0x7F;
   second = second & 0x7F;
   day = day &0x07;

   second += (mask & 0x08);
   minute += (mask & 0x04);
   hour += (mask & 0x02);
   day += (mask & 0x01);*/

   output_high(DS1306_CE);
   spi_write(0x87);
   spi_write(bin2bcd(second));
   spi_write(bin2bcd(minute));
   spi_write(bin2bcd(hour));
   spi_write(bin2bcd(day));
   output_low(DS1306_CE);

   return;
}

void ds1306_setalarm1_12hr(int8 hour, int8 minute, int8 second, int1 ampm, int8 day, int8 mask)
{
   /*hour = hour & 0x1F;
   hour += (ampm * 0x20);
   hour += 0x40;
   minute = minute & 0x7F;
   second = second & 0x7F;
   day = day &0x07;

   second += (mask & 0x08);
   minute += (mask & 0x04);
   hour += (mask & 0x02);
   day += (mask & 0x01);*/

   output_high(DS1306_CE);
   spi_write(0x8B);
   spi_write(bin2bcd(second));
   spi_write(bin2bcd(minute));
   spi_write(bin2bcd(hour));
   spi_write(bin2bcd(day));
   output_low(DS1306_CE);

   return;
}

void ds1306_setalarm1_24hr(int8 hour, int8 minute, int8 second, int8 day)
{
   /*hour = hour & 0x3F;
   minute = minute & 0x7F;
   second = second & 0x7F;
   day = day &0x07;

   second += (mask & 0x08);
   minute += (mask & 0x04);
   hour += (mask & 0x02);
   day += (mask & 0x01);*/

   output_high(DS1306_CE);
   spi_write(0x8B);
   spi_write(bin2bcd(second));
   spi_write(bin2bcd(minute));
   spi_write(bin2bcd(hour));
   spi_write(bin2bcd(day));
   output_low(DS1306_CE);

   return;
}


Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Wed Mar 08, 2006 7:13 am     Reply with quote

Quote:

but I can't seem to get the interrupt pin INT1 (pin 6) on the DS1306 to activate


I don't see in your code where do you activate the bit1 (AIE1) in the DS1306 Control Register. It is vital to assert INT1.

Code:

   if (hour < 10)
       printf("0%d:", hour);
   else
       printf("%d:", hour);


You can replace with:
Code:

      printf("%02d:", hour);



Humberto


Last edited by Humberto on Wed Mar 08, 2006 7:16 am; edited 2 times in total
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Mar 08, 2006 7:15 am     Reply with quote

Reading the DS1306 datasheet I noted two things in the following paragraph
Quote:
IRQF1 (Interrupt 1 Request Flag) – A logic 1 in the interrupt request flag bit indicates that the current
time has matched the Alarm 1 registers. If the AIE1 bit is also a logic 1, the INT1 pin generates a 62.5ms
active-high pulse. IRQF1 is cleared when the address pointer goes to any of the alarm 1 registers during a
read or write. IRQF1 is activated only when the device is powered by VCC2 or VBAT.

1) The IRQF1 flag is not automatically cleared, you will have to add this code in your interrupt handler.
2) It might be an error in the datasheet but here it explicitly mentions power must come from VCC2 or VBAT. For IRQF0 you have a choice out of three: VCC1, VCC2, or VBAT.
monkeytennis



Joined: 18 Feb 2004
Posts: 16
Location: UK

View user's profile Send private message

PostPosted: Wed Mar 08, 2006 8:45 am     Reply with quote

Humberto wrote:

I don't see in your code where do you activate the bit1 (AIE1) in the DS1306 Control Register. It is vital to assert INT1.


Sorry, I didn't remember to comment on my code. The following couple of lines should activate the AIE1 bit (hidden in the top of main.c).

Code:

   ds1306_init();
   ds1306_writebyte(0x8F, 0x00);  // Clear the configuration register (switch off write protection)
   delay_us(10);
   ds1306_writebyte(0x8F, 0x02);  // Set AIE1 bit high
monkeytennis



Joined: 18 Feb 2004
Posts: 16
Location: UK

View user's profile Send private message

PostPosted: Wed Mar 08, 2006 8:47 am     Reply with quote

ckielstra wrote:
Reading the DS1306 datasheet I noted two things in the following paragraph
Quote:
IRQF1 (Interrupt 1 Request Flag) – A logic 1 in the interrupt request flag bit indicates that the current
time has matched the Alarm 1 registers. If the AIE1 bit is also a logic 1, the INT1 pin generates a 62.5ms
active-high pulse. IRQF1 is cleared when the address pointer goes to any of the alarm 1 registers during a
read or write. IRQF1 is activated only when the device is powered by VCC2 or VBAT.

1) The IRQF1 flag is not automatically cleared, you will have to add this code in your interrupt handler.
2) It might be an error in the datasheet but here it explicitly mentions power must come from VCC2 or VBAT. For IRQF0 you have a choice out of three: VCC1, VCC2, or VBAT.


Ah, that could be the problem. I'll try powering the device from VCC2.
monkeytennis



Joined: 18 Feb 2004
Posts: 16
Location: UK

View user's profile Send private message

PostPosted: Mon Mar 13, 2006 7:26 am     Reply with quote

Powering the device from VCC2 seemed to solve the problem. Thanks. I knew it would be something stupid like that!
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