WeMos M0 / LCD shield incompatibility

I am currently developing an Arduino application that requires the use of an LCD 1602 shield with the corresponding Up/Down/Left/Right/Select buttons. I have two shields, a generic one and one badged D1 Robot, although I suspect this is not the genuine article. My code runs perfectly with either of these two shields attached directly to the board(s), but only with the following Arduino models:

  • Genuine Uno
  • Geekcreit Uno
  • Elegoo Mega 2560

So far, so good. I then purchased the WeMos SAMD21 M0 and a Segger J-link mini so that I could further debug my code in PlatformIO, and this works like a charm. However, the LCD will not display any characters, even with the most bare-bones "Hello World example" either with the J-link connected or disconnected. The backlight does work and can be adjusted via the on-board potentiometer. Examining the WeMos against the other boards, everything appears to be pin-for-pin compatible, and there are no suspect solder joints on the board(s). The pin assignments I use in my code are as follows:

#include <LiquidCrystal.h>

const String PROG_name = "Program";
const String PROG_ver = "Dev 0.0";

// LCD pin assignment

const int pin_RS = 8;
const int pin_EN = 9;
const int pin_d4 = 4;
const int pin_d5 = 5;
const int pin_d6 = 6;
const int pin_d7 = 7;
const int pin_BL = 10;

// This works on all other Arduinos apart from the WeMos Zero 

LiquidCrystal lcd(pin_RS, pin_EN, pin_d4, pin_d5, pin_d6, pin_d7);

void setup()
{

  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print(PROG_name + " " + PROG_ver);
  lcd.setCursor(0, 1);
  lcd.print("Press Key:");
}
void loop()
{
}

I have tried uploading this code both via PlatformIO and and Arduino IDE to no avail. I'm running in a Linux environment (Ubuntu 20.10 x86_64) and just using the standard Arduino LiquidCrystal library, and everything compiles fine with zero errors or warnings, even in verbose mode. The WeMos runs the standard "Blink" script OK.

I'm at a loss here as to what is causing this, and I really don't want to give up the luxury of debugging if I can at all help it. I'm happy to relocate the LCD off to a breadboard and use some jumpers to prove if it is a wiring issue, or for test purposes, if this will help.

Many thanks.

WeMos.txt (532 Bytes)

Hmmm. This discussion may be relevant.

old_holborn:
The backlight does work and can be adjusted via the on-board potentiometer.

That does not actually make sense! :grinning:

Thanks Paul, I had already seen that. As to the backlight, sorry, I meant the character brightness!

What that means is you can't take an existing sketch for say an AVR based board with UNO type connectors that used naked constants and just slap a "D" in front of the pin number since it will refer to a different physical pin.

This is the bit that confuses me, if the silk screen on the WeMos says the pinouts are identical to the Uno etc, surely this code will work across boards unless the underlying C library doesn't/can't reference the pins correctly? If that is indeed the case, wouldn't it just be a matter of recoding LiquidCrystal.h (or whatever) specifically for the WeMos?

It looks like I am going to have to break out with the multimeter and put the LCD on some flying leads and try and do some reverse engineering to prove if this is the case between boards. Unfortunately I don't have anything any more sophisticated to hand.

If I am right in my assertion that the library just needs a quick and dirty fix, I'm happy to put a diff up on GitHub if I get it to work. Or have I grasped the wrong end of the stick entirely?

old_holborn:
This is the bit that confuses me, if the silk screen on the WeMos says the pinouts are identical to the Uno etc, surely this code will work across boards unless the underlying C library doesn't/can't reference the pins correctly?

I very much doubt that the pinouts match. Bill has noted they do not in the WeMOS D1, and I would be almost surprised if they did for the WeMos SAMD21 M0.

It is an obvious limitation cramming a more powerful processor into the UNO format which I think is in itself, extremely limited. Of course, I do not have a SAMD21 M0 in any case. :grinning: I am an advocate of using Nanos where an ATmega328 is appropriate, a Pro Mini where you do not want USB and an ESP - and that not in the UNO form factor - where you want something more powerful, because it is just so cheap!

The previous discussion was about Wemos D1 R2 boards which contain an ESP8266 chip. The ESP8266 has limited GPIO pins and the "Uno format" board just duplicates certain Arduino pins e.g. SCK on D13, D5, SDA on D14, D4

I do not have the specific WeMos SAMD21 M0 board but other Chinese "M0 clones" use the M0_Pro pinout but with the Zero bootloader. They omit the debugger chip and "Programming Port USB"

M0_Pro and Zero have almost the same pinout. D2 and D4 are swapped.
There are plenty of GPIO pins. Plus SPI port on the 3x2

We do not know which board the OP has specified in the IDE. Obviously this will affect the pin mapping.

I would be much more concerned with the LCD Shield. How do the input buttons work? Are they pulled up to 5V? (which would break the SAMD21 chip)

The official "Arduino M0" has been discontinued. It would be sensible for the IDE to have an entry for WeMos SAMD21 M0 (and similar Chinese clones)

David.

Thank you both for your input, much appreciated.

I have been using the Arduino Zero specification in the IDE. I'll try the M0_Pro settings and see if that changes things.

I'm still struggling to get my head round why, if the pin-outs on my clone are printed identically to the Uno, functionally they perform differently? I assume here this is part of the lower level/programming/definition that happens via the LiquidCrystal.h module.

I've not seen (or smelt) any magic smoke yet, it is a possibility though. Warnings are silk-screened on the back about exceeding 3v3 levels, so fingers crossed :confused:.

Sadly, trying to get any decent datasheet for this specific clone draws a blank. As others have noted, it is badged WeMos, but who the real manufacturer is a total mystery.

The pinout should only make a difference if you use D2 or D4.

Easy enough to check. Just write a Blinky to digitalWrite() to 2 or 4.

Compare the relevant variant files e.g.
C:\Users\David Prentice\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.8.6\variants\arduino_mzero\variant.cpp

Since you are using D4 e.g.

const int pin_d4 = 4;

It will access PA08 or PA14 according to your board's variant.cpp file

David.

I am not familiar with this board. What platform (board package) and board type does it use?

I would be curious if the hd44780 library hd44780_pinIO class works on this board.
There are some potential issues related to using fast 3v processors with LCDs running at 5v
The hd44780 library has some s/w work arounds for this but the LiquidCrystal library does not.
So in some cases LiquidCrystal may not work when using a fast 3v processor connected to an LCD running at 5v whereas it may work with the hd44780 library.

That said, the s/w work arounds are only enabled for specific processors, currently esp8266 and esp32 so they would not be enabled for this processor.
However, I’m still curious if the hd44780 library works with this board and if it doesn’t, I’d like get it working.

david_prentice:
I would be much more concerned with the LCD Shield. How do the input buttons work? Are they pulled up to 5V? (which would break the SAMD21 chip)

Most LCD shields are wired to use the connector pin locations for UNO pins in the locations for Arduino pin #s 8,9,4,5,6,7
Those are directly connect the LCD pins rs,en,db4,db5,db6,db7 respectiviely.
Arduino pin 10 is typically wired to a transistor for backlight control but many shields are using a broken backlight circuit which can potentially damage the Arduino pin since it creates a a near short to ground because they didn’t use a resistor between digital pin 10 and the base of the transistor.
The hd44780 library will attempt to detect this issue running a quick test on the pin and switch to a s/w work around to avoid the short, should the user enable backlight control.

The buttons could be a BIG issue for this board, if the processor is 3v only.

The buttons on these lcd shields are wired to a resistor ladder network using 5v that is connected to A0
Using the buttons on a 3v only board could damage the processor.
With the

The buttons on these lcd shields are wired to a resistor ladder network using 5v that is connected to A0
Using the buttons on a 3v only board could damage the processor.
With the

david_prentice:
Think about it. The M0 SAMD21 output port drivers are much slower than M3 Due or M3 STM32 BluePills at a given clock speed. And considerably slower than M4. Lots of Due and BluePill owners use 16x2.

But I would think that slower output drivers can aggregate the potential timing issue.
The issue I see is that in some cases on very fast processors like the esp8266, and especially on the esp32, that using a delay of 1us after raising E is not long enough to allow the voltage on E signal to rise high enough to be seen as a high for the 5v LCD or doesn't allow it to be high for a long enough time period to ensure that it remained high for the minimum clock period.

If the output drivers are slower then I would think that it could aggravate that potential timing issue since it increases the time needed to fully rise the voltage on the pin all the way up to the high logic level after the processor sets the pin register h/w to set the pin to be high.

--- bill

Thank you David, you hit the nail on the head. Swapping D2->D4 and the LCD works. I can also confirm the board works as expected when configured as a Arduino Zero (Native USB port). It seemed erratic when configured as a M0 (Blinky LED would not go out fully).

For reference, here is my PlatformIO.ini file for this board and project:

[env:zeroUSB]
platform = atmelsam
board = zeroUSB
framework = arduino
debug_tool = jlink

; JTAG interface
upload_protocol = jlink-jtag

[env:debug]

platform = atmelsam
board = zeroUSB
framework = arduino
debug_tool = jlink
debug_init_break =

And the test code that works with the LCD shield:

#include <LiquidCrystal.h>

//LCD pin to Arduino
const int pin_RS = 8;
const int pin_EN = 9;
const int pin_d2 = 2; // Important !
const int pin_d5 = 5;
const int pin_d6 = 6;
const int pin_d7 = 7;
const int pin_BL = 10;
LiquidCrystal lcd(pin_RS, pin_EN, pin_d2, pin_d5, pin_d6, pin_d7);
void setup()
{
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Electropeak.com");
  lcd.setCursor(0, 1);
  lcd.print("Press Key:");
}
void loop()
{
  int x;
  x = analogRead(0);
  lcd.setCursor(10, 1);
  if (x < 60)
  {
    lcd.print("Right ");
  }
  else if (x < 200)
  {
    lcd.print("Up    ");
  }
  else if (x < 400)
  {
    lcd.print("Down  ");
  }
  else if (x < 600)
  {
    lcd.print("Left  ");
  }
  else if (x < 800)
  {
    lcd.print("Select");
  }
}

However, there seems to be another pin-out mapping issue insofar as the keys on the shield return the following when pressed:

  • Select => Nothing (Fail)
  • Left => Select (Fail)
  • Up => Down (Fail)
  • Down => Left (Fail)
  • Right => Right (OK)
  • Reset => Resets board (OK)

As expected, the above code worked flawlessly on the Mega 2560.

I get the following voltages in respect to ground at A0 when the buttons are pressed [Mega 2560 9in square brackets]:

  • No action => 3.780 [4.890 ] v
  • Select => 3.539 [3.460] v
  • Left => 2.367 [2.313] v
  • Up => 0.655 [0.640] v
  • Down => 1.519 [1.484] v
  • Right => 0.200 [1.100] v
  • Reset => N/A, tied to board reset
    [/li][/list]

All seem within spec for a 3v3 board, except for the Right button. All of the switches om one sided are tied to GND Taking into account what bperrybap says, is it a good idea to continue with using the switches on the shield? I getting quite fond of this board and I really don’t want to bake it :slight_smile: .

There is actually more than one design for these keypad shields.

This design is very common:

In this design all buttons go through resistors in the ladder except which goes straight to ground.
But the voltages you show don’t seem to be what I would expect, particularly for the button given a VCC of 5v.

You need to verify the ladder network used on your buttons.

How it is wired up will give you the answer as to if you should be using it on that Arduino board.

It will take a few minutes with an ohm meter.
With the shield not connected to the Arduino, measure the resistance between A0 and VCC on the shield.
Then measure the resistance between A0 and GND for each button press.

That will give you the total resistance for each button so you can figure out how the buttons are wired up to the ladder network and calculate the value for each resistor.

— bill

@old_holborn,

Please compare Bill's schematic with the item on your desk. Most importantly, measure resistance between A0 pin and 5V pin. i.e. R2

Your voltages in #10 are dangerous.

No action => 3.780 [4.890 ] v

means that current is flowing from 5V to A0 pin through the substrate diode. Which is why it is higher than 3.3V

This current is (5.0 - 3.78 ) / 2k0 = 0.61 mA when no buttons are pressed. Not fatal but not wise either.

I suggest that you modify the shield so that R2 connects to 3.3V pin instead of 5V pin. Should be fairly easy.

This should make the library software return keypresses correctly.

David.

Evening all,

Your voltages in #10 are dangerous

Looking back, I really should have checked this against the regulated 3v3 supply to see what was actually on the pin. Mea Culpa, I put that down to my elderly DVM, which has suffered considerable abuse over the years and has not been calibrated (Would cost more than I paid for it). My bad.

Here are the results of the resistance tests. I haven't included the el cheapo clone in this, my rough and ready test showed it was within 10% of this table. I have added a test between A0 => GND for completeness.

State A0 => 5V A0 => GND
No action 2.16K 8.64K
Select 1.83K 3.26K
Up 1.64K 315 Ohms
Down 1.68K 852 Ohms
Left 1.72K 1.58K
Right 1.62K 1.3 Ohms
Reset N/A N/A

On that basis, I did a test with D1 Robot board with some Dupont cables. I connected everything up to the WeMos with the exception of the 5V pin, which I connected to the 3v3 pin to the left. I also reverted the modifications to the code to use d4 rather than d2 (const int pin_d4 = 4;). While the board booted OK and the backlight lit, there were no characters displayed. Mindful that the LCD was calibrated to a 5v0 supply, I turned the pot fully clockwise and by magic, the test appeared. The button logic also worked as expected.

The permanent fix for the shield

  • With a solder sucker or braid, de-solder the 5V pin and remove by pulling out with some pliers
  • Add a solder link between the 5V pad (now vacated by the pin), and the pin on left, which corresponds to the 3v3 pinout on the WeMos (See the purple bit on the diagram)
  • Turn the pot fully clockwise until you hear a "Click"

This works, but as always there is a "YMMV". The D1 Robot board was considerably brighter running at 3v3 than the unmarked clone I was using to experiment with. It was on the border of legibility at some angles, but still readable head on.

Unless I have committed some cardinal sin here, I think we can call this "Solved".

Thanks everyone for your assistance, much appreciated.

You need the 5V pin for the LCD. Otherwise the contrast pot will not adjust properly.

You need the 3.3V pin for the switches.

I thought that I was very clear. Connect 2k0 to 3.3V pin instead of 5V pin.
You can do that by removing the 2k0 SMD resistor and soldering a small wire ended 2k0 from 3.3V pin to the pins 2,3 of SW5X6 marked RIGHT.

Of course there are other ways e.g. cut a copper track. Solder a fine wire.

I don't have your shield. So I don't know which would be easier.

If you can get a good contrast with your current solution it means a non-standard LCD.

David.

You need the 5V pin for the LCD. Otherwise the contrast pot will not adjust properly.

You need the 3.3V pin for the switches.

It was not that you weren't being clear, but I am having real difficulty translating both the circuit diagram and the 2K0 SMD resistor to my scenario. The only visible SMD resistor is R1, directly next to the LED. There are some "Black blobs" on the rear of the LCD itself, which I assume are the discrete LCD chip / transistor components. Without unsoldering the LCD board itself, it is impossible to trace what is on the base (or indeed the topside of the main shield PCB itself). Other than that, I could not clearly see the resistive ladder components.
The only conclusion I can come to is that those resistors are actually under the switches. I'm not at my computer at the moment, but I will look into this. As it is a cheap board, I might consider disassembling it to find out exactly what the best solution is (cutting track etc.). I'm not confident cutting tracks unless I can prove where they go or I can easily roll changes back.
I was lulled into a false sense of security here by the fluke that my "solution" worked reasonably well with Shield A when lashed up with ribbon cable. The fact that it didn't work as well with Shield B proves your point entirely. There must therefore be some differences between the two LCD's themselves, something worth looking into. Both modules appear identical, but this clearly is not the case.

I have never used your shield. I guess that it is a Shield pcb with some switches and a regular 16x2 that you would buy from Ebay.

You can compare with Bill's schematic. Bill is experienced with these things.
R1 is series resistor for power LED.
R2-R7 are either under the LCD or on the bottom side of the pcb.

If they are underneath the LCD you have no chance of accessing them.

You can easily solder a new 2k0 resistor from 3.3V header pin to A0 header pin
But you need to either cut a track or remove the existing R2

David.

On my LCD keypad shield, the ladder resistors are on the bottom of the shield PCB under the area where the buttons are and are very easy to access.

In looking at your code examples, while you have not used it, you have specified a pin for backlight control.
If you intend to do backlight control, you need to check to see if your keypad shield has the backlight control h/w issue.
If your shields have the backlight h/w issue, you don't want to control the backlight using pin with HIGH output or PWM as it could damage the processor.

This sticky in the displays subforum talks about the issue:

I would highly recommend running the LCDkeyPadCheck sketch, included in the hd44780 library to test the keypad to see if has the issue.

As a general comment, I'd recommend using the hd44780 library hd44780_pinIO i/o class instead of the LiquidCrystal library as it is faster, has some fixes and has some additional capabilities not found in the LiquidCrystal library.
For example, there is s/w work around for using very fast 3v processors like the ESP32 that will not work with the LiquidCrystal library when using LCDs running at 5v that will work with the hd44780 library hd44780_pinIO i/o class.

--- bill

On my LCD keypad shield, the ladder resistors are on the bottom of the shield PCB under the area where the buttons are and are very easy to access.

In which case:

  1. Remove R2
  2. Repair the 5V header pin that you removed earlier and previous hack.
  3. Solder 2k0 wire-ended between 3.3V header pin and A0 header pin.

Now you should have 5V at pin#2 on the 16x2 LCD
And read 3.3V on the A0 pin (with no buttons pressed)

As you press buttons you will read different voltages on the A0 pin.
They will all be between 0V and 3.3V

If you ever want to use the Shield with a 5V Uno, just move the wire-ended resistor from 3.3V pin to 5V pin.

David.

After further examination with a bright light, I can confirm the resistor ladder network is beneath the edge of the daughter LCD board. They are towards the front, far enough in not to be seen, unless you look at just the correct angle. The angle is so tight, I can't get a fine soldering iron bit in to unmount R2. There is also a metal post in the way from the LCD bezel itself, so the only way to gain access is to remove the LCD board.

I solved the mystery why the first shield worked with my crude hack, on this shield there is ~ 1mm gap between the backlight LED and the LCD. With the other shield there is no noticeable gap, hence being able to run at 3v3 and still illuminate the characters well enough.

As I'm generally not in the habit of taking boards apart, I've now got some solder braid and some flux on order so I can remove the daughter board (and undo my hack). It is years since I've done work like this, and lead-free solder is an absolute pain to remove.

Once it all arrives I'll post up the photos, that is if the tracks survive the experience :o.