PDA

View Full Version : Store Custom Characters for LCD in EEPROM?



wdmagic
- 18th April 2013, 02:38
Iv'e never messed with EEPROM, but I was thinking, I should be able to store custom Characters into EEPROM and load them on command, allowing me more free program space and more than 8 custom characters. But I'm not real sure where to start.

Thinking out loud here... EEPROM uses addresses so I should be able to make a include file with a list of all characters and there mempory address, include that in my program and then load as needed? or disreguard the include file and just make a printed list? any ideas. this will teach me a little about EEPROM and more with working on custom characters. Also, how do I load the EEPROM 1 time and not each time the chip powers up? as you can see I'm not sure what I'm doing.

HenrikOlsson
- 18th April 2013, 06:21
Hi Chris,
Remember that the CGRAM in the display controller is limited to 64 bytes (if we're talking HD44780) so even if you store 50 custom characters in your EEPROM I don't think you can display more than 8 of them simultaneously. Perhaps it's possible to load a character to the CGRAM, "print it" and then load another character to CGRAM replacing the first one without it automatically being replaced on the actual display. I don't know for sure, just something to think about.

Anyway, the DATA directive/command is used to embedd EEPROM data in the .hex file so that the EEPROM is programmed at the same time as the program flash (as long as the device programmer is setup to "program EEPROM"). READ is then used to retrieve the data from the EEPROM. WRITE is used to write to the EEPROM at runtime.

/Henrik.

CuriousOne
- 18th April 2013, 16:17
There were early implementations of these display modules, where discrete ICs were used, and charset was in separate mask rom. It was possible to replace such rom chip with own chip, with all custom chars in it. I haven't seen such module live maybe for last 15 years or so.

wdmagic
- 18th April 2013, 18:09
henrik, I was reading an article about someone that uses about 20 characters, he loads the character to lcd memory then send the display command, Im not looking to load more than 8 at a time or display more than that, just to have the choice of what to load. So if I want to load images for batteries with levels 1-8, reload new image batch, and then refresh screen with images for 8 temprature pics, etc... I figured I could do a 8 Character groups, Batteries, Temp Guages, Smileys, Misc symbols, Etc... if I did them 8 char x 4 groups that gives me 32 characters to call from. and it should be easier to handle memory addresses.

HenrikOlsson
- 18th April 2013, 18:27
Hi Chris,
Sure, that should work.
Yes, looking at the block diagram in the HD44780 datasheet it does seem like you COULD actually load 8 chars to CGRAM, display them (which writes them to DDRAM) and then overwrite the CGRAM with 8 new ones, display those and so on.
Anyway, if there's no need for more than 8 at a time then you're all set.

Keep us posted!
/Henrik.

spcw1234
- 19th April 2013, 02:06
Hi Chris,
Sure, that should work.
Yes, looking at the block diagram in the HD44780 datasheet it does seem like you COULD actually load 8 chars to CGRAM, display them (which writes them to DDRAM) and then overwrite the CGRAM with 8 new ones, display those and so on.
Anyway, if there's no need for more than 8 at a time then you're all set.

Keep us posted!
/Henrik.

My experience with this is when you try to load new characters into the CGRAM it overwrites the ones currently being displayed. I have not been successful displaying more than 8 characters, or even displaying 8 and loading more into CGRAM. Some displays do have slightly different features so it may be possible on the right display.

wdmagic
- 19th April 2013, 03:19
Ok it works, just want to give you a rundown before posting code.

you can store as many characters as your EEPROM Memory allows and you can load them individually or several at once to the LCD CGRAM (LCD Memory).
now there is a drawback but there is also a few bonuses.
1st Your LCD Can only display the Characters in memory, you cant display some and then chage the memory and add more.
2nd After changing the CGRAM any of these characters will be updated on display, even though you havent accessed the LCD again.
3rd This allows for ANIMATION woohoo! you can set a timer up to alternate sending updates to the lcd and animating a character.
4th This will allow you to animate or change characters on the fly

WARNING: Although this can animate and change characters, I have not been able to find information on the lifespan of CGRAM read/write cycles, this could be a problem if your animating characters or update alot. if anyone has any info on this please post.

So as my example I have 17 Custom Characters (I call sprites since the're pictures not letters)
I load the first 8 into CGRAM Memory, then display that to the LCD, pause for 1 second then update the CGRAM which updates whats on the LCD.
If someone wants a animation example I can do that too on request.


include "LCD_D.bas"

EEPROM 0,[4,4,4,31,0,14,0,4] ' Cust Char #0
EEPROM 8,[14,31,17,17,17,17,17,31] ' Cust Char #1
EEPROM 16,[14,31,17,17,31,31,31,31] ' Cust Char #2
EEPROM 24,[10,10,31,31,14,4,4,2] ' Cust Char #3
EEPROM 32,[14,17,17,17,10,14,14,4] ' Cust Char #4
EEPROM 40,[4,31,0,14,0,31,0,14] ' Cust Char #5
EEPROM 48,[0,0,8,21,2,0,0,0] ' Cust Char #6
EEPROM 56,[4,2,4,14,31,31,31,14] ' Cust Char #7
EEPROM 64,[0,17,19,23,19,17,0,0] ' Cust Char #8
EEPROM 72,[0,2,4,8,4,2,0,0] ' Cust Char #9
EEPROM 80,[0,0,14,14,14,0,0,0] ' Cust Char #10
EEPROM 88,[0,0,10,10,10,0,0,0] ' Cust Char #11
EEPROM 96,[0,8,12,14,12,8,0,0] ' Cust Char #12
EEPROM 104,[0,8,4,2,4,8,0,0] ' Cust Char #13
EEPROM 112,[0,17,9,5,9,17,0,0] ' Cust Char #14
EEPROM 120,[0,0,14,10,14,0,0,0] ' Cust Char #15
EEPROM 128,[$00,$0a,$0a,$00,$00,$11,$0e,$00] ' Cust Char #16

CGLOAD VAR WORD : CGLOAD = 0 ' Variable for holding Character # to Load
CGLLOC VAR BYTE : CGLLOC = 0 ' LCD Location to Store Character (0 to 7)
CGLOOP VAR BYTE ' Variable for Selecting Data Bits
CGDATA VAR BYTE[8] ' Variables to Hold Character Data

LCDOUT $FE, 2
Pause 1000

PreLoadLCD:
CGLOAD = 0 : CGLLOC = 0
GOSUB SETCGLCD
CGLOAD = 1 : CGLLOC = 1
GOSUB SETCGLCD
CGLOAD = 2 : CGLLOC = 2
GOSUB SETCGLCD
CGLOAD = 3 : CGLLOC = 3
GOSUB SETCGLCD
CGLOAD = 4 : CGLLOC = 4
GOSUB SETCGLCD
CGLOAD = 5 : CGLLOC = 5
GOSUB SETCGLCD
CGLOAD = 6 : CGLLOC = 6
GOSUB SETCGLCD
CGLOAD = 7 : CGLLOC = 7
GOSUB SETCGLCD

MainLoop:
LCDOUT $FE, 2
LCDOUT $FE, $80 ' This locations characters will change after charater update
LCDOUT 0,1,2,3,4,5,6,7
Pause 1000
Goto Reloadlcd 'Used GOTO instead of GOSUB since it would be Stacking GOSUBs
AddLCD: 'Return point after changing LCD Memory
'Add more code here if you want

END

SETCGLCD:
CGLOAD = CGLOAD * 8 ' Converts your Character Selection to EEPROM Address
CGLLOC = (CGLLOC * 8) + 64 ' Converts LCD Slot to LCD Memory Address
for CGLOOP = CGLOAD to (CGLOAD + 7)'Sets 1st Memory Address to Read + Next 7
read CGLOOP, CGDATA[CGLOOP-CGLOAD] ' Stores each Byte into Array
next CGLOOP
LCDOUT $FE,CGLLOC,CGDATA[0],CGDATA[1],CGDATA[2], _
CGDATA[3],CGDATA[4],CGDATA[5],CGDATA[6],CGDATA[7]
Return

ReLoadLCD:
CGLOAD = 8 : CGLLOC = 0
GOSUB SETCGLCD
CGLOAD = 9 : CGLLOC = 1
GOSUB SETCGLCD
CGLOAD = 10 : CGLLOC = 2
GOSUB SETCGLCD
CGLOAD = 11 : CGLLOC = 3
GOSUB SETCGLCD
CGLOAD = 12 : CGLLOC = 4
GOSUB SETCGLCD
CGLOAD = 13 : CGLLOC = 5
GOSUB SETCGLCD
CGLOAD = 14 : CGLLOC = 6
GOSUB SETCGLCD
CGLOAD = 15 : CGLLOC = 7
GOSUB SETCGLCD
goto addlcd

HenrikOlsson
- 19th April 2013, 06:09
Hi Chris,
Nice work! It's like I initially expected then and thinking it thru yet another time it makes sense.... When you write something to the display the DDRAM is loaded with the memory adress (be it the CGROM or CGRAM) of the character to display, not the actual character it self. I should have noticed that since the DDRAM is only 80 bytes...duh...

I wouldn't worry too much about wearing out the CGRAM, it's RAM so it should last "forever".

Instead of first copying the bytes from EEPROM to an array and then from the array to the LCD controller, why not do it byte-by-byte? I think it'll save some code space and RAM:

LCDOUT $FE, CGLLOC
FOR CGLOOP = CGLOAD to (CGLOAD + 7) 'Sets 1st Memory Address to Read + Next 7
read CGLOOP, CGDATA ' Retrieve byte from EEPROM <- Now only a byte variable instead of an array.
LCDOUT CGDATA
next CGLOOP
Return

/Henrik.

wdmagic
- 19th April 2013, 07:11
Thanks Henrik,
Yes thats a bit better, I'm just glad mine worked with my first try messing with EEPROM. Learned more after you posted :)

Here is the animation sample, I set it up so it draws a position marker based on a ADC input, and I used the modified code henrik posted.


Include "LCD_D.bas"
INCLUDE "ADC_Default.bas"

EEPROM 0,[0,0,4,8,16,0,0,0] ' Cust Char #0
EEPROM 8,[0,0,28,0,0,0,0,0] ' Cust Char #1
EEPROM 16,[16,8,4,0,0,0,0,0] ' Cust Char #2
EEPROM 24,[4,4,4,0,0,0,0,0] ' Cust Char #3
EEPROM 32,[1,2,4,0,0,0,0,0] ' Cust Char #4
EEPROM 40,[0,0,7,0,0,0,0,0] ' Cust Char #5
EEPROM 48,[0,0,4,2,1,0,0,0] ' Cust Char #6

CGLOAD VAR WORD : CGLOAD = 0 ' Variable for holding Character # to Load
CGLLOC VAR BYTE : CGLLOC = 0 ' LCD Location to Store Character (0 to 7)
CGLOOP VAR BYTE ' Variable for Selecting Data Bits
CGDATA VAR BYTE ' Variable to Hold Character Data
Position Var WORD : Position = 0

LCDOUT $FE, 2
Pause 1000

MainLoop:
ADCIN 0, Position ' Read ADC Channel 0 (16 bit)
position = position / 10000
CGLOAD = position
CGLLOC = 0
gosub SETCGLCD
LCDOUT $FE, $80 ' This locations characters will change after charater update
LCDOUT 0
Pause 50
goto mainloop
END

SETCGLCD:
CGLOAD = CGLOAD * 8 ' Converts your Character Selection to EEPROM Address
CGLLOC = (CGLLOC * 8) + 64 ' Converts LCD Slot to LCD Memory Address
LCDOUT $FE, CGLLOC
FOR CGLOOP = CGLOAD to (CGLOAD + 7) 'Sets 1st Memory Address to Read + Next 7
read CGLOOP, CGDATA ' Retrieve byte from EEPROM
LCDOUT CGDATA
next CGLOOP
Return