/* OLED_SSD1306 via I2C * * This program communicate with the OLED_SSD1306 via I2C. * It writes "ABC" on the display and fills the rest of the * display with a checker board pattern. * * I2C1SCL PA6 * I2C1SDA PA7 * * Built and tested with Keil MDK-ARM v5.24a and TM4C_DFP v1.1.0 */ #include "TM4C123GH6PM.h" #define SLAVE_ADDR 0x3C // 0111 100. #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define SCREEN_PAGE_NUM (SCREEN_HEIGHT / 8) void SSD1306_init(void); void SSD1306_data(char data); void SSD1306_command(char command); void I2C1_init(void); int I2C1_byteWrite(int slaveAddr, char memAddr, char data); void delayMs(int n); static int I2C_wait_till_done(void); char imagebuf[SCREEN_PAGE_NUM][SCREEN_WIDTH]; const static char font_table[][6] = { /* sample font table */ {0x7e, 0x11, 0x11, 0x11, 0x7e, 0}, /* A */ {0x7f, 0x49, 0x49, 0x49, 0x36, 0}, /* B */ {0x3e, 0x41, 0x41, 0x41, 0x22, 0}}; /* C */ int main(void) { int i, j, k; I2C1_init(); SSD1306_init(); SSD1306_command(0x22); /* set page */ SSD1306_command(0x00); /* starting page */ SSD1306_command(0x00); /* end page */ SSD1306_command(0x21); /* set column */ SSD1306_command(0); /* starting column */ SSD1306_command(SCREEN_WIDTH-1); /* end column */ /* write ABC at the beginning of first line */ for (j = 0; j < 3; j++) for (i = 0; i < 6; i++) SSD1306_data(font_table[j][i]); /* clear the rest of the line */ for (i = 0; i < SCREEN_WIDTH-3*6; i++) SSD1306_data(0); for (i = 1; i < SCREEN_PAGE_NUM; i++) { SSD1306_command(0x22); /* set pages */ SSD1306_command(i); /* starting page */ SSD1306_command(i); /* end page */ SSD1306_command(0x21); /* set columns */ SSD1306_command(0); /* starting column */ SSD1306_command(SCREEN_WIDTH-1); /* end column */ /* make checker board pattern */ for (j = 0; j < SCREEN_WIDTH/8; j++) { for (k = 0; k < 4; k++) SSD1306_data(0xF0); for (k = 0; k < 4; k++) SSD1306_data(0x0F); } } for (;;) { /* infinite loop */ } } const static char init_seq[] = { 0xae, // turn off oled panel 0x00, // set low column address 0x10, // set high column address 0x40, // set start line address 0x20, 0x02, // page addressing mode 0xc8, // top-down segment (4th quadrant) 0x81, // set contrast control register 0xcf, 0xa1, // set segment re-map 95 to 0 0xa6, // set normal display 0xa8, // set multiplex ratio(1 to 64) 0x3f, // 1/64 duty 0xd3, // set display offset 0x00, // not offset 0xd5, // set display clock divide ratio/oscillator frequency 0x80, // set divide ratio 0xd9, // set pre-charge period 0xf1, 0xda, // set com pins hardware configuration 0x12, 0xdb, // set vcomh 0x40, 0x8d, // set Charge Pump enable/disable 0x14, // set(0x10) disable 0xaf // turn on oled panel }; void SSD1306_init(void) { int i; delayMs(100); for (i = 0; i < sizeof(init_seq); i++) SSD1306_command(init_seq[i]); } void SSD1306_data(char data) { I2C1_byteWrite(SLAVE_ADDR, 0xC0, data); } void SSD1306_command(char command) { I2C1_byteWrite(SLAVE_ADDR, 0x80, command); } // 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 = 24; // 100 kHz @ 50 MHz } // 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 } // byte write: S-(saddr+w)-ACK-maddr-ACK-data-ACK-P int I2C1_byteWrite(int slaveAddr, char memAddr, char data) { char error; // 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(); // wait until write is complete if (error) return error; // send data I2C1->MDR = data; I2C1->MCS = 5; // -data-ACK-P error = I2C_wait_till_done(); // wait until write is complete while(I2C1->MCS & 0x40); // wait until bus is not busy error = I2C1->MCS & 0xE; if (error) return error; return 0; // no error } /* delay n milliseconds (50 MHz CPU clock) */ void delayMs(int n) { int i, j; for(i = 0 ; i< n; i++) for(j = 0; j < 6265; j++) {} /* do nothing for 1 ms */ }