/* ============================================================================ */ /* Copyright (c) 2024, LEBEL SAS */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* * Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* * Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* * Neither the name of LEBEL SAS nor the names of */ /* its contributors may be used to endorse or promote products derived */ /* from this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" */ /* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, */ /* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ /* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ /* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */ /* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, */ /* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; */ /* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ /* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ /* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* ============================================================================ */ /******************************************************************** * * subroutines for the East Rising ER-OLEDM032-1W * 256X64 Oled display. * * LEBEL SAS , Version 1.0 2024 * * Rev. 1.0, Setup * ********************************************************************/ /*----------------------------------------------------------------------------*/ /* CONSTANTS */ /*----------------------------------------------------------------------------*/ /* constants for SPI 4 wires Oled driving */ // if needed here are the definitions used in the main program // #define MOSI BIT7 // Serial Data line 1.7 // #define CLK BIT5 // Serial Clock line 1.5 // #define /CS BIT2 // Chip Select line 2.2 // #define /RST BIT1 // Chip Select line 2.1 // #define D/C BIT0 // Data/Command line 2.0 /************************************************************ * FUNCTIONS ************************************************************/ /******************************************************************* I2C functions */ /* A crude delay function. Tune by changing the counter value. */ void delay( unsigned int n ) { volatile int i; for( ; n; n-- ) { for( i = 500; i > 0; i-- ); } } void data_read(void ) { P2DIR &= ~I2C_SDA; // float to get ready to read } void data_high(void ) { P2DIR &= ~I2C_SDA; // float pin to go high //delay( 50 ); } void data_low(void ) { P2OUT &= ~I2C_SDA; // assert low P2DIR |= I2C_SDA; //delay( 50 ); } void clk_high(void) { P1DIR &= ~I2C_SCL; // float pin to go high //delay( 100 ); } void clk_low(void) { P1OUT &= ~I2C_SCL; // assert low P1DIR |= I2C_SCL; //delay( 50 ); } void clk_toggle(void) { P1OUT ^= I2C_SCL; // toggle p1.5 to test P2OUT ^= I2C_SDA; // assert low } void I2C_Start(void) { clk_high(); data_high(); data_low(); clk_low(); } /* I2C communication stops with both the clock and data * lines going high, in that order. */ void I2C_Stop(void) { data_low(); clk_low(); clk_high(); data_high(); } /* Outputs 8-bit command or data via I2C lines. */ void I2C_out(unsigned char d) { int n; for( n = 8; n > 0; n-- ) { if( d & 0x80 ) { data_high(); } else { data_low(); } clk_high(); clk_low(); d <<= 1; // Shift next bit into position. } data_read(); // Set data line to receive. clk_high(); // Clock goes high to wait for acknowledge. // Slave will pull data line low to acknowledge. //P1OUT |= (BIT0); // chip select not used while( P2IN & I2C_SDA ) { // Else toggle the clock line and check again clk_low(); clk_high(); } clk_low(); //P1OUT &= ~(BIT0); // chip select not used } /******************************************************************* reset the display * */ void reset_display(void){ int i; /* I2C Display Reset */ // P1OUT |= (BIT0); // chip select not used P2OUT |= (I2C_RESET); for (i = 30000; i > 0; i--); P2OUT &= ~(I2C_RESET); for (i = 30000; i > 0; i--); P2OUT |= (I2C_RESET); for (i = 30000; i > 0; i--); // P1OUT &= ~(BIT0); // chip select not used } /****************SET PAGE ADDRESS**************/ void Set_Page_Address(unsigned char add) { I2C_Start(); I2C_out(Oled_Addr); I2C_out(Command); add=0xb0|add; I2C_out(add); I2C_Stop(); } /****************SET COLUMN ADDRESS**************/ void Set_Column_Address(unsigned char add) { I2C_Start(); I2C_out(Oled_Addr); I2C_out(Command); I2C_out((0x10|(add>>4))); I2C_out(Command); I2C_out((0x0f&add)); I2C_Stop(); } /******************************************************************* Sends the "clear display" command to the display. */ void clear_display(void){ int n,i; for(i=0;i<2;i++) { Set_Page_Address(i); Set_Column_Address(0x00); I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Data ); // Control byte: data bytes follow, data is RAM data. for( n = 0; n < 128; n++ ) { I2C_out(0x00); } I2C_Stop(); } } /******************************************************************* display controls */ /* Initializes the display panel. */ void init_display(void) { reset_display(); clear_display(); I2C_Start(); I2C_out( Oled_Addr ); // Slave address of the LCD panel. I2C_out( Command ); // Control byte: all following bytes are commands. I2C_out( 0xAE ); // turn off panel delay( 100 ); I2C_out( Command ); I2C_out( 0x00 ); // set lower start column nibble ?? I2C_out( Command ); I2C_out( 0x1F ); // set higher start column nibble ?? delay( 100 ); I2C_out( Command ); I2C_out( 0xA8 ); // set multiplex ratio I2C_out( Command ); I2C_out( 0x0F ); // 1/16 delay( 100 ); I2C_out( Command ); I2C_out( 0xD3 ); // Display offset I2C_out( Command ); I2C_out( 0x00 ); // no offset delay( 100 ); I2C_out( Command ); I2C_out( 0x8D ); // charge pump I2C_out( Command ); I2C_out( 0x14 ); // is set delay( 100 ); I2C_out( Command ); I2C_out( 0x40 ); // start line adress delay( 100 ); //delay( 10 ); I2C_out( Command ); I2C_out( 0xA6 ); // normal display delay( 100 ); I2C_out( Command ); I2C_out( 0xA4 ); // show RAM content delay( 1000 ); I2C_out( Command ); I2C_out( 0xA1 ); // segment remap 96 to 1 delay( 100 ); I2C_out( Command ); I2C_out( 0xC8 ); // Set COM Output Scan Direction 16 to 1 delay( 100 ); I2C_out( Command ); I2C_out( 0xDa ); // set com pins hardware configuration I2C_out( Command ); I2C_out( 0x02 ); // delay( 100 ); I2C_out( Command ); I2C_out( 0x81 ); // set contrast control register I2C_out( Command ); I2C_out( 0x7F); // delay( 100 ); I2C_out( Command ); I2C_out( 0xD9 ); // set pre-charge period I2C_out( Command ); I2C_out( 0xF1 ); // impact the brightness delay( 100 ); I2C_out( Command ); I2C_out( 0xD5 ); // set osc frequency I2C_out( Command ); I2C_out( 0xF0 ); // 7-4 speed 3-0 divider delay( 100 ); I2C_out( Command ); I2C_out( 0xDB ); // set vcomh I2C_out( Command ); I2C_out( 0x20 ); // 0,83 Vcc delay( 100); I2C_out( Command ); I2C_out( 0x22 ); // set page I2C_out( Command ); I2C_out( 0x00 ); // I2C_out( Command ); I2C_out( 0x01 ); // delay( 100); I2C_out( Command ); I2C_out( 0x21 ); // set column I2C_out( Command ); I2C_out( 0x00 ); // 00 start I2C_out( Command ); //I2C_out( 0xFF ); //0xFF end 255 I2C_out( 0x5F ); //0x5F end 96 delay( 100); I2C_out( Command ); I2C_out( 0xAF ); // turn on led panel delay( 100); I2C_out( Command ); I2C_out( 0x20 ); // memory adressing mode I2C_out( Command ); I2C_out( 0x02 ); // page&column, page adressing mode delay( 100); I2C_Stop(); } /****************************************************************** write a page, 96 bytes*/ void show( unsigned char page,unsigned char col, unsigned char lenght, unsigned char *text ) { int n; Set_Page_Address(page); Set_Column_Address(col); // column in pixel I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Data ); // Control byte: data bytes follow, data is RAM data. for( n = lenght; n > 0; n-- ) { I2C_out( *text ); text++; } I2C_Stop(); } /****************************************************************** write a full screen, 192 bytes*/ void show_screen( unsigned char *text ) // 7,25ms @ 16MHz { int n; I2C_Start(); I2C_out(Oled_Addr); I2C_out( Command ); I2C_out( 0x20 ); // memory adressing mode I2C_out( Command ); I2C_out( 0x00 ); // horizontal adressing mode I2C_out( Command ); I2C_out( 0x21 ); // column config I2C_out( Command ); I2C_out( 0x00 ); // column start I2C_out( Command ); I2C_out( 0x5F ); // column end I2C_out( Command ); I2C_out( 0x22 ); // page config I2C_out( Command ); I2C_out( 0x00 ); // page start I2C_out( Command ); I2C_out( 0x01 ); // page end I2C_Stop(); I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Data ); // Control byte: data bytes follow, data is RAM data. for( n = 192; n > 0; n-- ) { I2C_out( *text ); // output screen text++; } I2C_Stop(); I2C_Start(); I2C_out(Oled_Addr); I2C_out( Command ); // back to standard page adressing mode I2C_out( 0x20 ); // memory page adressing mode I2C_out( Command ); I2C_out( 0x02 ); // page&column, page adressing mode I2C_Stop(); } /******************************************************************** write a caracter, 8 bytes*/ void showchr( unsigned char page,unsigned char col, unsigned char color, const unsigned char *text ) { int n; Set_Page_Address(page); Set_Column_Address(col*8); // column in caracter I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Data ); // Control byte: data bytes follow, data is RAM data. for( n = 0; n < 8; n++ ) // 8 bytes caracter { if (color == 0) { I2C_out( *text ); } else { I2C_out (~( *text )); } text++; } I2C_Stop(); } //////////// left scroll void hscroll( void ) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Command ); I2C_out( 0x27 ); // left scroll I2C_out( Command ); I2C_out( 0x00); // dummy I2C_out( Command ); I2C_out( 0x00 ); // start page 0 I2C_out( Command ); I2C_out( 0x00 ); // set time I2C_out( Command ); I2C_out( 0x01 ); // end page1 I2C_out( Command ); I2C_out( 0x00); // dummy I2C_out( Command ); I2C_out( 0xFF); // dummy I2C_out( Command ); I2C_out( 0x2F); // start scroll I2C_Stop(); } //////////// up scroll void scroll( unsigned char speed, unsigned char direction, unsigned char horizontal, unsigned char vertical) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Command ); I2C_out( 0xA3 ); // set vertical scroll area I2C_out( Command ); I2C_out( 0x00); // start line I2C_out( Command ); I2C_out( 0x10 ); // last line I2C_out( Command ); I2C_out( 0x00 ); // dummy I2C_out( Command ); if (direction == 'L') { I2C_out( 0x29 ); // horizontal scroll from left to right } else { I2C_out( 0x2A ); // horizontal scroll from right to left } I2C_out( Command ); I2C_out( 0x11); // dummy if ( horizontal == 0) { I2C_out( Command ); I2C_out( 0xFF ); // no start page horizontal scroll I2C_out( Command ); I2C_out( speed ); // set time I2C_out( Command ); I2C_out( 0xFF ); // no end page horizontal scroll } else { I2C_out( Command ); I2C_out( 0x01 ); // start page 1 horizontal scroll I2C_out( Command ); I2C_out( speed ); // set time I2C_out( Command ); I2C_out( 0x01 ); // end page 1 horizontal scroll } I2C_out( Command ); I2C_out( vertical ); // 1 line vertical scroll I2C_out( Command ); I2C_out( 0x2F); // start scroll I2C_Stop(); } //////////// blink void blink( void ) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Command ); I2C_out( 0x23 ); // blink command I2C_out( Command ); I2C_out( 0x11); // command, bit 4 is cycle mode, 0 to 3 is speed I2C_Stop(); } //////////// contrast void contrast( unsigned char value ) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Command ); I2C_out( 0x81 ); // contrast command I2C_out( Command ); switch (value) { case 0: I2C_out( 0x00); // low contrast break; case 1: I2C_out( 0x22); // medium contrast break; case 2: I2C_out( 0xFF); // high contrast break; } I2C_Stop(); } ////////// display on void display_on( void ) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Command ); I2C_out( 0x8D ); // charge pump setting I2C_out( Command ); I2C_out( 0x14 ); // charge pump on I2C_out( Command ); I2C_out( 0xAF ); // display on command I2C_Stop(); } ////////// display off void display_off( void ) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. I2C_out( Command ); I2C_out( 0xAE ); // display off command I2C_out( Command ); I2C_out( 0x8D ); // charge pump setting I2C_out( Command ); I2C_out( 0x10 ); // charge pump off I2C_Stop(); } ////////// invert display void display_invert( unsigned char value ) { I2C_Start(); I2C_out( Oled_Addr ); // Slave address of panel. if (value == 1) { I2C_out( Command ); I2C_out( 0xA7 ); // invert display } else { I2C_out( Command ); I2C_out( 0xA6 ); // normal display } I2C_Stop(); } /***************** display_alphanumeric (cursor)* // this function highlight (invert) a text zone, inputs are line, char, size, speed void display_alpha( int page, int line, int size); //, int speed ) { int i; for ( i=0,i==7,i++) { if (( i >= caract) || ( i <= (caract+size)) { showchr( page,i, 1, *text ); } else { showchr( page,i, 0, *text ); } text++; } } */ ////////// bargraph // this function put a bargraph (invert) in a graphic zone, inputs are graphic, line, column, size void bargraph (unsigned char column, unsigned char direction, unsigned char length, unsigned char masque, unsigned char *adresse) { adresse += column; while (!(length==0)) { if (direction == 0) // direction == FWD, L to R { *(adresse+(--length)) ^= masque; // bargraph plotting } else // direction == RWD, R to L { *(adresse-(--length)) ^= masque; // bargraph plotting } } } ////////// peak // this function put a peak dot in a graphic zone, inputs are graphic, line, column, size void peak( unsigned char column, unsigned char length, unsigned char masque, unsigned char *adresse) { adresse += column; while (!(length==0)) { *(adresse+(--length)) ^= masque; // bargraph plotting } } /************************************************************ * End of Modules ************************************************************/