Hi there, I'm hoping someone could please help me configure the MSP430Fr4133 for use with the SSD1306 I2C display?
// I2C.c
#include "i2c.h"
#include <msp430fr4133.h>
#include <stdint.h>
#define SDA BIT2 // i2c sda P5.2
#define SCL BIT3 // i2c scl P5.3
unsigned char* PTxData; // Pointer to TX data
unsigned char TxByteCtr; // number of bytes to TX
void i2c_init(void) {
P5SEL0 |= SCL + SDA; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTLW0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BRW = 10; // fSCL = SMCLK/10 = ~100kHz with SMCLK 1MHz
UCB0BRW = 0;
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0IE |= UCTXIE0; // Enable TX interrupt
} // end i2c_init
void i2c_write(unsigned char slave_address, unsigned char *DataBuffer, unsigned char ByteCtr) {
UCB0I2CSA = slave_address;
PTxData = DataBuffer;
TxByteCtr = ByteCtr;
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
// Remain in LPM0 until all data is TX'd
}
#pragma vector = USCI_B0_VECTOR
__interrupt void USCIB0_ISR(void){
switch(__even_in_range(UCB0IV,0x1E))
{
case USCI_NONE: break; // Vector 0: No interrupts break;
case USCI_I2C_UCALIFG: break;
case USCI_I2C_UCNACKIFG: break;
case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG break;
case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG break;
case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3 break;
case USCI_I2C_UCTXIFG3: break; // Vector 14: TXIFG3 break;
case USCI_I2C_UCRXIFG2: break; // Vector 16: RXIFG2 break;
case USCI_I2C_UCTXIFG2: break; // Vector 18: TXIFG2 break;
case USCI_I2C_UCRXIFG1: break; // Vector 20: RXIFG1 break;
case USCI_I2C_UCTXIFG1: break; // Vector 22: TXIFG1 break;
case USCI_I2C_UCRXIFG0: break; // Vector 24: RXIFG0 break;
case USCI_I2C_UCTXIFG0:
if (TxByteCtr)
{ // Check TX byte counter
UCB0TXBUF = *PTxData++; // Load TX buffer
TxByteCtr--; // Decrement TX byte counter
}
else
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
UCB0IE &= ~UCTXIE0; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF);// Exit LPM0
}
break; // Vector 26: TXIFG0 break;
case USCI_I2C_UCBCNTIFG: break; // Vector 28: BCNTIFG
case USCI_I2C_UCCLTOIFG: break; // Vector 30: clock low timeout
case USCI_I2C_UCBIT9IFG: break; // Vector 32: 9th bit
default: break;
}
}
//I2C.h
#ifndef I2C_H_
#define I2C_H_
#include <msp430fr4133.h>
/* ====================================================================
* I2C Prototype Definitions
* ==================================================================== */
void i2c_init(void);
void i2c_write(unsigned char, unsigned char *, unsigned char);
#endif /* I2C_H_ */
/*
* ssd1306.h
*/
#ifndef SSD1306_H_
#define SSD1306_H_
#include <msp430fr4133.h>
#include <stdint.h>
#include <string.h>
#include "i2c.h"
/* ====================================================================
* Horizontal Centering Number Array
* ==================================================================== */
#define HCENTERUL_OFF 0
#define HCENTERUL_ON 1
/* ====================================================================
* SSD1306 OLED Settings and Command Definitions
* ==================================================================== */
#define SSD1306_I2C_ADDRESS 0x3C
#define SSD1306_LCDWIDTH 128
#define SSD1306_LCDHEIGHT 64
#define SSD1306_128_64
#define SSD1306_SETCONTRAST 0x81
#define SSD1306_DISPLAYALLON_RESUME 0xA4
#define SSD1306_DISPLAYALLON 0xA5
#define SSD1306_NORMALDISPLAY 0xA6
#define SSD1306_INVERTDISPLAY 0xA7
#define SSD1306_DISPLAYOFF 0xAE
#define SSD1306_DISPLAYON 0xAF
#define SSD1306_SETDISPLAYOFFSET 0xD3
#define SSD1306_SETCOMPINS 0xDA
#define SSD1306_SETVCOMDETECT 0xDB
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_SETPRECHARGE 0xD9
#define SSD1306_SETMULTIPLEX 0xA8
#define SSD1306_SETLOWCOLUMN 0x00
#define SSD1306_SETHIGHCOLUMN 0x10
#define SSD1306_SETSTARTLINE 0x40
#define SSD1306_MEMORYMODE 0x20
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_PAGEADDR 0x22
#define SSD1306_COMSCANINC 0xC0
#define SSD1306_COMSCANDEC 0xC8
#define SSD1306_SEGREMAP 0xA0
#define SSD1306_CHARGEPUMP 0x8D
#define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2
// currently no scroll functionality, left for possible future use
#define SSD1306_ACTIVATE_SCROLL 0x2F
#define SSD1306_DEACTIVATE_SCROLL 0x2E
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
/* ====================================================================
* SSD1306 OLED Prototype Definitions
* ==================================================================== */
void ssd1306_init(void);
void ssd1306_command(unsigned char);
void ssd1306_clearDisplay(void);
void ssd1306_setPosition(uint8_t, uint8_t);
void ssd1306_printText(uint8_t, uint8_t, char *);
void ssd1306_printTextBlock(uint8_t, uint8_t, char *);
void ssd1306_printUI32(uint8_t, uint8_t, uint32_t, uint8_t);
uint8_t digits(uint32_t);
void ultoa(uint32_t, char *);
void reverse(char *);
#endif /* SSD1306_H_ */
/*
* ssd1306.c
*/
#include "ssd1306.h"
#include <msp430fr4133.h>
#include <stdint.h>
#include "font_5x7.h"
#include "i2c.h"
/* ====================================================================
* Horizontal Centering Number Array
* ==================================================================== */
unsigned char buffer[17]; // buffer for data transmission to screen
const unsigned char HcenterUL[] = { // Horizontally center number with separators on screen
0, // 0 digits, not used but included to size array correctly
61, // 1 digit
58, // 2 digits
55, // 3 digits
49, // 4 digits and 1 separator
46, // 5 digits and 1 separator
43, // 6 digits and 1 separator
37, // 7 digits and 2 separators
34, // 8 digits and 2 separators
31, // 9 digits and 2 separators
25 // 10 digits and 3 separators
};
void ssd1306_init(void) {
// SSD1306 init sequence
ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
ssd1306_command(0x80); // the suggested ratio 0x80
ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
ssd1306_command(SSD1306_LCDHEIGHT - 1);
ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
ssd1306_command(0x0); // no offset
ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
ssd1306_command(0x14); // generate high voltage from 3.3v line internally
ssd1306_command(SSD1306_MEMORYMODE); // 0x20
ssd1306_command(0x00); // 0x0 act like ks0108
ssd1306_command(SSD1306_SEGREMAP | 0x1);
ssd1306_command(SSD1306_COMSCANDEC);
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x12);
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
ssd1306_command(0xCF);
ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
ssd1306_command(0xF1);
ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
ssd1306_command(0x40);
ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
ssd1306_command(SSD1306_DISPLAYON); //--turn on oled panel
} // end ssd1306_init
void ssd1306_command(unsigned char command) {
buffer[0] = 0x80;
buffer[1] = command;
i2c_write(SSD1306_I2C_ADDRESS, buffer, 2);
} // end ssd1306_command
void ssd1306_clearDisplay(void) {
ssd1306_setPosition(0, 0);
uint8_t i;
for (i = 64; i > 0; i--) { // count down for loops when possible for ULP
uint8_t x;
for(x = 16; x > 0; x--) {
if (x == 1) {
buffer[x-1] = 0x40;
} else {
buffer[x-1] = 0x0;
}
}
i2c_write(SSD1306_I2C_ADDRESS, buffer, 17);
}
} // end ssd1306_clearDisplay
void ssd1306_setPosition(uint8_t column, uint8_t page) {
if (column > 128) {
column = 0; // constrain column to upper limit
}
if (page > 8) {
page = 0; // constrain page to upper limit
}
ssd1306_command(SSD1306_COLUMNADDR);
ssd1306_command(column); // Column start address (0 = reset)
ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset)
ssd1306_command(SSD1306_PAGEADDR);
ssd1306_command(page); // Page start address (0 = reset)
ssd1306_command(7); // Page end address
} // end ssd1306_setPosition
void ssd1306_printText(uint8_t x, uint8_t y, char *ptString) {
ssd1306_setPosition(x, y);
while (*ptString != '\0') {
buffer[0] = 0x40;
if ((x + 5) >= 127) { // char will run off screen
x = 0; // set column to 0
y++; // jump to next page
ssd1306_setPosition(x, y); // send position change to oled
}
uint8_t i;
for(i = 0; i< 5; i++) {
buffer[i+1] = font_5x7[*ptString - ' '][i];
}
buffer[6] = 0x0;
i2c_write(SSD1306_I2C_ADDRESS, buffer, 7);
ptString++;
x+=6;
}
} // end ssd1306_printText
void ssd1306_printTextBlock(uint8_t x, uint8_t y, char *ptString) {
char word[12];
uint8_t i;
uint8_t endX = x;
while (*ptString != '\0'){
i = 0;
while ((*ptString != ' ') && (*ptString != '\0')) {
word[i] = *ptString;
ptString++;
i++;
endX += 6;
}
word[i++] = '\0';
if (endX >= 127) {
x = 0;
y++;
ssd1306_printText(x, y, word);
endX = (i * 6);
x = endX;
} else {
ssd1306_printText(x, y, word);
endX += 6;
x = endX;
}
ptString++;
}
}
void ssd1306_printUI32( uint8_t x, uint8_t y, uint32_t val, uint8_t Hcenter ) {
char text[14];
ultoa(val, text);
if (Hcenter) {
ssd1306_printText(HcenterUL[digits(val)], y, text);
} else {
ssd1306_printText(x, y, text);
}
} // end ssd1306_printUI32
uint8_t digits(uint32_t n) {
if (n < 10) {
return 1;
} else if (n < 100) {
return 2;
} else if (n < 1000) {
return 3;
} else if (n < 10000) {
return 4;
} else if (n < 100000) {
return 5;
} else if (n < 1000000) {
return 6;
} else if (n < 10000000) {
return 7;
} else if (n < 100000000) {
return 8;
} else if (n < 1000000000) {
return 9;
} else {
return 10;
}
} // end digits
void ultoa(uint32_t val, char *string) {
uint8_t i = 0;
uint8_t j = 0;
// use do loop to convert val to string
do {
if (j==3) { // we have reached a separator position
string[i++] = ','; // add a separator to the number string
j=0; // reset separator indexer thingy
}
string[i++] = val%10 + '0'; // add the ith digit to the number string
j++; // increment counter to keep track of separator placement
} while ((val/=10) > 0);
string[i++] = '\0'; // add termination to string
reverse(string); // string was built in reverse, fix that
} // end ultoa
void reverse(char *s)
{
uint8_t i, j;
uint8_t c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
} // end reverse
/*
* font_5x7.h
*/
#ifndef FONT_5X7_H_
#define FONT_5X7_H_
const unsigned char font_5x7[96][5] = {{0x00, 0x00, 0x00, 0x00, 0x00}, // space
{0x00, 0x00, 0x4F, 0x00, 0x00}, // !
{0x00, 0x07, 0x00, 0x07, 0x00}, // "
{0x14, 0x7F, 0x14, 0x7F, 0x14}, // #
{0x24, 0x2A, 0x7F, 0x2A, 0x12}, // $
{0x23, 0x13, 0x08, 0x64, 0x62}, // %
{0x36, 0x49, 0x55, 0x22, 0x50}, // &
{0x00, 0x05, 0x03, 0x00, 0x00}, // '
{0x00, 0x1C, 0x22, 0x41, 0x00}, // (
{0x00, 0x41, 0x22, 0x1C, 0x00}, // )
{0x14, 0x08, 0x3E, 0x08, 0x14}, // *
{0x08, 0x08, 0x3E, 0x08, 0x08}, // +
{0x00, 0x50, 0x30, 0x00, 0x00}, // ,
{0x08, 0x08, 0x08, 0x08, 0x08}, // -
{0x00, 0x60, 0x60, 0x00, 0x00}, // .
{0x20, 0x10, 0x08, 0x04, 0x02}, // /
{0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0
{0x00, 0x42, 0x7F, 0x40, 0x00}, // 1
{0x42, 0x61, 0x51, 0x49, 0x46}, // 2
{0x21, 0x41, 0x45, 0x4B, 0x31}, // 3
{0x18, 0x14, 0x12, 0x7F, 0x10}, // 4
{0x27, 0x49, 0x49, 0x49, 0x31}, // 5
{0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6
{0x01, 0x71, 0x09, 0x05, 0x03}, // 7
{0x36, 0x49, 0x49, 0x49, 0x36}, // 8
{0x06, 0x49, 0x49, 0x29, 0x1E}, // 9
{0x00, 0x36, 0x36, 0x00, 0x00}, // :
{0x00, 0x56, 0x36, 0x00, 0x00}, // ;
{0x08, 0x14, 0x22, 0x41, 0x00}, // <
{0x14, 0x14, 0x14, 0x14, 0x14}, // =
{0x00, 0x41, 0x22, 0x14, 0x08}, // >
{0x02, 0x01, 0x51, 0x09, 0x06}, // ?
{0x32, 0x49, 0x79, 0x41, 0x3E}, // @
{0x7E, 0x11, 0x11, 0x11, 0x7E}, // A
{0x7F, 0x49, 0x49, 0x49, 0x36}, // B
{0x3E, 0x41, 0x41, 0x41, 0x22}, // C
{0x7F, 0x41, 0x41, 0x22, 0x1C}, // D
{0x7F, 0x49, 0x49, 0x49, 0x41}, // E
{0x7F, 0x09, 0x09, 0x09, 0x01}, // F
{0x3E, 0x41, 0x49, 0x49, 0x7A}, // G
{0x7F, 0x08, 0x08, 0x08, 0x7F}, // H
{0x00, 0x41, 0x7F, 0x41, 0x00}, // I
{0x20, 0x40, 0x41, 0x3F, 0x01}, // J
{0x7F, 0x08, 0x14, 0x22, 0x41}, // K
{0x7F, 0x40, 0x40, 0x40, 0x40}, // L
{0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M
{0x7F, 0x04, 0x08, 0x10, 0x7F}, // N
{0x3E, 0x41, 0x41, 0x41, 0x3E}, // O
{0x7F, 0x09, 0x09, 0x09, 0x06}, // P
{0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q
{0x7F, 0x09, 0x19, 0x29, 0x46}, // R
{0x46, 0x49, 0x49, 0x49, 0x31}, // S
{0x01, 0x01, 0x7F, 0x01, 0x01}, // T
{0x3F, 0x40, 0x40, 0x40, 0x3F}, // U
{0x1F, 0x20, 0x40, 0x20, 0x1F}, // V
{0x3F, 0x40, 0x38, 0x40, 0x3F}, // W
{0x63, 0x14, 0x08, 0x14, 0x63}, // X
{0x07, 0x08, 0x70, 0x08, 0x07}, // Y
{0x61, 0x51, 0x49, 0x45, 0x43}, // Z
{0x7F, 0x41, 0x41, 0x00, 0x00}, // [
{0x02, 0x04, 0x08, 0x10, 0x20}, // forward slash
{0x00, 0x41, 0x41, 0x7F, 0x00}, // ]
{0x04, 0x02, 0x01, 0x02, 0x04}, // ^
{0x40, 0x40, 0x40, 0x40, 0x40}, // _
{0x00, 0x01, 0x02, 0x04, 0x00}, // `
{0x20, 0x54, 0x54, 0x54, 0x78}, // a
{0x7F, 0x48, 0x44, 0x44, 0x38}, // b
{0x38, 0x44, 0x44, 0x44, 0x20}, // c
{0x38, 0x44, 0x44, 0x48, 0x7F}, // d
{0x38, 0x54, 0x54, 0x54, 0x18}, // e
{0x08, 0x7E, 0x09, 0x01, 0x02}, // f
{0x0C, 0x52, 0x52, 0x52, 0x3E}, // g
{0x7F, 0x08, 0x04, 0x04, 0x78}, // h
{0x00, 0x44, 0x7D, 0x40, 0x00}, // i
{0x20, 0x40, 0x44, 0x3D, 0x00}, // j
{0x7F, 0x10, 0x28, 0x44, 0x00}, // k
{0x00, 0x41, 0x7F, 0x40, 0x00}, // l
{0x7C, 0x04, 0x18, 0x04, 0x78}, // m
{0x7C, 0x08, 0x04, 0x04, 0x78}, // n
{0x38, 0x44, 0x44, 0x44, 0x38}, // o
{0x7C, 0x14, 0x14, 0x14, 0x08}, // p
{0x08, 0x14, 0x14, 0x18, 0x7C}, // q
{0x7C, 0x08, 0x04, 0x04, 0x08}, // r
{0x48, 0x54, 0x54, 0x54, 0x20}, // s
{0x04, 0x3F, 0x44, 0x40, 0x20}, // t
{0x3C, 0x40, 0x40, 0x20, 0x7C}, // u
{0x1C, 0x20, 0x40, 0x20, 0x1C}, // v
{0x3C, 0x40, 0x30, 0x40, 0x3C}, // w
{0x44, 0x28, 0x10, 0x28, 0x44}, // x
{0x0C, 0x50, 0x50, 0x50, 0x3C}, // y
{0x44, 0x64, 0x54, 0x4C, 0x44}, // z
};
#endif /* FONT_5X7_H_ */
#include <msp430fr4133.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "SSD1306.h"
#include "i2c.h"
#define ANUMBER 19052019
#define MAX_COUNT 4.2e9
#define LONG_DELAY __delay_cycles(3000000)
#define SHORT_DELAY __delay_cycles(50000)
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
i2c_init(); // initialize I2C to use with OLED
ssd1306_init(); // Initialize SSD1306 OLED
ssd1306_clearDisplay(); // Clear OLED display
__enable_interrupt();
PMM_unlockLPM5();
while(1) {
// =========================================
// Display a Long Text Block
// =========================================
// There seems to be a bug in the ssd1306_printTextBlock code,
// long text blocks like below need 1 extra character in their array
// so the code does not read outside of the array. The below 91 character
// text block should only need a array of 92 but to fix the bug use an array of 93.
// !!!! MUST FIX BUG IN THE FUTURE !!!!
char txtBlock[93] = "This is a long multiline text block. The code will automatically add extra lines as needed.";
ssd1306_printTextBlock(0, 1, txtBlock);
LONG_DELAY; // Avoid delay loops in real code, use timer
ssd1306_clearDisplay();
// =========================================
// Print Single Lines of Text at each row
// =========================================
ssd1306_printText(0, 1, "Line 1");
ssd1306_printText(0, 2, "Line 2");
ssd1306_printText(0, 3, "Line 3");
ssd1306_printText(0, 4, "Line 4");
ssd1306_printText(0, 5, "Line 5");
ssd1306_printText(0, 6, "Line 6");
ssd1306_printText(0, 7, "Line 7");
// Print these at a column other then zero
ssd1306_printText(40, 1, "40");
ssd1306_printText(50, 2, "50");
ssd1306_printText(60, 3, "60");
ssd1306_printText(70, 4, "70");
ssd1306_printText(80, 5, "80");
ssd1306_printText(90, 6, "90");
ssd1306_printText(100, 7, "100");
// Hold screen for some time before displaying the next sample
LONG_DELAY; // Avoid delay loops in real code, use timer
ssd1306_clearDisplay();
// =========================================
// Print Unsigned 32 bit number
// =========================================
ssd1306_printUI32(0, 1, ANUMBER, HCENTERUL_OFF); // Print number on line 1
ssd1306_printUI32(0, 2, ANUMBER, HCENTERUL_ON); // Print number on line 2, horizontally centered
// Print counting on line 6 horizontally centered
uint32_t i = 1;
uint32_t j;
uint32_t val = 0;
while (i<1e9) {
for(j=0; j<10; j++) {
val = i * j;
ssd1306_printUI32(0, 6 , val, HCENTERUL_ON);
SHORT_DELAY;
}
i *= 10;
}
for (j=0; j<5; j++) {
val = i * j;
ssd1306_printUI32(0, 6 , val, HCENTERUL_ON);
SHORT_DELAY;
}
LONG_DELAY;
ssd1306_clearDisplay();
}
}
I have attached my code for reference. I think the issue may be related to the configuration of the I2C pins/ interrupt vector since this was what I have changed from the original library the code has been adapted from on GitHub. Any help would be greatly appreciated! Thank you