/* This program writes and reads an I2C device on the Wytec EduPad board. * * The Wytec EduPad board has a 24LC02B Serial EEPROM. This program writes * ramdom data to the memory and read back to verify. Both data written and * read back are displayed on the console (UART0 at the virtual COM port). * If there is a mismatch, five asterisks are printer. * Both single byte write/read and page write/read are tested. * * Built and tested with MSP432P401R Rev. C, Keil MDK-ARM v5.24a and MSP432P4xx_DFP v3.1.0 */ #include "msp.h" #include #include void UART_init(int baud); void I2C1_init(void); int I2C1_Write(int slaveAddr, unsigned char memAddr, unsigned char data); int I2C1_burstWrite(int slaveAddr, unsigned char memAddr, int byteCount, unsigned char* data); int I2C1_burstRead(int slaveAddr, unsigned char memAddr, int byteCount, unsigned char* data); void I2C1_ackPoll(int slaveAddr); #define SLAVE_ADDR 0x53 // 1010 011. #define SIZE 256 unsigned char readback[SIZE]; unsigned char testData[SIZE]; int main(void) { int i; UART_init(115200); // call subroutine to init uart lib i = *((int*)0x20001540); printf("\r\n24LC02B Serial EEPROM Test \r\n"); srand(i); I2C1_init(); /* generate some random data for testing */ for (i = 0; i < SIZE; i++) testData[i] = rand() & 0xff; /* program the memory one byte at a time */ for (i = 0; i < SIZE; i++) { //I2C1_Write(SLAVE_ADDR, i, testData[i]); I2C1_burstWrite(SLAVE_ADDR, i, 1, &testData[i]); I2C1_ackPoll(SLAVE_ADDR); // wait until write completed printf("."); } /* read back the memory */ for (i = 0; i < SIZE; i++) { I2C1_burstRead(SLAVE_ADDR, i, 1, &readback[i]); } /* compare the data written to the readback * mismatch bytes are followed by asterisks. */ for (i = 0; i < SIZE; i++) { printf("\r\n%2X: %2X - %2X %s", i, testData[i], readback[i], (testData[i] == readback[i]) ? " " : "*****"); } printf("\r\n\r\n24LC08B Serial EEPROM Page Write Test \r\n"); /* generate some random data for testing */ for (i = 0; i < SIZE; i++) testData[i] = rand() & 0xff; /* program the memory one page (8 bytes) at a time */ for (i = 0; i < (SIZE / 8); i++) { I2C1_burstWrite(SLAVE_ADDR, i * 8, 8, &testData[i * 8]); I2C1_ackPoll(SLAVE_ADDR); // wait until write completed printf("."); } /* read back the memory */ I2C1_burstRead(SLAVE_ADDR, 0, 256, readback); /* compare the data written to the readback * mismatch bytes are followed by asterisks. */ for (i = 0; i < SIZE; i++) { printf("\r\n%2X: %2X - %2X %s", i, testData[i], readback[i], (testData[i] == readback[i]) ? " " : "******"); } for (;;) { } } /* configure UCB1 as I2C */ void I2C1_init(void) { EUSCI_B1->CTLW0 |= 1; /* disable UCB1 during config */ EUSCI_B1->CTLW0 = 0x0F81; /* 7-bit slave addr, master, I2C, synch mode, use SMCLK */ EUSCI_B1->BRW = 15; /* set clock prescaler 1.5 MHz / 15 = 100kHz */ P6->SEL0 |= 0x30; /* P6.5, P6.4 for UCB1 */ P6->SEL1 &= ~0x30; EUSCI_B1->CTLW0 &= ~1; /* enable UCB1 after config */ } /* Use burst write to write multiple bytes to consecutive locations * burst write: S-(slaveAddr+w)-ACK-memAddr-ACK-data-ACK...-data-ACK-P */ int I2C1_burstWrite(int slaveAddr, unsigned char memAddr, int byteCount, unsigned char* data) { if (byteCount <= 0) return -1; /* no write was performed */ EUSCI_B1->I2CSA = slaveAddr; /* setup slave address */ EUSCI_B1->CTLW0 |= 0x0010; /* enable transmitter */ EUSCI_B1->CTLW0 |= 0x0002; /* generate START and send slave address */ while(!(EUSCI_B1->IFG & 2)); /* wait till it's ready to transmit */ EUSCI_B1->TXBUF = memAddr; /* send memory address to slave */ /* send data one byte at a time */ do { while(!(EUSCI_B1->IFG & 2)); /* wait till it's ready to transmit */ EUSCI_B1->TXBUF = *data++; /* send data to slave */ byteCount--; } while (byteCount > 0); while(!(EUSCI_B1->IFG & 2)); /* wait till last transmit is done */ EUSCI_B1->CTLW0 |= 0x0004; /* send STOP */ while(EUSCI_B1->CTLW0 & 4) ; /* wait until STOP is sent */ return 0; /* no error */ } /* Use burst read to read multiple bytes from consecutive locations * read: S-(slaveAddr+w)-ACK-memAddr-ACK-R-(slaveAddr+r)-ACK-data-ACK-...-data-NACK-P */ int I2C1_burstRead(int slaveAddr, unsigned char memAddr, int byteCount, unsigned char* data) { if (byteCount <= 0) return -1; /* no read was performed */ EUSCI_B1->I2CSA = slaveAddr; /* setup slave address */ EUSCI_B1->CTLW0 |= 0x0010; /* enable transmitter */ EUSCI_B1->CTLW0 |= 0x0002; /* generate START and send slave address */ while(!(EUSCI_B1->IFG & 2)); /* wait till it's ready to transmit */ EUSCI_B1->TXBUF = memAddr; /* send memory address to slave */ while(!(EUSCI_B1->IFG & 2)); /* wait till last transmit is done */ EUSCI_B1->CTLW0 &= ~0x0010; /* enable receiver */ EUSCI_B1->CTLW0 |= 0x0002; /* generate RESTART and send slave address */ while(EUSCI_B1->CTLW0 & 2); /* wait till RESTART is finished */ /* receive data one byte at a time */ do { if (byteCount == 1) /* when only one byte of data is left */ EUSCI_B1->CTLW0 |= 0x0004; /* setup to send STOP after the last byte is received */ while(!(EUSCI_B1->IFG & 1)); /* wait till data is received */ *data++ = EUSCI_B1->RXBUF; /* read the received data */ byteCount--; } while (byteCount); while(EUSCI_B1->CTLW0 & 4) ; /* wait until STOP is sent */ return 0; /* no error */ } /* It takes 3-4 milliseconds to program a byte or a page. * When a write is complete and the STOP condition is issued, the * programming of the EEPROM starts. During programming, the memory * returns no ACK when addressed. Polling ACK allows us to know when * programming is done. */ void I2C1_ackPoll(int slaveAddr) { int noAck; EUSCI_B1->I2CSA = slaveAddr; /* setup slave address */ EUSCI_B1->CTLW0 |= 0x0010; /* enable transmitter */ do { noAck = 0; EUSCI_B1->CTLW0 |= 0x0002; /* generate START and send slave address */ while(!(EUSCI_B1->IFG & 2)); /* wait till it's ready to transmit */ EUSCI_B1->TXBUF = 0; /* send memory address to slave */ while(!(EUSCI_B1->IFG & 2)) { if (EUSCI_B1->IFG & 0x20) { noAck = 1; EUSCI_B1->IFG &= ~0x20; break; } } /* wait till it's ready to transmit */ } while (noAck); EUSCI_B1->CTLW0 |= 0x0004; /* send STOP */ while(EUSCI_B1->CTLW0 & 4) ; /* wait until STOP is sent */ } #define SYSCLOCK 50000000 #define SCICLOCK SYSCLOCK/16 #define BAUDINT(baud) SCICLOCK / baud #define BAUDFRAC(baud) (((SCICLOCK * 128 - SCICLOCK / baud * 128 * baud) + baud) / baud / 2) void UART_init(int baud) { EUSCI_A0->CTLW0 |= 1; /* put in reset mode for config */ EUSCI_A0->MCTLW = 0; /* disable oversampling */ EUSCI_A0->CTLW0 = 0x0081; /* 1 stop bit, no parity, SMCLK, 8-bit data */ EUSCI_A0->BRW = 26; /* 3,000,000 / 115200 = 26 */ P1->SEL0 |= 0x0C; /* P1.3, P1.2 for UART */ P1->SEL1 &= ~0x0C; EUSCI_A0->CTLW0 &= ~1; /* take UART out of reset mode */ } int UART0Tx(unsigned char c){ while(!(EUSCI_A0->IFG & 0x02)) { } /* wait for transmit buffer empty */ EUSCI_A0->TXBUF = c; /* send a char */ return c; } /* The code below is the interface to the C standard I/O library. * All the I/O are directed to the console, which is UART3. */ struct __FILE { int handle; }; FILE __stdin = {0}; FILE __stdout = {1}; int fputc(int c, FILE *f) { return (UART0Tx(c)); /* debugging hardware used */ }