/* * This program writes and reads an I2C device on the Wytec EduBase board. * * The Wytec EduBase board has a real-time clock device (BQ32000) with I2C * interface. This program writes a zero to the second register (address 0) * of the RTC and reads it back repetitively and display the second count * at the LEDs. Since the second register uses binary coded decimal format, * the LEDs will count up from 0 to 9 in binary and wrap around to 0. */ #include "MKL25Z4.h" void I2C1_init(void); int I2C1_byteRead(unsigned char slaveAddr, unsigned char memAddr, unsigned char* data); int I2C1_byteWrite(unsigned char slaveAddr, unsigned char memAddr, unsigned char data); void delayUs(int n); #define SLAVE_ADDR 0x68 /* 1101 000. */ #define ERR_NONE 0 #define ERR_NO_ACK 0x01 #define ERR_ARB_LOST 0x02 #define ERR_BUS_BUSY 0x03 int main(void) { unsigned char second; int rv; I2C1_init(); /* enable PTC 6-3 as output for LEDs*/ SIM->SCGC5 |= 0x800; /* enable clock to Port C */ PORTC->PCR[3] = 0x100; /* make PTC3 pin as GPIO */ PORTC->PCR[4] = 0x100; /* make PTC4 pin as GPIO */ PORTC->PCR[5] = 0x100; /* make PTC5 pin as GPIO */ PORTC->PCR[6] = 0x100; /* make PTC6 pin as GPIO */ PTC->PDDR |= 0x78; /* make PTC6-3 as output pin */ rv = I2C1_byteWrite(SLAVE_ADDR, 0, 0); if (rv) for(;;) ; /* replace with error handling */ for (;;) { rv = I2C1_byteRead(SLAVE_ADDR, 0, &second); if (rv) for(;;) ; /* replace with error handling */ PTC->PDOR = (second & 0xF) << 3; delayUs(1000000); } } /* initialize I2C1 and the port pins */ void I2C1_init(void) { SIM->SCGC4 |= 0x80; /* turn on clock to I2C1 */ SIM->SCGC5 |= 0x0800; /* turn on clock to PortC */ PORTC->PCR[1] = 0x0200; /* PTE1 I2C1 SCL */ PORTC->PCR[2] = 0x0200; /* PTE0 I2C1 SDA */ I2C1->C1 = 0; /* stop I2C1 */ I2C1->S = 2; /* Clear interrupt flag */ I2C1->F = 0x1C; /* set clock to 97.09KHz @13.981MHz bus clock */ I2C1->C1 = 0x80; /* enable I2C1 */ } /* Write a signle byte to slave memory. * write: S-(saddr+w)-ACK-maddr-ACK-data-ACK-P */ int I2C1_byteWrite(unsigned char slaveAddr, unsigned char memAddr, unsigned char data) { int retry = 1000; while (I2C1->S & 0x20) { /* wait until bus is available */ if (--retry <= 0) return ERR_BUS_BUSY; delayUs(100); } /* send start */ I2C1->C1 |= 0x10; /* Tx on */ I2C1->C1 |= 0x20; /* become master */ /* send slave address and write flag */ I2C1->D = slaveAddr << 1; while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ if (I2C1->S & 0x10) { /* arbitration lost */ I2C1->S |= 0x10; /* clear IF */ return ERR_ARB_LOST; } if (I2C1->S & 0x01) /* got NACK from slave */ return ERR_NO_ACK; /* send memory address */ I2C1->D = memAddr; while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ if (I2C1->S & 0x01) /* got NACK from slave */ return ERR_NO_ACK; /* send data */ I2C1->D = data; while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ if (I2C1->S & 0x01) /* got NACK from slave */ return ERR_NO_ACK; /* stop */ I2C1->C1 &= ~0x30; return ERR_NONE; } /* Read a single byte from slave memory. * Burst read: S-(saddr+w)-ACK-maddr-ACK-R-(saddr+r)-data-NACK-P */ int I2C1_byteRead(unsigned char slaveAddr, unsigned char memAddr, unsigned char* data) { int retry = 100; volatile unsigned char dummy; while (I2C1->S & 0x20) { /* wait until bus is available */ if (--retry <= 0) return ERR_BUS_BUSY; delayUs(100); } /* start */ I2C1->C1 |= 0x10; /* Tx on */ I2C1->C1 |= 0x20; /* become master */ /* send slave address and write flag */ I2C1->D = slaveAddr << 1; while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ if (I2C1->S & 0x10) /* arbitration lost */ return ERR_ARB_LOST; if (I2C1->S & 0x01) /* got NACK from slave */ return ERR_NO_ACK; /* send address of target register in slave */ I2C1->D = memAddr; while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ if (I2C1->S & 0x01) /* got NACK from slave */ return ERR_NO_ACK; /* restart */ I2C1->C1 |= 0x04; /* send Restart */ /* send slave address and read flag */ I2C1->D = (slaveAddr << 1) | 1; while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ if (I2C1->S & 0x01) /* got NACK from slave */ return ERR_NO_ACK; /* change bus direction to read */ I2C1->C1 &= ~0x10; /* Tx off */ I2C1->C1 |= 0x08; /* prepare to give NACK */ dummy = I2C1->D; /* dummy read to initiate bus read */ /* read data */ while(!(I2C1->S & 0x02)); /* wait for transfer complete */ I2C1->S |= 0x02; /* clear IF */ I2C1->C1 &= ~0x20; /* stop the bus before reading the byte */ *data = I2C1->D; /* read received data */ return ERR_NONE; } /* delay n microseconds * The CPU core clock is set to MCGFLLCLK at 41.94 MHz in SystemInit(). */ void delayUs(int n) { int i; int j; for(i = 0 ; i < n; i++) { for(j = 0; j < 7; j++) ; } }