Corrige l'init OLED (/CS pendant reset, vitesse SPI) et ajoute la ref MSP430

/CS n'est plus force a LOW avant l'impulsion de reset (seul oled_command/
oled_data le pilotent par octet, comme dans le firmware MSP430 de
reference qui fonctionnait). Vitesse SPI ramenee a 400kHz et delais de
reset alonges a 100ms pour fiabiliser la liaison sur cable ruban IDC.

Ajoute aussi l'ancienne lib MSP430 (doc/librairies/) qui a servi de
reference pour comparer la sequence d'init SSD1322 octet par octet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StKu9rqrsdz8CAVt1XMxon
This commit is contained in:
2026-08-01 16:40:47 +02:00
parent 95ce6999ef
commit 77f78bb088
6 changed files with 4112 additions and 4 deletions

View File

@ -0,0 +1,636 @@
/* ============================================================================ */
/* 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
************************************************************/

File diff suppressed because it is too large Load Diff

Binary file not shown.

1291
doc/librairies/erM032_oled.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,225 @@
/***************************************************
//Web: http://www.buydisplay.com
EastRising Technology Co.,LTD
****************************************************/
//#include "erM032_oled.h"
#define HIGH 1 //
#define LOW 0 //
#define OLED_Control P2OUT
#define OLED_CS BIT2 // P2.2 chip select
#define OLED_DC BIT0 // P2.0 Data Command High = Data, Low = Command
#define OLED_RST BIT1 // P2.0 Data command
void send_spi_byte(uint8_t byte)
{
// Envoi des données
UCB0TXBUF = byte;
// Attente de la fin de la transmission
// while (!(UCB0IFG & UCTXIFG));
while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
// __delay_cycles(35); // 2 MHz
__delay_cycles(100);
}
void digitalWrite(uint16_t sortie, uint8_t etat)
{
if (etat)
{
OLED_Control |= sortie;
}
else
{
OLED_Control &= ~sortie;
}
}
void command(uint8_t cmd)
{
digitalWrite(OLED_DC, LOW);
digitalWrite(OLED_CS, LOW);
send_spi_byte(cmd);
digitalWrite(OLED_CS, HIGH);
}
void data(uint8_t dat)
{
digitalWrite(OLED_DC, HIGH);
digitalWrite(OLED_CS, LOW );
send_spi_byte(dat);
digitalWrite(OLED_CS, HIGH);
}
void er_oled_begin()
{ uint16_t k;
// digitalWrite(OLED_CS, LOW);
digitalWrite(OLED_RST, HIGH);
// delay(10);
for (k=20; k>0;k--)
{
__delay_cycles(100000);
}
digitalWrite(OLED_RST, LOW);
// delay(10);
for (k=20; k>0;k--)
{
__delay_cycles(100000);
}
digitalWrite(OLED_RST, HIGH);
command(0xFD); /*SET COMMAND LOCK*/
data(0x12); /* UNLOCK */
command(0xAE); /*DISPLAY OFF*/
command(0xB3);/*DISPLAYDIVIDE CLOCKRADIO/OSCILLATAR FREQUANCY*/
data(0x91); command(0xCA); /*multiplex ratio*/
data(0x3F); /*duty = 1/64*/
command(0xA2); /*set offset*/
data(0x00);
command(0xA1); /*start line*/
data(0x00);
command(0xA0); /*set remap*/
data(0x14);
data(0x11);
command(0xAB); /*funtion selection*/
data(0x01); /* selection external vdd */
command(0xB4); /* */
data(0xA0);
data(0xfd);
command(0xC1); /*set contrast current */
data(0x80);
command(0xC7); /*master contrast current control*/
data(0x0f);
command(0xB1); /*SET PHASE LENGTH*/
data(0xE2);
command(0xD1); /**/
data(0x82);
data(0x20);
command(0xBB); /*SET PRE-CHANGE VOLTAGE*/
data(0x1F);
command(0xB6); /*SET SECOND PRE-CHARGE PERIOD*/
data(0x08);
command(0xBE); /* SET VCOMH */
data(0x07);
command(0xA6); /*normal display*/
command(0xAF); /*display ON*/
}
void er_oled_SetWindow(uint8_t Xstart, uint8_t Ystart, uint8_t Xend, uint8_t Yend)
{
command(0x15);
data(Xstart+0x1c);
data(Xend+0x1c);
command(0x75);
data(Ystart);
data(Yend);
command(0x5c);//write ram command
}
void er_oled_clear()
{int i,row;
command(0x15);
data(0x00); //col start
data(0x77); //col end
command(0x75);
data(0x00); //row start
data(0x7f); //row end
command(0x5c);
for (row = 0; row < 128; row++) {
for(i = 0; i< 240; i++ ) {
data(0x00);// write data
}
}
}
void er_oled_char(uint8_t x, uint8_t y, const char *acsii, uint8_t mode) // void er_oled_char(uint8_t x, uint8_t y, const char *acsii, uint8_t mode)
{ uint8_t i,str;uint16_t OffSet;
x=x/4;
OffSet = (*acsii - 32)*16;
er_oled_SetWindow(x, y, x+1, y+15);
for (i=0;i<16;i++)
{
str =(AsciiLib[OffSet + i]); //Buydisplay
// str =(FontLib[OffSet + i]); //FontLib
if(mode) str=~str;
Data_processing (str);
}
}
void er_oled_string(uint8_t x, uint8_t y, const char *pString, uint8_t Mode)
{
while(1)
{
if (*pString == 0)
{
return;
}
er_oled_char(x, y, pString,Mode);
x += 8;
pString += 1;
}
}
void Data_processing(uint8_t temp) //turns 1byte B/W data to 4 bye gray data with 8 Pixel
{uint8_t temp1,temp2;
if(temp&0x80)temp1=0xf0;
else temp1=0x00;
if(temp&0x40)temp2=0x0f;
else temp2=0x00;
temp1=temp1|temp2;
data(temp1); //Pixel1,Pixel2
if(temp&0x20)temp1=0xf0;
else temp1=0x00;
if(temp&0x10)temp2=0x0f;
else temp2=0x00;
temp1=temp1|temp2;
data(temp1); //Pixel3,Pixel4
if(temp&0x08)temp1=0xf0;
else temp1=0x00;
if(temp&0x04)temp2=0x0f;
else temp2=0x00;
temp1=temp1|temp2;
data(temp1); //Pixel5,Pixel6
if(temp&0x02)temp1=0xf0;
else temp1=0x00;
if(temp&0x01)temp2=0x0f;
else temp2=0x00;
temp1=temp1|temp2;
data(temp1); //Pixel7,Pixel8
}
void er_oled_bitmap_mono(const uint8_t *pBuf)
{ uint8_t row,col,dat;
er_oled_SetWindow(0, 0, 255/4, 63);
for (row = 0; row < 64; row++) {
for(col = 0;col<256/8; col++ ) {
dat=(*pBuf);
pBuf++;
Data_processing(dat);
}
}
}
void er_oled_bitmap_gray(const uint8_t * pBuf)
{ uint8_t row,col;
er_oled_SetWindow(0, 0, 255/4, 63);
for (row = 0; row < 64; row++) {
for(col = 0;col<128; col++ ) {
data(*pBuf);
pBuf++;
}
}
}