RTC Module (Part 2)
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