question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

winstar eh1602a SPI interface

See original GitHub issue

Type of Raspberry Pi

Pi 3 Model B+

Linux Kernel version

Linux moode 5.4.72-v7+ #1356 SMP Thu Oct 22 13:56:54 BST 2020 armv7l GNU/Linux

Expected behaviour

I would like to render text on the display. I already tested the display with an arduino with spi and parallel interface and both works. Here ist the arduino code for the spi interface

#define SPIPORT (PORTB)
#define SPITOGGLE (PINB)
// PB5 (0x20) is SCK  (output) green  OLED pin 12
#define SPI_SCK_PIN (13)
#define SCK_MASK (0x20)
#define CLR_SCK (PORTB &= ~(SCK_MASK))
#define SET_SCK (PORTB |=  (SCK_MASK))
// PB4 (0x10) is MISO (input)  blue   OLED pin 13
//(reference only, it is an input)
#define SPI_MISO_PIN (12)
#define MISO_MASK (0x10)
#define CLR_MISO (PORTB &= ~(MISO_MASK))
#define SET_MISO (PORTB |=  (MISO_MASK))
// PB3 (0x08) is MOSI (output) violet OLED pin 14
#define SPI_MOSI_PIN (11)
#define MOSI_MASK (0x08)
#define CLR_MOSI (PORTB &= ~(MOSI_MASK))
#define SET_MOSI (PORTB |=  (MOSI_MASK))
// DB2 (0x04) is SS   (output) gray   OLED pin 16
#define SPI_SS_PIN (10)
#define SS_MASK (0x04)
#define CLR_SS  (PORTB &= ~(SS_MASK))
#define SET_SS  (PORTB |=  (SS_MASK))

#define DATA (1)
#define COMMAND (0)
//===========================================================================
void write_to_OLED_SPI(uint8_t destination,uint8_t data)
  {
  //Bits sent in this order:
  //  data(1)/command(0) flag
  //  read(1)/write(0) flag
  //  data.7 (msb)
  //  data.6
  //  data.5
  //  data.4
  //  data.3
  //  data.2
  //  data.1
  //  data.0 (lsb)

#if(1)
  //Pretty fast software SPI 10-bit transfer code
  //Several ideas taken from the fastest non-assembly implementation at:
  //http://nerdralph.blogspot.com/2015/03/fastest-avr-software-spi-in-west.html
  //
  // The SS pin is low for ~3.8uS, the clock frequency is ~ 2.6MHz
  // 47x faster than above

  //Pre-calculate the value that will drive clk and data low in one cycle.
  //(Note that this is not interrupt safe if an ISR is writing to the same port)
  register uint8_t
    force_clk_and_data_low;

  //Select the chip
  CLR_SS;

  //Pre-calculate the value that will drive clk and data low in one
  //operation.
  force_clk_and_data_low = (SPIPORT & ~(MOSI_MASK | SCK_MASK) );

  //Set clock and data low
  SPIPORT = force_clk_and_data_low;
  //Set the data(1)/command(0) flag
  if(DATA==destination)
    {
    SPITOGGLE = MOSI_MASK;
    }
  //Use a toggle to bring the clock up
  SPITOGGLE = SCK_MASK;

  //Set clock and data low
  SPIPORT = force_clk_and_data_low;
  //MOSI is already 0, for read(1)/write(0) flag as write
  //Use a toggle to bring the clock up
  SPITOGGLE = SCK_MASK;

  //Now clock the 8 bits of data out
  SPIPORT = force_clk_and_data_low;
  if(data & 0x80)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x40)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x20)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x10)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x08)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x04)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x02)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;
  SPIPORT = force_clk_and_data_low;
  if(data & 0x01)
    SPITOGGLE = MOSI_MASK;
  SPITOGGLE = SCK_MASK;

  //Release the chip
  SET_SS;
#else
  //Straight-forward software SPI 10-bit transfer code, perhaps
  //easier to understand, possibly more portable. Certainly slower.
  //
  // The SS pin is low for ~180uS, the clock frequency is ~57KHz
  // 47x slower than above

  //Select the chip, starting a 10-bit SPI transfer
  digitalWrite(SPI_SS_PIN, LOW);

  //(bit 0) Set the data(1)/command(0) flag
  if(DATA==destination)
    digitalWrite(SPI_MOSI_PIN, HIGH);
  else
    digitalWrite(SPI_MOSI_PIN, LOW);
  //Clock it in.
  digitalWrite(SPI_SCK_PIN, LOW);
  digitalWrite(SPI_SCK_PIN, HIGH);

  //(bit 1) Clear the read(1)/write(0) flag to write, clock it in.
  digitalWrite(SPI_MOSI_PIN, LOW);
  //Clock it in.
  digitalWrite(SPI_SCK_PIN, LOW);
  digitalWrite(SPI_SCK_PIN, HIGH);

  //(bits 2-9) Push each of the 8 data bits out.
  for(uint8_t mask=0x80;mask;mask>>=1)
    {
    //Set the MOSI pin high or low depending on if our mask
    //corresponds to a 1 or 0 in the data.
    if(mask&data)
      {
      digitalWrite(SPI_MOSI_PIN, HIGH);
      }
    else
      {
      digitalWrite(SPI_MOSI_PIN, LOW);
      }
    //Clock it in.
    digitalWrite(SPI_SCK_PIN, LOW);
    digitalWrite(SPI_SCK_PIN, HIGH);
    }

  //Release the chip, ending the 10-bit SPI transfer
  digitalWrite(SPI_SS_PIN, HIGH);
#endif
  }
//===========================================================================
void position_cursor(uint8_t column, uint8_t line)
  {
  //Set CGRAM Address, RS=0,R/W=0
  // 7654 3210
  // 1AAA AAAA
  //  0x00 to 0x27 => Line 1
  //  0x40 to 0x67 => Line 2
  write_to_OLED_SPI(COMMAND,0x80 | (line?0x40:0x00) | (column & 0x3F));
  }
//===========================================================================
// According to the WS0010 data sheet, only the clear display time has
// an appreciable execution time of 6mS. All others are listed at 0.
void clear_display(void)
  {
  //Display Clear RS=0,R/W=0
  // 7654 3210
  // 0000 0001
  write_to_OLED_SPI(COMMAND,0x01);
  _delay_ms(6);
  }
//===========================================================================
void initialize_display()
  {
  //Refer to WS0010 data sheet, page 21
  // https://www.crystalfontz.com/products/document/3176/WS0010.pdf

  //The display controller requests:
  //  "Wait for power stabilization 500ms:
  _delay_ms(500);

  //Function set, RS=0,R/W=0
  // 7654 3210
  // 0011 NFFT
  //  N = lines: N=1 is 2 lines
  //  F = Font: 0 = 5x8, 1 = 5x10
  //  FT = Font Table:
  //     FT=00 is English/Japanese ~"standard" for character LCDs
  //     FT=01 is Western European I fractions, circle-c some arrows
  //     FT=10 is English/Russian
  //     FT=11 is Western European II my favorite, arrows, Greek letters
  write_to_OLED_SPI(COMMAND,0x3B);

  //Graphic vs character mode setting, RS=0,R/W=0
  // 7654 3210
  // 0001 GP11
  //  G = Mode: 1=graphic, 0=character
  //  C = Power: 1=0n, 0=off
  write_to_OLED_SPI(COMMAND,0x17);

  //Display On/Off Control RS=0,R/W=0
  // 7654 3210
  // 0000 1DCB
  //  D = Display On
  //  C = Cursor On
  //  B = Cursor Blink
  write_to_OLED_SPI(COMMAND,0x0E);

  //Display Clear RS=0,R/W=0
  // 7654 3210
  // 0000 0001
  clear_display();

  //Display home
  write_to_OLED_SPI(COMMAND,0x02);

  //Entry Mode Set RS=0,R/W=0
  // 7654 3210
  // 0000 01IS
  //  I = Increment/or decrement
  //  S = Shift(scroll) data on line
  write_to_OLED_SPI(COMMAND,0x06);

  //Display Clear RS=0,R/W=0
  // 7654 3210
  // 0000 0001
  clear_display();
  }
//===========================================================================
void setup()
  {
  //General setup, port directions.

  // PB5 (0x20) is SCK  (output) green  OLED pin 12
  pinMode(SPI_SCK_PIN, OUTPUT);
  // PB4 (0x10) is MISO (input)  blue   OLED pin 13
  //(reference only, it is an input)
  pinMode(SPI_MISO_PIN, INPUT);
  // PB3 (0x08) is MOSI (output) violet OLED pin 14
  pinMode(SPI_MOSI_PIN, OUTPUT);
  // DB2 (0x04) is SS   (output) gray   OLED pin 16
  pinMode(SPI_SS_PIN, OUTPUT);
  }
//===========================================================================
void loop()
  {
  //Simple demo loop, shows a screen of text, including high order characters
  //( see page 10 of https://www.crystalfontz.com/controllers/WinstarDisplay/WS0010/378 )
  //
  //Then there is a screen with solid characters on the left, and 50%
  //checkerboard characters on the right.

  // Initialize the display
  initialize_display();

  //Display text screen
  //              0123456789012345
  char line1[17]=">}CRYSTALFONTZ{<";
  line1[ 0]=0xF6; // right triange;
  line1[ 1]=0xC7; // right triange;
  line1[14]=0xC8; // left triange;
  line1[15]=0xF7; // left triange;

  //              0123456789012345
  char line2[17]="OLED:aaaaaaaaaaS";
  line2[ 5]=0xE0; //beta
  line2[ 6]=0xA8; //function
  line2[ 7]=0xB8; //divide
  line2[ 8]=0xDA; //sigma
  line2[ 9]=0xEA; //mu (micro)
  line2[10]=0xDF; //alpha
  line2[11]=0xDE; //omega
  line2[12]=0xCF; //circle C
  line2[13]=0x1A; //about equal
  line2[14]=0xED; //pi

  // write to the first line
  position_cursor(0,0);
  for(int col=0;col<16;col++)
    {
    write_to_OLED_SPI(DATA,line1[col]);
    }

  // write to the second line
  position_cursor(0,1);
  for(int col=0;col<16;col++)
    {
    write_to_OLED_SPI(DATA,line2[col]);
    }

  //Show the text message for a bit
  _delay_ms(1000);

  //Use the custom characters (CGRAM) to make the
  //left half solid, the right half checkerboard

  //Set CGRAM [0], to solid
  write_to_OLED_SPI(COMMAND,0x40 | (0 <<3));
  for(int i=1;i<=8;i++)
  write_to_OLED_SPI(DATA,0xFF);
  //Set CGRAM [1], checkerboard
  write_to_OLED_SPI(COMMAND,0x40 | (1 <<3));
  for(int i=1;i<=4;i++)
    {
    write_to_OLED_SPI(DATA,0xAA);
    write_to_OLED_SPI(DATA,0x55);
    }

  // write to the first line
  position_cursor(0,0);
  for(int col=0;col<8;col++)
    {
    write_to_OLED_SPI(DATA,0);  // CGRAM[0]
    }
  for(int col=8;col<16;col++)
    {
    write_to_OLED_SPI(DATA,1);  // CGRAM[1]
    }

  // write to the second line
  position_cursor(0,1);
  for(int col=0;col<8;col++)
    {
    write_to_OLED_SPI(DATA,0);  // CGRAM[0]
    }
  for(int col=8;col<16;col++)
    {
    write_to_OLED_SPI(DATA,1);  // CGRAM[1]
    }

  //Show the pattern for a bit
  _delay_ms(1000);
  }
//=====================================

Actual behaviour

Nothing happens with following code:

from time import sleep
from luma.core.interface.serial import spi
from luma.oled.device import ws0010

p = spi(device=0, port=0)
d = ws0010(p, selected_font='FT01')
sleep(2)
d.text = 'HELLO'
sleep(10)

I use the 3-wire SPI and connected through a logic level converter SCK, MISO, MOSI, SS (CE0), VSS, VDD. Maybe I missing something like the Data/Command Pin which I want to use inline instead of a extra pin.

My goal is to use the pydPiper lib somehow. The pydPiper lib doesn’t support SPI yet but I saw @dhrone pushing some code here.

Regards

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:10

github_iconTop GitHub Comments

1reaction
ghostcommented, Nov 12, 2020

Solved it!. Rearranged the RS and E pin away from GPIO7/8 which are the SPI pins (SPI is deactivated) and it works now. Startes rearranging because I checked my soundcard pins usage…

0reactions
dhronecommented, Nov 12, 2020

Excellent news. Interesting about GPIO pins 7/8. While their use shouldn’t matter if SPI is not enabled perhaps the documentation should be updated to avoid pins that have special purposes. I would still be interested in any materials that you have discovered that describe the SPI interface capabilities of the weh001602a.

Read more comments on GitHub >

github_iconTop Results From Across the Web

WEH001602A - Winstar Display
There are different interfaces optional for this model; its default 6800, available options 8080 and SPI. All Winstar standard COB OLED Character types...
Read more >
WEH001602A 16X2 COB OLED Character Display 5V ...
There are different interfaces optional for this model; its default 6800, available options 8080 and SPI. All Winstar standard COB OLED Character types...
Read more >
Winstar WEH1602 OLED display - SPI - Raspberry Pi Forums
Hello all, I'm working on Winstar WEH1602 OLED display in SPI mode (something like this: http://www.adafruit.com/products/823).
Read more >
Interface Winstar OLEDs using the SPI interface - PICAXE Forum
... datasheet for the Winstar OLEDs that Rev-Ed sell as part of the AXE133Y should have noticed a brief mention of the SPI...
Read more >
О подключении и работе с текстовыми OLED-дисплеями ...
В HD44780 встроенный резет, возможно, оправдан — автор не имеет достаточно опыта работы с ЖК-экранами, чтобы утверждать это наверняка. Но Winstar, пытаясь в ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found