Interfacing 16x2 LCD in ATmega4809

Go To Last Post
35 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all.

 

I'm new in AVR, and now I'm trying to create a program that displays characters to an 16x2 LCD in 4-bit mode using ATmega4809 Curiosity Nano board.

As a guide, I've used this tutorial on how to interface LCD with ATmega: Interfacing LCD 16x2 with ATmega16

 

Below is my code:

LCD header file: lcd.h

#include <avr/io.h>
#include <util/delay.h>

#define lcdPort PORTC_OUT                   //Data Output value of PORTC
#define lcdDir PORTC.DIR                    //Setting pins as I/O
#define EN (PORTC.IN & (1 << 0))            //ENABLE (EN) pin to PORTC PIN0
#define RS (PORTC.IN & (1 << 1))            //REGISTER SELECT (RS) pin to PORTC PIN1

void lcdInit(void);
void lcdClear();
void lcdCmd(uint8_t cmnd);
void lcdChar(uint8_t cmnd);
void lcdString(uint8_t *str);

And lcd.c

/*** PIN ASSIGNMENTS ***/
/*
EN - PC0
RS - PC1
D4 - PC4
D5 - PC5
D6 - PC6
D7 - PC7
*/

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"

/* INITIALIZATION */
void lcdInit(void)
{
  lcdDir = PORTC.DIRSET;	//LCD port direction as output
  _delay_ms(20);					//LCD power initialization time

  lcdCmd(0x02);						//Initializes LCD in 4-bit mode
  lcdCmd(0x28);						//Configures LCD in 2-line 4-bit mode and 5x7 matrix
  lcdCmd(0x0c);						//Display on, cursor off
  lcdCmd(0x06);						//Increment cursor: shift cursor to right
  lcdCmd(0x01);						//Clear display screen
}

/* FOR CLEARING LCD DISPLAY */
void lcdClear()
{
  lcdCmd(0x01);						//Clear display screen
  _delay_ms(2);
  lcdCmd(0x08);						//Clear display without clearing ram content
}

/* LCD COMMAND MODE */
void lcdCmd(uint8_t cmnd)
{
  //Sending upper nibble since 4-bit
  lcdPort = (lcdPort & 0x0F) | (cmnd & 0xF0);
  lcdPort &= ~(1<<RS);					//RS OFF
  lcdPort |= (1<<EN);					//Set bit in EN
  _delay_us(1);
  lcdPort &= ~(1<<EN);					//Clear bit in EN
  _delay_us(200);
  //Sending lower nibble
  lcdPort = (lcdPort &0x0F) | (cmnd <<4);
  lcdPort |= (1<<EN);
  _delay_us(1);
  lcdPort &= ~(1<<EN);
  _delay_ms(2);
}

/* ACCEPTING CHARACTERS IN LCD */
void lcdChar(uint8_t cmnd)
{
  //Sending upper nibble since 4-bit
  lcdPort = (lcdPort & 0x0F) | (cmnd & 0xF0);
  lcdPort &= ~(1<<RS);					//RS ON
  lcdPort |= (1<<EN);					//Set bit in EN
  _delay_us(1);
  lcdPort &= ~(1<<EN);					//Clear bit in EN
  _delay_us(200);
  //Sending lower nibble
  lcdPort = (lcdPort &0x0F) | (cmnd <<4);
  lcdPort |= (1<<EN);
  _delay_us(1);
  lcdPort &= ~(1<<EN);
  _delay_ms(2);
}

/* CONVERTS THE CHARACTER INTO STRING */
void lcdString(uint8_t *str)
{
  int i;
  for(i=0; str[i] != 0; i++)
  {
    lcdChar(str[i]);
  }
}

And for the main.c

#include <avr/io.h>
#include <avr/delay.h>
#include "lcd.c"
#include "twswitch.c"

int main(void)
{
  lcdInit();
  lcdString("hello");
  lcdCmd(0xC0);
  lcdString("world");
}

The LCD displays only black pixels on the upper line; just the default display when plugged into a 5V, but none on the second line.

It does not also display any characters I wanted to appear.

 

I am pretty sure that it's not due to hardware because I've tried the same set-up to an Arduino UNO board, and it works just fine.

So my guess is the problem is really in the code but I'm kind of new at this.

 

Any insights on the code? It would be much appreciated. Thank you!

This topic has a solution.

I'm new.

Last Edited: Fri. Jan 24, 2020 - 06:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you set F_CPU to match the actual clock rate? These LC displays are slow and timing sensitive so you need to ensure the delays are correct. You also need to allow them to recover from reset - you need to allow 200ms (if memory serves correct) before talking to them. 

 

I seem to recall we had the same question recently -  4809/lcd. you might want to do a search.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, Kartman. Thanks for replying.

 

I've been using F_CPU 3333333UL ever since I've worked with USART. 

 

I've seen the thread re 4809/lcd. The author of the thread used an existing library, which is okay. So I also tried the library.

The suggested fixes on the thread are:

1. Changing the pin configurations on the header

2. F_CPU

3. Grounding the RW

 

As much as I want to just fix the existing library, it looks a bit complicated to me and generated A LOT of errors I'm unfamiliar with.

 

So maybe I've been thinking, before I disregard this code I made, I want to understand what went wrong.

 

Regards,

franco

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suggest that you use proven library.   There is no need to understand how the library works.   Just how to call the functions correctly.

I know the brake, clutch and go-faster pedal on my car.    I assume that Opel designed the car adequately.    I trust my local garage to service the car.

 

If you are specifically interested in programming LCD,   start with a regular AVR.

Set the macros correctly for the regular AVR.   e.g. for a mega324 (with JTAG disabled)

#define lcdPort PORTC                   //Data Output value of PORTC
#define lcdDir  DDRC                    //Setting pins as I/O
#define EN (1 << 0)                     //ENABLE (EN) pin to PORTC PIN0
#define RS (1 << 1)                     //REGISTER SELECT (RS) pin to PORTC PIN1

 

Then re-write the macros for the 4809 e.g.

#define lcdPort PORTC_OUT               //Data Output value of PORTC
#define lcdDir  PORTC_DIR               //Setting pins as I/O
#define EN (1 << 0)                     //ENABLE (EN) pin to PORTC PIN0
#define RS (1 << 1)                     //REGISTER SELECT (RS) pin to PORTC PIN1

Untested.   I have not bothered to build your code for either 324 or 4809

 

Let us know how you get on.    If you have a problem,  I might connect up the hardware in real life.

 

The important difference for 4809 ports is that the registers have different names e.g. PORTC_IN versus PINC

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

I suggest that you use proven library.   There is no need to understand how the library works.   Just how to call the functions correctly.

 

As much as I wanted to use the existing library, I've mentioned that it only generates errors I'm very unfamiliar with. It includes errors in the existing libraries in Atmel.

 

david.prentice wrote:

#define lcdPort PORTC_OUT               //Data Output value of PORTC
#define lcdDir  PORTC_DIR               //Setting pins as I/O
#define EN (1 << 0)                     //ENABLE (EN) pin to PORTC PIN0
#define RS (1 << 1)                     //REGISTER SELECT (RS) pin to PORTC PIN1

I've rewritten the code in this way but still, the LCD only displays black boxes in the first line, and none on the second line.

In the tutorial I've used, I started to wonder if are there really no header or defines for the data pins D4-D7? I'm thinking that might be one of the problem?

I appreciate any insights on this. Thank you!

 

franco

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

My apologies. EN should be 0 not 1<<0. Likewise RS should be 1.
.
I might even wire up a real 4809.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

you have some mistakes going on-

lcdDir = PORTC.DIRSET; this does not do what you want

lcdPort &= ~(1<<RS);  //RS ON  this is OFF, not ON and you already have RS as a bitmask

 

Rather than try to correct the above, how about a different tactic, such as the following. Get the lcd code to do simple things, then piece them together. The Data pins can be whatever is convenient, but still on the same port (although that could be changed with few more defines, so all pins could be on any port).

 

This is all single file, and compiles, but I don't know if the lcd commands are correct so am assuming you have that right. Also assuming any needed timing delays are also correct. I have some lcd's somewhere I could test this, but will wait for now (I have a surplus noritake vf 4x20 I bought many years ago for cheap, may I will try it out).

 

//Tiny817 Xplained (tested with a noritake 4x20 vfd)

//(there may be timing that would need tweaking, probably mostly for additional commands that would be added)

//lcd.h
#include <stdint.h> //uncomment in lcd.h
void lcdDat(uint8_t);
void lcdCmd(uint8_t);
void lcdString(char *);
void lcdInit();
void lcdClear();

 

//lcd.c
//#include "lcd.h" //uncomment in lcd.c
#include <avr/io.h>
#include <stdbool.h>
#define F_CPU 3333333ul
#include <util/delay.h>

 

#define lcdPortCtrl VPORTB.OUT
#define lcdDirCtrl  VPORTB.DIR
#define lcdPortDat  VPORTA.OUT
#define lcdDirDat   VPORTA.DIR
#define EN PIN1_bm
#define RS PIN0_bm
#define D7 PIN4_bm
#define D6 PIN5_bm
#define D5 PIN6_bm
#define D4 PIN7_bm

 

static void lcdPinInit(){ lcdDirCtrl |= EN|RS; lcdDirDat |= D4|D5|D6|D7; }
static void lcdEN(){ lcdPortCtrl |= EN; _delay_us(2); lcdPortCtrl &= ~EN; }
static void lcdRS(bool tf){ if(tf) lcdPortCtrl |= RS; else lcdPortCtrl &= ~RS; }
static void lcdD4(bool tf){ if(tf) lcdPortDat |= D4; else lcdPortDat &= ~D4; }
static void lcdD5(bool tf){ if(tf) lcdPortDat |= D5; else lcdPortDat &= ~D5; }
static void lcdD6(bool tf){ if(tf) lcdPortDat |= D6; else lcdPortDat &= ~D6; }
static void lcdD7(bool tf){ if(tf) lcdPortDat |= D7; else lcdPortDat &= ~D7; }
static void lcdD(uint8_t v){ lcdD4(v&1); lcdD5(v&2); lcdD6(v&4); lcdD7(v&8); lcdEN(); }

void lcdCmd(uint8_t v){ lcdD(v>>4); lcdD(v); lcdRS(0); }
void lcdDat(uint8_t v){ lcdRS(1); lcdCmd(v); }
void lcdString(char *str){ for( ; *str; lcdDat((uint8_t)*str++) ); }
void lcdInit(void){
    lcdPinInit();

    //HD44780 datasheet
    _delay_ms(20);
    lcdD(0x3); //8bit mode
    _delay_ms(5);
    lcdD(0x3); //8bit mode
    _delay_us(100);
    //0x32 = 4bit mode (3=8bit, 2=4bit)
    //0x28 = 4bit, 2line
    //0x08 = display off
    //0x01 = display clear
    //0x06 = entry mode, increment
    //0x0f = display on, cursor on, blink on
    static const uint8_t initv[]={0x32,0x28,0x08,0x01,0x06,0x0f,0};
    for(uint8_t i = 0; initv[i]; i++) lcdCmd(initv[i]);
}
void lcdClear(){
  lcdCmd(0x01);     //Clear display screen

  _delay_ms(5); //not sure what is needed, but something is needed
}

//main.c
//#include "lcd.h" //uncomment in main.c
#include <avr/io.h>
int main(void)
{
  lcdInit();
  for(;;){
    lcdString("Hello World ");
    _delay_ms(2000);
  }
}

 

Last Edited: Mon. Jan 6, 2020 - 04:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi David.

 

I've kind of considered your advice regarding existing libraries. As of now, I have 4 drafts of LCD module coming from different tutorials or existing libraries.

I've also edited the code with this

david.prentice wrote:
My apologies. EN should be 0 not 1<<0. Likewise RS should be 1.
, but still, with the same default display on LCD.

 

In all the drafts, one of them is responding with the LCD. The library comes from this. 

Although it's not much of a response, I think it's better that I work on this code rather than working on something with no response at all.

 

The existing code is a bit long so I deleted some lines to shorten it.

I've also liked this code a bit since defines are very clear.

Code for lcd.h

#ifndef LCD_H
#define LCD_H
#define _BV(bit) (1 << (bit))

#include <util/delay.h>

#ifndef LCD_LINES
#define LCD_LINES           2     /**< number of visible lines of the display */
#endif
#ifndef LCD_DISP_LENGTH
#define LCD_DISP_LENGTH    16     /**< visibles characters per line of the display */
#endif
#ifndef LCD_LINE_LENGTH
#define LCD_LINE_LENGTH  0x40     /**< internal line length of the display    */
#endif
#ifndef LCD_START_LINE1
#define LCD_START_LINE1  0x00     /**< DDRAM address of first char of line 1 */
#endif
#ifndef LCD_START_LINE2
#define LCD_START_LINE2  0x40     /**< DDRAM address of first char of line 2 */
#endif
#ifndef LCD_START_LINE3
#define LCD_START_LINE3  0x14     /**< DDRAM address of first char of line 3 */
#endif
#ifndef LCD_START_LINE4
#define LCD_START_LINE4  0x54     /**< DDRAM address of first char of line 4 */
#endif
#ifndef LCD_WRAP_LINES
#define LCD_WRAP_LINES      0     /**< 0: no wrap, 1: wrap at end of visibile line */
#endif

#define LCD_IO_MODE      1            /**< 0: memory mapped mode, 1: IO port mode */

#if LCD_IO_MODE

#ifndef LCD_DATA0_PORT
#define LCD_DATA0_PORT   VPORTC		  /**< port for 4bit data bit 0 */
#endif
#ifndef LCD_DATA1_PORT
#define LCD_DATA1_PORT   VPORTC     /**< port for 4bit data bit 1 */
#endif
#ifndef LCD_DATA2_PORT
#define LCD_DATA2_PORT   VPORTC     /**< port for 4bit data bit 2 */
#endif
#ifndef LCD_DATA3_PORT
#define LCD_DATA3_PORT   VPORTC     /**< port for 4bit data bit 3 */
#endif
#ifndef LCD_DATA0_PIN
#define LCD_DATA0_PIN    0           /**< pin for 4bit data bit 0  */
#endif
#ifndef LCD_DATA1_PIN
#define LCD_DATA1_PIN    1            /**< pin for 4bit data bit 1  */
#endif
#ifndef LCD_DATA2_PIN
#define LCD_DATA2_PIN    2            /**< pin for 4bit data bit 2  */
#endif
#ifndef LCD_DATA3_PIN
#define LCD_DATA3_PIN    3            /**< pin for 4bit data bit 3  */
#endif
#ifndef LCD_RS_PORT
#define LCD_RS_PORT      VPORTC     /**< port for RS line         */
#endif
#ifndef LCD_RS_PIN
#define LCD_RS_PIN       4	            /**< pin  for RS line         */
#endif
#ifndef LCD_RW_PORT
#define LCD_RW_PORT      VPORTC     /**< port for RW line         */
#endif
#ifndef LCD_RW_PIN
#define LCD_RW_PIN       5            /**< pin  for RW line         */
#endif
#ifndef LCD_EN_PORT
#define LCD_EN_PORT      VPORTC     /**< port for Enable line     */
#endif
#ifndef LCD_EN_PIN
#define LCD_EN_PIN        6            /**< pin  for Enable line     */
#endif
#endif

#ifndef LCD_DELAY_BOOTUP
#define LCD_DELAY_BOOTUP   16000      /**< delay in micro seconds after power-on  */
#endif
#ifndef LCD_DELAY_INIT
#define LCD_DELAY_INIT      5000      /**< delay in micro seconds after initialization command sent  */
#endif
#ifndef LCD_DELAY_INIT_REP
#define LCD_DELAY_INIT_REP    64      /**< delay in micro seconds after initialization command repeated */
#endif
#ifndef LCD_DELAY_INIT_4BIT
#define LCD_DELAY_INIT_4BIT   64      /**< delay in micro seconds after setting 4-bit mode */ 
#endif
#ifndef LCD_DELAY_BUSY_FLAG
#define LCD_DELAY_BUSY_FLAG    4      /**< time in micro seconds the address counter is updated after busy flag is cleared */
#endif
#ifndef LCD_DELAY_ENABLE_PULSE
#define LCD_DELAY_ENABLE_PULSE 1      /**< enable signal pulse width in micro seconds */
#endif

#define LCD_CLR               0      /* DB0: clear display                  */
#define LCD_HOME              1      /* DB1: return to home position        */
#define LCD_ENTRY_MODE        2      /* DB2: set entry mode                 */
#define LCD_ENTRY_INC         1      /*   DB1: 1=increment, 0=decrement     */
#define LCD_ENTRY_SHIFT       0      /*   DB2: 1=display shift on           */
#define LCD_ON                3      /* DB3: turn lcd/cursor on             */
#define LCD_ON_DISPLAY        2      /*   DB2: turn display on              */
#define LCD_ON_CURSOR         1      /*   DB1: turn cursor on               */
#define LCD_ON_BLINK          0      /*     DB0: blinking cursor ?          */
#define LCD_MOVE              4      /* DB4: move cursor/display            */
#define LCD_MOVE_DISP         3      /*   DB3: move display (0-> cursor) ?  */
#define LCD_MOVE_RIGHT        2      /*   DB2: move right (0-> left) ?      */
#define LCD_FUNCTION          5      /* DB5: function set                   */
#define LCD_FUNCTION_8BIT     4      /*   DB4: set 8BIT mode (0->4BIT mode) */
#define LCD_FUNCTION_2LINES   3      /*   DB3: two lines (0->one line)      */
#define LCD_FUNCTION_10DOTS   2      /*   DB2: 5x10 font (0->5x7 font)      */
#define LCD_CGRAM             6      /* DB6: set CG RAM address             */
#define LCD_DDRAM             7      /* DB7: set DD RAM address             */
#define LCD_BUSY              7      /* DB7: LCD is busy                    */

/* set entry mode: display shift on/off, dec/inc cursor move direction */
#define LCD_ENTRY_DEC            0x04   /* display shift off, dec cursor move dir */
#define LCD_ENTRY_DEC_SHIFT      0x05   /* display shift on,  dec cursor move dir */
#define LCD_ENTRY_INC_           0x06   /* display shift off, inc cursor move dir */
#define LCD_ENTRY_INC_SHIFT      0x07   /* display shift on,  inc cursor move dir */

/* display on/off, cursor on/off, blinking char at cursor position */
#define LCD_DISP_OFF             0x08   /* display off                            */
#define LCD_DISP_ON              0x0C   /* display on, cursor off                 */
#define LCD_DISP_ON_BLINK        0x0D   /* display on, cursor off, blink char     */
#define LCD_DISP_ON_CURSOR       0x0E   /* display on, cursor on                  */
#define LCD_DISP_ON_CURSOR_BLINK 0x0F   /* display on, cursor on, blink char      */

/* move cursor/shift display */
#define LCD_MOVE_CURSOR_LEFT     0x10   /* move cursor left  (decrement)          */
#define LCD_MOVE_CURSOR_RIGHT    0x14   /* move cursor right (increment)          */
#define LCD_MOVE_DISP_LEFT       0x18   /* shift display left                     */
#define LCD_MOVE_DISP_RIGHT      0x1C   /* shift display right                    */

/* function set: set interface data length and number of display lines */
#define LCD_FUNCTION_4BIT_1LINE  0x20   /* 4-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_4BIT_2LINES 0x28   /* 4-bit interface, dual line,   5x7 dots */
#define LCD_FUNCTION_8BIT_1LINE  0x30   /* 8-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_8BIT_2LINES 0x38   /* 8-bit interface, dual line,   5x7 dots */


#define LCD_MODE_DEFAULT     ((1<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) )

/**
 @brief    Initialize display and select type of cursor
 @param    dispAttr \b LCD_DISP_OFF display off\n
          \b LCD_DISP_ON display on, cursor off\n
          \b LCD_DISP_ON_CURSOR display on, cursor on\n
          \b LCD_DISP_ON_CURSOR_BLINK display on, cursor on flashing             
 @return  none
*/
extern void lcd_init(uint8_t dispAttr);


/**
 @brief    Clear display and set cursor to home position
 @return   none
*/
extern void lcd_clrscr(void);


/**
 @brief    Set cursor to home position
 @return   none
*/
extern void lcd_home(void);


/**
 @brief    Set cursor to specified position
 
 @param    x horizontal position\n (0: left most position)
 @param    y vertical position\n   (0: first line)
 @return   none
*/
extern void lcd_gotoxy(uint8_t x, uint8_t y);


/**
 @brief    Display character at current cursor position
 @param    c character to be displayed                                       
 @return   none
*/
extern void lcd_putc(char c);


/**
 @brief    Display string without auto linefeed
 @param    s string to be displayed                                        
 @return   none
*/
extern void lcd_puts(const char *s);


/**
 @brief    Display string from program memory without auto linefeed
 @param    progmem_s string from program memory be be displayed                                        
 @return   none
 @see      lcd_puts_P
*/
extern void lcd_puts_p(const char *progmem_s);


/**
 @brief    Send LCD controller instruction command
 @param    cmd instruction to send to LCD controller, see HD44780 data sheet
 @return   none
*/
extern void lcd_command(uint8_t cmd);


/**
 @brief    Send data byte to LCD controller 
 
 Similar to lcd_putc(), but without interpreting LF
 @param    data byte to send to LCD controller, see HD44780 data sheet
 @return   none
*/
extern void lcd_data(uint8_t data);


/**
 @brief macros for automatically storing string constant in program memory
*/
#define lcd_puts_P(__s)         lcd_puts_p(PSTR(__s))

/**@}*/

#endif //LCD_H

 Code for lcd.c

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"

#define _BV(bit) (1 << (bit))

#if LCD_IO_MODE
#define LCD_EN_delay()   _delay_us(LCD_DELAY_ENABLE_PULSE)
#define LCD_EN_high()    LCD_EN_PORT.OUT  |=  _BV(LCD_EN_PIN);			// PORTC PIN6
#define LCD_EN_low()     LCD_EN_PORT.OUT  &= ~_BV(LCD_EN_PIN);
#define LCD_EN_toggle()  toggle_e()

#define LCD_RW_high()   LCD_RW_PORT.OUT |=  _BV(LCD_RW_PIN)					// PORTC PIN5
#define LCD_RW_low()    LCD_RW_PORT.OUT &= ~_BV(LCD_RW_PIN)

#define LCD_RS_high()   LCD_RS_PORT.OUT |=  _BV(LCD_RS_PIN)					// PORTC PIN7
#define LCD_RS_low()    LCD_RS_PORT.OUT &= ~_BV(LCD_RS_PIN)
#endif

//***************************************************************************************//

#if LCD_IO_MODE
#if LCD_LINES==1
#define LCD_FUNCTION_DEFAULT    LCD_FUNCTION_4BIT_1LINE
#else
#define LCD_FUNCTION_DEFAULT    LCD_FUNCTION_4BIT_2LINES 						// 2-LINE LCD
#endif
#endif

#if LCD_IO_MODE
static void toggle_e(void);
#endif

//***************************************************************************************//


/************************************************************************* 
delay for a minimum of <us> microseconds
the number of loops is calculated at compile-time from MCU clock frequency
*************************************************************************/
#define delay(us)  _delay_us(us) 

#if LCD_IO_MODE
/* toggle Enable Pin to initiate write */
static void toggle_e(void)
{
    LCD_EN_high();
    LCD_EN_delay();
    LCD_EN_low();
}
#endif


/*************************************************************************
Low-level function to write byte to LCD controller
Input:    data   byte to write to LCD
          rs     1: write data    
                 0: write instruction
Returns:  none
*************************************************************************/
#if LCD_IO_MODE
static void lcd_write(uint8_t data,uint8_t rs) 
{
    unsigned char dataBits ;

    if (rs) {        /* write data        (RS=1, RW=0) */
       LCD_RS_high();
    } else {         /* write instruction (RS=0, RW=0) */
       LCD_RS_low();
    }
    LCD_RW_low();    /* RW=0  write mode      */

    if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT )
      && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT )
      && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
      && (LCD_DATA0_PIN == 0)
      && (LCD_DATA1_PIN == 1)
      && (LCD_DATA2_PIN == 2)
      && (LCD_DATA3_PIN == 3) )
    {
        /* configure data pins as output */
        LCD_DATA0_PORT.DIR |= 0x0F;

        /* output high nibble first */
        dataBits = LCD_DATA0_PORT.OUT & 0xF0;
        LCD_DATA0_PORT.OUT = dataBits |((data>>4)&0x0F);
        LCD_EN_toggle();

        /* output low nibble */
        LCD_DATA0_PORT.OUT = dataBits | (data&0x0F);
        LCD_EN_toggle();

        /* all data pins high (inactive) */
        LCD_DATA0_PORT.OUT = dataBits | 0x0F;
    }
    else
    {
        /* configure data pins as output */
        LCD_DATA0_PORT.DIR |= _BV(LCD_DATA0_PIN);
        LCD_DATA1_PORT.DIR |= _BV(LCD_DATA1_PIN);
        LCD_DATA2_PORT.DIR |= _BV(LCD_DATA2_PIN);
        LCD_DATA3_PORT.DIR |= _BV(LCD_DATA3_PIN);
        
        /* output high nibble first */
        LCD_DATA3_PORT.OUT &= ~_BV(LCD_DATA3_PIN);
        LCD_DATA2_PORT.OUT &= ~_BV(LCD_DATA2_PIN);
        LCD_DATA1_PORT.OUT &= ~_BV(LCD_DATA1_PIN);
        LCD_DATA0_PORT.OUT &= ~_BV(LCD_DATA0_PIN);
        
      if(data & 0x80) LCD_DATA3_PORT.OUT |= _BV(LCD_DATA3_PIN);
      if(data & 0x40) LCD_DATA2_PORT.OUT |= _BV(LCD_DATA2_PIN);
      if(data & 0x20) LCD_DATA1_PORT.OUT |= _BV(LCD_DATA1_PIN);
      if(data & 0x10) LCD_DATA0_PORT.OUT |= _BV(LCD_DATA0_PIN);   
        LCD_EN_toggle();
        
        /* output low nibble */
        LCD_DATA3_PORT.OUT &= ~_BV(LCD_DATA3_PIN);
        LCD_DATA2_PORT.OUT &= ~_BV(LCD_DATA2_PIN);
        LCD_DATA1_PORT.OUT &= ~_BV(LCD_DATA1_PIN);
        LCD_DATA0_PORT.OUT &= ~_BV(LCD_DATA0_PIN);
      if(data & 0x08) LCD_DATA3_PORT.OUT |= _BV(LCD_DATA3_PIN);
      if(data & 0x04) LCD_DATA2_PORT.OUT |= _BV(LCD_DATA2_PIN);
      if(data & 0x02) LCD_DATA1_PORT.OUT |= _BV(LCD_DATA1_PIN);
      if(data & 0x01) LCD_DATA0_PORT.OUT |= _BV(LCD_DATA0_PIN);
        LCD_EN_toggle();        
        
        /* all data pins high (inactive) */
        LCD_DATA0_PORT.OUT |= _BV(LCD_DATA0_PIN);
        LCD_DATA1_PORT.OUT |= _BV(LCD_DATA1_PIN);
        LCD_DATA2_PORT.OUT |= _BV(LCD_DATA2_PIN);
        LCD_DATA3_PORT.OUT |= _BV(LCD_DATA3_PIN);
    }
}
#else
#define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d;
/* rs==0 -> write instruction to LCD_IO_FUNCTION */
/* rs==1 -> write data to LCD_IO_DATA */
#endif


/*************************************************************************
Low-level function to read byte from LCD controller
Input:    rs     1: read data    
                 0: read busy flag / address counter
Returns:  byte read from LCD controller
*************************************************************************/
#if LCD_IO_MODE
static uint8_t lcd_read(uint8_t rs) 
{
    uint8_t data;
    
    
    if (rs)
        LCD_RS_high();                       /* RS=1: read data      */
    else
        LCD_RS_low();                        /* RS=0: read busy flag */
    LCD_RW_high();                           /* RW=1  read mode      */
    
    if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
      && ( LCD_DATA0_PIN == 0 )&& (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
    {
        LCD_DATA0_PORT.DIR &= 0xF0;         /* configure data pins as input */
        
        LCD_EN_high();
        LCD_EN_delay();        
        data = LCD_DATA0_PORT.IN << 4;     /* read high nibble first */
        LCD_EN_low();
        
        LCD_EN_delay();                       /* Enable 500ns low       */
        
        LCD_EN_high();
        LCD_EN_delay();
        data |= LCD_DATA0_PORT.IN &0x0F;    /* read low nibble        */
        LCD_EN_low();
    }
    else
    {
        /* configure data pins as input */
        LCD_DATA0_PORT.DIR &= ~_BV(LCD_DATA0_PIN);
        LCD_DATA1_PORT.DIR &= ~_BV(LCD_DATA1_PIN);
        LCD_DATA2_PORT.DIR &= ~_BV(LCD_DATA2_PIN);
        LCD_DATA3_PORT.DIR &= ~_BV(LCD_DATA3_PIN);
                
        /* read high nibble first */
        LCD_EN_high();
        LCD_EN_delay();        
        data = 0;
        if ( LCD_DATA0_PORT.IN & _BV(LCD_DATA0_PIN) ) data |= 0x10;
        if ( LCD_DATA1_PORT.IN & _BV(LCD_DATA1_PIN) ) data |= 0x20;
        if ( LCD_DATA2_PORT.IN & _BV(LCD_DATA2_PIN) ) data |= 0x40;
        if ( LCD_DATA3_PORT.IN & _BV(LCD_DATA3_PIN) ) data |= 0x80;
        LCD_EN_low();

        LCD_EN_delay();                       /* Enable 500ns low       */
    
        /* read low nibble */    
        LCD_EN_high();
        LCD_EN_delay();
        if ( LCD_DATA0_PORT.IN & _BV(LCD_DATA0_PIN) ) data |= 0x01;
        if ( LCD_DATA1_PORT.IN & _BV(LCD_DATA1_PIN) ) data |= 0x02;
        if ( LCD_DATA2_PORT.IN & _BV(LCD_DATA2_PIN) ) data |= 0x04;
        if ( LCD_DATA3_PORT.IN & _BV(LCD_DATA3_PIN) ) data |= 0x08;        
        LCD_EN_low();
    }
    return data;
}
#else
#define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ)
/* rs==0 -> read instruction from LCD_IO_FUNCTION */
/* rs==1 -> read data from LCD_IO_DATA */
#endif


/*************************************************************************
loops while lcd is busy, returns address counter
*************************************************************************/
static uint8_t lcd_waitbusy(void)

{
    register uint8_t c;
    
    /* wait until busy flag is cleared */
    while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) {}
    
    /* the address counter is updated 4us after the busy flag is cleared */
    delay(LCD_DELAY_BUSY_FLAG);

    /* now read the address counter */
    return (lcd_read(0));  // return address counter
    
}/* lcd_waitbusy */


/*************************************************************************
Move cursor to the start of next line or to the first line if the cursor 
is already on the last line.
*************************************************************************/
static inline void lcd_newline(uint8_t pos)
{
    register uint8_t addressCounter;


#if LCD_LINES==1
    addressCounter = 0;
#endif
#if LCD_LINES==2
    if ( pos < (LCD_START_LINE2) )
        addressCounter = LCD_START_LINE2;
    else
        addressCounter = LCD_START_LINE1;
#endif
    lcd_command((1<<LCD_DDRAM)+addressCounter);

}/* lcd_newline */


/*
** PUBLIC FUNCTIONS 
*/

/*************************************************************************
Send LCD controller instruction command
Input:   instruction to send to LCD controller, see HD44780 data sheet
Returns: none
*************************************************************************/
void lcd_command(uint8_t cmd)
{
    lcd_waitbusy();
    lcd_write(cmd,0);
}


/*************************************************************************
Send data byte to LCD controller 
Input:   data to send to LCD controller, see HD44780 data sheet
Returns: none
*************************************************************************/
void lcd_data(uint8_t data)
{
    lcd_waitbusy();
    lcd_write(data,1);
}


/*************************************************************************
Set cursor to specified position
Input:    x  horizontal position  (0: left most position)
          y  vertical position    (0: first line)
Returns:  none
*************************************************************************/
void lcd_gotoxy(uint8_t x, uint8_t y)
{
#if LCD_LINES==1
    lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
#endif
#if LCD_LINES==2
    if ( y==0 ) 
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
    else
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
#endif
#if LCD_LINES==4
    if ( y==0 )
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
    else if ( y==1)
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
    else if ( y==2)
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x);
    else /* y==3 */
        lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x);
#endif

}/* lcd_gotoxy */


/*************************************************************************
*************************************************************************/
int lcd_getxy(void)
{
    return lcd_waitbusy();
}


/*************************************************************************
Clear display and set cursor to home position
*************************************************************************/
void lcd_clrscr(void)
{
    lcd_command(1<<LCD_CLR);
}


/*************************************************************************
Set cursor to home position
*************************************************************************/
void lcd_home(void)
{
    lcd_command(1<<LCD_HOME);
}


/*************************************************************************
Display character at current cursor position 
Input:    character to be displayed                                       
Returns:  none
*************************************************************************/
void lcd_putc(char c)
{
    uint8_t pos;

    pos = lcd_waitbusy();   // read busy-flag and address counter
    if (c=='\n')
    {
        lcd_newline(pos);
    }
    else
    {
#if LCD_WRAP_LINES==1
#if LCD_LINES==1
        if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
        }
#elif LCD_LINES==2
        if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);    
        }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ){
            lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
        }
#endif
        lcd_waitbusy();
#endif
        lcd_write(c, 1);
    }

}/* lcd_putc */


/*************************************************************************
Display string without auto linefeed 
Input:    string to be displayed
Returns:  none
*************************************************************************/
void lcd_puts(const char *s)
/* print string on lcd (no auto linefeed) */
{
    register char c;

    while ( (c = *s++) ) {
        lcd_putc(c);
    }

}/* lcd_puts */

/*************************************************************************
Initialize display and select type of cursor 
Input:    dispAttr LCD_DISP_OFF            display off
                   LCD_DISP_ON             display on, cursor off
                   LCD_DISP_ON_CURSOR      display on, cursor on
                   LCD_DISP_CURSOR_BLINK   display on, cursor on flashing
Returns:  none
*************************************************************************/
void lcd_init(uint8_t dispAttr)
{
#if LCD_IO_MODE
    /*
     *  Initialize LCD to 4 bit I/O mode
     */
    /*configure all port bits as output (LCD data and control lines on different ports */
    LCD_RS_PORT.DIR   |= _BV(LCD_RS_PIN);
    LCD_RW_PORT.DIR    |= _BV(LCD_RW_PIN);
    LCD_EN_PORT.DIR     |= _BV(LCD_EN_PIN);
    LCD_DATA0_PORT.DIR |= _BV(LCD_DATA0_PIN);
    LCD_DATA1_PORT.DIR |= _BV(LCD_DATA1_PIN);
    LCD_DATA2_PORT.DIR |= _BV(LCD_DATA2_PIN);
    LCD_DATA3_PORT.DIR |= _BV(LCD_DATA3_PIN);

    delay(LCD_DELAY_BOOTUP);             /* wait 16ms or more after power-on       */
    
    /* initial write to lcd is 8bit */
    LCD_DATA1_PORT.OUT |= _BV(LCD_DATA1_PIN);    // LCD_FUNCTION>>4;
    LCD_DATA0_PORT.OUT |= _BV(LCD_DATA0_PIN);    // LCD_FUNCTION_8BIT>>4;
    LCD_EN_toggle();
    delay(LCD_DELAY_INIT);               /* delay, busy flag can't be checked here */
   
    /* repeat last command */ 
    LCD_EN_toggle();      
    delay(LCD_DELAY_INIT_REP);           /* delay, busy flag can't be checked here */
    
    /* repeat last command a third time */
    LCD_EN_toggle();      
    delay(LCD_DELAY_INIT_REP);           /* delay, busy flag can't be checked here */

    /* now configure for 4bit mode */
    LCD_DATA0_PORT.OUT &= ~_BV(LCD_DATA0_PIN);   // LCD_FUNCTION_4BIT_1LINE>>4
    LCD_EN_toggle();
    delay(LCD_DELAY_INIT_4BIT);          /* some displays need this additional delay */
    
    /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */    
#endif
}/* lcd_init */

Code for main.c

#define F_CPU 3333333ul
#define _BV(bit) (1 << (bit))

#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.c"

int main(void)
{
	lcd_init(LCD_DISP_ON);
	lcd_clrscr();
	lcd_puts("hello");
}

When the LCD is supplied with 5V, the LCD displays black boxes on the first row but none on the second row.

Upon running the code above, the LCD suddenly displays black boxes on both first and second row, but with lower contrast. This could mean, the display is cleared right?
So that's why I'm assuming this is a start.

 

Pin Assignments are:

D4 - PC0

D5 - PC1

D6 - PC2

D7 - PC3

RS - PC4

RW - PC5 (But connected to ground. I just need the W)

EN - PC6

 

Running this code and wiring this to your 4809 might help me a lot.

Thank you very much!

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, curtvm! I really appreciate your help and code suggestion!

 

I've tried to run this code and hopefully find some progress, but to no avail.
However, the reply I previously posted on this thread contains a code that makes the LCD display somewhat respond to the MCU, so I guess I'll be working on that instead.

 

franco

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

This is the same as in some previous thread- you define F_CPU in main.c, but where its used in lcd.c its not defined. You must be getting an error that you are ignoring about F_CPU not defined.

 

Set F_CPU where its needed- in lcd.c, or lcd.h since its included in lcd.c (or create a -DF_CPU=3333333 compiler option so all files get the same value and you don't have to create a copy of the define in various files).

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

curtvm wrote:
 create a -DF_CPU=3333333 compiler option so all files get the same value and you don't have to create a copy of the define in various files

That's the way to do it!

 

For how to do it in Atmel Studio, see: https://www.avrfreaks.net/commen... - which links to illustrated instructions.

 

Other IDEs are similar.

 

@francoder if you're using Atmel Studio, there's a load of introductory videos to get you started with Atmel Studio on the Atmel Studio page:

 

https://www.microchip.com/mplab/avr-support/atmel-studio-7 - scroll down to the end 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

francoder wrote:
I'm new in AVR

Do you have experience with any other microcontroller(s) ?

 

Do you have experience with programming in general ?

 

Driving an LCD is not really a beginner project - if this is your first project, I would strongly suggest that you start with something simpler!

 

See:  https://www.avrfreaks.net/comment/1138166#comment-1138166

 

And:  https://www.avrfreaks.net/comment/2079906#comment-2079906

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I built your code but had to make several corrections.  Hint search for "kbv"

 

I attach the AS7 project.

 

Note that the m4809 will default to 16MHz div 6 i.e. 2.67MHz

Functions like lcdString() should expect char* and not uint8_t*

 

It would be sensible to use a library with documented functions e.g. lcd_gotoxy()

 

David.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I took my code in #7, made a few changes as I was using a tiny817 xplained (using both portb and porta). I also just used a standard 44780 datasheet to do the init code as I figured it best to go right to the source (also changed the Clear function). I updated the code in #7 to reflect the functioning code I used for the 817. It is of course incomplete, but works (and I'm of course making a mess by writing the same string repeatedly with no position control).

 

I will probably add an lcd class to my c++ code and test on the 4809 board, but it just shows that a couple dozen lines of code can get you started and I think a beginner is capable of pulling this off with a little work.

 

edit-

Have been tossing random numbers at it for a while (second picture), and seems to work. I'm not sure if I have timing requirements optimized (or met), but other than EN I don't think one can get in too much trouble with a max 20MHz mcu. I think I would probably go the extra step and make use of the r/w pin so I could read the busy bit.

 

Now I'm going to have to figure out a use for my vfd display (which has been stashed away for many years).

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I followed my own advice.   i.e. start with the Tutorial link from the Original Post

 

You can see my edited defines for your 4809 wiring.    The "4809 porting" was nothing more than the defines.    The tutorial code was already correct.

If you call a function LCD_String_xy() I would expect the arguments to be LCD_String_xy(msg, x, y) and not LCD_String_xy(y, x, msg)

 

/*
   LCD16x2 4 bit ATmega4809 interface .kbv
   http://www.electronicwings.com
*/

//#define F_CPU 8000000UL			/* Define CPU Frequency e.g. here 8MHz */
#define F_CPU 2666667UL			/* .kbv Define CPU Frequency e.g. here 2.67MHz */
#include <avr/io.h>			/* Include AVR std. library file */
#include <util/delay.h>			/* Include Delay header file */

#define LCD_Dir  PORTC_DIR			/* .kbv Define LCD data port direction */
#define LCD_Port PORTC_OUT			/* .kbv Define LCD data port */
#define RS 1				/* .kbv Define Register Select pin */
#define EN 0 				/* .kbv Define Enable signal pin */

void LCD_Command( unsigned char cmnd )
{
	LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0); /* sending upper nibble */
	LCD_Port &= ~ (1<<RS);		/* RS=0, command reg. */
	LCD_Port |= (1<<EN);		/* Enable pulse */
	_delay_us(1);
	LCD_Port &= ~ (1<<EN);

	_delay_us(200);

	LCD_Port = (LCD_Port & 0x0F) | (cmnd << 4);  /* sending lower nibble */
	LCD_Port |= (1<<EN);
	_delay_us(1);
	LCD_Port &= ~ (1<<EN);
	_delay_ms(2);
}

void LCD_Char( unsigned char data )
{
	LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0); /* sending upper nibble */
	LCD_Port |= (1<<RS);		/* RS=1, data reg. */
	LCD_Port|= (1<<EN);
	_delay_us(1);
	LCD_Port &= ~ (1<<EN);

	_delay_us(200);

	LCD_Port = (LCD_Port & 0x0F) | (data << 4); /* sending lower nibble */
	LCD_Port |= (1<<EN);
	_delay_us(1);
	LCD_Port &= ~ (1<<EN);
	_delay_ms(2);
}

void LCD_Init (void)			/* LCD Initialize function */
{
	LCD_Dir = 0xFF;			/* Make LCD port direction as o/p */
	_delay_ms(20);			/* LCD Power ON delay always >15ms */

	LCD_Command(0x02);		/* send for 4 bit initialization of LCD  */
	LCD_Command(0x28);              /* 2 line, 5*7 matrix in 4-bit mode */
	LCD_Command(0x0c);              /* Display on cursor off*/
	LCD_Command(0x06);              /* Increment cursor (shift cursor to right)*/
	LCD_Command(0x01);              /* Clear display screen*/
	_delay_ms(2);
}

void LCD_String (char *str)		/* Send string to LCD function */
{
	int i;
	for(i=0;str[i]!=0;i++)		/* Send each char of string till the NULL */
	{
		LCD_Char (str[i]);
	}
}

void LCD_String_xy (char row, char pos, char *str)	/* Send string to LCD with xy position */
{
	if (row == 0 && pos<16)
	LCD_Command((pos & 0x0F)|0x80);	/* Command of first row and required position<16 */
	else if (row == 1 && pos<16)
	LCD_Command((pos & 0x0F)|0xC0);	/* Command of first row and required position<16 */
	LCD_String(str);		/* Call LCD string function */
}

void LCD_Clear()
{
	LCD_Command (0x01);		/* Clear display */
	_delay_ms(2);
	LCD_Command (0x80);		/* Cursor at home position */
}

int main()
{

	LCD_Init();			/* Initialization of LCD*/

	LCD_String("ElectronicWINGS");	/* Write string on 1st line of LCD*/
	//LCD_Command(0xC0);		/* Go to 2nd line*/
	//LCD_String("Hello World");	/* Write string on 2nd line*/
	LCD_String_xy(1, 4, "Hello World");	/* .kbv set cursor to 4, 1 and print string*/
	while(1);
}
 

 

Last Edited: Mon. Jan 6, 2020 - 05:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
For how to do it in Atmel Studio, see: https://www.avrfreaks.net/commen... - which links to illustrated instructions.

I've tried to do this, but it seems I'm doing it wrong. I've added "-DF F_CPU=3333333UL" in the defined symbols but an errors says that "F_CPU=3333333UL: No such file or directory"

 

awneil wrote:

Do you have experience with any other microcontroller(s) ?

Do you have experience with programming in general ?

Driving an LCD is not really a beginner project - if this is your first project, I would strongly suggest that you start with something simpler!

Regarding this, I've tried Arduino UNO before, and a bit of Edison. But I'm trying this 4809 Curiosity Nano Board. It's very far from Arduino's C++, so I'm having a little bit of a hard time.

My first project in 4809 only involves blinking of LEDs, and I also worked on the 4809s UART. So now I'd like to see some display from the board hence the LCD. I am very sorry for giving you guys a hard time, too.

 

curtvm wrote:
I took my code in #7, made a few changes

Thanks for the help! Really appreciate it, will try it and give an update to whatever will happen!

 

david.prentice wrote:
You can see my edited defines for your 4809 wiring.    The "4809 porting" was nothing more than the defines.    The tutorial code was already correct.

Hi, David! Thank you very much for you help! I've tried to run this code just now, and the LCD responds to it. Please see image below. Now I have literally no idea what just happened.

 

 

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

francoder wrote:
I've added "-DF F_CPU=3333333UL" in the defined symbols but an errors says that "F_CPU=3333333UL: No such file or directory"

Look again at the illustration!

 

You don't put the "-D" in the box!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I provided you with a ready to go AS7.0 project.
Unzip and open the .CPROJ or .ATSLN. Open the Properties to see how to define F_CPU
.
I tested on real hardware with the wiring scheme from #1. 470R from pin#3 to GND. Which is easier than using a pot.
Post a clear photo of your wiring. It is worth buying some single core wire and cutting each wire to length. Then readers can compare your actual with your scheme.
.
I also posted the minimally changed tutorial code.
.
Seriously. You can start with writing an AS7.0 project to blink an LED. It will give you confidence.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Just a general point but as those of us old enough to remember "the dark boxes are coming" will tell you, dark boxes, simply mean the LCD has failed initialisation.

 

99.9% of the time (experience shows) this is all about timing (the other 0.1% it's about treating an R/W display as if it were R only).

 

So before concentrating on your goto's and printstring's I'd spend some time concentrating on LCD_Init(). If it works you will not see dark boxes.

 

Also use David's code - he's got the same setup to work. If it works for him and not for you it almost certainly points to a fault in your wiring, not your code. (say, for example that the "E" line were not connected - the LCD would never initialize/work if something like that were faulty - this is where a scope/logic analyser could also help).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

francoder wrote:
I've added "-DF F_CPU=3333333UL" in the defined symbols but an errors says that "F_CPU=3333333UL: No such file or directory"

Look again at the illustration!

 

You don't put the "-D" in the box!

I'm sorry for this. Also, thank you for introducing this! I got it now.

 

david.prentice wrote:
I tested on real hardware with the wiring scheme from #1. 470R from pin#3 to GND. Which is easier than using a pot.
Post a clear photo of your wiring. It is worth buying some single core wire and cutting each wire to length. Then readers can compare your actual with your scheme.

Hi! I've now soldered the LCD and 4809Curiosity Nano to a board. It's the same display, but I figured I'll try to rewrite each and every line of code and see where the problem is going on.

I really appreciate your help on this. Also I followed your advice regarding being back to basic to LED, there's so much I learned especially in defines. Thank you and sorry for giving you problems.

 

clawson wrote:
So before concentrating on your goto's and printstring's I'd spend some time concentrating on LCD_Init().

Working on this now too. Thank you clawson!

 

---------

 

Thank you all for your help. I'll try to start again from scratch (of course, using all of your help) and try to make it work. I will give updates again as soon as I've finish rebuilding the project!

 

franco

 

 

 

I'm new.

Last Edited: Thu. Jan 9, 2020 - 03:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

francoder wrote:
Thank you all for your help. I'll try to start again from scratch
... but please do not start another thread just to tell us of progress. Use this one instead.

 

Thanks.

 

Moderator.

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

valusoft wrote:

... but please do not start another thread just to tell us of progress. Use this one instead.

 

Haha will definitely do this! I'm not planning to start another thread. Thanks for the reminder though! :)

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not planning to start another thread

You should start a new thread when you have a new question: keep all stuff on the same question in the same thread, but don't pile lots of unrelated questions into one thread.

 

You can always post link to reference other threads ...

 

 

And, when your issue is resolved, remember to mark the solution - see Tip #5 (in my signature, below; may not be visible on mobile)

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Time for more apologies !!

 

Yes,  I ran your tutorial code on a typical 16x2 (an HD44780 compatible).   And it worked.   Even with a power cycle.

 

Then I looked at your poor photos in #16.   And realised you have a 16x2 with unusual wiring i.e. pin#14 on bottom-left, backlight on bottom-right.

So I tried an elderly 16x2 with this unusual pinout.   It gave black boxes.    So I suspect it is a genuine HD44780.

 

Most "compatibles" are forgiving when it comes to initialisation.    The genuine HD44780 is not.

 

Which is why respected libraries implement the strict HD44780 timing procedure.   This guarantees success on ALL controllers.

 

Your tutorial does not obey the strict timing.      However the following kludge will probably work:

void LCD_Init (void)			/* LCD Initialize function */
{
    LCD_Dir = 0xFF;			/* Make LCD port direction as o/p */
    _delay_ms(30);			/* .kbv 30ms is safer with Curiosity voltage control */
    LCD_Command(0x33);		    /* .kbv sets regular 8-bit mode */
    _delay_ms(5);                   /* .kbv needs delay */
    LCD_Command(0x32);		    /* .kbv 4 bit initialization of LCD  */
    LCD_Command(0x28);              /* 2 line, 5*7 matrix in 4-bit mode */
    LCD_Command(0x0c);              /* Display on cursor off*/
    LCD_Command(0x06);              /* Increment cursor (shift cursor to right)*/
    LCD_Command(0x01);              /* Clear display screen*/
    _delay_ms(2);
}

Never trust Internet tutorials.   Some are good.   Some are not.

I strongly advise starting with proven library code e.g. from GCC,  Codevision, ...

 

Codevision lets you configure every pin on your LCD using a GUI.   And supports m4809, tiny817, Xmega, Mega, ...

You don't have to buy the full version.   The free Evaluation version will let you run many (small) examples.

 

Likewise,   Arduino supports lots of hardware.   You don't have to use it in your final project.   But it is an excellent (and quick) way to verify that your hardware is working.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

So I tried an elderly 16x2 with this unusual pinout.   It gave black boxes.    So I suspect it is a genuine HD44780.

Most "compatibles" are forgiving when it comes to initialisation.    The genuine HD44780 is not.

You're right, I have to apologize again. I didn't know this stuff until now.

 

As of now, I still don't have a working code. I have 3 drafts on me, one of these is directly from you. And it's still not working for me.

I'll attach the following drafts, and if I may request, could you run it from your board? :(

 

david.prentice wrote:

Codevision lets you configure every pin on your LCD using a GUI.   And supports m4809, tiny817, Xmega, Mega, ...

You don't have to buy the full version.   The free Evaluation version will let you run many (small) examples.

I've also known this just now, and it works wonders on my LCD. Configuring the pins is very easy, D4-D7: PC0-PC3, RS:PC4, EN:PC6, clock set to 16MHz.

And it really did display strings on my LCD! How I wish I could just see the source codes from this, but I'm still trying to figure out what really is the problem.

 

 

Attachment(s): 

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3

This is silly.

 

You have succeeded in running the LCD.    Please post the successful project.

I don't mind if it is AS7.0, Codevision, Arduino, ... project.   Just as long as it is the one that worked on your hardware.

Clear photos of your hardware e.g. pcb view of the LCD

Clear photos of your wiring.  e.g. short cropped jumper links on a breadboard with coloured wires.  

 

I will debug your non-working code.   But only if I know what the successful project is.

 

Your RAR files appear to have completely different wiring to the scheme in #1.

They also appear to be "different" to the tutorial link in #1.

 

General advice:

1.   Always start with proven library code.   Libraries often come with examples.  

2.   Attach the working project.   i.e. with a link to the proven library.

3.   If you have written some code for the same hardware and wiring,   attach the non-working project.

4.   Explain the problems

5.   Post ZIP files instead of RAR.

 

This applies to most projects.    e.g. Start with an Arduino or Codevision example.   Even if you intend to use different tools for your final project.

Readers are more likely to help you with home-grown code if you have verified that your hardware works with proven code first.

 

David.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I Googled for "Moji14 GitHub" and found https://github.com/Moji14/megaAVR-0-Series-LCD-library

I copied the code to an AS7.0 project.   It compiled without error.    However,  I have moved F_CPU to Project/Symbols

 

I added an extra two Moji14 projects to show how to configure for different wiring.

I attach the updated LCD_m4809 Solution with several LCD projects.

 

As usual,  search for ".kbv" to show my edits.

 

Note that I found it convenient to wire the LCD to PORTD on the Curiosity.    Most of the pins line up on a mini-breadboard.
I produced the Moji14_PORTC by guessing your wiring.

 

I am happy to test "your wiring" but only when you have shown what it is.   I do not like moving unknown wires on a breadboard.

 

Seriously.   Start with proven code.   It is your job to provide any links e.g. Moji14 GitHub.

 

I don't mind explaining how the code works.   But I would choose the simple ElectronicWings project rather than the Moji14 code.   Life is simpler with timed delays and contiguous DATA pins e.g. PC4-PC7  (or PC0-PC3)

 

I gave up with your lcd_code_v7.   You do not understand how to configure the defines.

 

David.

Attachment(s): 

Last Edited: Fri. Jan 10, 2020 - 05:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@francoder,

 

If you are still there,   please say so.     I would like to dismantle my Curiosity / LCD / breadboard if you are no  longer interested in this thread.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
@francoder,

 

If you are still there,   please say so.     I would like to dismantle my Curiosity / LCD / breadboard if you are no  longer interested in this thread.

Sorry David! I just got back on track with the project. A volcano is literally erupting nearby (~14km radius), and it gets in the way of me doing this project.

I'm very sorry. I will try what you suggested right now, and give updates as soon as possible! Again I'm very sorry.

 

franco

I'm new.

Last Edited: Mon. Jan 13, 2020 - 11:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Franco.

 

Is it Taal volcano? Stay safe.

 

Ross

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

valusoft wrote:
Is it Taal volcano? Stay safe.
 

Yes! It's the Taal Volcano. I live nearby, and Taal Volcano is in our province. It has been in unrest since Sunday.

I am safe as long as I don't go outside haha. I see nothing but ash outside. Anyway, thank you!

 

franco

 

 

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@david.prentice

Hi again, David! I've tried all the codes in the zip.file, but still it doesn't work. Same results: black boxes in 2 lines with lower contrast.

I've also tried your edited Moji's code that uses PORTC (which is my wiring), but still no progress at that.

 

The attachment below is the working CodeVision project, along with a picture of it. Also, the rar file consists of the wiring of my LCD to the Curiosity board (with and without labels; I apologize in advance for my poor labeling), and the hardware of the LCD.

 

I really appreciate your help in everything. Thank you very much! 

Attachment(s): 

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

francoder wrote:

...but still it doesn't work. Same results: black boxes in 2 lines with lower contrast.

 

Have a read of this...

 

https://www.avrfreaks.net/forum/...

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had it configured now to 8-bit. I can't really make it work on 4-bit mode. It's working now on 8-bit mode. Thank you all!

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

My apologies.   Please try this AS7.0 project.   It is configured for wiring:
 

D4-D7   on PC0-PC3
RS      on PC4
RW      on PC5
EN      on PC6
BL      on PC7

David.

 

Attachment(s):