Go Down

Topic: Small SPI LCD program seems to have some communication issue (Read 166 times) previous topic - next topic

JPlanck

Hey good morning all,
I seem to be having a problem attaching a simple SPI LCD device to an arduino micro (device link: https://www.digikey.com/products/en?keywords=NHD-0420D3Z-FL-GBW-V3-ND)

The pins connected are (micro-display):
D5-1
SCK-3
MO-4

(breadboard_ground-5)
(breadboard_5v-6)

This is in line with what the device's pinout says in the datasheet.

The problem I am having with the following code (below) is that I seem to be COMMUNICATING with the device, but there is something wrong with the communication. Instead of writing the line I want, it ends up being repeated characters of a random letter somewhere in the line of text. For example, if I use LCD_WriteString("Hello World") it will instead write "lllllllllll". If I use LCD_WriteString("aaa") it correctly sends "aaa". Some of the commands, such as the clear screen command, are not working, but the LCD is correctly showing a blinking cursor that does seem to move to the top left 0x00 position when I tell it to.

As might be expected, when starting up the four lines of text do print to the LCD, but they end up being a full row of 20 D's, a full row of 20 g's, a full row of 20 U's, and a full row of 20 O's.

So there seems to be a solid connection, but something is wrong with the coding maybe or the protocol or possibly some SPI config or the library itself is having issues with the device.

If anyone has any suggestions or ideas on where to go from here that'd help, I can't seem to come up with any explanation of what is going on.

Code: [Select]
/*
  SPI LCD software, written by J. Planck
*/

//#####################################################################################################################
//#####################################################################################################################
//INCLUDES-----------------------------------------------------------------------------------------------------INCLUDES

#include <SPI.h>

//#####################################################################################################################
//#####################################################################################################################
//CONSTANTS---------------------------------------------------------------------------------------------------CONSTANTS

#define CS_LCD 5 //pin D5 on arduino micro
#define LCD_SPEED 100000
#define LCD_DATAORDER MSBFIRST
#define LCD_DATAMODE SPI_MODE3
#define PREFIX 0xFE
#define DISPLAY_ON 0x41
#define CURSOR_UNDERLINE_ON 0x47
#define BLINK_CURSOR_ON 0x4B
#define MOVE_CURSOR 0x45
#define DELETE 0x4E
#define CLEAR 0x51
#define MOVE_RIGHT 0x4A //FOR POSITIONS, LINE1:0-19, LINE2:40-53, LINE3:14-27, LINE4:54-67
#define ID_POS 0x05 //ID_LINE 1, ID_POS 6
#define BYTE_POS 0x45 //BYTE_LINE 2, BYTE_POS 6
#define BUZZER_POS 0x21 //BUZZER_LINE 3, BUZZER_POS 8
#define BITMASK_POS 0x18 //BITMASK_LINE 1, BITMASK_POS 19
#define BITSELECT_POS 0x52 //BITSELECT_LINE 2, BITSELECT_POS 19



//#####################################################################################################################
//#####################################################################################################################
//MAIN-------------------------------------------------------------------------------------------------------------MAIN

void setup()
{
  Serial.begin(115200);
  Serial.println("Serial initialize: OK. Use:  buzon, buzoff, testrx, mask xx, code xx, id xx, byte xx");
 
  SPI.begin(); //omitted because CAN.begin^ initializes SPI already, as part of the CAN startup
 
  pinMode(CS_LCD, OUTPUT);
  digitalWrite(CS_LCD, HIGH);

  LCD_Start();
 
  delay(500);
}

void loop()
{
  if (Serial.available() > 0)
  {
    parseSerialInput(Serial.readString());
  }
}

//#####################################################################################################################
//#####################################################################################################################
//SERIAL PARSE FUNCTION---------------------------------------------------------------------------SERIAL PARSE FUNCTION

void parseSerialInput(String userInput)
{
  if (userInput.startsWith("lcdwrite"))
  {
    Serial.println("Sent");
    LCD_WriteString(0x00, userInput.substring(10));
  }
  else if (userInput.startsWith("clear"))
  {
    Serial.println("clearing");
    LCD_Clear();
  }
  else
  {
    Serial.println("Invalid command. Use: clear, lcdwrite");
  }
}

//#####################################################################################################################
//#####################################################################################################################
//LCD FUNCTION-----------------------------------------------------------------------------------------UTILITY FUNCTION
/*
#define PREFIX 0xFE
#define DISPLAY_ON 0x41
#define CURSOR_UNDERLINE_ON 0x47
#define BLINK_CURSOR_ON 0x4B
#define MOVE_CURSOR 0x45
#define DELETE 0x4E
#define CLEAR 0x51
#define MOVE_RIGHT 0x4A //FOR POSITIONS, LINE1:0-19, LINE2:40-53, LINE3:14-27, LINE4:54-67
#define ID_POS 0x05 //ID_LINE 1, ID_POS 6
#define BYTE_POS 0x45 //BYTE_LINE 2, BYTE_POS 6
#define BUZZER_POS 0x21 //BUZZER_LINE 3, BUZZER_POS 8
#define BITMASK_POS 0x18 //BITMASK_LINE 1, BITMASK_POS 19
#define BITSELECT_POS 0x52 //BITSELECT_LINE 2, BITSELECT_POS 19

ASCII LETTERS: ('A' is equivalent to 0x41, etc, chart unnecessary)
Use 'A', 'x', '=', '-', '*', 'x'

ACSII NUMBERS:
0 0x30 5 0x35
1 0x31 6 0x36
2 0x32 7 0x37
3 0x33 8 0x38
4 0x34 9 0x39
*/

inline void LCD_Start()
{
  digitalWrite(CS_LCD, LOW);
  SPI.beginTransaction(SPISettings(LCD_SPEED, LCD_DATAORDER, LCD_DATAMODE));
 
  SPI.transfer(PREFIX);
  SPI.transfer(DISPLAY_ON);
  delayMicroseconds(100);
 
  SPI.transfer(PREFIX);
  SPI.transfer(CURSOR_UNDERLINE_ON);
  delayMicroseconds(1500);
 
  SPI.transfer(PREFIX);
  SPI.transfer(BLINK_CURSOR_ON);
  delayMicroseconds(100);

  LCD_WriteString(0x00, "ID=0x457   MASK=0xFF"); //Top-line
  LCD_WriteString(0x40, "Byte=1     CODE=0x00"); //2nd-line
  LCD_WriteString(0x14, "BUZZER=ON   --------"); //3rd-line
  LCD_WriteString(0x54, "MON=0x00 -- --------"); //4th-line

  SPI.endTransaction();
  digitalWrite(CS_LCD, HIGH);
}

inline void LCD_WriteString(byte pos, String text)
{
  SPI.beginTransaction(SPISettings(LCD_SPEED, LCD_DATAORDER, LCD_DATAMODE));
  digitalWrite(CS_LCD, LOW);
 
  SPI.transfer(PREFIX);
  SPI.transfer(MOVE_CURSOR);
  SPI.transfer(pos);
  delayMicroseconds(100);
 
  int charpos = 1;
  char c = text.charAt(charpos);
  SPI.transfer(c);
  delayMicroseconds(100);
  charpos++;
 
  while (text.charAt(charpos) != '\0') //if the current character is null terminator, end while loop
  {
    LCD_WriteNext(c);
   
    charpos++;
  }
 
  SPI.endTransaction();
  digitalWrite(CS_LCD, HIGH);
}

inline void LCD_WriteNext(byte character)
{
  SPI.transfer(character);
  delayMicroseconds(100);
}

inline void LCD_Clear()
{
  SPI.transfer(PREFIX);
  SPI.transfer(CLEAR);
  delayMicroseconds(100);
}

inline void LCD_WriteChar(byte pos, byte character) //character defined in ascii standard stuff
{
  digitalWrite(CS_LCD, LOW);
  SPI.beginTransaction(SPISettings(LCD_SPEED, LCD_DATAORDER, LCD_DATAMODE));
 
  SPI.transfer(PREFIX);
  SPI.transfer(MOVE_CURSOR);
  SPI.transfer(pos);
  delayMicroseconds(100);
 
  SPI.transfer(character);
  delayMicroseconds(100);
 
  SPI.endTransaction();
  digitalWrite(CS_LCD, HIGH);
}

inline void LCD_Delete(byte pos) //character defined in ascii standard stuff
{
  digitalWrite(CS_LCD, LOW);
  SPI.beginTransaction(SPISettings(LCD_SPEED, LCD_DATAORDER, LCD_DATAMODE));

  SPI.transfer(PREFIX);
  SPI.transfer(MOVE_CURSOR);
  SPI.transfer(pos);
  delayMicroseconds(100);
 
  SPI.transfer(PREFIX);
  SPI.transfer(DELETE);
  delayMicroseconds(100);
 
  SPI.endTransaction();
  digitalWrite(CS_LCD, HIGH);
}

JPlanck

Solved: Apparently normal sending speeds are too fast, I introduced 100uS delays even where there shouldn't be any (before and after every transfer, even between prefix and command) and the device now works. It doesn't make sense to me because the clock speed listed is what I am using, but it works.
Incidentally this means that buffer transfers via SPI.transmit(buffer,size) do not work at all because I cannot introduce a delay between transmissions/clock cycles. I'm still not sure what the actual cause is, but it works as a fix.

Go Up