// File: ds3231_3.cpp // Read and display the current time - read from a DS3231 RTC on the I2C bus // Author: Jim Merkle #include // printf() #include // open() #include // open() #include // open() #include // ioctl() #include // errno #include // strerror() #include // close() #include // struct i2c_msg #include // struct i2c_rdwr_ioctl_data // The DS3231 is located on I2C bus 1, address 0x68 // The AT24C32 is located on I2C bus 1, address 0x56 #define I2C_DEVICE_NAME "/dev/i2c-1" #define PROG_NAME "ds3231_2" #define DS3231 0x68 #define AT24C32 0x56 #ifndef u8 typedef unsigned char u8; #endif // Return number of i2c_msg's transferred, else negative value for error int i2cWriteRead(int i2cAddress, u8 * pWriteData, int writeBytes, u8 * pReadData, int readBytes) { struct i2c_msg msg[2]; // declare a two i2c_msg array struct i2c_rdwr_ioctl_data i2c_data; // declare our i2c_rdwr_ioctl_data structure int msgsUsed=0; // how many i2c_msg structures are used int result; // return value from ioctl() call // Assume the first i2c_msg is used for writing if(pWriteData && writeBytes) { msg[0].addr = i2cAddress; msg[0].flags = 0; msg[0].buf = pWriteData; msg[0].len = writeBytes; msgsUsed++; // Load the second i2c_msg for receiving if the first one is used if(pReadData && readBytes) { // Load up receive msg msg[1].addr = i2cAddress; msg[1].flags = I2C_M_RD; msg[1].buf = pReadData; msg[1].len = readBytes; msgsUsed++; } } else if(pReadData && readBytes) { // Load the first i2c_msg for receiving (no transmit data) msg[0].addr = i2cAddress; msg[0].flags = I2C_M_RD; msg[0].buf = pReadData; msg[0].len = readBytes; msgsUsed++; } // Continue if we have data to transfer if(msgsUsed) { // i2c_msg array is loaded up. Now load i2c_rdwr_ioctl_data structure. i2c_data.msgs = msg; i2c_data.nmsgs = msgsUsed; // Open file descriptor to I2C bus int fd = open(I2C_DEVICE_NAME,O_RDWR); if(fd<0) { printf("Failed to open i2c-1."); return -1; } // With our open file descriptor, perform I2C message transfers // This function call returns the number of i2c_msg structures processed, // or a negative error value result = ioctl(fd,I2C_RDWR,&i2c_data); close(fd); // go ahead and close open file descriptor if(result < 0) { printf("ioctl error: %s\n", strerror(errno)); return -2; } } else { printf("i2cWriteRead: No i2c_msg's processed\n"); } return result; // return number of i2c_msg structures processed } // Given a byte containing BCD format data, return unsigned char value // Example: Convert 0x12 into the value 12 decimal : 0x0C u8 bcdToInt(u8 bcd) { u8 ret = bcd>>4; // high nibble ret = (ret * 10) + (bcd & 0xF); // low nibble return ret; } // Given a byte of "normal" data, convert into BCD format data // Example: Convert 0x20 (decimal 32) into 0x32 u8 intToBcd(u8 value) { u8 ret = value / 10; // high nibble ret = (ret << 4) + (value % 10); // low nibble return ret; } // Given a month, 1-12, provide a month string const char * monthString[] = {"zero","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; int main(int argc, char * argv[]) { // Read the first 7 registers (index: 0-6) from the DS3231 into an array // The DS3231 will auto-increment the index register following each register read. // Thus, write the first index, then read all the registers you need unsigned char ucIndex = 0; unsigned char regData[7] = {0}; int iResult = i2cWriteRead(DS3231, &ucIndex, sizeof(ucIndex), regData, sizeof(regData)); if(iResult >= 0) { // array, regData, now contains the contents of the indexed registers 0 - 6 of the DS3231 // The data is BCD, which displays wonderfully well when displayed as HEX (each nibble a digit) printf("%s %02X, %02X:%02X\n",monthString[bcdToInt(regData[5])], regData[4],regData[2],regData[1]); } else printf("Error calling i2cWriteRead()\n"); return 0; }