HD44780 2×16 Character Display for Kinetis and Freedom Board

In my earlier Nokia LCD post I described a ‘free of charge’ way to add a LCD display to my FRDM-KL25Z board. If that Nokia display is not available, or an alphanumeric display is enough, then the Hitachi HD44780 display is a low cost option as well.

The HD44780 (or compatible) display is one of the most common displays available. And they usually conly costs around $10 or less. I have used a ‘blue’ 3.3V version of such a display already in my lectures with a Freescale S08 microcontroller. So I thought it would be nice to port the driver to the Kinetis and the KL25Z on it.

LCD Boards with FRDM-KL25Z

LCD Boards with FRDM-KL25Z

A recent post of TKJ Electronics about such a really inexpensive (only $5) HD44780 display caught my attention. And finally I had two of such TKJ displays in my postal mail box yesterday. Time to have some fun on a weekend 🙂

TKJ Electronics Display

The LCD from TKJ Electronics has no connector solderd, so this makes it convenient to solder my own ones. The small (66 mm x 27 mm)  size makes it ideal for many applications.

TKJ LCD Frontside

TKJ LCD Frontside

The display features two ‘half-holes’ on the side for easy mounting, e.g. for robotic applications.

TKJ LCD Backside

TKJ LCD Backside

The display is availble from http://shop.tkjelectronics.dk/.

Processor Expert LCD Component

To simplify usage of the LCD, I have written a Processor Expert component: LCDHTA. ‘HTA’ is the abbreviation of the University of Lucerne where I teach Embedded Systems Software. The LCDHTA offers the following methods:

LCDHTA Methods

LCDHTA Methods

In the properties, the display settings are configured:

LCDHTA Properties

LCDHTA Properties

It supports both 4-bit and 8-bit data bus connection. If used in 4-bit mode, then DB4 to DB7 lines need to be connected. For the 8-bit mode, all data lines (DB0 to DB7) are connected.

4bit LCD Mode

4-bit LCD Mode

The following pins are supported in the component:

  • LCD Enable (optional): used to select/deselect display if multiple displays are used
  • RW (optional): Read/Write signal. Some displays have that pin which allows to read from the display. This is used to check if the display is busy or ready for new data.
  • E (required): this ‘Enable’ signal is a strobe signal to start read/write operations.
  • RS (required): Register Select, used to switch between command (RS=0) and data (RS=1) mode
  • DBx (required): either 4 or 8 pins have to be assigned for the data/command bus.

The screenshot below shows the communication: first it reads from the LCD if it is ready (pulling down RS, then reading two 4-bit values). If ready, it pulls RS to HIGH level and puts the data on the bus. Then the data is transmitted with a Strobe signal on the E line:

Communication Detail

Communication Detail

In 4-bit mode, I used the following pin connections on the Freedom Board:

=================================================================
 SIGNAL LIST
-----------------------------------------------------------------
SIGNAL-NAME [DIR]        => PIN-NAME [PIN-NUMBER]
-----------------------------------------------------------------
DB4_D4 [I/O]             => TSI0_CH5/PTA4/I2C1_SDA/TPM0_CH1/NMI_b [30]
DB5_D5 [I/O]             => PTA5/USB_CLKIN/TPM0_CH2 [31]
DB6_D6 [I/O]             => CMP0_IN2/PTC8/I2C0_SCL/TPM0_CH4 [65]
DB7_D7 [I/O]             => CMP0_IN3/PTC9/I2C0_SDA/TPM0_CH5 [66]
E_D10 [Output]           => PTD0/SPI0_PCS0/TPM0_CH0 [73]
RS_D8 [Output]           => PTA13/TPM1_CH1 [33]
RW_D9 [Output]           => ADC0_SE6b/PTD5/SPI1_SCK/UART2_TX/TPM0_CH5 [78]
=================================================================
8bit LCD Mode

8-bit LCD Mode

While in 8-bit mode I used the following pin mapping:

=================================================================
 SIGNAL LIST
-----------------------------------------------------------------
SIGNAL-NAME [DIR]        => PIN-NAME [PIN-NUMBER]
-----------------------------------------------------------------
DB0_D0 [I/O]             => TSI0_CH2/PTA1/UART0_RX/TPM2_CH0 [27]
DB1_D1 [I/O]             => TSI0_CH3/PTA2/UART0_TX/TPM2_CH1 [28]
DB2_D2 [I/O]             => PTD4/LLWU_P14/SPI1_PCS0/UART2_RX/TPM0_CH4 [77]
DB3_D3 [I/O]             => PTA12/TPM1_CH0 [32]
DB4_D4 [I/O]             => TSI0_CH5/PTA4/I2C1_SDA/TPM0_CH1/NMI_b [30]
DB5_D5 [I/O]             => PTA5/USB_CLKIN/TPM0_CH2 [31]
DB6_D6 [I/O]             => CMP0_IN2/PTC8/I2C0_SCL/TPM0_CH4 [65]
DB7_D7 [I/O]             => CMP0_IN3/PTC9/I2C0_SDA/TPM0_CH5 [66]
E_D10 [Output]           => PTD0/SPI0_PCS0/TPM0_CH0 [73]
RS_D8 [Output]           => PTA13/TPM1_CH1 [33]
RW_D9 [Output]           => ADC0_SE6b/PTD5/SPI1_SCK/UART2_TX/TPM0_CH5 [78]
=================================================================

The blue LCD we use at the university is a true 3.3V one. So the supply voltage of this one is connected to the 3.3V on the FRDM-KL25Z board. The display needs about 10 mA for operation because of the backlight feature.

And here the LCD from TKJ Electronics gets really interesting, as the current needed for it is only 2-3 mA, but without backlight support. But that display needs 5V supply voltage. That 5V is provided from the Freedom board:

TKJ LCD Supply Details

TKJ LCD Supply Details

The LCD Driving Voltage/Contast can be affected with a potentiometer (10-20k Ohm between Vdd and Vss to V0).

💡 Pulling V0 to Ground/GND is an easy way to avoid the potentiometer.

Software

Using the LCDHTA component, writing to the LCD is easy:

int main(void)
/*lint -restore Enable MISRA rule (6.3) checking. */
{
  /* Write your local variable definition here */

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/

  /* Write your code here */
  LCD1_Clear();
  LCD1_WriteLineStr(1, "Hello FRDM-KL25K");
  for(;;) {
    uint8_t cnt;
    uint8_t buf[5];

    LCD1_GotoXY(2,1);
    UTIL1_Num16uToStr(buf, sizeof(buf), cnt);
    LCD1_WriteString((char*)buf);
    cnt++;
    WAIT1_Waitms(100);
  }
  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
  #ifdef PEX_RTOS_START
    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of RTOS startup code.  ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

The above code writes a welcome message to the display and then increments a counter every 100 ms:

Hello on the TKJ Display

Hello on the TKJ Display

Summary

Using HD44780 displays with this Processor Expert component driver makes my life much easier. And having access to a broad range of inexpensive displays makes creating embedded systems projects even more fun.

The components are hosted on SourceForge, and example project (CodeWarrior) is on GitHub. The example project for Kinetis Design Studio is on GitHub here.

UPDATE: The latest version of the components are on SourceForge, see https://mcuoneclipse.com/2014/10/21/mcuoneclipse-releases-on-sourceforge/

Happy Displaying 🙂

Advertisements

128 thoughts on “HD44780 2×16 Character Display for Kinetis and Freedom Board

    • Yes, I use the displays it as well with HCS08 and ColdFire. There it is actually a little bit more efficient, as I can use BitsIO and ByteIO (there is a problem with using these for Kinetis).

      Like

  1. Pingback: Tutorial: Ultrasonic Ranging with the Freedom Board | MCU on Eclipse

  2. Yes, you are right. However, after do this, I am still receiving the same error:

    C:\Users\Lucio\workspace\Freedom_2x16_LCD\FLASH/../Project_Settings/Startup_Code/__arm_start.c:179: undefined reference to `__init_registers’
    C:\Users\Lucio\workspace\Freedom_2x16_LCD\FLASH/../Project_Settings/Startup_Code/__arm_start.c:231: undefined reference to `__copy_rom_sections_to_ram’
    C:\Users\Lucio\workspace\Freedom_2x16_LCD\FLASH/../Project_Settings/Startup_Code/__arm_start.c:251: undefined reference to `__init_cpp’
    C:\Users\Lucio\workspace\Freedom_2x16_LCD\FLASH/../Project_Settings/Startup_Code/__arm_start.c:257: undefined reference to `__init_user’
    c:/freescale/cw mcu v10.3/cross_tools/arm-none-eabi-gcc-4_6_2/bin/../lib/gcc/arm-none-eabi/4.6.2/../../../../arm-none-eabi/lib/armv6-m\libg.a(lib_a-exit.o): In function `exit’:
    exit.c:(.text.exit+0x18): undefined reference to `_exit’
    collect2: ld returned 1 exit status
    mingw32-make: *** [Freedom_2x16_LCD.elf] Error 1

    Inside of folder “Project Settings” –> “Startup Code” –> _”arm_start.c” appears with a ‘red X’ now.

    Like

      • Hi, Thanks! I just have sent it to you. I don’t know what happens, I only compile the example project of this page.

        Like

      • Hello, It looks like you are using MCU10.3 beta, while I’m on MCU10.3 (final). The thing is that the libraries have been changed from beta to final (final is using EWL libraries), so this is very likely the problem.

        Like

  3. I’m having a problem when running the code, my LCD just show black boxes in the second line and nothing more, do you happen to know what could be wrong?

    Like

    • Hi Eduardo,
      That sounds like the communication to the LCD does not work at all. Can you check your wiring/connections? Additionally it could be that you are too fast for your LCD. Try increasing the waiting time in the component settings. Step through the initialization code with the debugger (this slows down things too). Hope this helps.

      Like

      • Thank for the help, i did try to debug (sorry i’m a newbie i don’t really know much about MCU’s yet) i’m using a JHD162A display, perhaps that has something to do with it, i also triple checked the connections

        Like

      • Hi Eduardo,
        I don’t know that JHD162A display, so I hope it is compatible with the command sets for the one I used in the post. But you might need to check the data sheet. I have seen some modules with different timing, so this might be a problem.

        Like

      • Indeed the problem seemed to be the wires i’ve been using to connect the LCD to freedom, thanks a lot!

        Like

    • Hi Kelvin,
      is it using the HC44780 protocol, but just having 20 instead of 16 characters? If so, I could easily change the component. Do you have a link to the data sheet or any other reference?

      Like

      • Hi Biron,
        at a glance, the display commands look compatible. Have you verified that your connection/wiring is correct? Are you using it in 8bit or 4bit mode?
        What you can try is to set the ‘Wait (us)’ value in the display component. Maybe set it to 100, then it will wait 100 us before sending a command or data value.
        The other thing you could try is to set the display type in the compenent settings from ‘generic’ to ‘DisplayTech 162c’: for this display I needed to wait 2 ms instead of 500 ns during the EnablePulse.
        I hope this helps.

        Like

      • It works in this display, but the problem is that only 16 characters appear.
        If you can tell us if it is possible change the code for put it in 2×20 characters display.

        Like

  4. Pingback: Character LCD with 4 Lines | MCU on Eclipse

  5. I’ve finally got around to getting this going. After some frustration, I discovered:

    * The display I was using was only 1 line, addresses seem to be out, even when setting it as 1 line. (It also got upset about a FunctionSet_1Lines in LCD1.c – had to correct that to FunctionSet_1Line, but my version of the bean is the original, may be fixed by now.)

    * Changing to a two-line display, I was just getting what look like Japanese characters: one of the four data wires was broken.

    * Losing the first characters of the first line – had to bump the wait property all the way up to 1000us before this would work. (This is a write-only setup.) Note that this is also an HD44780 “compatible” display, so don’t know if this has any bearing on timings.

    Many thanks for this, Erich, now I can get feedback through the LCD, I can get on to debugging the rest of the system!

    Like

    • Thanks for the note about FunctionSet_1Line: this was still wrong in my version. Now I have fixed it and committed it to the GitHub sources.
      Abou the waiting time: yes, this is different from display to display. HC44780 pretty much only defines the commands, but not the timing of the protocol.
      Thanks again for your feedback!

      Like

  6. Another observation: for no reason that I can determine, changing code that in no way should impact the LCD code sees random garbage [mostly what looks like Japanese characters] appear in and around (sometimes before) the data I send out LCD1_WriteLineStr(). [The before scenario happened quite a lot: I’d get a consistent one or two characters BEFORE my string.]

    The only thing I could think of that might impact this was the garbage already being in the buffer. I tried changing my line:

    uint8_t buf[16];

    to:

    uint8_t buf[16] = {0};

    So far, no garbage. But I haven’t made any changes elsewhere in the code since, so will continue to keep an eye on this, in case it’s not the full solution.

    Like

    • Yes, on power-up the display might contain random characters. Typically I overwrite the display RAM memory in my application at the beginning and do not rely on any content.

      Like

      • I’m getting the random characters when the system is running, rather than what’s on the LCD at startup. They’ll appear suddenly in the middle of the display. Now been running 7.5 hours since I added the buffer initialisation – no problems so far. Will have another play changing code elsewhere on Wednesday – this is when the problem started to manifest last time.

        Like

      • In the first iteration of the main loop of ProcessorExpert.c, I invoke LCD1_Clear(). The initialisation of the buffer is performed in the function telltale() which gets called by an interrupt handler. (It’s displaying the value of a set of registers that will be driving a BCD clock.)

        I haven’t made any modification to the generated LCD1.c


        void telltale(void)
        {
        uint8_t buf[16] = {0};

        secsrun++;

        UTIL1_strcatNum8u(buf, sizeof(buf), tNow.hTens);
        UTIL1_strcatNum8u(buf, sizeof(buf), tNow.hOnes);
        UTIL1_chcat(buf, sizeof(buf), ':');
        UTIL1_strcatNum8u(buf, sizeof(buf), tNow.mTens);
        UTIL1_strcatNum8u(buf, sizeof(buf), tNow.mOnes);
        UTIL1_chcat(buf, sizeof(buf), ':');
        UTIL1_strcatNum8u(buf, sizeof(buf), tNow.sTens);
        UTIL1_strcatNum8u(buf, sizeof(buf), tNow.sOnes);

        UTIL1_chcat(buf, sizeof(buf), ' ');
        UTIL1_strcatNum16Hex(buf, sizeof(buf), secsrun);

        LCD1_WriteLineStr(2, (char*)buf);
        Heartbeat_Neg();
        }

        Like

      • Hmmm, in my view it is a very bad thing to do things like writing to a LCD during an interrutp service routine. You get a lot of interrupt latency because of this. I rather suggest that you set a flag and then write text from your main application loop.
        And yes, you need to initialize the buf[] array, otherwise this is a programming error. UTIL1_strcat adds a string to after the ” byte, and if you do not initialize the buffer, this will give you random results.

        Like

      • Is this an issue when the ISR only fires every second? I’ll move to the flag-setting approach, as good practice, but just curious.

        Like

      • It is just that writing to the LCD is not very fast, thus blocks other interrupts. Plus in case you write from other code to the display, you need to make sure things are re-entrant.

        Like

      • I’m not entirely sure how to make the functions re-entrant if they are triggered by the presence of a global flag, but I’ve changed my code to work like this:

        * ISRs to only do “low-level” stuff: logical operations, set variables (set to a specific value, or increment/decrement.)

        * All more complex operations that were in ISRs are invoked from the main loop in ProcessorExpert.c, by checking for a flag being set (by the ISRs, etc,) doing whatever is required, then un-setting the flag.

        Does that sound more reasonable?

        Like

      • Yes, that sounds more reasonable. Just make sure that your flag is volatile, like
        volatile bool msgToLCD;

        In case you have many such event flags, then have a look at the ‘SimpleEvents’ Processor Expert module I have created. It manages an array of bits for this kind of things in a reentrant way.
        With SetEvent(event) you can set an event, and with GetEvent() or HandleEvent() you can check the event flags.
        Let me know if you need an example or more information.

        Like

      • Thanks, Erich! I’ll certainly have a look at this, as I’ve been using a system status struct – and adding members all the time, which I have to remember to initialise. Some magic that can hide all that would be good 🙂

        Like

  7. HI Erich
    I was watching your projects and there are very interesting, but I just want to tell you,I took your lcd project and modify to make it serial using the SPI module and a 595, I could give you the libraries with the small modifications I did and you share with others, but also I would like to I attach the changes in the component of PEX but I’m in the ending of my semester and I’m very busy.

    Like

  8. Pingback: Character LCD with 4 Lines and up to 64 Characters per Line | MCU on Eclipse

  9. Excellent items for the KL25Z. I am trying to used the code you have posted and I am having trouble getting the text to display on the LCD. The lcd I am using is https://www.sparkfun.com/datasheets/LCD/GDM1602K-Extended.pdf. Any suggestions. I am downloaded the LCD, Wait, and until components, made sure the pin connection match to the pin I/O. No trouble building the project or running the project, just will not display any text.

    Like

    • Really hard to tell from remote, without having one of these LCD’s. Is the backlight ok? As well the contrast settings? Are you using the R/W signal? Otherwise I suggest to increase the delay time in the component to make the communication slower. You might single step through the initialization code of the LCD with the debugger: this slows down things and maybe then you see something on the display.
      In any case: hook up a logic analyzer to the signals and check what is going on on the wires.

      Like

  10. I enjoyed this tutorial. It has helped to understand some of the mechanics of the IDE and using PE. Thanks for the excellent work.

    Like

    • With which board are you using this LCD? If you are going to use it with the FRDM board, then I think it will not work, as this LCD is a 5V one (according to the information in the link you provided). What you need is a display which is compatible with 3.3V of the FRDM board. Using a 5V display with a 3.3V system can in the worst case damage your hardware: you need to use a proper 3.3V display or level shifters.

      Like

      • I had not set the pins correctly, now is working, do you think I can damage the board using this display?

        Like

      • Thanks, I tested the display feeding him with 3.3 V and it worked. I will use it in unbonded direntamente plate making wired connections. I will adjust the reading of the buttons, there was a button that was before generating 3.6V. Now I think I can use without fear with this new arrangement.

        Like

  11. hello! you have a great page, but I have a question:

    I’m doing a project and I need print in a lcd decimal numbers, for example: 0.2, 1.4, 5.5, etc. Could you help me with these?

    Like

    • What is the type of your number?
      I usually use the Utility component for this, something like (out of my head):
      unsigned char buf[32];
      uint8_t deciGrade; /* temperature in deci grade, e.g. 235 means 23.5 degree */

      buf[0] = ”;
      UTIL1_strcatNum8u(buf, sizeof(buf), deciGrade/10);
      UTIL1_chcat(buf, sizeof(buf), ‘.’);
      UTIL1_strcatNum8u(buf, sizeof(buf), deciGrade%10);

      Like

      • the number is a variable that i’ll changin it while the program is runing. May you please make some really fast video about this?

        Like

      • Creating a video is a very time consuming task.

        But that example works with any variable, independent if you are changing it while the program runs.

        I do not see that this would be an issue?

        Like

  12. Hello,
    Great bean as always!
    I’m using this bean and several others you have created in my serial diagnostic
    device I am building.
    One question though, I see you like to use pta4 for a data line on the LCD.
    I’d like to use it as well, but i have a interference with the NMI (non maskable interrupt) for the CPU that is also on pta4.
    Is it safe to pin share this? or disable nmi?

    Thanks again!
    -Ben

    Like

    • Hi Ben,
      I use this pin as sometimes I do not have anything left on my FRDM headers. If you are using PTA4, then you need to disable the NMI interrupt in the CPU component (you cannot share it).

      Like

  13. Hi,
    I try to control my LCD screen (ref FDCC1601E-FLYYBW-91LE) with my tower K70.
    The link for the datasheet : http://www.farnell.com/datasheets/653649.pdf

    The connection are :
    • PTC0 = DB0 connected to pin 7 LCD screen
    • PTC1= DB1 connected to pin 8 LCD screen
    • PTC2 = DB2 connected to pin 9 LCD screen
    • PTC3 = DB3 connected to pin 10 LCD screen
    • PTC4 = DB4 connected to pin 11 LCD screen
    • PTC5 = DB5 connected to pin 12 LCD screen
    • PTC6 = DB6 connected to pin 13 LCD screen
    • PTC7 = DB7 connected to pin 14 LCD screen
    • PTC8 = RS connected to pin 4 LCD screen
    • PTC9 = R/W connected to pin 5 LCD screen
    • PTC10 = E connected to pin 6 LCD screen

    I did the software with the GPIOs and I follow the initialization (page 16/20).
    It displayed in my screen 8 black characters into 8 first places and nothing after.
    Could you help me please?
    Thank you.

    Please find below my software.

    /***********************************************************************/
    /*Initialisation de l’écran LCD */
    /***********************************************************************/
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(10);
    tempo(100);
    tempo(1000); //500µs
    tempo(10000); //6ms

    for(int i=0; i<20; i++)
    {
    tempo(10000); //6ms
    }

    functionSet_LCD(8, 1,format5x8);
    tempo(10000); //6ms
    functionSet_LCD(8, 1,format5x8);
    tempo(10000); //6ms
    functionSet_LCD(8, 1,format5x8);
    tempo(10000); //6ms
    displayOnOffControl_LCD(DISPLAY_OFF, CURSOR_OFF, CURSOR_BLINK_OFF);
    tempo(10000); //6ms
    clearDisplay_LCD();
    tempo(10000); //6ms
    entryModeSet_LCD(INC, SHIFT_ON);
    tempo(10000); //6ms
    displayOnOffControl_LCD(DISPLAY_ON, CURSOR_ON, CURSOR_BLINK_ON);
    /***********************************************************************/

    for(;;)
    {

    /***************************************/
    /*Affichage sur l'écran LCD */
    /***************************************/
    setDdramAddress_LCD(0,0,0,0,0,0,0); // Adresse 0H
    tempo(10000); //6ms
    writeData_LCD(0,0,1,1,0,0,0,0); //Chiffre 0
    tempo(10000); //6ms
    writeData_LCD(0,0,1,1,0,0,0,1); //Chiffre 1
    tempo(10000); //6ms
    writeData_LCD(0,0,1,1,0,0,1,0); //Chiffre 2
    /***************************************/
    }

    void setCgramAddress_LCD(char AC5, char AC4, char AC3, char AC2, char AC1, char AC0)
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);
    tempo(100);
    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    if(AC0 == 0)
    {
    DB0_LCD_ClrVal(DB0_LCD_DeviceData);
    }
    else
    {
    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    }

    if(AC1 == 0)
    {
    DB1_LCD_ClrVal(DB1_LCD_DeviceData);
    }
    else
    {
    DB1_LCD_SetVal(DB1_LCD_DeviceData);
    }

    if(AC2 == 0)
    {
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    }
    else
    {
    DB2_LCD_SetVal(DB2_LCD_DeviceData);
    }

    if(AC3 == 0)
    {
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    }
    else
    {
    DB3_LCD_SetVal(DB3_LCD_DeviceData);
    }

    if(AC4 == 0)
    {
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    }
    else
    {
    DB4_LCD_SetVal(DB4_LCD_DeviceData);
    }

    if(AC5 == 0)
    {
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    }
    else
    {
    DB5_LCD_SetVal(DB5_LCD_DeviceData);
    }

    DB6_LCD_SetVal(DB6_LCD_DeviceData);
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/

    }

    void setDdramAddress_LCD(char AC6, char AC5, char AC4, char AC3, char AC2, char AC1, char AC0)
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    if(AC0 == 0)
    {
    DB0_LCD_ClrVal(DB0_LCD_DeviceData);
    }
    else
    {
    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    }

    if(AC1 == 0)
    {
    DB1_LCD_ClrVal(DB1_LCD_DeviceData);
    }
    else
    {
    DB1_LCD_SetVal(DB1_LCD_DeviceData);
    }

    if(AC2 == 0)
    {
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    }
    else
    {
    DB2_LCD_SetVal(DB2_LCD_DeviceData);
    }

    if(AC3 == 0)
    {
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    }
    else
    {
    DB3_LCD_SetVal(DB3_LCD_DeviceData);
    }

    if(AC4 == 0)
    {
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    }
    else
    {
    DB4_LCD_SetVal(DB4_LCD_DeviceData);
    }

    if(AC5 == 0)
    {
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    }
    else
    {
    DB5_LCD_SetVal(DB5_LCD_DeviceData);
    }

    if(AC6 == 0)
    {
    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    }
    else
    {
    DB6_LCD_SetVal(DB6_LCD_DeviceData);
    }

    DB7_LCD_SetVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/
    }

    void writeData_LCD(char D7, char D6, char D5, char D4, char D3, char D2, char D1, char D0)
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_SetVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    if(D0 == 0)
    {
    DB0_LCD_ClrVal(DB0_LCD_DeviceData);
    }
    else
    {
    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    }

    if(D1 == 0)
    {
    DB1_LCD_ClrVal(DB1_LCD_DeviceData);
    }
    else
    {
    DB1_LCD_SetVal(DB1_LCD_DeviceData);
    }

    if(D2 == 0)
    {
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    }
    else
    {
    DB2_LCD_SetVal(DB2_LCD_DeviceData);
    }

    if(D3 == 0)
    {
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    }
    else
    {
    DB3_LCD_SetVal(DB3_LCD_DeviceData);
    }

    if(D4 == 0)
    {
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    }
    else
    {
    DB4_LCD_SetVal(DB4_LCD_DeviceData);
    }

    if(D5 == 0)
    {
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    }
    else
    {
    DB5_LCD_SetVal(DB5_LCD_DeviceData);
    }

    if(D6 == 0)
    {
    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    }
    else
    {
    DB6_LCD_SetVal(DB6_LCD_DeviceData);
    }

    if(D7 == 0)
    {
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);
    }
    else
    {
    DB7_LCD_SetVal(DB7_LCD_DeviceData);
    }

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/
    }

    void clearDisplay_LCD()
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    DB1_LCD_ClrVal(DB1_LCD_DeviceData);
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/
    }

    void returnHome_LCD()
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    DB1_LCD_SetVal(DB1_LCD_DeviceData);
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/
    }

    void entryModeSet_LCD(char incDec, char shiftOfEntireDisplay)
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    if(shiftOfEntireDisplay == SHIFT_ON)
    {
    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    }
    else
    {
    DB0_LCD_ClrVal(DB0_LCD_DeviceData);
    }

    if(incDec == INC)
    {
    DB1_LCD_SetVal(DB1_LCD_DeviceData);
    }
    else
    {
    DB1_LCD_ClrVal(DB1_LCD_DeviceData);
    }

    DB2_LCD_SetVal(DB2_LCD_DeviceData);
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/
    }

    void displayOnOffControl_LCD(char displayOnOff, char cursorOnOff, char cursorBlink)
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    if(cursorBlink == CURSOR_BLINK_ON)
    {
    DB0_LCD_SetVal(DB0_LCD_DeviceData);
    }
    else
    {
    DB0_LCD_ClrVal(DB0_LCD_DeviceData);
    }

    if(cursorOnOff == CURSOR_ON)
    {
    DB1_LCD_SetVal(DB1_LCD_DeviceData);
    }
    else
    {
    DB1_LCD_ClrVal(DB1_LCD_DeviceData);
    }

    if(displayOnOff == DISPLAY_ON)
    {
    DB2_LCD_SetVal(DB2_LCD_DeviceData);
    }
    else
    {
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    }

    DB3_LCD_SetVal(DB3_LCD_DeviceData);
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    DB5_LCD_ClrVal(DB5_LCD_DeviceData);
    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/

    }

    void functionSet_LCD(char interfaceData, char nbrLine, char fontType)
    {
    E_LCD_ClrVal(E_LCD_DeviceData);
    RW_LCD_ClrVal(RW_LCD_DeviceData);
    RS_LCD_ClrVal(RS_LCD_DeviceData);

    tempo(100);

    /********Front Montant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    E_LCD_SetVal(E_LCD_DeviceData);
    /******************************/

    if(fontType == format5x8)
    {
    DB2_LCD_ClrVal(DB2_LCD_DeviceData);
    }
    else
    {
    DB2_LCD_SetVal(DB2_LCD_DeviceData);
    }

    if(nbrLine == 1)
    {
    DB3_LCD_ClrVal(DB3_LCD_DeviceData);
    }
    else
    {
    DB3_LCD_SetVal(DB3_LCD_DeviceData);
    }
    if(interfaceData == 8)
    {
    DB4_LCD_SetVal(DB4_LCD_DeviceData);
    }
    else
    {
    DB4_LCD_ClrVal(DB4_LCD_DeviceData);
    }

    DB5_LCD_SetVal(DB5_LCD_DeviceData);

    DB6_LCD_ClrVal(DB6_LCD_DeviceData);
    DB7_LCD_ClrVal(DB7_LCD_DeviceData);

    tempo(100);

    /********Front Descendant*********/
    E_LCD_ClrVal(E_LCD_DeviceData);
    /********************************/

    }

    void tempo(int j)
    {
    DEBUG_TEMPO_SetVal(DEBUG_TEMPO_DeviceData);
    for(int i=0;i<j; i++)
    {
    __asm("nop");
    }
    DEBUG_TEMPO_ClrVal(DEBUG_TEMPO_DeviceData);
    }

    Like

    • Hi Armando,
      and why are you not using the component I have created? It took me a very long time to get the timing right and correctly working. So if you start from scratch, it seems that you are facing yourself all these problems. So I suggest that you use that component code, instead creating your own version. Be free then to change it your own version, but I think it is much easier to start with something working? I hope this helps,
      Erich

      Like

  14. I managed to use.
    This with this notice.

    LCD1_LoadSoftChar(0,&SoftCharUE[0]);

    passing argument 2 of ‘LCD1_LoadSoftChar’ discards ‘const’ qualifier from pointer target type [enabled by default] ProcessorExpert.c /Freedom_2x16_LCD/Sources line 111 C/C++ Problem

    Like

  15. I did what I was told.
    It all worked out, this library is wonderful.
    Thank you very much.
    Now I have a graphic display 128/64 would have a library for this?
    This site is very good.
    Thank you very much.

    Like

  16. Hey Erich,
    I am getting an error in the given line of the above mentioned code

    UTIL1_Num16uToStr(buf, sizeof(buf), cnt);
    The error is – Undefined reference to UTIL1_Num16uToStr

    Can you please help ?
    Thanks

    Like

  17. Hi,
    I have two displays, at first it works perfectly but on second display it shows only black boxes, but in both lines. The difference between display is, that first is 1602E v1.1 and second which does not work is 1602A v2.0. I checked wires and increase cycles in function WAIT1_Waitms from 1000 to 10000, but it still does not work. Do you have any tips?
    Thanks.

    Like

    • Hi Sumi,
      probably the timing is different. I suggest you check the LCD1.c (generated) sources. There are several timing defines in there, e.g.
      #define Timing_PWeh_ns 230 /* PWeh: Enable Pulse width (high level) */
      #define Timing_tAS_ns 40 /* tAB: Address set-up time (RS, RW to E ) */
      #define Timing_tDDR_ns 160 /* tDDR: Data delay time */
      #define Timing_tCYCLE_ns 500 /* tCYLE: Enable Cycle time */
      You might increase these numbers. Otherwise: can you single step through your code and have a logic analyzer attached to your hardware so you see what is going on?

      Like

  18. Good Evening Mr Styger I stuck for a little more than an hour trying to install the LCDHTA program but I haven’t been successful. Can you plese explain me how I can achieve that. I will really appreciate it.

    German C.

    Like

  19. After downloaded the custom character (ê), is possible use it with LCD1_write?
    the CGRAM position is of custom chacarter is 0x00.
    LCD1_WriteLineStr(1, “My ê mensage”); how can i put this custom character in the function “ê”?

    Like

    • Hi Gabriel, have you loaded your custom character to the ‘charCode’ ASCII value of ‘ê’:
      void LCD1_LoadSoftChar(byte charCode, byte *softChar)
      ?
      Then you can use it with LCD1_WriteLineStr(1, “My ê mensage”);

      Like

      • Hi Erich,

        First, i defined the custom (ã) character with:
        const byte Til_a[8] = {0x16,0x09,0x0E,0x01,0x0F,0x11,0x0F,0x00};

        and then,
        void Program_disp(void){
        LCD1_WriteLCDCommand(0x40);
        for (i=0; i<=7; i++){ //send ã
        LCD1_Write(Til_a[i]);
        }
        }

        But, when i use LCD1_WriteLineStr(1, “Tensão”) the LCD doesn't show "ã".

        PS:Tensão means voltage (portugues)

        Like

      • Hi Gabriel,
        you need to do this:
        static const byte Til_a[8] = {0x16,0x09,0x0E,0x01,0x0F,0x11,0x0F,0x00};
        then call
        LCD1_LoadSoftChar(‘ã’, &Til_a[0]);
        Now you can use it e.g. with
        LCD1_WriteLineStr(1, “Tensão”);

        I hope this helps,
        Erich

        Like

  20. HI Erich,

    I tried to use the LDCHTA component on my KDS (version 3.0) and with a FRDM-KL25Z, but when I want to change settings on the component I have multiples errors saying that “The component is not supported for selected processor”…do you have an idea of where the problem could come from?

    PS: I checked twice and I initialised well my project with the KL25Z128

    Like

    • Hi Yohan, it seems to me that you have created a project with the Kinetis SDK enabled? Keep in mind that using the Kinetis SDK is not compatible with all the available components, except the special fsl_ ones. Create the project with the SDK option set to ‘none’.
      I hope this helps.

      Like

      • Yes indeed, I changed the project with only PE and it compiles, however I still run into some issues when I debug my program, it doesn’t pass through the LCD1Init function in the PE_low_level_init() .

        Like

      • I’m affraid that you have to debug through that function and identify what is going wrong. The logic analyzer should help you too to inspect the signals.

        Like

  21. Hi Erich,

    I’m trying to use the LCDHTA component with KDS 3.0, but when building the project appears an error in WAIT1.c file:

    undefined reference to ‘asm’

    Do you have an idea of where the problem could come from?

    Best Regards,

    Wesley

    Like

  22. G’day Erich,

    Thanks for your work on your LCD component!

    I’m just starting out with KDS, and have got v3.1.0 installed. I’ve got your latest components installed, also, and am trying to build your example project. It doesn’t seem to build though, I only get

    **** Clean-only build of configuration FLASH for project Freedom_2x16_LCD ****
    make clean
    make: *** No rule to make target `clean’. Stop.

    Looking at the project properties, I’m seeing a lot of ‘…orphaned…’ warnings around the place. For instance, under C/C++ Build -> Tool Chain Editor, under Configuration I have

    Orphaned configuration. No base extension cfg exists for org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.debug.784994391

    Under Current toolchain I see

    Orphaned toolchain org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.toolchain.debug.2056576785 (ARM Ltd Windows GCC (G++ Lite))

    While under current builder I see

    Orphaned builder org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.builder.debug.861107585 (ARM Ltd Windows GNU Make builder)

    I’m not sure what to do from here, have you seen this previously? How would I go about fixing it?

    Kind regards,

    Stephen

    Like

      • Ah, that might do it, you think? I got the example from the link in your summary [“…an example project here.”].

        I extracted the archive Freedom_2x16_LCD.zip, fired up KDS, File -> Import, General -> Existing Projects into Workspace. I clicked Next, browsed for the root directory, found the location of the extracted archive, and clicked OK.

        At this point, the Projects pane showed only the Freedom_2x16_LCD project, and I hit Finish.

        Was this the right way to go about it? If not, how would you recommend I try again?

        Thanks again for your help, it’s very much appreciated!

        Like

      • Oh, I see. That is indeed a CodeWarrior project (rather old). I have update the link to a newer version on GitHub (for CodeWarrior too). I don’t have the same for KDS. Should not be a big deal, but it does not exist yet 😦 Sorry for that.

        Like

      • Ah, fair enough. Well, if you do end up putting together an example for KDS I’d love to hear it, in the meantime I’ll keep trying myself.

        Kind regards,

        Stephen

        Like

      • Thanks Erich, much appreciated! I’ll download it now and give it a go sometime through the day.

        Like

  23. Hi Erich,

    I’m using KDS with Processor Expert to add the LCDHTA module. Unfortunately I can’t create a project in KDS that includes the base Processor Expert modules such as the BitIO.

    The E and RS signals allow using your GenericBitIO module however the Data/Control Bus requires to use the BItIO module. Is there any way to use GenericBitIO instead?

    Thanks,
    Dan

    Like

    • Hi Dan,
      it seems to me that you have created a project with the Kinetis SDK enabled. Such a project does not allow you to add the BitIO component. Create a new project with the Kinetis SDK not included/disabled, then you can use the BitIO.
      I hope this helps,
      Erich

      Like

      • Unfortunately I’m using a KL27Z and it isn’t directly supported through Processor Expert – only with the KSDK. Is there any way around this without switching boards?

        Like

      • The easiest way is to switch boards. Or you create a project with Processor Expert say for the KL25Z128, then add the component, create the code and then copy the code to the KL25Z project. Still you will have to make source changes to be able to use the driver with the SDK.

        Like

  24. Erich:

    I’m following this tutorial and everything runs OK but compiling the code: it fails saying that “amp” is not declared. What am I doing wrong? Thank you!

    Like

    • Hi Hector,
      I think you might have copied the source code from the web page? Then the ‘&’ might get translated into ‘amp’.
      I suggest you use the source files on the GitHub location mentioned at the end of this article.
      I hope this helps,
      Erich

      Like

      • Erich, thanks for the reply,

        Another question, (seems like it’s a basic error, but I am not an expert in the kl25z) I followed your sugesstions and I downloaded the project from the GitHub location and updated PEupd files since I noticed some other PE components were missing in order to compile it.

        I installed the missing components (UTIL1 and KSDK1) from the sourceforge (file Components 2016-04-03.zip) page mentioned in the article which also updated the LCDHTA component.

        It compiles now with a warning:
        C:/Freescale/CW MCU v10.6/MCU/ARM_GCC_Support/ewl/EWL_C/include/stdbool.h:20:3: warning: #warning “EWL support for C99 is not enabled” [-Wcpp]

        And if I try to flash the KL25z, an error window pops up saying something like:

        Error executing task flash. Wrong expression ${ProjDirPath}/Project_Settings/Debugger/init_kinetis.tcl;
        Could not expand variable ProjDirPath

        Like

      • Hi Hector,
        you can ignore that warning about EWL and C99, at least I do. It warns about usage of ‘bool’ type which is only available in C99. The driver code uses its own version of ‘bool’. The thing about the init_kinetis.tcl: you could disable that tcl in the debugger settings (I think this comes from an older CodeWarrior version, I need to check this).

        Like

      • Hi Hector,
        I checked the project on GitHub, and I missed to add the launch configuration file settings. I have now pushed them to the repository/project.
        Sorry for that problem, I hope it works now for you?

        Like

  25. I have come across what I think is a problem.

    I am using a TWR-K60D100M board with a Tower System and the Arduino Shield Adapter. I can not seem to select the pins I require in the configuration for LCDHTA.

    Like

    • Hi Matthew,
      if you are using a different board, then of course you have to use different pins. You can use any matching pins with Processor Expert, but you need to consult the schematics to know which ones-

      Erich

      Like

  26. It’s good. I nid this, but i can’t edit it with KeilC because too many file to add to my project, i can’t manage them all.
    Can you help me to make it easy? Cuz i can’t rebuilt my project now with PE, the size will be huge 😦

    Like

    • Hi Ryuuka,
      why there are too many files: there is just one driver file for the LCD itself. And why is this too huge for your Keil environment? Maybe just use free-of-charge GNU and Eclipse tools: that whole demo application is less than 5 KByte code with Kinetis Design Studio.

      Like

    • Hi Ryuuka,
      Use Kinetis Design Studio and create a blank project for KL46Z and Processor Expert (takes 1 minute). Then add LCDHTA, Utility and Wait components to the project (one more minute) and assign it to the pins you for your board (one more minute). So in less than 5 minutes you have it running on a FRDM-KL46Z.
      I hope this helps,
      Erich

      Like

  27. If I use this code, and I need to use the potentiometer in a variable, and constantly change that variable and display it on the lcd, how do I?
    ADC_Measure (TRUE);
    ADC_GetChanValue16 (0, & potential);
    Level = ((90/65535) * pot level) + 10; // 10% to 100%
    Lcd_goto (0x00000006);
    Lcd_show_ch (level);

    I do this and it’s wrong … I hope you can help me … will it be in ASCII code?

    Like

    • Hi Mateo,
      first, you have a serious bug in your code: (90/65535) is an integer division and will result in the value 0 (and not a floating point value).
      I don’t know what Lcd_goto() does, and I ask the question if you have 6 lines on your LCD? Maybe this is yet another problem.
      And then I don’t know what LCD_show_ch() does. I assume that it assumes an ASCII character, and *not* a number (as you pass it).
      If you want to display a ‘0’ character for the zero value, then you probably should use Lcd_show_ch(‘0’+level) instead?
      In C there is a difference between numerical formats and the ASCII representation.
      I hope this helps,
      Erich

      Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s