I say at the beginning, that i'm the beginner :)
I'm trying to write a simple code to control Adfruit Oled 128x64 I2C display. I have problems from the bigining.
My code was based on those examples:
There is olso example for SPI, but it's to complicated fo me to make it wor for I2C.
MSP430 Oled SSd1306 128x64 SPI
And This is begining of my code:
#include <msp430G2553.h> #include "stdint.h" #include "ascii_char.h" #define OLED_CONTROL_BYTE_CMD_SINGLE 0x80 #define OLED_CONTROL_BYTE_CMD_STREAM 0x00 #define OLED_CONTROL_BYTE_DATA_STREAM 0x40 // Fundamental commands (pg.28) #define OLED_CMD_SET_CONTRAST 0x81 // follow with 0x7F #define OLED_CMD_DISPLAY_RAM 0xA4 #define OLED_CMD_DISPLAY_ALLON 0xA5 #define OLED_CMD_DISPLAY_NORMAL 0xA6 #define OLED_CMD_DISPLAY_INVERTED 0xA7 #define OLED_CMD_DISPLAY_OFF 0xAE #define OLED_CMD_DISPLAY_ON 0xAF // Addressing Command Table (pg.30) #define OLED_CMD_SET_MEMORY_ADDR_MODE 0x20 // follow with 0x00 = HORZ mode = Behave like a KS108 graphic LCD #define OLED_CMD_SET_COLUMN_RANGE 0x21 // can be used only in HORZ/VERT mode - follow with 0x00 + 0x7F = COL127 #define OLED_CMD_SET_PAGE_RANGE 0x22 // can be used only in HORZ/VERT mode - follow with 0x00 + 0x07 = PAGE7 // Hardware Config (pg.31) #define OLED_CMD_SET_DISPLAY_START_LINE 0x40 #define OLED_CMD_SET_SEGMENT_REMAP 0xA1 #define OLED_CMD_SET_MUX_RATIO 0xA8 // follow with 0x3F = 64 MUX #define OLED_CMD_SET_COM_SCAN_MODE 0xC8 #define OLED_CMD_SET_DISPLAY_OFFSET 0xD3 // follow with 0x00 #define OLED_CMD_SET_COM_PIN_MAP 0xDA // follow with 0x12 // Timing and Driving Scheme (pg.32) #define OLED_CMD_SET_DISPLAY_CLK_DIV 0xD5 // follow with 0x80 #define OLED_CMD_SET_PRECHARGE 0xD9 // follow with 0x22 #define OLED_CMD_SET_VCOMH_DESELCT 0xDB // follow with 0x30 // Charge Pump (pg.62) #define OLED_CMD_SET_CHARGE_PUMP 0x8D // follow with 0x14 // NOP #define OLED_CMD_NOP 0xE3 unsigned char *PTXData; unsigned char TXByteCtr; uint16_t i; uint8_t j,c,s,b; //const unsigned char init_cmd_array[] = { 0x00,0xAE,0xA8,0x3F,0xD3,0x00,0x40,0xA1,0xC8,0xDA,0x12,0x81,0x7F,0xA4,0xA6,0xD5,0x80,0x8D,0x14,0xD9,0x22,0xDB,0x30,0x20,0x00,0xAF}; const unsigned char init_cmd_array[] = { OLED_CONTROL_BYTE_CMD_STREAM, // Follow instructions on pg.64 of the dataSheet for software configuration of the SSD1306 // Turn the Display OFF OLED_CMD_DISPLAY_OFF, // Set mux ration tp select max number of rows - 64 OLED_CMD_SET_MUX_RATIO, 0x3F, // Set the display offset to 0 OLED_CMD_SET_DISPLAY_OFFSET, 0x00, // Display start line to 0 OLED_CMD_SET_DISPLAY_START_LINE, // Mirror the x-axis. In case you set it up such that the pins are north. // Wire.write(0xA0); - in case pins are south - default OLED_CMD_SET_SEGMENT_REMAP, // Mirror the y-axis. In case you set it up such that the pins are north. // Wire.write(0xC0); - in case pins are south - default OLED_CMD_SET_COM_SCAN_MODE, // Default - alternate COM pin map OLED_CMD_SET_COM_PIN_MAP, 0x12, // set contrast OLED_CMD_SET_CONTRAST, 0x7F, // Set display to enable rendering from GDDRAM (Graphic Display Data RAM) OLED_CMD_DISPLAY_RAM, // Normal mode! OLED_CMD_DISPLAY_NORMAL, // Default oscillator clock OLED_CMD_SET_DISPLAY_CLK_DIV, 0x80, // Enable the charge pump OLED_CMD_SET_CHARGE_PUMP, 0x14, // Set precharge cycles to high cap type OLED_CMD_SET_PRECHARGE, 0x22, // Set the V_COMH deselect volatage to max OLED_CMD_SET_VCOMH_DESELCT, 0x30, // Horizonatal addressing mode - same as the KS108 GLCD OLED_CMD_SET_MEMORY_ADDR_MODE, 0x00, // Turn the Display ON OLED_CMD_DISPLAY_ON }; const unsigned char WriteInit[] = { 0x00, 0x21, 0x00, 0x7F, 0x22, 0x00, 0x07 }; //const unsigned char TX[] = {0x00,0x7E,0x42,0x42,0x42,0x42,0x7E,0x00,0x00,0x7E,0x42,0x42,0x42,0x42,0x7E,0x00}; const unsigned char TX[] = {0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81,0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81}; const unsigned char TEST[]= {"This is test "}; unsigned char buffer[100]; unsigned int value; int strlen(const unsigned char * str) { const unsigned char *len; for (len = str; *len; ++len); return(len - str); } int WriteString(const unsigned char* character) { unsigned int size = strlen(character); for (s = 0; s < size; s++) { for (c = 0; c < 5; c++) { buffer[b] = ascii_table[(unsigned int) *character][c]; b++; } *character++; if (b == size) { b = 0; character = 0; } } return size; } void WriteOLED(const unsigned char* data, unsigned char size) { PTXData = (unsigned char*)data; TXByteCtr = size; while (UCB0CTL1 & UCTXSTP); UCB0CTL1 |= UCTR + UCTXSTT; } void OLEDInit() { WriteOLED(init_cmd_array, sizeof(init_cmd_array)); __delay_cycles(160000); } int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1=CALBC1_16MHZ; DCOCTL=CALDCO_16MHZ; P1DIR |= BIT0; P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0 P1SEL2 |= BIT6 + BIT7; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 12; UCB0BR1 = 0; UCB0I2CSA = 0x3C; // Slave Address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation IE2 |= UCB0TXIE; // Enable TX interrupt __enable_interrupt(); OLEDInit(); value = (WriteString(TEST)*5); while (1) { WriteOLED(WriteInit, sizeof(WriteInit)); for (i = 0; i < 1024; i++) { WriteOLED((unsigned char*)OLED_CONTROL_BYTE_DATA_STREAM,1); for (j = 0; j < 16; j++) { //j=1 for text WriteOLED((unsigned char*)0x81,1); WriteOLED((unsigned char*)0x02,1); WriteOLED(TX, sizeof(TX)); //Test array //WriteOLED(buffer, value); //Text i++; } i--; } __delay_cycles(160000); } } #pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (TXByteCtr) // Check TX byte counter { UCB0TXBUF = *PTXData++; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB0CTL1 |= UCTXSTP; // I2C stop condition IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag } P1OUT ^= BIT0; }
"ascii_char.h" is from the third exaple.
This is how it looks like:
So in the first place I want to ask You, why I have to set:
BCSCTL1=CALBC1_16MHZ; DCOCTL=CALDCO_16MHZ;
and
UCB0BR0 = 12;
to make this work.
Which is different than in the first example, to make this work, may someone explain me this?
My second question is...
I have to use
__enable_interrupt();
becouse it also doesn't work with:
__bis_SR_register(CPUOFF + GIE);
and
__bic_SR_register_on_exit(CPUOFF);
Could You explain me that too?
And my last question is...
For example if I want to send some big array to Oled, for exaple with 1024 bytes, the same like
here...
How should I do this? Any ideas? This is MSP430G2553 microcontroller, so I can't put so big array to it memory I guess.
I will appreciate any help and explanations. Greetings from Poland.