element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • Experts & Guidance
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • 'Choose another store...'
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog LCD parallel driver using Pico PIO
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Raspberry Pi requires membership for participation - click to join
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
Raspberry Pi Wishlist
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: BigG
  • Date Created: 19 Sep 2022 11:26 AM Date Created
  • Views 4627 views
  • Likes 10 likes
  • Comments 13 comments
Related
Recommended
  • raspberry pi pico
  • lcd_screen
  • rp2040
  • PIO
  • oled character display

LCD parallel driver using Pico PIO

BigG
BigG
19 Sep 2022

Introduction

In this blog, I demonstrate how to use Raspberry Pi Pico’s Programmable IO (PIO) interface to drive an LCD module using either the 8-bit and 4-bit parallel data bus.

image

In this demo project I started with an FDCC0802B 8x2 LCD module (shown above) as I had one and I had modified it before to fit on my breadboard. Of course, a 16x2 LCD module would work equally as well here too.

I then progressed onto a 20x4 OLED Display (NHD-0420DZW-AY5) from Newhaven Displays, which also can be driven using the same driver firmware although I found it was not perfect and probably would need a few tweaks.

The reason behind this project was to help me learn more about the PIO interface than anything else. I am also sticking with C/C++ and I used the Arduino IDE and associated libraries to develop the project.

My LCD module controllers

So to start, here are the key specifications for the two LCD modules I used in this project.

Fordata FDCC0802B (8x2 LCD)

image

source: Fordata on-line LCD Module catalogue ( V6.0 )

According to the Fordata Electronic Co. COB(Chip On Board) SERIES on-line catalogue ( V6.0 ), the LCD module is controlled internally by the Sunplus SPLC780D LCD Controller (or equivalent). This controller is also compatible with the Hitatchi HD44780 driver, which can be found on many text-based LCDs.

Thus this LCD module is pin compatible and has a similar pin configuration, which can be broken down as follows:

  • Power
    • VSS: GND (pin 1)
    • Vdd: +5V (pin 2)
  • Control/Signal lines
    • V0: LCD Contrast Adjustment via a variable resistor (pin 3)
    • RS: Register Select informs controller whether the value to be received is a command (when set LOW) or is a display character (when set HIGH)
    • R/W: Want to read data (when set HIGH) or want to write data (when set LOW)
    • E: a pulse Enable Signal that causes the internal controller to read the value sent via the data bus.
  • Data Bus
    • DB0 - DB7 for 8 bit mode or DB4 - DB7 for 4 bit mode
  • LED Backlight
    • A: LED Anode (usually 5V with current limiting resistor added)
    • K: LED Cathode (GND)

Newhaven Display NHD-0420DZW-AY5 (20x4 Character OLED Display Module)

image

source: NHD_0420DZW_AY5-2953149.pdf

The NHD 20x4 character OLED display module is pin compatible with a standard 16x2 or 8x2 LCD module and similarly the same driver commands will also work. It is worth noting that there are some timing differences in terms of the internal processor "busy periods", which may or may not impact display performance. I did have to slow timings down a bit.

Pico Programmable Input Output (PIO)

I decided to start with the Arduino’s LiquidCrystal library as this library was developed for the Hitatchi HD44780 driver and is available for all Arduino compatible boards and is compatible with the above LCD modules I was planning to use.

After a review of the Arduino LiquidCrystal library and the datasheets I knew that in order to get the Pico’s PIO to drive all or parts of the LCD module, I had to mimic the LCD controller instruction sequence and bus timings to successfully write to the LCD module to display data.

image

source: Waveshare's LCD1602.pdf

Having reviewed a couple of different datasheets, it appears that they all have the following sequence characteristics with some minor minimal nanosecond timing differences, namely:

  • When the Register Select (RS) signal is set then there needs to be a minimum delay (tsu1) before the Enable signal can be changed from LOW to HIGH. In the above diagram the minimum delay time is 100ns.
  • The Enable pulse high signal has a minimal time it needs to stay high, which in the above diagram is shown as tw. The high signal needs to be at least 300ns long.
  • The Enable signal can only be pulsed again (shown in diagram as the cycle time (tc) after at least 500ns. Some driver datasheets have a minimum cycle time of 1000ns (1us).
  • The data sent to the 8 pin data bus (DB0-DB7) has to remain set for at least 80ns (a derive value, made up of tsu2 + tf + th2).

Based on the above diagram, I figured that there was probably no point getting the PIO to drive the RS signal as this only changes once to indicate if the data about to be sent is a command or is data to be displayed. But this needed further evaluation.

The HD44780 driver datasheet also provided a timing diagram for 4-bit mode operation, which informed me that the 1st (IR4-IR7) and 2nd (IR0-IR3) nibbles of data could be pulsed quickly before the busy read flag (BF) was set and then cleared.

image

The part that was unclear in the above diagram was the duration of internal operation, when the busy flag was set. Thankfully all the datasheets I reviewed provided timing guidance within an instruction table. Thus execution times depended on what commands were sent. For example, a Clear Display command would typically take up to 2ms to execute, while a Display ON/OFF Control command would typically take about 40us to complete.

So after a bit of thought, I decided to use PIO for the data bus as I could shift data in parallel using the PIO OUT command and I would use the PIO SET for the Enable signal as this was timing critical during operation.

Thus in my project, the R/W signal will be tied to ground as I am not checking the busy flag and I would then set the RS signal outside of the PIO using a GPIO to tell the LCD whether I am sending a command or writing data.

To get the PIO code started I began with the 8 bit mode as this transferred all data at once.

Here is the 8-bit databus PIO code:

.program data8Pins

; Shifts 8 bits of data to the LCD data pins d0, d1, d2, d3, d4, d5, d6, d7
; Use set pin (for ENABLE) to pulse.

set pindirs, 1              ; set ENABLE pin (set pins) as output
set pins, 0                 ; initialise ENABLE pin to 0
loop:
    pull block              ; wait for data

    ; --------------------------------------------------------------------
    ; shift data to the lcd data pins (8 bit mode)
    out pins, 8             ; shift last 8 bits from OSR to LCD data pins

    ; --------------------------------------------------------------------

    ; wait a short period (tsu1) before setting enable pin high to send the data to LCD
    set x 24                ; set x to 11000 (and clear the higher bits)
    mov ISR x               ; copy x to ISR
    in NULL 3               ; shift in 3 more 0 bits
    mov x ISR               ; move the ISR to x (now contains 11000 000)

delay1:
    jmp x-- delay1          ; count down to 0: a delay of (about) 1us

    set pins, 1             ; set ENABLE pin HIGH

    set x 24                ; set x to 11000 (and clear the higher bits)
    mov ISR x               ; copy x to ISR
    in NULL 3               ; shift in 3 more 0 bits
    mov x ISR               ; move the ISR to x (now contains 11000 000)
delay2:
    jmp x-- delay2          ; count down to 0: a delay of (about) 1us

    ; set ENABLE to LOW and wait a short period (> t cycle time)
    set pins, 0             ; set ENABLE pin LOW
    set x 20                ; set x to 11010 (and clear the higher bits)
    mov ISR x               ; copy x to ISR
    in NULL 4               ; shift in 4 more 0 bits
    mov x ISR               ; move the ISR to x (now contains 11010 0000)
delay3:
    jmp x-- delay3          ; count down to 0: a delay of (about) 1us

    set x 1
    mov ISR x
    push block              ; push a 1 to say complete
    jmp loop

The above PIO instruction sequence can be broken down into 4 steps:

  • It waits for data (PULL).
  • It shifts data to the 8 output pins (OUT Pins, 8).
  • It latches the data by setting the Enable pin high (SET pins, 1) and then low (SET pins, 0) with a specific timing sequence.
  • It pushes the Input Shift Register (PUSH), which has a dummy value, so say sequence is complete - this is to ensure that the next byte of data does not arrive too early.

With 4 bit mode I could make some improvement to the Arduino code as I could send 8 bits of data at once and then get the PIO to repeat the 4 bit pattern twice by shifting the MSB nibble (4 bits) of data first and then the LSB nibble of data. As the HD44780 driver datasheet 4-bit timing diagram showed, the delay between the two nibbles is shorter. So in this case I used the Y Scratch Register to create a repeat sequence in the PIO code.

.program data4Pins

; Shifts 4 bits of data to the LCD data pins d4, d5, d6, d7
; Use set pin (for ENABLE) to pulse.

set pindirs, 1              ; set ENABLE pin (set pins) as output
set pins, 0                 ; initialise ENABLE pin to 0

loop:
    pull block              ; wait for data
    set y 1                 ; used to repeat the cycle for 4 bit mode
repeat4bit:

    ; --------------------------------------------------------------------
    ; shift data to the lcd data pins (4 bit mode)
    out pins, 4             ; shift last 4 bits from OSR to LCD data pins

    ; --------------------------------------------------------------------

    ; wait a short period (tsu1) before setting enable pin high to send the data to LCD
    set x 24                ; set x to 11000 (and clear the higher bits)
    mov ISR x               ; copy x to ISR
    in NULL 3               ; shift in 3 more 0 bits
    mov x ISR               ; move the ISR to x (now contains 11000 000)

delay1:
    jmp x-- delay1          ; count down to 0: a delay of (about) 1us

    set pins, 1             ; set ENABLE pin HIGH

    set x 24                ; set x to 11000 (and clear the higher bits)
    mov ISR x               ; copy x to ISR
    in NULL 3               ; shift in 3 more 0 bits
    mov x ISR               ; move the ISR to x (now contains 11000 000)
delay2:
    jmp x-- delay2          ; count down to 0: a delay of (about) 1us

    ; set ENABLE to LOW and wait a short period (> t cycle time)
    set pins, 0             ; set ENABLE pin LOW
    set x 20                ; set x to 10100 (and clear the higher bits)
    mov ISR x               ; copy x to ISR
    in NULL 4               ; shift in 4 more 0 bits
    mov x ISR               ; move the ISR to x (now contains 10100 0000)
delay3:
    jmp x-- delay3          ; count down to 0: a delay of (about) 1us

    jmp y-- repeat4bit      ; repeat 4bit data shift one more time

    set x 1
    mov ISR x
    push block              ; push a 1 to say complete
    jmp loop
    

I then created a custom PIO initialisation routine that would handle both 4-bit or 8-bit shift mode.

static inline void LCDPIO_program_init(PIO pio, uint sm, uint offset, uint Basepin, uint Setpin, uint bitmode) {

    // Ensure that the state machine is not running before config
    pio_sm_set_enabled(pio, sm, false);
    pio_sm_clear_fifos(pio, sm);
    pio_sm_restart(pio, sm);

    pio_sm_config c = data4Pins_program_get_default_config(offset);
    if  (bitmode == 8) c = data8Pins_program_get_default_config(offset);

    // Initialise all the pin's GPIO function (connect PIO to the pad)

    for (uint i = 0; i < bitmode; i++) pio_gpio_init(pio, Basepin+i);

    pio_gpio_init(pio, Setpin);

    // Map the DATA PINS state machine's OUT pin group to one pin, namely the `Basepin_DP`
    sm_config_set_out_pins(&c, Basepin, bitmode);

    // Define the output shift direction for the DP pins - set at 8 (max shift for both 4-bit and 8-bit transfer)
    sm_config_set_out_shift(&c, true, true, 8);

    // Map the ENABLE state machine's SET pin group to one pin, namely the `Setpin_ENABLE`
    sm_config_set_set_pins(&c, Setpin, 1);
    // Set all the DP pin directions to output at the PIO
    pio_sm_set_consecutive_pindirs(pio, sm, Basepin, bitmode, true);
    // Load our configurations, and jump to the start of the program
    pio_sm_init(pio, sm, offset, &c);
    // Now enable the 2 state machines to run
    pio_sm_set_enabled(pio, sm, true);
}

With the PIO code out the way, I needed to work out how to incorporate the PIO into the Arduino LiquidCrystal library, as there was no point reinventing the wheel and starting from scratch. It turned out to be quite straightforward.

Modified Arduino LiquidCrystal library

The first step was to amend the parameters found within the LiquidCrystal class constructor as the DB0 to DB7 pins and the Enable Pin would be defined within PIO. This was achieved by creating a separate PIO class and a simple constructor, as follows:

/*************************************************************************
 @brief Constructor
 @param AllocatedPio: reference to chosen PIO
*************************************************************************/
LCDPicoPIO::LCDPicoPIO(PIO AllocatedPio, uint8_t bitmode):
    pio(AllocatedPio)

{
	  offset_DP = 0;

	  if (pio == pio0 || pio == pio1) {
      // Check to see if pio can be added
      pio_clear_instruction_memory (pio);
      if (bitmode == LCD_4BITMODE) {
        mode = true;
        if (pio_can_add_program(pio, &data4Pins_program)) {
          offset_DP = pio_add_program(pio, &data4Pins_program);
        }
        else offset_DP = -1;       // failed could not get a valid memory offset value

      }
      else if (bitmode == LCD_8BITMODE) {
      mode = false;
        if (pio_can_add_program(pio, &data8Pins_program)) {
          offset_DP = pio_add_program(pio, &data8Pins_program);
        }
        else offset_DP = -1;       // failed could not get a valid memory offset value

      }
	  }
}

// @brief Destructor
LCDPicoPIO::~LCDPicoPIO(){}

LiquidCrystal_PicoPIO::LiquidCrystal_PicoPIO(LCDPicoPIO &PicoPio, const uint8_t rs, const uint8_t en, const uint8_t basepin):
  _PicoPio(PicoPio), _rs_pin(rs), _enablePin(en), _basePin(basepin)
  {

    _error = 1;
    if (_PicoPio.offset_DP > 0) {
        _smDP = pio_claim_unused_sm(_PicoPio.pio, false);
        if (_smDP >= 0) {

          if (_PicoPio.mode) NumPins = 4;
          else NumPins = 8;

          LCDPIO_program_init(_PicoPio.pio, _smDP, _PicoPio.offset_DP, _basePin, _enablePin, NumPins);
          // PIO Program initialised - now set up some defaults
          // Assume 4 bit mode only (for now)
          _error = 0;

          LCD_init(_PicoPio.mode);

        }
        else _error = -1;     // failed to get sm
    }
  }

// @brief Destructor
LiquidCrystal_PicoPIO::~LiquidCrystal_PicoPIO(){}

The second step was to amend two private functions write4bits(uint8_t) and write8bits(uint8_t) as this is where my code would push data to the PIO to drive the LCD. In fact it turned out that it was simpler just to call the PIO routine from the send function using a new single writeDB function.

/************ low level data pushing commands **********/

// write either command or data, with automatic 4/8-bit selection
void LiquidCrystal_PicoPIO::send(uint8_t value, uint8_t mode) {

  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }

  if (_displayfunction & LCD_8BITMODE) {
    writeDB(value);

  } else {

    writeDB((value<<4 & 0xff) | (value>>4 & 0xff));

  }

}


void LiquidCrystal_PicoPIO::writeDB(uint8_t value) {

  /********* PIO Function call **************/
  /******************************************/

  pio_sm_put_blocking(_PicoPio.pio, _smDP, value);
  pio_sm_get_blocking(_PicoPio.pio, _smDP);

}

And finally the third and last step was to delete the pulseEnable() function as this was all handled inside the PIO routine.

LCD module demos

Fordata FDCC0802B (8x2 LCD)

This module works in either 8 bit mode or 4 bit mode. Here is the 8-bit mode in operation.

/*
  LiquidCrystal Library - Custom Characters

 Demonstrates how to add custom characters on an LCD  display.
 The LiquidCrystal library works with all LCD displays that are
 compatible with the  Hitachi HD44780 driver. There are many of
 them out there, and you can usually tell them by the 16-pin interface.

 This sketch prints "I <heart> Arduino!" and a little dancing man
 to the LCD.

 created 21 Mar 2011
 by Tom Igoe
 modified 11 Nov 2013
 by Scott Fitzgerald
 modified 7 Nov 2016
 by Arturo Guadalupi

 Based on Adafruit's example at
 https://github.com/adafruit/SPI_VFD/blob/master/examples/createChar/createChar.pde

 This example code is in the public domain.
 http://www.arduino.cc/en/Tutorial/LiquidCrystalCustomCharacter

 Also useful:
 http://icontexto.com/charactercreator/

*/

// include the library code:
#include <LiquidCrystal_PicoPIO.h>

// define the pin numbers:
static const int RS_PIN =     20;
static const int EN_PIN =     21;
static const int BASE_PIN =   12;

// This class will provide the PIO memory offset for the capsensing PIO (only need once)
// Bitmode parameter is optional (default is LCD_4BITMODE). Bitmode determines which PIO routine to use
LCDPicoPIO PicoPIO(pio0, LCD_8BITMODE);
LiquidCrystal_PicoPIO lcd(PicoPIO, RS_PIN, EN_PIN, BASE_PIN);


// make some custom characters:
static byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};

static byte armsDown[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b00100,
  0b01110,
  0b10101,
  0b00100,
  0b01010
};

static byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};

static int delayTime = 0;
static uint8_t i = 0;
bool ManArmsDown = true;
char lcdbuff1[8];
char lcdbuff2[8];

void setup() {
  // initialize LCD and set up the number of columns and rows:
  lcd.begin(8, 2);

  // create a new character
  lcd.createChar(0, heart);
  // create a new character
  lcd.createChar(1, armsDown);
  // create a new character
  lcd.createChar(2, armsUp);

  // set the cursor to the top left
  lcd.setCursor(0, 0);

  // Print a message to the lcd.
  lcd.print("I ");
  lcd.write(byte(0)); // when calling lcd.write() '0' must be cast as a byte
  lcd.print(" e14! ");

  delay(1000);
  randomSeed(analogRead(A0));

}

void loop() {

  delayTime = random(200, 2000);
  // set the cursor to the bottom row, 5th position:
  lcd.setCursor(0, 1);

  memset(lcdbuff1, '\0', 8);
  memset(lcdbuff2, '\0', 8);
  if (i) {
    sprintf(lcdbuff1, "%*s", i, "");
    lcd.print(lcdbuff1);
  }
  // draw the little man, arms down:
  if (ManArmsDown) lcd.write(1);
  else lcd.write(2);
  ManArmsDown =  !ManArmsDown;

  if (i < 7) {
    sprintf(lcdbuff2, "%*s", 6-i, "");
    lcd.print(lcdbuff2);
  }

  delay(delayTime);

  if (i < 8) i++;
  else i = 0;

}

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

Newhaven Display NHD-0420DZW-AY5 (20x4 LCD)

image

The same cannot be said with this module. Whilst the NHD OLED module is pin compatible and the same LiquidCrystal library works (successfully tested using Arduino UNO), I simply could not get anything displayed on the screen.

Talk about frustration. I kept thinking there was something wrong with my code, but it turned out to be a power problem and once I had reduced the voltage a fraction, it worked.

As I don’t have a variable desktop power supply, I decided to improvise by using different dev boards as my power source. Here are the results of my power source experiments:

  • Raspberry Pi Pico USB Vbus pin: V5.13 (Does not work).
  • Raspberry Pi Pico USB Vbus pin through diode: V4.3 (works although row text issue more common - see below).
  • Arduino Duemilanove Vin pin: V4.56 (works).
  • Arduino Duemilanove 5V pin: V5.08 (Does not work).
  • FRDM-KL25Z Vin pin: V4.70 (works).
  • FRDM-KL25Z 5V pin: V5.06 (works)

So I determined that the voltage drop across Vss and Vdd could range from 4.3V up to 5.06V. I also discovered that I could operate this module at below the recommended voltage of 4.8V although I suspect (can’t say for certain) that voltage causes the quirk described below.

Yes, there was still one thing that was perplexing. For some reason the rows of text displayed often get jumbled. So for example row 1 text is displayed in row 2, and vice versa, and row 3 text is displayed in row 4, and vice versa. The problem is that it is not consistent. So every now and then it switches back to normal.

The other quirk that I have not sorted is creating and displaying customer characters correctly. But I am sure this can be resolved by digging deeper into the datasheet. It was something I observed but did not investigate further.

Other than these quirks, it almost works seamlessly.

Here is a demo of the Pico-W driving this 20x4 character OLED module (hint this is a precursor to another project - a Passenger Information Display to show my local train arrival/departure times at home).

/*
 LiquidCrystal Library

 Demonstrates the use on a 20x4 NHD character OLED display.
  
 This sketch prints out four lines of text to the LCD
 and then clears the screen to show another four lines of text etc.

 The text was obtained from an example developed by Newhaven Displays
 and their code was used as guidance. Source:
 https://support.newhavendisplay.com/hc/en-us/articles/4413878167191-NHD-0420DZW-6800-4-Bit-8-Bit-with-Arduino
 
*/

// include the library code:
#include <LiquidCrystal_PicoPIO.h>

// define the pin numbers:
static const int RS_PIN =     10;
static const int EN_PIN =     11;
static const int BASE_PIN =   16;

/****************************************************
*                 Text Strings                      *
****************************************************/

static char const text1[] = ("  Newhaven Display  ");
static char const text2[] = ("   International    ");
static char const text3[] = ("   CHARACTER TEST   ");

static char const text4[] = ("   4-Bit Parallel   ");
static char const text5[] = ("   8-Bit Parallel   ");

static char const text6[] = ("ABCDEFGHIJKLMOPQRSTU");
static char const text7[] = ("VWXYZabcdefghijklmno");
static char const text8[] = ("pqrstuvwxyz123456789");
static char const text9[] = (" <(' ')> || <(' ')> ");

// This class will provide the PIO memory offset for the capsensing PIO (only need once)
LCDPicoPIO PicoPIO(pio0, LCD_4BITMODE);
LiquidCrystal_PicoPIO lcd(PicoPIO, RS_PIN, EN_PIN, BASE_PIN);

uint32_t t_start = 0;

void setup() {
  delay(300);
  // set up the LCD's number of columns and rows:
  lcd.begin(20, 4);

  lcd.home(); 
  lcd.clear();

  lcd.home(); 
  lcd.clear();

  // Print a message to the LCD.
  lcd.setCursor(0, 0);
  lcd.print(text1);
  lcd.setCursor(0, 1);
  lcd.print(text2);
  lcd.setCursor(0, 2);
  lcd.print(text3);
  lcd.setCursor(0, 3);
  lcd.print(text4);

  delay(5000);
  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print(text6);
  lcd.setCursor(0, 1);
  lcd.print(text7);
  lcd.setCursor(0, 2);
  lcd.print(text8);
  lcd.setCursor(0, 3);
  lcd.print(text9);

  delay(5000);
  
  lcd.home(); 
  lcd.clear();

  lcd.home(); 
  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.setCursor(0, 0);
  lcd.print(F("Hello Element14."));
  // set the cursor to the top left
  lcd.setCursor(0, 1);
  // Print a message to the lcd.
  lcd.print(F("I love electronics!"));
  
  //lcd.write(byte(1)); // when calling lcd.write() '0' must be cast as a byte
  delay(5000);

  t_start = millis();
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 2);
  // print the number of seconds since reset:
  lcd.print((millis()-t_start) / 1000);
  
}

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

  • Sign in to reply
  • BigG
    BigG over 1 year ago

    Came up with a quick fix for the Newhaven Display row order issue... involves a little test at setup and some manual intervention using a micro switch and 1 GPIO.

    You don't have permission to edit metadata of this video.
    Edit media
    x
    image
    Upload Preview
    image

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz over 1 year ago in reply to shabaz

    (can't edit): I meant "It works with 3.3V or 5V supplies"

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz over 1 year ago in reply to BigG

    This one is not bad, I've used it before, but it's only 16x2 so probably won't meet your needs:  https://thepihut.com/products/rgb-16x2-i2c-lcd-display-3-3v-5v

    It works with both 3.3V and 4V supplies and has a RGB backlight which is very neat, but the text is not anywhere near as clear as the OLED (nor as clear as some more higher-end LCD displays either). For non-OLED, check out these 'VATN' displays, they are impressive, they visually look like OLED in real life (very close anyway):

    https://uk.farnell.com/midas/mc21605g12w-vnmly/lcd-alpha-num-16-x-2-yellow-green/dp/2483339

    Depressing how expensive it gets finding nice large displays!

    I bought a large TFT recently, and smashed it when it fell by a few inches (onto a glass surface) before I even powered it up! : ) Luckily, the cracks were on the touch glass portion (which I didn't want anyway) and I was able to remove that layer by heating the edges of the glass.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • BigG
    BigG over 1 year ago in reply to shabaz

    I've just done some online searching and it appears that Newhaven Displays have another option (NHD-0420CW-AY3), which allows for a lower operating voltage - down to 2.8V. That would, no doubt, be a more reliable choice. This product also allows for I2C operation (at 2.8V only).

    image

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz over 1 year ago in reply to BigG

    Interestingly, sometimes I've got it very wrong but the logic levels have worked. For instance, a claimed datasheet 0.8*VDD at 5V sometimes may work completely well at 25 deg C 100% of the time at 3.3V logic interfacing despite being powered at 5V : ) That would be ok for a prototype one-off or very non-critical ultra-cheap application where items can be rejected if they occasionally fail perhaps! : ) Not good for a proper design of course. Example is TLC5620 running at 5V, which has datasheet spec of 0.8*VDD, but seems to reliably be controllable with 3.3V devices.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube