#include "ds1302.h" #include #include uint8_t ds1302_readAddress(uint8_t address) { return address | 0x01; } void ds1302_spi_session_start(struct ds1302_spi_session * session) { /*Setup Pins*/ bcm2835_gpio_fsel(session->clock, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_fsel(session->select, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_fsel(session->io, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_write(session->clock, LOW); bcm2835_delayMicroseconds(10); bcm2835_gpio_write(session->select, HIGH); bcm2835_gpio_write(session->io, LOW); bcm2835_delayMicroseconds(10); } void ds1302_spi_session_end(struct ds1302_spi_session * session) { bcm2835_gpio_write(session->select, LOW); bcm2835_delayMicroseconds(10); } void ds1302_spi_session_write(struct ds1302_spi_session * session, int8_t value) { bcm2835_gpio_fsel(session->io, BCM2835_GPIO_FSEL_OUTP); for(int i = 0; i < 8; i++) { /*The LSB is written first*/ uint8_t out = value & 0x01; value = value >> 1; uint8_t o; if(out != 0x0) o = HIGH; else o = LOW; /*ds1302 reads the value while the clock is high. Ensure that value is written*/ bcm2835_gpio_write(session->io, o); bcm2835_delayMicroseconds(DS1302_CLOCKDELAY); bcm2835_gpio_write(session->clock, HIGH); /*TODO: Lookup the required wait time*/ bcm2835_delayMicroseconds(DS1302_CLOCKDELAY); bcm2835_gpio_write(session->clock, LOW); } } uint8_t ds1302_spi_session_read(struct ds1302_spi_session * session) { bcm2835_gpio_fsel(session->io, BCM2835_GPIO_FSEL_INPT); uint8_t value = 0; /*The LSB is read first*/ for(int i = 0; i < 8; i++) { value = value >> 1 | bcm2835_gpio_lev(session->io) << 7; bcm2835_gpio_write(session->clock, HIGH); bcm2835_delayMicroseconds(DS1302_CLOCKDELAY); bcm2835_gpio_write(session->clock, LOW); //bcm2835_delayMicroseconds(DS1302_CLOCKDELAY); } return value; } uint8_t ds1302_set_writeprotect(struct ds1302_spi_session * session, uint8_t protect) { if(protect != 0x0) protect = 0x80; ds1302_spi_session_write(session, DS1302_WRITE_PROTECT); ds1302_spi_session_write(session, protect); } uint8_t ds1302_read_register(struct ds1302_spi_session * session, uint8_t address) { ds1302_spi_session_write(session, ds1302_readAddress(address)); return ds1302_spi_session_read(session); } void ds1302_write_register(struct ds1302_spi_session * session, uint8_t address, uint8_t data) { ds1302_spi_session_write(session, address); ds1302_spi_session_write(session, data); } uint8_t ds1302_burst_read(struct ds1302_spi_session * session, ds1302BurstType type, uint8_t * output, size_t size) { if(size <= 0) return 0; uint8_t command = ds1302_readAddress(DS1302_CLOCK_BURST); uint8_t bytesRead = 0; if(type == DS1302_MEMORY) command = command | 0x40; ds1302_spi_session_write(session, command); /*read more about burst reads from memory*/ for(int i = 0; i < size && i < 9; i++) { output[i] = ds1302_spi_session_read(session); bytesRead++; } /*Pull the select line down to signal that we are done reading*/ bcm2835_gpio_write(session->select, LOW); bcm2835_delayMicroseconds(10); bcm2835_gpio_write(session->select, HIGH); return bytesRead; } uint8_t ds1302_burst_write(struct ds1302_spi_session * session, ds1302BurstType type, uint8_t * input, size_t size) { if(size <= 0) return 0; uint8_t command = DS1302_CLOCK_BURST; uint8_t bytesWritten = 0; if(type == DS1302_MEMORY) command = command | 0x40; ds1302_spi_session_write(session, command); for(int i = 0; i < size; i++) { ds1302_spi_session_write(session, input[i]); bytesWritten++; } /*Pull the select line down to signal that we are done writing*/ bcm2835_gpio_write(session->select, LOW); bcm2835_delayMicroseconds(10); bcm2835_gpio_write(session->select, HIGH); return bytesWritten; } /*Convert the base 10 hex representation to just base 10 The upper half represents the tens digit and the lower half represents the ones digit. Make sure to clear any bits that are not used in the representation. (EG the 12/24 and AM/PM bits for the hour register) */ uint8_t ds1302_convertToDecimal(uint8_t input) { uint8_t result = 0x0; result = ((input >> 4) * 10) + (input & 0x0F); return result; } /*Convert base 10 to the 10 hex representation Inverse of ds1302_convertToDecimal */ uint8_t ds1302_convertToDecimalHex(uint8_t input) { uint8_t result = 0x0; uint8_t tens = input / 10; uint8_t ones = input - (tens * 10); result = (tens << 4) | ones; return result; } void ds1302_getCalendarTime(struct ds1302_spi_session * session, struct tm * date) { uint8_t data[7] = {0xff}; /*Clock hour format: High: 12hr, Low: 24h*/ uint8_t h12; /*PM or AM: High: PM, Low: AM*/ uint8_t pm; uint8_t hour; ds1302_burst_read(session, DS1302_REGISTER, data, 7); date->tm_sec = ds1302_convertToDecimal(data[0] & (~0x80)); date->tm_min = ds1302_convertToDecimal(data[1] & (~0x80)); /*struct tm represents hours in 24 format. Convert the 12hr clock to 24hr*/ h12 = data[2] & 0x80; pm = data[2] & 0x20; hour = ds1302_convertToDecimal(data[2] & 0x1F); if(h12) { if(pm) { date->tm_hour = hour + 11; } else { date->tm_hour = hour - 1; } } else { date->tm_hour = hour; } date->tm_mday = ds1302_convertToDecimal(data[3]); /*struct tm starts counting from 0 whereas the ds1302 starts from 1*/ date->tm_mon = ds1302_convertToDecimal(data[4]) - 1; /*struct tm starts counting from 0 whereas the ds1302 starts from 1*/ date->tm_wday = ds1302_convertToDecimal(data[5]) - 1; /*Number of year that have passed since 1900*/ date->tm_year = (ds1302_convertToDecimal(data[6]) + DS1302_START_YEAR) - 1900; } void ds1302_setCalendarTime(struct ds1302_spi_session * session, struct tm * date) { /*TODO: disable Write protect*/ uint8_t data[8] = {0}; uint8_t hour = 0; data[0] = ds1302_convertToDecimalHex(date->tm_sec); data[1] = ds1302_convertToDecimalHex(date->tm_min); data[2] = ds1302_convertToDecimalHex(date->tm_hour); data[3] = ds1302_convertToDecimalHex(date->tm_mday); data[4] = ds1302_convertToDecimalHex(date->tm_mon + 1); data[5] = ds1302_convertToDecimalHex(date->tm_wday + 1); data[6] = ds1302_convertToDecimalHex((date->tm_year + 1900) - DS1302_START_YEAR); data[7] = 0x00; ds1302_burst_write(session, DS1302_REGISTER, data, 8); }