Monday, June 24, 2013

An AVR Atmega library for HD44780 based lcd connected through i2c

This library implements a driver for HD44780 lcd connected through PCF8574 port expander.
Data is transmitted using only 2 wire over i2c with the PCF8574.


Lcd driver is based upon Peter Fleury's lcd driver.
Setup parameters can be found in file lcdpcf8574.h and pcf8574.h
This library was developed on Eclipse, built with avr-gcc on Atmega8 @ 1MHz.




Code
Notes
  • read risk disclaimer
  • excuse my bad english

103 comments:

  1. Hello Davide.

    I have a problem I want to use this code with the atmega328.
    But I can't get it working I get error afther errror and when I fix one error I get an other, I struggling for almost 3 day's so it's time to ask for help.
    Can you help me converting this code so it work with a atmega328? I would really appreciate it thank you.

    Best regards Tom
    E-mail: tomklijn@outlook.com

    ReplyDelete
    Replies
    1. to me, it compiles and works on atmega328p without any compiling error.
      check you wiring, check you fuses, check you cpu frequency, try debug using uart.

      Delete
  2. Hi David,
    I am using atmega168 and avr studio I am new to this stuff and my screen is just showing one solid block of squares in one line only. Do I need to set the port and pin numbers for TWI in some file. I saw that none of the headers files set the port numbers.
    Appreciate your help,
    Thanks

    ReplyDelete
    Replies
    1. yes, you have to setup pin number in file: lcdpcf8574.h

      Delete
    2. I apologoze for bothering you again, but figure out that pin numbers are hardwired so we do not need to use them, but you are running it a 4Mhz frequency, I am trying to so it at 8Mhz, in what places should I change the code. Also I used the meter to check ao,a1,a2 and all three report avoltage of 4.9v. this means they are tied high, so my address will be 0x27, correct? I am using PCF8574T. The program is hanging somewhere in lcd_init. Any help will be appreciated.

      Delete
    3. i'm running it at 1Mhz, but i've run it at 8Mhz on other project only changing the i2c speed.
      the only problem i've encountered during my experiments, is when pin connection are wrong.
      debug using logic analizer on the pcf8574 lines, or simply using uart output to check where it stucks.

      Delete
    4. Well, we have to use a multimeter to match the LCD pins to the PCF8574T pins, on our board they were totally different. After setting the pins correctly in LCDPCF8574.h file, the code worked like a charm
      Thanks for all the help.

      Delete
    5. I also get solid block of squares in one line only but I can't get this even to compile... i keep getting some compile errors about LCD_DISP_ON_BLINK and 2, or 3 other lines.
      To be clear i really don't understand all this stuff what it mean and avr studio is quite strange to me, but even i know that my pin connections are different I could fix that later based on Your previous advice for lcdpcf8574.h.
      For now i don't know how to get compile ok. My mcu is Atmega168 @8MHz internall. I'm trying to get this to work just to know does my pcf8574t chip is still live at all because i'm also trying to controll lcd on such was using some other programming method.

      Please sir i need help. For You it's maybe 5minutes of work, can you provide me with hex file just to burn it to my mcu?

      pcf8574 adress is 0x20, and my connection is like this
      http://mmdolze.users.sourceforge.net/images/myLoS-i2c.png but my and my backlight is npn transistor so turned on is PCF_P7=1
      i use atmega168

      Delete
    6. Hello,
      try Eclipse with avrgcc and AVR plugin, it's very simple to use it and compile it with Eclipse avr plugin.
      Or you can write your own makefile. There are a few tutorial out there.
      Yes, i could compile it for you, but every time you have to make a change, you have to ask me to compile, and it could not bring anything to your knowledge :)

      Delete
    7. i really don't know how to do anything of that. Write my own makefile? hah, good one... :) I don't know even #C at all. That's why I'm using Flowcode, programming mcu by putting blocks around but there are also some tricky issues about i2c LCD that gives me a headache and matrix multimedia support sucks.
      Actually I'm medical worker and electronics is just my hobby, complete noob :)
      I don't think that i will need that hex more than one (this) time, simply to check my hardware to know am I doing something wrong in Flowcode or my PCF8574 chip is simply dead for some reason and that's why I don't get normal result on LCD. that's all


      at least i would be happy with zip that include avr studio solution and all those .c and .h included so I can look around and try to understand what is what and how things should be done.

      Delete
    8. Ok. For neebie you should consider working with Arduino, which is really simple! Just import that code in your avr studio project. Keep in mind that you will have to change some registers in order to make this works on mega16. Give it a try to arduino, the LCD i2c library is really simple.

      Delete
    9. i don't have arduino and as far as i saw how it works it also need some knowledge about #C... also arduino IDE won't work on my laptop, i don't know why and i don't care, i will not use it.
      and i did tried already to import code in avr studio, as I said before i get build errors. registers to change?! i don't know how to do that

      never mind. i will continue my fight with Flowcode. thanks

      Delete
    10. Ali, could you please post your pin configuration?
      I have the PCF8574T too.
      Thanks!

      Delete
  3. Hi David,

    Nice work, but I'm having trouble getting it to work.

    I'm using a 20x4 LCD from YwRobot, which comes with a PCF8574. I have it connected to analog pins 4 (SDA) and 5 (SCL) on an ATmega328P. I have made the following connections, which I believe are correct: DATA0 = 4, DATA1 = 5, DATA2 = 6, DATA3 = 7, RS = 0, RW = 1, EN = 2. The backlight seems to just be connected to Vcc (which pin should I set it to?).

    I am not sure what address to use. I've tried both 0x20 and 0x27 (this worked when I used the LCD with an Arduino library some time ago).

    Any idea what the problem might be?

    ReplyDelete
    Replies
    1. hello,
      at first try with a 16x2 LCD, HD44780, pretty standard and a cheap PCF8574 board-
      Then when you are shure it works, test it with your hardware.
      Anyway, pin numbers are in file: lcdpcf8574.h

      Delete
    2. I don't have one :( My LCD is a HD44780 though. I have set the pin numbers in lcdpcf8574.h.

      Delete
  4. Davide, thank you for your library!
    The pins for PCF8574T I2C LCD adapter (bought from Ebay):

    #define LCD_DATA0_PIN 4
    #define LCD_DATA1_PIN 5
    #define LCD_DATA2_PIN 6
    #define LCD_DATA3_PIN 7
    #define LCD_RS_PIN 0
    #define LCD_RW_PIN 1
    #define LCD_E_PIN 2
    #define LCD_LED_PIN 3

    ReplyDelete
    Replies
    1. Thank you for sharing your feedback!

      Delete
    2. and address into 0x27
      #define PCF8574_ADDRBASE (0x27) //device base address

      Delete
  5. Looking for an assembly version of this, is there a way to concert the c to assembly? I can read assembly but not c well. Thanks. Even compile it with avr studio and send me the hex and I will decompile it.

    Thanks

    ReplyDelete
    Replies
    1. Hello, I can send you a compiled hex or the compiler lss avrgcc file, which contains the assembly. Keep in mind that it will be assembly code from the compiler, so it can not be so "clean". Anyway, just send me an email, or give me your address and i will reply with the code.

      Delete
    2. admin at tipsntricks dot ca

      Delete
  6. Hello,
    I used this library to run PCF8574T on ATmega16A. I got cheap ebay display with I2C backpack ( PCF8574T) module. I changed pins in .h file and communication works ok (Im able to write something on display), but there is no backlight. The thing is that there is backlight for some ms, but when display init method starts, it turns off backlight somehow and I cant figure out why. Its some kind of invert mode I think.

    If you got any ideas, please share. Thanks,

    ReplyDelete
    Replies
    1. The setup pin for the lcd light is LCD_LED_PIN (lcdpcf8574.h). The function to light up and down is lcd_led. In normal mode lcd_led(1) will turn the led on, lcd_led(0) off, in inverted mode, it works inverted, so 1 to off, o to on.
      It your board works and it's all connected properly, this is the way it should work.
      It could also be your hardware that is damaged.
      You can double check your wiring, and try different pins.

      Delete
    2. Problem solved! Thank you very much!

      Delete
    3. Thank you for your feedback ;)

      Delete
    4. This comment has been removed by the author.

      Delete
  7. im using this files with ATmega32. i have this module
    http://www.ebay.com/itm/310565362720?_trksid=p2059210.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT
    i had already used the based libraries about lcd 2x16 and works fine. so i dont have edit my code as it use same functions.

    i've change the
    F_CPU with my xtal freq.
    also i change the adress to 0x27 (A0,A1,A2 = 4.8V)
    and finally change pins several times with different combination.

    i had build circuit with module and lcd on breadboard and connections with wires. to make sure that pins corresponding right.

    nothing works :(

    ReplyDelete
    Replies
    1. Check your hardware with other libraries, or with Arduino. So you will be sure that your hardware works, and what the pin of your hardware are.
      You could also check where your code stops working, using a serial debugger.

      Delete
    2. thanks for reply.
      i can't use debugger now. im trying to add i2c in an already working circuit with FTDI and atmega32. my uart its reserved from ftdi chip

      Delete
    3. my hardware works perfectly. checked with arduino hardware, arduino ide and arduino libraries.

      Delete
    4. So, it could be the I2C library, you have to check the bus using a logic analizer, or debug in other way to check where your code stop working.
      The code was tested using avrgcc.

      Delete
    5. This comment has been removed by the author.

      Delete
    6. 1- gnd
      2- vcc-
      3- contrast-
      4- rs- pcf0
      5- rw- pcf1
      6- e- pcf2
      7- db0-
      8- db1-
      9- db2-
      10- db3-
      11- db4- pcf4
      12- db5- pcf5
      13- db6- pcf6
      14- db7- pcf7
      15- +led- led_jumper
      16- -led- led_jumper

      Delete
  8. i tried define:
    #define LCD_DATA0_PIN 4
    #define LCD_DATA1_PIN 5
    #define LCD_DATA2_PIN 6
    #define LCD_DATA3_PIN 7
    #define LCD_RS_PIN 0
    #define LCD_RW_PIN 1
    #define LCD_E_PIN 2
    #define LCD_LED_PIN 3
    but nothing works :(

    ReplyDelete
    Replies
    1. Check if your I2C works, check the output of your PCF8574 with a multimeter.
      Hack the code to test every pin output using pcf8574_setoutputpin funcion.

      Delete
    2. thanks for advice davide. i will...

      Delete
    3. It works!
      There was connection error on breadboard!
      Works perfectly...!
      thank you Davide!

      Delete
  9. I have another problem.
    i had made a project with atmega32 which communicates with pc via ft232rl.
    pc sends data through ftdi (uart) to atmega32 and while sends data, the mcu interrupted.
    the atmega32 while its not in interrupt routine, it running a code which measuring a distance with HCSR04.
    now, while i running the pc program for sending data to mcu, my main routine stop to work and in lcd i see only data from pc and not from ultrasonic sensor.
    it working without i2c.

    ReplyDelete
    Replies
    1. Try to put a watchdog, to test if the mcu restart.

      Delete
    2. I mean.. if the mcu restarts when the data is sent. Then, debug your HCSR04 routine.
      Start at small steps, try at first with a simple ADC read routine, then attach your distance sensor code.

      Delete
  10. Hello everyone,

    I had a problem with compilation that code . Something like " Poisoned SIG_USART_DATA nad SIG_USART_RECV . So I found and changed that uasrt.h file and uart.c file into almost the same ( now SIG_USART_DATA is UART_UDRE_vect for example ) the rest is same. Compillation is without any problems, but nothing appeared on my LCD :( I have been trying to resolve that problem for 8 hours. I am using pcf8574T and I changed pins :(

    Do you know what should I do?

    I would add that I am using that set http://www.ebay.com/itm/Arduino-IIC-I2C-TWI-162-1602-16X2-Serial-Blue-LCD-Module-Display-Screen-/190573003243 and ATMEGA8 .

    ReplyDelete
    Replies
    1. I took that new files ( uart.h and uart.c ) from that site http://mmdolze.users.sourceforge.net/use-a-lcd-with-twi.html

      Delete
    2. Uart is there just for debug purpose. You could also remove that, or use anyother library. What i can say is that on HD44780 based LCD wiring is really important. So double chek it. Also, you could use a logic analyzer to debug the pcl8574 to lcd bus. Check that pcl8574 output works as desider, debug the output editing the code. Compile using avrgcc. Compile using your actual micro F_CPU. Check SCL_CLOCK of the twimaseter.c
      Hope this helps.

      Delete
    3. Thanks for answer, I will try to remove uart files. Can u only please tell me about configuration of pins for that: http://www.ebay.com/itm/Arduino-IIC-I2C-TWI-162-1602-16X2-Serial-Blue-LCD-Module-Display-Screen-/190573003243

      How it should looks like:

      #define LCD_DATA0_PIN 0 /**< pin for 4bit data bit 0 */
      #define LCD_DATA1_PIN 1 /**< pin for 4bit data bit 1 */
      #define LCD_DATA2_PIN 2 /**< pin for 4bit data bit 2 */
      #define LCD_DATA3_PIN 3 /**< pin for 4bit data bit 3 */
      #define LCD_RS_PIN 4 /**< pin for RS line */
      #define LCD_RW_PIN 5 /**< pin for RW line */
      #define LCD_E_PIN 6 /**< pin for Enable line */
      #define LCD_LED_PIN 7 /**< pin for Led */

      To be honest I don't get it. What are that numbers from 0-7? Are they numbers of P0-P7 ?

      Thanks for answer ;)

      Delete
    4. Hello, for that module, you have to trace out the pinout using a multimeter or whatelse.
      As example: LCD_RS_PIN -> 4 means that the pcl8574 P4 output goes to RS input pin of your 16x2 HD44780 based lcd.

      Delete
  11. This comment has been removed by the author.

    ReplyDelete
  12. Hi David
    Thank you for libraries
    Works fine in AtmelStudio6
    I added the library into a new project and wrote in Project\Properties\Toolchain\AVR/GNU C Compiler\Symbols: F_CPU = 16000000UL
    and comment string #include PCF8574_I2CFLEURYPATH in pcf8574.c
    "F_CPU = 16000000UL" for Atmega328P for other chips another frequency
    Good luck to everyone!

    ReplyDelete
  13. This comment has been removed by the author.

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hi David,

    I have a quick question. Where do I set the i2c device id in your code? The default device id 0x27 and the device id of my i2c lcd backpack is 0x3F.

    Thanks,

    -Justin

    ReplyDelete
    Replies
    1. Hello, it's in the pcf8574.h file: look at this PCF8574_ADDRBASE definition.

      Delete
  16. This comment has been removed by the author.

    ReplyDelete
  17. Hi Davide,

    I'm trying to use a LCD2004A/PCF8574T with an atmega328P but after hours of debugging I still can't get it to work.

    I already checked the pin mapping between the lcd display and the attached port expander by using a multimeter.

    See here:

    P0 -> RS
    P1 -> RW
    P2 -> E
    P3 -> not connected to any of the lcd pins
    P4 -> D4
    P5 -> D5
    P6 -> D6
    P7 -> D7

    The pin mapping and wiring shouldn't be the problem. I found out that my code hangs in the following while-loop in the i2c_start function.

    while( !(TWCR & (1<<TWINT)) );

    It seems that the TWINT flag never changes and therefore causes the program to hang in the while-loop.

    In order to ensure there's no hardware issue I tested the i2c communication with the LiquidCrystal_I2C library from the Arduino IDE and it all worked fine. I could send text to my LCD display via i2c.
    But I really want to use your code because it's completely written in C and not in C++ like the Arduino library.

    Do you have an idea why the program freezes in the following code section?

    uint8_t i2c_start(uint8_t address)
    {
    // reset TWI control register
    TWCR = 0;
    // transmit START condition
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    // wait for end of transmission
    while( !(TWCR & (1<<TWINT)) ); // The program freezes at this point


    Thanks in advance.

    ReplyDelete
    Replies
    1. Hello, good explanation, and debugging! So, now I'm out of my main PC, but one first question is. Check with another SCL clock, and/or test your F_CPU settings, and you atmega fuse setting. Also, are you compiling it with avrgcc?

      Delete
    2. Hello Davide,

      thanks for your reply.

      Today I changed the SCL from 100000UL (100 KHz) to 400 KHz and 1.7 MHz, but none of these configurations worked. My F_CPU is at 16 MHz. According to the datasheet of the port expander (pcf8574) it requires an i2c SCL of 100 KHz to work properly, so I made my changes undone and set it back to 100 KHz.

      In order to program my atmega328p I'm using an Arduino Uno with the "ArduinoISP" sketch installed on it. Further I'm using avrdude to uploaded the compiled .hex file of my C program to my atmega328p with the following fuse configuration.

      lfuse: 0xe6
      hfuse: 0xd9

      This is my complete parameter chain of avrdude:
      -U lfuse:w:0xe6:m -U hfuse:w:0xd9:m -e -F -v -patmega328p -carduino -P COM3 -b19200 -D -Uflash:w:"$(ProjectDir)Debug\$(ItemFileName).hex":i -C"C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"

      And yes I think I'm using avrgcc as a compiler, at least the project properties claims that.

      Do you think it might have something to do with the fuse config?

      Best regards,
      Frans

      Delete
    3. So, if you are compiling for 16Mhz ( One simple think could be check it using UART debugging ). Check the PCF8574_ADDRBASE, is that the same of the Arduino library? Try this library: http://davidegironi.blogspot.it/2013/03/pcf8574-gpio-expander-library-for-avr.html Can you pull up/down any of the GPIO pin (check it with a multimeter)?

      Delete
  18. This comment has been removed by the author.

    ReplyDelete
  19. Thanks for this code...works like a champ. Used the pinout posted by Andrew (April 22, 2014), device address of 0x27, F_CPU=1MHz. Hardest part for this newbie was climbing the "make" learning curve to compile the code. Once that's accomplished, life gets much easier.

    ReplyDelete
    Replies
    1. Hello, and thank you for this feedback!

      Delete
  20. This comment has been removed by the author.

    ReplyDelete
  21. This comment has been removed by the author.

    ReplyDelete
  22. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hello. Step 1, debug your pcf8754 output. Check that the library really put a pin up and down, using the pcf8574_setoutputpinhigh function and a multimeter.

      Delete
  23. Hello,
    Great Library, but I was wondering how I set it up to control multiple displays. I have a PCF8574 connected to each display and each '8574 has a unique address.

    Any help on this would be greatly appreciated.

    JIm

    ReplyDelete
    Replies
    1. Hello, this libary was built to drive one display at time, anyway, if you want to drive more than one you can do it by changing functions in lcdpcf8574 files. You should built up an array of deviceid, then add the deviceid variable to all the funcitions. This is one way to do what you need, not the only one.

      Delete
  24. Thanks, but I guess I should have been a little more clearer in my question. I do not want to update multiple displays with the same information, but have multiple displays with different information driven off the same I2C bus, with each display being serviced individually. How does one add the Device ID to teh functions?
    Jim

    ReplyDelete
    Replies
    1. Yes, i understaind it. You have to implement multiple deviceid on the lcdpcf8574 library. This library cant at present drive one display. If you implement an array of multimple device id, you can drive many display at the same time.

      Delete
    2. I've implemented a libray based upon this, to drive up to 8 LCD display. It will be soon online.

      Delete
  25. I am guessing I would have to create multiple lines of these in the .h file:

    #define LCD_PCF8574_INIT 1 //init pcf8574

    #define LCD_PCF8574_DEVICEID 0 //device id, addr = pcf8574 base addr + LCD_PCF8574_DEVICEID

    As I see the DEVICE ID in the .c file, but I am wondering how in my main code I tell the library what display I want to talk to.

    Sorry to be a bother, but I just think I am missing one key piece to this.

    JIm

    ReplyDelete
  26. Great libraries. Got them to work with an atmega328p at 16000000Hz on 20x4 lcd. Thank you so much.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Came up with a problem after changing 20x4 blue series lcd screen to a green lcd series screen.Screen sometimes started up perfectly other times just produced garbage. Reliability was restored by adding 20ms delays after the lcd_e_toggle function calls in lcd_write function. This would seem a rather heavy handed solution if the problem is an iniation issue. I'll keep looking.

      Delete
    3. Is your AVR using the internal oscillator, or an external crystal? Also did you set up the clock frequencies in the .H files properly?

      JIm

      Delete
    4. This comment has been removed by the author.

      Delete
    5. This comment has been removed by the author.

      Delete
    6. Thanks for your reply. External crystal at 16000000hz.
      F_CPU has been defined correctly at all appropriate locations.
      A pwm timer has been included in the code to verify clock speed.

      Delete
  27. I am unable to successfully get the libraries to work, I get many errors in the twimaster. I am trying to use an ATmega325PA 16Mhz on a (20x4). I'm assuming its a little change but I just can't figure it out. Any assistance would be greatly appreciated.

    ReplyDelete
    Replies
    1. TWXX undeclared (first use in this function)

      Delete
    2. Hello, are you compiling with avr-gcc? This project is tested for this compiler usinc Eclipse.

      Delete
    3. Dweck,
      Take a look at your threads on AVRfreaks. I just posted there that the Mega325 WILL NOT work with Davides library, nor Peter Fleury's, and I explained why too.

      I have a demo that you may have to get you going if you want it.

      Jim

      Delete
  28. I am using this library in AVR-GCC and it does work Dweck as I recommended it to you on AVRfreaks. IF you want you can ZIP up your Studio project and post it in your thread and I can take a look

    JIm

    ReplyDelete
    Replies
    1. Hello, I'm sorry but I have no time to check your project, hope you understaind. So, is that a compile error, or a runtime error?

      Delete
  29. DAvide,
    I was offering to help out Dweck as he has a thread going on AVRfreaks. I was not asking you to look at anything.

    Jim

    ReplyDelete
    Replies
    1. Ups, I'm sorry, it's my mistake part due to my bad english, and part due to the fact that usually people ask me to look at their project. Any help is apriciated. Thank you for you help James.

      Delete
    2. This comment has been removed by the author.

      Delete
  30. No Problem. Happy to help if I can

    Jim

    ReplyDelete
  31. Davide,
    Congratulations! Your code works nice. My display is 20x4 and works. But, he write the text slowly. What's happen?

    ReplyDelete
    Replies
    1. Thank you! It could be your I2C clock. Set it on twimaster.c. If you set your ATmega to run @ 8Mhz or more you could even set the clock at 100kbit/s (#define SCL_CLOCK 100000L)

      Delete
  32. The schematic shown must be for a rather old version of the I2C-to-HD44780 character LCDs. All the ones available in 2016 have been updated to have 3 address offset solder pad jumpers. Also, the LED backlight driver circuit has a 2-pin push-on jumper to cut/supply power to the backlight LED.

    Note that the series resistor to current-limit the backlight LED should be connected to the transistor's collector pin, not the emitter pin, just the same as with a NPN transistor. Emitter resistors are used exclusively to compensate for temperature drift in linear applications. There is no need for to do this for digital drive circuits.

    I have redrawn the schematic and can make it available to you, but there is no way for me to attach the file to this message.

    ReplyDelete
    Replies
    1. Hello, thank you for your suggestion. I've updated the schematics.

      Delete
  33. Hi Davide,
    I don't understand the lcd_read() function
    In particular the line:
    data = pcf8574_getoutputpin(LCD_PCF8574_DEVICEID, LCD_DATA0_PIN) << 4;
    Isn't pcf8574_getinput() supposed to be the right one to apply the <<4?
    Grazie
    Ciao

    ReplyDelete
    Replies
    1. Hello, you are right. There Peter Fleury use a trick, he read the PORT register - 2, so he read the PIN register.
      Look at the read function here: http://pastebin.com/TF0ugKNa expires in 1 month. Let me know if it works, I will update the library.

      Delete
  34. Good job , but the most popular lcd model have "0x27" adress and in "twimaster.c" "F_CPU" is 4MHz , not 1MHz. I don't know Why?

    ReplyDelete
    Replies
    1. Thank you! You have to define the F_CPU according to your crystal. Anyway the twimaster it is setup only if any F_CPU directive is used.

      Delete