Closed ghost closed 4 years ago
Have you tried testing your weh001602a with Luma.Oled using the parallel style interface?
I do not have any documentation on how to drive a Winstar weh001602a using SPI. If you could point me in the direction of some it will help me to determine if there is something I can recommend. Also, it would be helpful to know how you had the display wired to your arduino when running the above code.
I also tried the parallel interface with luma.oled but I got nothing on the display. I tried it with 3V and 5V and four data wires (d4-d7) like in the examples but without a logic level converter because mine only has 4 connections.
The connection to the arduino with SPI: Arduino <-> Display 13 <-> 12 (SCK) 12 <-> 13 (MISO) 11 <-> 14 (MOSI) 10 <-> 16 (SS)
The connection in parallel mode on the raspberry was like in the luma.oled example https://luma-oled.readthedocs.io/en/latest/hardware.html#parallel
I also tried the pydPiper docker image with no results. The fonts took a really long time to load and the container did nothing else. I already used a hd44780 display which worked without any problems.
That is odd. I note that your issue title says you are using the eh1602a. I had thought that was a typo and that you were actually using a weh1602a. Those displays do not use pins 15 and 16. Could you confirm the display you are using? For what it's worth, I am also unaware that the weh1602a supports an SPI interface but would happy to be corrected.
The original weh001602a has a SPI interface, see here https://www.winstar.com.tw/products/oled-module/oled-character-display/weh001602a.html But it's unusual to use I think. It took me some time to find the working arduino example :) It's not a original winstar display but it looks the same and uses the same pinout. The pins 15 and 16 probably won't get used in parallel mode.
I see that it is available as an option but there is no description as to how it is implemented on the device making it very difficult to determine how to guide you. SPI is a relatively loose standard so having clear documentation on how the SPI for your display is implemented is important for debugging your problem.
It is possible that your SPI implementation is using a different mode assumption than the spidev based implementation that Luma uses. You may want to try using different SPI modes. There are four possible values (0, 1, 2, 3) which can be specified using the spi_mode argument of class spi.
p = spi(device=0, port=0, spi_mode=n)
where n is an integer in the range 0-3
That said, I know that the weh001602a works correctly using the 4 bit parallel wiring provided in the documentation. Perhaps we should focus on getting your display set up using that method.
I tried the spi_mode option and used the reset_release_time and reset_hold_time with one second with no result. Ok let's try the parallel mode. I will solder the jumpers later and attach an image with the wiring.
Okay I resoldered the display and verified it's working with the arduino on 3v.
Arduino setup as picture.
I connected the pins exactly like here https://luma-oled.readthedocs.io/en/latest/hardware.html#parallel Using the following code, nothing happens :)
from time import sleep
from luma.core.interface.parallel import bitbang_6800
from luma.oled.device import winstar_weh
p = bitbang_6800(RS=7, E=8, PINS=[25,24,23,27])
d = winstar_weh(p, width=16, height=2, selected_font='FT01')
sleep(2)
d.text = 'HELLO'
sleep(10)
Maybe there is something wrong with the initialization process?
The process on the arduino with the Adafruit_CharacterOled
lib looks like this:
void Adafruit_CharacterOLED::begin(uint8_t cols, uint8_t lines, uint8_t character_set = LCD_JAPANESE)
{
_numlines = lines;
_currline = 0;
pinMode(_rs_pin, OUTPUT);
pinMode(_rw_pin, OUTPUT);
pinMode(_enable_pin, OUTPUT);
digitalWrite(_rs_pin, LOW);
digitalWrite(_enable_pin, LOW);
digitalWrite(_rw_pin, LOW);
delayMicroseconds(50000); // give it some time to power up
// Now we pull both RS and R/W low to begin commands
for (int i = 0; i < 4; i++) {
pinMode(_data_pins[i], OUTPUT);
digitalWrite(_data_pins[i], LOW);
}
// Initialization sequence is not quite as documented by Winstar.
// Documented sequence only works on initial power-up.
// An additional step of putting back into 8-bit mode first is
// required to handle a warm-restart.
//
// In the data sheet, the timing specs are all zeros(!). These have been tested to
// reliably handle both warm & cold starts.
// 4-Bit initialization sequence from Technobly
write4bits(0x03); // Put back into 8-bit mode
delayMicroseconds(5000);
if(_oled_ver == OLED_V2) { // only run extra command for newer displays
write4bits(0x08);
delayMicroseconds(5000);
}
write4bits(0x02); // Put into 4-bit mode
delayMicroseconds(5000);
write4bits(0x02);
delayMicroseconds(5000);
write4bits(0x08 | character_set);
delayMicroseconds(5000);
command(0x08); // Turn Off
delayMicroseconds(5000);
command(0x01); // Clear Display
delayMicroseconds(5000);
command(0x06); // Set Entry Mode
delayMicroseconds(5000);
command(0x02); // Home Cursor
delayMicroseconds(5000);
command(0x0C); // Turn On - enable cursor & blink
delayMicroseconds(5000);
}
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...
fyi: JustBoom DAC HAT Functional pin occupancy (GPIO numbers): RS -> 12 E -> 5 D4 -> 20 D5 -> 16 D6 -> 13 D7 -> 6 GND -> GND VDD -> 3.3V
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.
Type of Raspberry Pi
Linux Kernel version
Expected behaviour
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); } //=====================================
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)