PIC 16F88 SPI Interface with DS3234 RTC

Thread Starter

b_gravedigger

Joined May 12, 2009
6
Ι have a ds3234 RTC with which i successfully interacted via SPI using an Arduino Duemilanove.

I did this using the code below:

Rich (BB code):
#include <SPI.h>
#include <avr/sleep.h>
const int alarmPin = 2;
const int RTC_CS=10;
int count =0;

void setup()
{ 
    RTC_init();
}

void loop(){
   if (count >= 10) {
      delay(100);     
      count = 0;
  
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 

    attachInterrupt(0,rtcAlarm, LOW); // use interrupt 0 (pin 2) and run function
                                       // rtcAlarm when pin 2 gets LOW 

    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(0);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.                       
  }                           
}


void RTC_init(){
  pinMode(RTC_CS,OUTPUT); // chip select
	 // start the SPI library:
	 SPI.begin();
	 SPI.setBitOrder(MSBFIRST); 
	 SPI.setDataMode(SPI_MODE1); // both mode 1 & 3 should work 
	 //set control register 
	 digitalWrite(RTC_CS, LOW);  
	 SPI.transfer(0x8E);
         SPI.transfer(0x05); //00000110 EOSC/BBSQW/TEMPCONV/RS1/RS2/INTCN/A2IE/A1IE
         digitalWrite(RTC_CS, HIGH);
         delay(10);
         digitalWrite(RTC_CS, LOW);
         SPI.transfer(0x8F);
         SPI.transfer(0x0);
	 digitalWrite(RTC_CS, HIGH);
	 delay(10);
    SetAlarm();
 //Turn on internal pullup for INT/SQW pin 
         pinMode(alarmPin, INPUT);
         digitalWrite(alarmPin, HIGH);  
         attachInterrupt(0, rtcAlarm, LOW);     
}

void rtcAlarm(){
  digitalWrite(RTC_CS, LOW);
  SPI.transfer(0x8F);
  SPI.transfer(0x0);
  digitalWrite(RTC_CS, HIGH);
}

void SetAlarm(){
 delay(10);
 digitalWrite(RTC_CS, LOW);

  //Set Alarm 1 to once per sec
        
  SPI.transfer(0x87);
  SPI.transfer(0x80);
  
  digitalWrite(RTC_CS, HIGH);
  delay(10);
  digitalWrite(RTC_CS, LOW);

  SPI.transfer(0x88);
  SPI.transfer(0x80);
   
  digitalWrite(RTC_CS, HIGH);
  delay(10);
  digitalWrite(RTC_CS, LOW);

  SPI.transfer(0x89);
  SPI.transfer(0x80);
  delay(10);
  
  digitalWrite(RTC_CS, HIGH);
  delay(10);
  digitalWrite(RTC_CS, LOW);
  
  SPI.transfer(0x8A);
  SPI.transfer(0x80);
  delay(10);

  digitalWrite(RTC_CS, HIGH);
}
I then tried to program a PIC16F88 to take the place of Arduino. As i didn't want to program it in assembly, i started looking for a way to program it in C. After rejecting HI-TECH C compiler due to non-helpfull documentation, i ended up using CCS C compiler.

I tried to replicate the commands used in the Arduino program, as it had proven to be working all right. After several hours, i managed to blink a led using an external interrupt with my PIC, but no luck in using the SPI.

The code i have created so far is this:
Rich (BB code):
#include <16F88.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES LVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES FCMEN                    //Fail-safe clock monitor enabled

#use delay(clock=16000000)
#INT_EXT


void blink(){
   output_high(PIN_A2);
   delay_ms(1000);
   output_low(PIN_A2);
   delay_ms(1000);
   clear_interrupt(INT_EXT);
   output_low(PIN_B5);
   spi_write(0x8F);
   spi_write(0x0);
   output_high(PIN_B5);
}

void setalarm()
{
   output_low(PIN_B5);
   spi_write(0x87);
   spi_write(0x80);
   output_high(PIN_B5);
   delay_ms(10);
   output_low(PIN_B5);  
   spi_write(0x88);
   spi_write(0x80);
   output_high(PIN_B5);
   delay_ms(10);
   output_low(PIN_B5);  
   spi_write(0x89);
   spi_write(0x80);
   output_high(PIN_B5);
   delay_ms(10);
   output_low(PIN_B5);  
   spi_write(0x8A);
   spi_write(0x80);
   output_high(PIN_B5);
}

void rtcinit()
{
   output_high(PIN_B5);
   spi_write(0x8E);
   spi_write(0x05);
   output_low(PIN_B5);
   delay_ms(10);
   output_high(PIN_B5);  
   spi_write(0x8F);
   spi_write(0x00);
   output_low(PIN_B5);
   delay_ms(10);
   setalarm();
}

void main()
{ 
   output_low(PIN_B5);
   setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
   delay_ms(3000);
   set_tris_a(0x00);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   rtcinit();

   while(1){

   }
}
The connections on the breadboard are:

ds3234 PIC16F88

SQW -> RB0
MISO -> RB1
MOSI -> RB2
CLK -> RB4
SS -> RB5

and i have a led connected in pin RA2.

The led blinks if i manually cause an external interrupt on RB0, so i now that my basic connections (oscillator, ground, vcc and led) and programming are correct.

However, an interrupt from the ds3234 never occurs, so there's something i'm not doing right with the SPI.

Any help will be appreciated. :)
 

Thread Starter

b_gravedigger

Joined May 12, 2009
6
I managed to get it to work after all, so i'm posting the code here for future reference.

Programming DS3234 RTC through SPI using PIC 16F88 (programming in C with CCS compiler).

Rich (BB code):
#include <16F88.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                     
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOPROTECT                //Code not protected from reading
#FUSES FCMEN                    //Fail-safe clock monitor enabled

#define DS3234_CS  PIN_B5

#use delay(clock=8000000) 
//#use rs232(baud=9600, xmit=PIN_A0, rcv=PIN_A1) 

#INT_EXT
void ext_isr()
{
   output_high(PIN_A2);
   delay_ms(150);
   output_low(PIN_A2);
   
   output_low(DS3234_CS);
   spi_write(0x8F);
   spi_write(0x00);
   output_high(DS3234_CS);
   
   ext_int_edge(H_TO_L);  
}

void setalarm()
{
   output_low(DS3234_CS);
   spi_write(0x87);
   spi_write(0x80);
   output_high(DS3234_CS);
   
   output_low(DS3234_CS);  
   spi_write(0x88);
   spi_write(0x80);
   output_high(DS3234_CS);

   output_low(DS3234_CS);  
   spi_write(0x89);
   spi_write(0x80);
   output_high(DS3234_CS);

   output_low(DS3234_CS);  
   spi_write(0x8A);
   spi_write(0x80);
   output_high(DS3234_CS);
   
   output_low(DS3234_CS);  
   spi_write(0x8F);
   spi_write(0x00);
   output_high(DS3234_CS);
}

void rtcinit()
{
   output_low(DS3234_CS);
   spi_write(0x8E);
   spi_write(0x05);
   output_high(DS3234_CS);
   
   output_low(DS3234_CS);  
   spi_write(0x8F);
   spi_write(0x00);
   output_high(DS3234_CS);
   
   setalarm();
}

void main()
{ 
   setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4|SPI_XMIT_L_TO_H);
   
   rtcinit();
   
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   
   while(TRUE)
   { 
   sleep();
   }
}

Maybe i'll post a full description of the project when i finish it (that's after the exams period is over :D)
 
Top