I am looking to talk directly to the standard Hitachi controller on an LCD. I am using the ATmega3208 which will not have had a library written for it yet so I'll have to write my own. I have found:
https://www.sparkfun.com/datasheets/LCD/HD44780.pdf is there any better document i should refer to or is this being the datasheet of the original controller "the source" ?
I tried that new fangled Google thing and found https://github.com/duinoWitchery/hd44780
Being new fangled it needs some polishing up
So that is an arduino library. I am looking to write my own. I struggle to understand other's code and libraries invariably come with no instructions.
I am more interested in understanding the actual protocol so that I can "talk it".
Oh well... never mind...
ATmega3208 is quite interesting... it looks like a PIC but it is an AVR... 3 UARTS and some CLC... nice.
This is by far the most common display controller hobby projects use. There are literally thousands of projects on various microcontrollers that use it and it is probably right up there as a rite-of-passage as a blinky program. Its a standard 6800 interface which is at least a couple of decades older than I am.
The datasheet(s) can be pretty good considering a lot of LCD controller datasheets are terribly written (think Epson), and gives a fairly clear init routine for both 8-bit mode and 4-bit modes. With that said there are many different datasheets floating about. The first hit I got on google was from sparkfun:
https://www.sparkfun.com/datasheets/LCD/HD44780.pdf Table 11 and Table 12 give the init routines for 8-bit and 4-bit modes respectively, figures 23 and 24 are the flow charts for those too.
Writing your own library for this should be pretty trivial, you just need the init routine, and simple functions like writing text, cursor manipulations, clear screen etc.. I understand not wanting to use other peoples libraries, I often write my own, and for something relatively straightforward like this, it shouldn't take long. But
looking at other peoples code is a good way to learn - if you struggle to understand other peoples code you will struggle to understand your own (unless you have very weird habits which means others will struggle to read your code, which isn't a good thing).
Actually the new mega's are the Xmegas or so I am told. It's a right pain in the ass as they are completely different from what i am sure will soon be called "legacy mega" architecture parts but if I wan to research what little information is being put out I just get a see of what will be incompatible/out of date stuff. I think they are generically referred to as ATmega4809 which is the biggest memory and pin count.
Writing your own library for this should be pretty trivial, you just need the init routine, and simple functions like writing text, cursor manipulations, clear screen etc.. I understand not wanting to use other peoples libraries, I often write my own, and for something relatively straightforward like this, it shouldn't take long. But looking at other peoples code is a good way to learn - if you struggle to understand other peoples code you will struggle to understand your own (unless you have very weird habits which means others will struggle to read your code, which isn't a good thing).
I know my knowledge is limited but I will not increase it by simply reading books, I need to start flexing it and learn as I go so writing something like this will give enough reasons to find out the stuff I need to know. I was going to use an SPI/I2C display but it seems that there are not very many and the few there are are so atrociously documented if at all that i may as well learn the actual hitachi protocol and have a much wider availability of parts available.
Simon,
The HD44780 datasheet is the gold standard for how to talk to the HD44780. But most projects will require only a subset of the chip's functionality. You may not need custom character sets, for example.
Peter Fleury offers time-tested (c. 2003) examples for interfacing a Mega AVR with the HD44780 in C. Online library documentation is included.
http://homepage.hispeed.ch/peterfleury/avr-lcd44780.htmlFrom your reply, it seems the ATmega3208 may be fundamentally different from older ATmega parts. But the HD44780 interface is a fairly simple parallel I/O application; I would be surprised if earlier code examples could not be easily ported.
Peter Fleury offers time-tested (c. 2003) examples for interfacing a Mega AVR with the HD44780 in C. Online library documentation is included.
http://homepage.hispeed.ch/peterfleury/avr-lcd44780.html
From your reply, it seems the ATmega3208 may be fundamentally different from older ATmega parts. But the HD44780 interface is a fairly simple parallel I/O application; I would be surprised if earlier code examples could not be easily ported.
Yes I was wondering how long before Peters library came up. I guess i could read through it and try and alter it for the ATMega 0-series, that would be the fastest and safest and give me a start at reading how others code.
I know my knowledge is limited but I will not increase it by simply reading books, I need to start flexing it and learn as I go so writing something like this will give enough reasons to find out the stuff I need to know.
I wasn't suggesting books. But delving into Arduino libraries, or AVR libraries, just to see what other people are doing. Agreed that writing your own code and going through the datasheets to found out what you need is the best way to gain experience, but avoiding reading anyone elses code isn't going to help you. Also as far as I'm aware there is no "protocol" to the HD44780. It's a 6800 interface, with 8 or 4 bits.
Also yes, the many SPI/I2C displays there are everywhere these days, generally have pretty poor documentation, sometimes they don't even tell you the controller used! But also many of those controllers are compatible, the serial nature means you save IO, and they have things like digitally controllable contrast. There are also again, many libraries available, although often the Arduino ones are terribly bloated as they try to create a universal library for everything (u8g2 is handy, supports lots but is huge). In that case, often a combination of using other peoples work ("research"), and writing your own is the best way.
@Simon:
Probably a bit on the simplistic side, but you may just find the attached two part article from EPE back in 1997 helpful.
@Simon:
Probably a bit on the simplistic side, but you may just find the attached two part article from EPE back in 1997 helpful.
thanks, simplistic is a good place to start from.
Looking at peters library I am wondering if it will work as is given that i have to put the port in I want to use so I just use the correct register name and that will be called through defines.
Right so i am going through Peters library and I am a little stumped here from the c file:
#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */
Now going further down I find the implementattion of this from the c file:
/* configure data pins as output */
DDR(LCD_DATA0_PORT) |= 0x0F;
OK so on the assumption that the lower 4 bits of the port are the data out that second statement makes sense but I am a bit confused about the first statement.
In the header file we have as an example:
#define LCD_PORT PORTA /**< port for the LCD lines */
#define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */
But if I use PORTA as "x" in
#define DDR(x) (*(&x - 1))
How does the text that is not a define that I know of going to represent the address number? Even if i assume that by using A I am calling the ports number in looking at the first datasheet that comes to hand neither A in ASCII code or the hex value "A" have anything to do with port addresses or being one number higher than the addres s of the registers being manipulated. I can see what is supposed to be happening and in theory all i have to do is adjust the address pointing to work for the ATMega 0-series but I don't see how this even works on legacy AVR.
OK, I have it, looking at the datasheets again PORTA is a register name and DDRA is one address down so pointing he is pointing at the register below the address of the named register which is DDRA carrying out the usual operations for the register, other registers will work.
So basically I need to find the port addresses in the mega 0-series and make sure each register manipelation code works for the register in question.
I don't want to address pixels. I am only needing to send text so the 44780 is fine by me. No point in the overhead of pixel addressing and having to write my own library/driver to put text on the screen. The 44780 is in effect my graphics controller.
Right, I have made a start. Things are a bit different given that the struct variables change things. I have a successful compile but I am in doubt about one little thing:
// Simon removed #define DDR(x) (*(&x + 1)) /* address of data direction register of port x which is at the port base address*/
#define DDR(x) x.DIR /* (Simon's version) address of data direction register of port x which is at the port base address*/
Is the syntax OK?
i have actually found some defines that end with a ";" and some that don't
#defines are esentially just a pure text substitution, just before the compiler looks at the line. One "good practice" tip I use is to always enclose the argument in parentheses:
#define DDR(x) ((x).DIR)
This ensures that even if you pass an expression as x, the macro expands as expected
If you add a semicolon at the end, this is also nserted in the expansion. Essentialy everything after the macro name/arguments to the end of line is included in the expansion (including your comment).
I am looking to write my own. I struggle to understand other's code and libraries invariably come with no instructions.
I am more interested in understanding the actual protocol so that I can "talk it".
The hd44780 library has quite a bit of documentation including links to other information like web sites and datasheets.
If you want to understand how to talk to the hd44780 chip, then at some point you will have to read and understand the hd44780 datasheet.
I would suggest that you actually go read the hd44780 library code in the hd44780.cpp module.
There is TONS of comments that explains how the chip is initialized in 4 bit or 8 bit mode. The information in there is much better and more complete than what is in the hd44780 data sheet.
--- bill
In general, having a semicolon at the end of a #define is something I would not like to see.
Essentialy everything after the macro name/arguments to the end of line is included in the expansion (including your comment).
To be precise, no.
According to the language as defined in e.g.
C99, in the chapter 5.1.1.2 "Translation phases", comments are removed in phase 3 and substituted with a single whitespace.
After phase 3 completes, the program consist of preprocessing tokens and whitespaces only.
Preprocessing directives are then excuted (and then deleted) in phase 4.
You can test this yourself (e.g. with gcc -E, if you disregard the gcc specific crap at the beginning...):
newbrain@lepton:~$ gcc -E -
#define DEFINEDNAME 12345 // This will not appear in the output
int main(void)
{
return DEFINEDNAME - DEFINEDNAME;
}
/* Ouput of gcc follows */
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "<stdin>"
int main(void)
{
return 12345 - 12345;
}
newbrain@lepton:~$
So I have edited the library and wired the thing up. I have written the following so far:
lcd_init(LCD_DISP_ON_CURSOR_BLINK);
lcd_gotoxy ( 0, 0 );
lcd_putc('C');
Should that work? I get nothing yet.
So I have edited the library and wired the thing up. I have written the following so far:
lcd_init(LCD_DISP_ON_CURSOR_BLINK);
lcd_gotoxy ( 0, 0 );
lcd_putc('C');
Should that work? I get nothing yet.
Is your contrast voltage correct? For the usual character LCD modules pin 3 is called V0 (by Newhaven) or similar. You need a voltage on this pin to actually make the display turn on.
Worse, it's sometimes given as a negative voltage! But it's not. It's usually something like 0.8 V or thereabouts.
Check the particular display's datasheet.
You might see something like a 10k pot between VDD and GND with the wiper going to the display's Pin 3 or V0 pin. Tweak the pot until the contrast looks good.
Or get a display that doesn't need that -- a lot of the Newhaven displays dispense with V0 and generate it on the module.
No I have just been trying it on 5 or 0V hoping either would be good enough to get something but maybe not. In a final product I'd low pass filter a PWM output so that contrast can be adjusted.
So my code is sufficient to get something on the screen?
No I have just been trying it on 5 or 0V hoping either would be good enough to get something but maybe not. In a final product I'd low pass filter a PWM output so that contrast can be adjusted.
It can't be 0V or 5V, it has to be something "in between."
So my code is sufficient to get something on the screen?
I honestly didn't dig into it deeply! (others have).