/* p9_3: I2C to DS1307 Multi-byte burst read */ /* This program communicate with the DS1307 Real-time Clock via I2C. */ /* It reads all seven time/date registers using burst read. */ /* DS1307 parameters: fmax = 100 kHz I2C1SCL PA6 I2C1SDA PA7 */ #include "TM4C123GH6PM.h" #define SLAVE_ADDR 0x68 /* 0110 1000 */ void I2C1_init(void); char I2C1_read(int slaveAddr, char memAddr, int byteCount, char* data); int main(void) { char timeDateReadBack[7]; I2C1_init(); for (;;) { /* use burst read to read time and date */ I2C1_read(SLAVE_ADDR, 0, 7, timeDateReadBack); /* display date time here */ } } /* initialize I2C1 as master and the port pins */ void I2C1_init(void) { SYSCTL->RCGCI2C |= 0x02; /* enable clock to I2C1 */ SYSCTL->RCGCGPIO |= 0x01; /* enable clock to GPIOA */ /* PORTA 7, 6 for I2C1 */ GPIOA->AFSEL |= 0xC0; /* PORTA 7, 6 for I2C1 */ GPIOA->PCTL &= ~0xFF000000; /* PORTA 7, 6 for I2C1 */ GPIOA->PCTL |= 0x33000000; GPIOA->DEN |= 0xC0; /* PORTA 7, 6 as digital pins */ GPIOA->ODR |= 0x80; /* PORTA 7 as open drain */ I2C1->MCR = 0x10; /* master mode */ I2C1->MTPR = 7; /* 100 kHz @ 16 MHz */ } /* This function is called by the startup assembly */ /* code to perform system specific initialization tasks. */ void SystemInit(void) { /* Grant coprocessor access */ /* This is required since TM4C123G has a floating point coprocessor */ SCB->CPACR |= 0x00f00000; } /* Wait until I2C master is not busy and return error code */ /* If there is no error, return 0 */ static int I2C_wait_till_done(void) { while(I2C1->MCS & 1); /* wait until I2C master is not busy */ return I2C1->MCS & 0xE; /* return I2C error code */ } /* Read memory */ /* read: S-(saddr+w)-ACK-maddr-ACK-R-(saddr+r)-ACK-data-ACK-data-ACK-...-data-NACK-P */ char I2C1_read(int slaveAddr, char memAddr, int byteCount, char* data) { char error; if (byteCount <= 0) return -1; /* no read was performed */ /* send slave address and starting address */ I2C1->MSA = slaveAddr << 1; I2C1->MDR = memAddr; I2C1->MCS = 3; /* S-(saddr+w)-ACK-maddr-ACK */ error = I2C_wait_till_done(); if (error) return error; /* to change bus from write to read, send restart with slave addr */ I2C1->MSA = (slaveAddr << 1) + 1; /* restart: -R-(saddr+r)-ACK */ if (byteCount == 1) /* if last byte, don't ack */ I2C1->MCS = 7; /* -data-NACK-P */ else /* else ack */ I2C1->MCS = 0xB; /* -data-ACK- */ error = I2C_wait_till_done(); if (error) return error; *data++ = I2C1->MDR; /* store the data received */ if (--byteCount == 0) /* if single byte read, done */ { while(I2C1->MCS & 0x40); /* wait until bus is not busy */ return 0; /* no error */ } /* read the rest of the bytes */ while (byteCount > 1) { I2C1->MCS = 9; /* -data-ACK- */ error = I2C_wait_till_done(); if (error) return error; byteCount--; *data++ = I2C1->MDR; /* store data received */ } I2C1->MCS = 5; /* -data-NACK-P */ error = I2C_wait_till_done(); *data = I2C1->MDR; /* store data received */ while(I2C1->MCS & 0x40); /* wait until bus is not busy */ return 0; /* no error */ }