April 27, 2024, 02:36:14 AM

LCD 16x2 freezes

Started by sdh4, December 02, 2015, 11:59:49 PM

Previous topic - Next topic

sdh4

I'm having a problem with the LCD16x2 shield freezing when subjected to very rapid output. It will freeze anywhere between a few seconds and 15-30 minutes after power up. The backlight stays on during the freeze, but the display blanks.

This is with just the bare shield and a genuine Arduino Due (3.3V, ARM CPU). I have verified that the CPU keeps operating correctly (by generating and watching serial output).

I have tested with an alternate LCD 16x2 shield and also tried adding extra power supply decoupling capacitors, to no avail.

Sketch is pasted below.  To make this work on the DUE you must modify LCD16x2.cpp, changing "Wire" to Wire1" to use the correct i2c interface (without manually rerouting the I2C lines).

#include <Wire.h>
#include "LCD16x2.h"

LCD16x2 lcd;

void setup()
{
  Wire1.begin();

  lcd.lcdClear();
 
  delay(500);
  lcd.lcdSetBlacklight(127);
 
  delay(500);
}

void loop()
{
  static uint32_t counter;
  counter++;
  lcd.lcdGoToXY(counter % 16,counter % 2);
  lcd.lcdWrite((int)(counter % 10));
  if (!(counter % 16)) {
    lcd.readButtons(); 
    delay(25);
  }
}


Modified LCD16x2.cpp:

/*
* LCD16x2.cpp
*
* Copyright 2013 OLIMEX LTD <support@olimex.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include <Wire.h>

#include "LCD16x2.h"


/**
* Default constructor.
*/
LCD16x2::LCD16x2(){
    X = 0;
    Y = 1;
}

/**
* Default destructor.
*/
LCD16x2::~LCD16x2(){
}

/**
* Read the id of the shield.
* @return      If read value match BOARD_ID(0x65) the method return 1,
* otherwise - 0.
*/
uint8_t LCD16x2::getID(){
    uint8_t id = 0;
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(GET_ID);
    Wire1.endTransmission();
    Wire1.requestFrom((int)ADDRESS, 1);
    while(Wire1.available() > 0)
        id = Wire1.read();
     
    return id;
}

void LCD16x2::lcdSetBlacklight(uint8_t value){
Wire1.beginTransmission(ADDRESS);
Wire1.write(SET_BL);
Wire1.write(value);
Wire1.endTransmission();
}
void LCD16x2::uartEnable(bool state){
    uint8_t en;
    if(state == true)
        en = 0x01;
    else
        en = 0x00;
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(UART_EN);
    Wire1.write(en);
    Wire1.endTransmission();
}
uint8_t LCD16x2::getFirmwareVersion(){
    uint8_t firm = 0;
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(GET_FRM);
    Wire1.endTransmission();
    Wire1.requestFrom((int)ADDRESS, 1);
    while(Wire1.available() > 0)
        firm = Wire1.read();
   
    return firm;
}
/**
* Set direction of GPIO.
* @param pin   The pin number according to schematic: GPIO1, GPIO2, etc...
* @param direction     The direction of the GPIO: OUTPUT or INPUT.
*/
void LCD16x2::pinMode(uint8_t pin, uint8_t direction){
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(SET_TRIS);
    Wire1.write(pin);
    Wire1.write(!direction);
    Wire1.endTransmission();
}

/**
* If pin is set as output this method define the level of the GPIO.
* If pin is input - it enables internal pull-up resistor (only available
* for PORTB pins).
* @param pin   The number of the desired GPIO: GPIO1, GPIO2, etc...
* @param level The output level: HIGH or LOW
*/
void LCD16x2::digitalWrite(uint8_t pin, uint8_t level){
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(SET_LAT);
    Wire1.write(pin);
    Wire1.write(level);
    Wire1.endTransmission();
}

/**
* Read the state of individual GPIO, if configured as input.
* @param pin   The number of the GPIO: GPIO1, GPIO2, etc...
* @return      If input level is high - 1, else - 0.
*/
uint8_t LCD16x2::digitalRead(uint8_t pin){
    uint8_t port;
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(GET_PORT);
    Wire1.write(pin);
    Wire1.endTransmission();
    Wire1.requestFrom((int)ADDRESS, 1);
    while(Wire1.available() > 0)
        port = Wire1.read();
   
    return port;
}

/**
* Read the state of the 4 buttons.
* @return      Bitmask with the 4 values: LSB - BUT1, MSB - BUT4
*/
uint8_t LCD16x2::readButtons(){
    uint8_t buttons;
   
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(GET_BUT);
    Wire1.endTransmission();
    Wire1.requestFrom((int)ADDRESS, 1);
    while(Wire1.available() > 0)
        buttons = Wire1.read();
       
    return buttons;
}

/**
* Clear the LCD screen.
*/
void LCD16x2::lcdClear(){
    Wire1.beginTransmission(ADDRESS);
    Wire1.write(LCD_CLR);
    Wire1.endTransmission();
    delay(100);
}

/**
* Position the cursor of the LCD to a given X and Y coordinates.
* @param x     X coordinate
* @param y     Y coordinate
*/
void LCD16x2::lcdGoToXY(uint8_t x, uint8_t y){
    if(x > 16 || x < 1)
        return;
    else
        X = x - 1;
       
    if(y > 2)
        return;
    Y = y;
}

/**
* Write string to the LCD screen.
* @param string        String to be written.
*/
void LCD16x2::lcdWrite(char* string){
    uint8_t len;
    uint8_t x, y;
    x = X;
    y = Y;
   
    len = strlen(string);
    for(int i = 0; i < len; i++){
        Wire1.beginTransmission(ADDRESS);
        Wire1.write(LCD_WR);
        Wire1.write(y);
        Wire1.write(x);
        Wire1.write(string[i]);
        Wire1.endTransmission();
       
        delay(20);
        x++; 
        if(x > 15){
            x = 0;
            y++;
            if(y > 2)
                return;
        }   
    }
}

void LCD16x2::lcdWrite(int intVal){
    String Str = String (intVal);
    char charBuf[6];
    Str.toCharArray(charBuf, 6);
    lcdWrite(charBuf);
}

void LCD16x2::lcdWrite(float floatVal, uint8_t precision){
    char charBuf[30];
    snprintf(charBuf,30,"%.*f",precision,floatVal);
//dtostrf(floatVal, 3, precision, charBuf);
    lcdWrite(charBuf);
}