Need help connecting an I2C 20x4 LCD

easterly81

New Member
-----------SOLVED--------------------------------


Hello i am new to Picaxe but familiar with Arduino.

I was trying to connect an I2C LCD with the adress 0x3f, but get the error:

Error: Please use full 8 bit slave address (with bit0 clear)

Code:
init:
pause 500
i2cslave $3f,i2cslow,i2cbyte 
main: 
writei2c 0,(254,128,255)
pause 10 
writei2c 1,("Hello!123",255) 
end
Soo i guessing i am total doing this wrong. I am having a hard time finding an example to steer me in the right direction. I have read the axe033 lcd pdf but i am caught up on the address.

The LCD's address 3f has a 1 for bit 0 does this mean i cannot use it? (00111111)

Here is a link to the LCD i am using
http://www.sainsmart.com/sainsmart-iic-i2c-twi-serial-2004-20x4-lcd-module-shield-for-arduino-uno-mega-r3.html

Thanks
 
Last edited:

inglewoodpete

Senior Member
Welcome to the world of PICAXE.

Just shift the address value up by 1 bit, leaving bit 0 as value 0: %01111110 or $7E
 
Last edited:

hippy

Technical Support
Staff member
From the details at the link it appears this is an I2C to 8-bit parallel interface and therefore needs to be initialised and controlled in a more complicated manner than the AXE033 can be controlled over I2C.
 
Last edited:

AllyCat

Senior Member
Hi,

Welcome to the forum.

writei2c 1,("Hello!123",255)
Yes, as hippy says, you can't use simple ASCII-like commands. The LCD is being driven in "4-bit parallel mode". Basically, you need to call a subroutine which sends a pair of 4-bit codes to the I2C expander for each character or control byte.

Several versions of code have been shown on the forum, but I can't find the most recent at present. However, perhaps this thread is a reasonable starting point to show some of the issues. Arduino "hides" many of the complications in its "libraries". ;)

Cheers, Alan.
 

Goeytex

Senior Member
The I2C LCD device is typically made up of a Parallel LCD module with an attached I2C I/O Expander chip such as a PCF8574 or a MCP230008, This just gives you the hardware. There is no intelligence in the module. To make it all work you need a "driver" or code that sends the proper commands to the IC2 Chip that then translates these commands to 4-Bit parallel data that is understood by the HD44780 LCD Controller chip on the LCD module.

The code will need a routine to initialize the LCD module as well as routines to perform various commands such as printing a character locating the cursor and clearing the screen. This code is not trivial. I am pretty sure that there is some code posted here that "might" work. It depends upon what LCD module you have.

Please provide the make/model of your device. If a no-name Ebay device then provide a link so that others might further advise.
 

easterly81

New Member
The link is in the first post there is a zip file with the details on the page thanks for the help

I believe the expander chip is the PCF8574 and lcd is 204a if that helps
 
Last edited:

easterly81

New Member
im pretty sure this is what i have going on.

So the PCF8574 cannot communicate with the picaxe I2C commands? Do you have to build it from the ground up and bit bang it?

Sorry for all the silly questions
Thanks

 

hippy

Technical Support
Staff member
So the PCF8574 cannot communicate with the picaxe I2C commands? Do you have to build it from the ground up and bit bang it?
You can control the PCF8574 using the I2C commands, but to send a byte to the LCD itself, you have to treat it as if a parallel display attached to a PICAXE port, then, rather than simply outputting the data via that PICAXE port, you have to send the bytes out via I2C and get the PCF8574 output to be what would have been put on the PICAXE port.

You can't just send character and cursor positioning sequences over I2C, you have to send all the initialisation and command bytes, as well as controlling the RS line and strobing E.
 

hippy

Technical Support
Staff member
Untested but the following should work. The bit allocation should match your hardware but you may need to change the #PICAXE directive ...
 

Attachments

AllyCat

Senior Member
Hi,

Yes your diagram looks correct. Except that P6 is probably (somehow) connected through to the Backlight, so also it can be controlled.

There have been numerous threads on the forum concerning these displays, but I can't find one with definitive code. Many potential users appear to give up trying to use the I2C backpacks, resorting to a separate ASCII serial to 8-bit parallel controller/converter instead.

Personally, I've sucessfully used the code in post #8 of this thread, and there is other useful information in that thread. But it seems that most PICaxe users want (or need) to use ASCII-serial "Printing" commands (serout/sertxd, etc) with "strings" and these are not available when using the I2C expander/driver hardware.

Cheers, Alan.
 

Goeytex

Senior Member
im pretty sure this is what i have going on.

So the PCF8574 cannot communicate with the picaxe I2C commands? Do you have to build it from the ground up and bit bang it?

Sorry for all the silly questions
Thanks

I am pretty sure that the diagram you posted above is incorrect. I downloaded the RAR file from the Sainsmart link and looked at the board layout. The board layout Translates as follows:

P7 --- D7
P6 --- D6
P5 --- D5
P4 --- D4
P3 --- LCD Transistor base on I2C Backpack
P2 --- EN
P1 --- R/W
P0 --- RS

The documentation is poor and I cannot tell from the photo if there is a small SOT transistor on the backpack but most have one. This transistor controls the Backlight. When P3 is Set High the LCD Backlight should be on. See attachment below for BackPack pin outs based upon SainSmart supplied board layout
 

Attachments

Last edited:

AllyCat

Senior Member
Hi,

Yes, Goey is correct. I was lazy and didn't check the actual pin numbering. But I did post the pin mapping back in post #4 of the thread I linked to from #11 above.

Cheers, alan.
 

easterly81

New Member
Thanks very much for all the useful info you guys are great!
Is this how i configure the display? How do i set the address?
I ask because i tried it and it does not work :( lol



Code:
'drive 8574 based I2C lcd display in 4 bit mode
'D7- D4 of display mapped to P7-P4 of 8574
'changed pules enable line to single  hi2cout command
'removed edelay constant
'removed other 'pause 10'delays between hi2cout commands
'works up to 32 MHz / remember to use I2CSLOW_32 
'put BL = 1 after InitLcd so it won't be reset


#picaxe 08m2

'***************************************************************
'---------MAKE SURE LCD_ADR IS CORRECT--------------------------
'***************************************************************
'Symbol LCD_ADR = $40		'I2C address of lcd
Symbol LCD_ADR = %01111110		'I2C address of lcd

Symbol RSCMD = 0	' Select Command register
Symbol RSDAT = 1	' Select Data register

Symbol shadow = b0	'used for hi2cout shadow port
'change the following 4 symbols to match display
Symbol RS = bit0     ' bit0 of shadow register (0 = Command   1 = Data bit)
Symbol RD = bit1     ' bit1 of shadow register (0 = Write     1 = Read)
Symbol E = bit2   	' bit2 of shadow register (0 = Idle      1 = Active)
Symbol BL = bit3     ' bit3 of shadow register (backlight)

Symbol fetch = b4
Symbol char = b5
Symbol nibReg = b6
Symbol temp = b7

Symbol hunsDig = b8
Symbol tensDig = b9
Symbol onesDig = b10
Symbol counter = b11

'-------------------------------------------
	'setfreq M32 -------------JTE Removed

	Gosub InitLcd
	
main:

	BL = 1						'backlight on

	char = 1 					'clear screen
	gosub SendCmdByte
	pause 20 					'pause after clear screen

'Move to line 1
	char = 128
	Gosub SendCmdByte
	For fetch = 6 TO 24  	'"THANKS PICaxe FORUM" from eeprom
   	Read fetch,char		
      Gosub SendDataByte
	Next

'Move to line 2
	char = 192
	Gosub SendCmdByte

   For fetch = 26 To 44 	'"I FINALLY FIGURED  " from eeprom
   	Read fetch,char
      Gosub SendDataByte
   Next
   
 'Move to line 3
	char = 148
	Gosub SendCmdByte 
	
	For fetch = 46 To 64 	'"OUT THIS DISPLAY!!!" from eeprom
   	Read fetch,char
      Gosub SendDataByte
   Next
 
   
  'Move to line 4
	char = 212
	Gosub SendCmdByte 
	
	For fetch = 66 To 84 	'":) 03/04/2015      " from eeprom
   	Read fetch,char
      Gosub SendDataByte
   Next



   End

InitLcd:
	'make sure I2CSLOW_X matches clock speed
	HI2cSetup I2CMASTER, LCD_ADR, I2CSLOW_32, I2CBYTE

	shadow = %00110000 	  ' 8-bit mode
	RS  = RSCMD 				' Send to Command register
	RD = 0

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E 1X
	Pause 100
	HI2cOut(temp,shadow,temp )  ' Pulse E 2X
	Pause 100
	HI2cOut(temp,shadow,temp )  ' Pulse E 3X
	pause 100

	shadow = %00100000          ' 4-bit mode
	RS  = RSCMD             ' Send to Command register
	RD = 0

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E
	E = 0
	pause 100

	'now we can use 4 bit interface for rest of initialization
	char = $28  			' %00101000 %001LNF00   Display Format
	Gosub SendInitCmdByte

	char = $0C  			' %00001100 %00001DCB   Display On
	Gosub SendInitCmdByte

	char = $06  			' %00000110 %000001IS   Cursor Move
	Gosub SendInitCmdByte

	char = 1 	 			'Clear Screen
	Gosub SendInitCmdByte

	pause 20 					'important beacuse last command was clear screen

	Return	'InitialiseLcd

SendInitCmdByte:
	Pause 60 					' Delay 15mS

SendCmdByte:
	RS  = RSCMD 				' Send to Command register
	RD = 0						' Write to the display
       
SendDataByte:
	'high nibble of char or instruction first
	nibReg= char & %11110000	'high nibble of char
	shadow = shadow & %00001111	  	'low nibble contains control signals
	shadow = shadow | nibReg

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E
	E = 0

	'lo nibble
	nibReg = char * 16		'low nibble of char into high nibble of nibReg
	shadow = shadow & %00001111	  'low nibble contains control signals
	shadow = shadow | nibReg

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E
	E = 0
	RS  = RSDAT 				' Send default to Data register

	Return	'SendDataByte , SendCmdByte , SendInitCmdByte

	Eeprom 6, ("THANKS PICaxe FORUM")
      Eeprom 26,("I FINALLY FIGURED  ")
	Eeprom 46,("OUT THIS DISPLAY!!!")
	Eeprom 66,(":) 03/04/2015      ")
I cannot get this code to work because of the address $3F contains a 1 in bit zero. I also tried shifting it a bit to $FE. What do i do about the address?

Thanks
 
Last edited:

westaust55

Moderator
As you already familir with the Arduino programming, you could also have a look at this thread by nick12ab:
http://www.picaxeforum.co.uk/showthread.php?23707-Newbies-guide-to-parallel-HD44780-LCDs-and-Winstar-OLEDs-AXE133-as-a-project-board
while this is covering a PICAXE directly controlling an LCD in parallel mode (8-bit and later 4- bit) the theory is the same but now you must send the data to the i2c interface chip and pulse the two control pins instead of directly controlling the LCD through the PICAXE parallel port.

How do i set the address?
You need to use the hi2csetup command - that is already in the second listing you posted (post 15)

I cannot get this code to work because of the address $3F contains a 1 in bit zero. I also tried shifting it a bit to $FE
$3F = %0011 1111 (binary) and shifted one bit left = %0111 1110 = $7F (not $FE)
 

hippy

Technical Support
Staff member
Is this how i configure the display? How do i set the address?
In my code a $3F 7-bit address should be specified as -

Symbol ADDR = $3F * 2

Or as a direct 8-bit address as -

Symbol ADDR = $7E

Unfortunately I had $37 is the code example I posted, not $3F. The major problem with all these I2C to 8-bit interfaces is that there is no standard for addressing or for pin allocations to the LCD or OLED.

@ easterly81 : Can you confirm that the code I provided with the above address set does work. If so we can provide and support that as definitive example code.

Could you also clarify if the pin allocations are as given in post# 10 or as you show them in post #15 where they appear to have been changed. Perhaps easiest to post the code from post #10 as modified to get it working.
 
Last edited:

easterly81

New Member
Yes Hippy your code did work. Here is what i did you get it working. I haven't had the time to fully analyze it yet. The code I use is below yours.

Code:
Symbol ADDR  = $3f * 2 ; 7-bit I2C Device Address of backpack made 8-bit

;                 .----- Set to output pin number of I2C backpack driver chip
;                 |
Symbol lcdD4 = bit4    ; LCD Data Line 4
Symbol lcdD5 = bit5    ; LCD Data Line 5
Symbol lcdD6 = bit6    ; LCD Data Line 6
Symbol lcdD7 = bit7    ; LCD Data Line 7

Symbol lcdRS = bit0    ; Register Select - 0 = Command   1 = Data
Symbol lcdWR = bit1    ; Write Control   - 0 = Write     1 = Read
Symbol lcdBL = bit3    ; Backlight       - 0 = Off       1 = On 
Symbol lcdE  = bit2    ; Command Strobe  - 0 = Idle      1 = Active

Here was the code I used

Code:
'drive 8574 based I2C lcd display in 4 bit mode
'D7- D4 of display mapped to P7-P4 of 8574
'changed pules enable line to single  hi2cout command
'removed edelay constant
'removed other 'pause 10'delays between hi2cout commands
'works up to 32 MHz / remember to use I2CSLOW_32 
'put BL = 1 after InitLcd so it won't be reset


#picaxe 08m2

'***************************************************************
'---------MAKE SURE LCD_ADR IS CORRECT--------------------------
'***************************************************************
'Symbol LCD_ADR = $40		'I2C address of lcd
Symbol LCD_ADR = %01111110		'I2C address of lcd

Symbol RSCMD = 0	' Select Command register
Symbol RSDAT = 1	' Select Data register

Symbol shadow = b0	'used for hi2cout shadow port
'change the following 4 symbols to match display
Symbol RS = bit0     ' bit0 of shadow register (0 = Command   1 = Data bit)
Symbol RD = bit1     ' bit1 of shadow register (0 = Write     1 = Read)
Symbol E = bit2   	' bit2 of shadow register (0 = Idle      1 = Active)
Symbol BL = bit3     ' bit3 of shadow register (backlight)

Symbol fetch = b4
Symbol char = b5
Symbol nibReg = b6
Symbol temp = b7

Symbol hunsDig = b8
Symbol tensDig = b9
Symbol onesDig = b10
Symbol counter = b11

'-------------------------------------------
	'setfreq M32 -------------JTE Removed

	Gosub InitLcd
	
main:

	BL = 1						'backlight on

	char = 1 					'clear screen
	gosub SendCmdByte
	pause 20 					'pause after clear screen

'Move to line 1
	char = 128
	Gosub SendCmdByte
	For fetch = 6 TO 24  	'"THANKS PICaxe FORUM" from eeprom
   	Read fetch,char		
      Gosub SendDataByte
	Next

'Move to line 2
	char = 192
	Gosub SendCmdByte

   For fetch = 26 To 44 	'"I FINALLY FIGURED  " from eeprom
   	Read fetch,char
      Gosub SendDataByte
   Next
   
 'Move to line 3
	char = 148
	Gosub SendCmdByte 
	
	For fetch = 46 To 64 	'"OUT THIS DISPLAY!!!" from eeprom
   	Read fetch,char
      Gosub SendDataByte
   Next
 
   
  'Move to line 4
	char = 212
	Gosub SendCmdByte 
	
	For fetch = 66 To 84 	'":) 03/04/2015      " from eeprom
   	Read fetch,char
      Gosub SendDataByte
   Next



   End

InitLcd:
	'make sure I2CSLOW_X matches clock speed
	HI2cSetup I2CMASTER, LCD_ADR, I2CSLOW_32, I2CBYTE

	shadow = %00110000 	  ' 8-bit mode
	RS  = RSCMD 				' Send to Command register
	RD = 0

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E 1X
	Pause 100
	HI2cOut(temp,shadow,temp )  ' Pulse E 2X
	Pause 100
	HI2cOut(temp,shadow,temp )  ' Pulse E 3X
	pause 100

	shadow = %00100000          ' 4-bit mode
	RS  = RSCMD             ' Send to Command register
	RD = 0

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E
	E = 0
	pause 100

	'now we can use 4 bit interface for rest of initialization
	char = $28  			' %00101000 %001LNF00   Display Format
	Gosub SendInitCmdByte

	char = $0C  			' %00001100 %00001DCB   Display On
	Gosub SendInitCmdByte

	char = $06  			' %00000110 %000001IS   Cursor Move
	Gosub SendInitCmdByte

	char = 1 	 			'Clear Screen
	Gosub SendInitCmdByte

	pause 20 					'important beacuse last command was clear screen

	Return	'InitialiseLcd

SendInitCmdByte:
	Pause 60 					' Delay 15mS

SendCmdByte:
	RS  = RSCMD 				' Send to Command register
	RD = 0						' Write to the display
       
SendDataByte:
	'high nibble of char or instruction first
	nibReg= char & %11110000	'high nibble of char
	shadow = shadow & %00001111	  	'low nibble contains control signals
	shadow = shadow | nibReg

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E
	E = 0

	'lo nibble
	nibReg = char * 16		'low nibble of char into high nibble of nibReg
	shadow = shadow & %00001111	  'low nibble contains control signals
	shadow = shadow | nibReg

	temp = shadow
	E = 1
	HI2cOut(temp,shadow,temp )  ' Pulse E
	E = 0
	RS  = RSDAT 				' Send default to Data register

	Return	'SendDataByte , SendCmdByte , SendInitCmdByte

	Eeprom 6, ("THANKS PICaxe FORUM")
      Eeprom 26,("I FINALLY FIGURED  ")
	Eeprom 46,("OUT THIS DISPLAY!!!")
	Eeprom 66,(":) 03/04/2015      ")
 

Goeytex

Senior Member
@Hippy

I can confirm that the code you provided works. I had to change the Address (Mine is $27 * 2) and remapped the bits according to OP's Post#15. I used a 20X2 instead of 18M2.

However, with these cheap White on Blue displays I'm using, the backlight MUST be on or the characters are not visible, so I had to set the back light bit on permanently.

Working code attached.
 

Attachments

hippy

Technical Support
Staff member
Many thanks for testing and posting your settings Goeytex.

There seems to be three main types of I2C to LCD expanders; PCF8754 ( 7-bit address of $20-$27 ), PCF8754A ( $38-$3F ) and MCP23008 ($20-$27 ).

That code should work with PCF8754 and PCF8754A with an appropriate address set as otherwise they are functionally equivalent. Sainsmart seem to be the notable manufacturer using PCF8754A and it seems the style which is most often cloned by others. Whether PCF8754 or PCF8754A and I/O pin allocations vary depending on who supplies the board.

The MCP23008 won't work with that code because it is a more complicated device, requires its own initialisation and needs an appropriate register address when sending to it. Adafruit are the notable manufacturer using that device and this is what Sparkfun and Ladyada seem to stock.
 
Top