RTC Module (Part 2)

Part 1234567

After the hardware description of the module, I will describe here the code required for driving it with Arduino. Firstly, we need to establish a SPI communication between Arduino (the master) and DS1306 (the slave). And here is the initialization routine for the SPI

void spi_init(void) {
// Initialize SPI port 	
	// Input pin
	DDRB  &= ~(1 << PIN_MISO); 
	// Ouput pins
	DDRB  |=  (1 << PIN_CS); 
	DDRB  |=  (1 << PIN_MOSI); 
	DDRB  |=  (1 << PIN_CLOCK);
	// Bias pins
	PORTB &= ~(1 << PIN_CS); // Disable chip select
	PORTB &= ~(1 << PIN_CLOCK); // Set clock level to LOW
	// Warning: 2 of the 4 SPI modes are supported by the RTCs: mode 1 (CPOL=0, CPHA=1) and mode 3 (CPOL=1, CPHA=1)
	// SPI mode 1 is implemented here (CPOL=0, CPHA=1), clock level is LOW in idle state, Setup on Rising edge, sample on falling edge.
  // Enable SPI, Master, Set bit on rising edge, sample on falling edge, set clock rate fck/16
	SPCR = ((1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << SPR0)); 
  byte clr; // dummy read registers to clear previous results
	clr = SPSR; 
	clr = SPDR;
	delay(1);
}

using pins assignment, as per:

byte PIN_CS = PINB2; // DS306 pin 10, chip select
byte PIN_MOSI = PINB3; // DS306 pin 12, master out / slave in
byte PIN_MISO = PINB4; // DS306 pin 13, master in / slave out
byte PIN_CLOCK = PINB5; // DS306 pin 11, clock

Two warnings so far:

  • PORTB &= ~(1 << PIN_CLOCK); is mandatory because of the automatic SPI mode recognition by the DS1306 (Check data sheet)
  • CPHA must be set to one in SPCR

Then is the classic SPI command, which is used for reading bytes as well as for writing bytes:

byte spi_cmd(byte data){
// Send an SPI command, includes time out management
	int maxNbrRetries = 100;
	SPDR = data; // start the transmission by loading the output byte into the spi data register
  int retries = 0;
  while (!(SPSR & (1 << SPIF)) && (retries++ < maxNbrRetries)) {
		asm volatile ("NOP");
	}
	if (retries >= maxNbrRetries) {
		// Manage error here if you wish so
	}
	// Returned value
	return(SPDR); 
}

The time out management prevents the command from looping for ever. And that’s all about SPI settings!
Now let’s build a routine and a function for accessing registers on DS1306:

byte rtc_readRegister(byte address){	
	PORTB |=  (1 << PIN_CS); // Assert chip
	delayMicroseconds(5); // Wait for Tcc, 4us maximum
	spi_cmd(address); // Send address of data to be read
	byte data = spi_cmd(0x00); // Read data
	delayMicroseconds(5); // Wait for Tcc, 4us maximum
	PORTB &= ~(1 << PIN_CS); // Deassert chip
	return(data);
}

void rtc_writeRegister(byte address, byte data){
	PORTB |=  (1 << PIN_CS); // Assert chip
	delayMicroseconds(5); // Wait for Tcc, 4us maximum
	spi_cmd(address); // Send address of data to be written
	spi_cmd(data);// Write data
	delayMicroseconds(5); // Wait for Tcc, 4us maximum
	PORTB &= ~(1 << PIN_CS); // Deassert chip
}

Coming next: simple application

Leave a Reply

You must be logged in to post a comment.