LCD text wrapping and looking at previous text cut off?
Circuitbuilder9
Posts: 85
Hey, guys.
(by the way, sorry for all my previous thread questions where i asked extremely broad questions and didn't get to the point)
I was wondering if anyone could direct me to any object that saves text on an LCD when it wraps and gets cut off the last line.
I would also like to know, in addition, if there where any sidebar scrolling (or just plain scrolling) objects/techniques for looking at the previous text put into the LCD, after it was cut off by new lines of text.
(by the way, sorry for all my previous thread questions where i asked extremely broad questions and didn't get to the point)
I was wondering if anyone could direct me to any object that saves text on an LCD when it wraps and gets cut off the last line.
I would also like to know, in addition, if there where any sidebar scrolling (or just plain scrolling) objects/techniques for looking at the previous text put into the LCD, after it was cut off by new lines of text.
Comments
I know this won't be perfect code but it does demonstrate things like scrolling and wrapping text. This is a 20x4 display so declare an array with 80 bytes.
It won't be perfect but it might be a place to start.
So, to clarify, if i were to use a 2 * 16 display, i would just use an array of 32 bytes?
Next is, if i were to use buttons to do my scrolling to see the text, what would i insert into the program to do so?
If i wanted to write the data to an SD card or Micro SD, would i direct the memory string of bytes to the SD card object instead of main memory address?
How would you do so?
By the way (this is for MagIO2), i couldn't find the benkylcddriver on the OBEX. is it named differently, or what? plz help me.
If you want to write data to an SD-card you need an SD-card driver like FSRW or Kyes FAT driver. You'd then open a file and call the str, dec or whatever functions of that driver to write the data into the file. It depends on what you want to do later on with the file. If it should only be used by a self written PC-program you can store the values directly as long, word, byte ... whatever.
If you want to open that file with a text-editor or Excell you'd write those values as strings separated by commas.
Thanks, MagIO2, for the redirection. But still, one of my questions haven't been answered yet: if i going to use buttons for scrolling, what would i do in spin (or assembly) to do so?
And, if i am using FSRW specifically, how does Dr. Acula's object previously mentioned intertwine with the FSRW object? What would i do to make sure things worked smoothly with the two, to write the data to the SD and transfer the text to the LCD while you can scroll to see the text previous?
You can setup the driver in a way that it uses a portion of the HUB-RAM as a display buffer. This buffer can have any number of columns (I think in the range of 1-128) and any number of rows (only limited by amount of available HUB-RAM) and you can see the display as being a window showing only a portion of this buffer.
For displaying something you simply copy the string you want to display into this buffer.
So, let's say if you want to have 2 rows with 128 columns you simply reserve 256 bytes and tell the driver where row 1 starts and where row 2 starts. For scrolling left/right you'd simply send an CMD_LCDOTSCROLL (LCD one time scroll) to the driver giving the number of columns to go left or right. You can have a look at LCD_menu.spin which uses this to scroll a menu up and down automatically. The difference between up and down versus left and right is that for up/down the number of bytes to move is equal to + or - of the line length where for horizontal scrolling you simply use +1 or -1.
Well .. Dr. Acula's object comes with it's own conversion-functions, which send the string representation (like HEX or BIN) of a long/word/byte directly to the display. FSRW on the other hand does not have such functions at all and my display driver neither. Why? Because the conversion from long/word/byte to a string should rather be coded in a separate object which avoids duplicate code.
So, Dr.Acula + SD means that you need a string object for the conversion. Call LCD.hex to output a number to screen, call string.hex to convert the number again, call SD.pputs to write the string to SD card. -> duplicate code + duplicate conversion
BenkyLCD + SD means that you also need a string object. Call string.hex to convert a number, copy string into screen buffer (bytemove), call SD.pputs.
There is the LCD driver above, plus a String object that can do all sorts of string manipulation, plus the SD driver code, plus a keyboard. There is a lot of other stuff you won't need so it might take some time to find the useful parts.
32 bytes will hold the 2*16 display but later you might want a bigger text buffer. The propeller can do this. Say it held 100 lines so 1600 bytes. Plenty of room in the propeller for that. Then you can load in a large text file from an SD card and scroll it up and down with two lines visible on the display.
Are you going to have a keyboard?
Yes, Dr. Acula, i do plan to have a keyboard, and it will be attached via the keyboard hardware from parallax's store. But when i said 32 bytes (one for each character, right?), i meant for just those lines of text being shown on the LCD. So that means i need more than 32 multiplied by the amount of total space needed for all the text put into bytes for the whole buffering thing?
And to just put the whole buffering thing into a simple view, the characters are arranged on main memory, and the LCD simply is a window to part of the text, right?
Sorry for being simple here, i am a freshman at high school with only some computer science experience. If i'm wrong, can you explain the buffering part to me?
You can do all sorts of clever things. You could certainly scroll up and down. You could also scroll left and right as well. The display acts like a little window on a page of text. The page of text can be loaded from the SD card into the propeller memory. Then you can edit it. Then save back the edited text onto the SD card.
So one thing to think about - if you have a line of text, say 20 characters wide, do you "wrap" that at character 16 onto the next line, or do you not display the last 4 characters unless the user scrolls right?
If you have 'word wrap' off, then an new line is a 'carriage return' and 'line feed'. Ascii characters 13 and 10.
Another thing to think about is Backspace and Delete. Are you going to add those?
If you have a keyboard, you can use the arrow keys and Home and Page Down etc to scroll your text.
I am also confused about main memory. Is it that easy to access; simply put data into the memory address for later retrieval? Or is it far more complicated than that; are there protocols? Or am i over-complicating things? Please tell me about this, this is where i get confused in programming: memory and methods to retrieve and write memory.
LCD drivers that I know do not implement these special characters. This has to be done in your code for example in the code that reads a keyboard. If you receive a byte you need to check whether it's a backspace and if so delete the last character in the input buffer and update the LCD.
You already know ways how to access main memory (HUB-RAM): Define a variable and use it, define an array and use it.
and
There may be some reluctance to answer as it is a little unclear what your level of experience is, and so therefore is harder to phrase an answer. If the meaning of CRLF is unclear then we may need to take a step towards a simpler explanation.
As MagIO2 says, CR and LF do whatever you code them to do. For a simple terminal program, you might write some Spin code that looks at the ascii value of a character. If >31 and <127 then print it. If 13, move cursor to the beginning of the line. If 10, scroll up one line. If 8 then delete the last character and move the cursor left by 1 (but not if already as far left as it can go). Home/End/Page Up etc come out of the keyboard as two byte codes and you can process them as well if you want to. If so, you will need to think about a way to pass two byte codes from the keyboard object to the display object.
This is the code you need to write, although there are many examples that have already been written.
Re memory, yes it is easy to access. Like MagIO2 says, you can define variables and arrays. For a screen buffer you would use a byte array. Say your text page was 80 columns wide and 40 high = 3200 bytes, then define an array with 3200 bytes. Then there is some maths to work out where you are - address = row * 80 + column. And to convert back the other way from address to row and column. Then work out the window for your display.
Some of this can be a bit daunting. In fact, I don't think this has actually been fully coded for the propeller yet.
Where it gets really complicated is where you have a page of text originally written for a wider screen and you now want to display on a smaller screen. Do you word wrap or not? What size screen do you emulate - 16 col, 40 col, 80 col? How do you handle a paragraph of text 300 characters long?
I'm not sure of the answers to that - I'm vaguely thinking of taking an existing page of text on an 80 col VGA display and squeezing it into a 16x2 but if I ever coded that I'd like the original text in front of me on the VGA screen to check the window is correct as you move it around. Nothing the prop can't do but it would be quite a coding effort.
People tend to stick with much simpler LCD objects which just put text on the screen and auto wrap and possibly scroll.
I've found the best way to code LCD drivers is to start very simple. Get the display to display an "A". Then work on each piece one at a time - eg how to handle backspace. Then test it.
Some things have already been coded - eg talking to an SD card is quite complicated but thanks to existing objects, it becomes one line of code to open the file, one line to read in an entire text file to hub memory, one line to close the file.
I don't think exactly that code has been written. But it can be. Are you ok with writing this code yourself?
I would love to write it myself. However, since i am fairly new to propeller assembly (i'm good at knowing the code itself, but i still need to practice for a consistent, effective use as well as knowing protocols and standard procedure), and would like to know where to start. In other words, how do you start a propeller project effectively so it can actually be finished? If i had some guidance, i'll know what to do for this and perhaps many more projects.
It may be easier to write this in Spin and later translate to assembly. Spin may be fast enough anyway.
ha ha - didn't someone start a poll recently where people had to confess about all the unfinished propeller projects they had lying around?
Seriously, start simple and break the project up into manageable pieces. For an LCD, I'd start with a simple 32 byte array. Have a row and column pointer for the array. When each character comes in, send it to both the display and the array.
Normally characters just go through. But there are some special cases. eg
If the column is 15 on the display, then newline
If the character is 10 then newline
If the character is 8 then process a backspace and redraw the line from the array.
'newline' scrolls up one line.
Grow it from there. Have you got a character on the display yet? Have you got a keyboard working?
I must say I was pretty pleased with the propeller chip when I managed to find some LCD code in the Obex, couple it with some keyboard code, and glue them together with a few lines of Spin so the characters went to the display.
Arrays are fairly easy to work with. Declare the array at the beginning in the VAR section
and this becomes a global array so any PUB can use this
I think when you start a bigger project you first have to have a big picture already including all known components. Which devices do I want to attach - keyboard, LCD, Sensors?, Motor? With this big picture you can estimate which platform should be feasible. Do I need external RAM, SD card, a bigger EEPROM, a port extension, motor drivers .... With this information you can also search for objects in the object exchange. When you find more than one driver for a device - for example for the LCD - you can now investigate which one fits best to your needs.
LCD is actually a good example:
There are several LCD drivers available. When I wrote mine all of them were written in SPIN and having some disadvantages. One was not capable of doing a proper reset. The SPIN drivers block your code as the output functions run in the same COG. My PASM driver is fire and forget in several ways. You can set it up as usual where you simply call output functions to print a string. But even then you only pass the address of the string to the driver COG and you own COG can continue immediately. You can also set it up in screen-buffer mode where a part of propeller memory is displayed. In this mode your scrolling left/right and up/down thing is easy to implement. And I think this is the easiest way of driving an LCD when several COGs should output values/strings totally independent. On the negative list there is of course the need of a COG - which actually is negative only if your project runs out of COGs. Oh .. and maybe that for using my driver you really need to know how the display works (it's described in the comment). There are no wrapper functions which increase the comfort ... hmm ... I posted these somewhere, but they are not part of the driver-package. But the demos should help a lot.
So, ... for a beginner I think it's a good idea to pick the objects that you might need and write some test-code per object to really understand how you can use these objects.
After that you can really go on with the project. As you have the big picture you can now devide it into several small AND preferably independend pieces. Independent because you can then reuse your own code or parts of the code for the projects coming up in future!
1. Make the LCD run in general
2. Do the setup for screen-buffer mode
3. Do the scrolling
4. Make the SD card run
5. Make the keyboard run
6. Write your input-routine according to your needs (backspace....)
x. put all pieces together
For your backlog ... how big shall this backlog be? Just a few lines? Will it be reset after switch off/switch on or should it remember the old data?
Anyway .. I have an enhancement of the FSRW which would help! ( http://forums.parallax.com/showthread.php?117573-Virtual-Memory ) I called it virtual memory because you create a big SWAP-file on the SD-card and can easily access each byte/word/long by simply giving it's address. It's functions also support moving memory blocks from HUB-RAM to the file and the other way around.
Let's say you setup a screen-buffer mode LCD driver with 128 x 2 characters. When appending you write the line into the screen-buffer and then directly copy it into virtual memory. Line 0 at address 0, line 1 at address 128, line 2 at address 256 and so on.
If you scroll up (which means go back in the backlog) you'd simply copy the actual lines back into the screen buffer. This is only a few lines of code.
Scrolling left/right is done in HUB-RAM only.
And .. by the way ... if you need help it also helps to share the big picture here on the forum. It helps in giving you the right tipps, because one solution might be good in a special case where it's bad in another case.
OK, that sounds great. I'll post my "master object code" when i am finished implementing the LCD, SD, the modified FSRW, and Keyboard objects. However, during the "screen buffering", i will probably ask a few questions. Does that sound good?
I have not even compiled this, so I have no idea if it is going to work or not, but I think it gets my idea across. The biggest limitations would be text file size vs. how much free hub ram you have, and how long it would take to copy the contents to the buffer just after the init of the SD card. On the plus side tho, it would take hardly any time at all to fetch the info out of the buffer and get it to the screen.
The FSRW is of course the version including my virtual memory functions, which needs some preparation of the SD-card. First you have to format it and then copy an empty file with 256MB named SWAP3.SYS to the card.
Also make sure that the PIN-numbers are correct. The backlight of my LCD display is driven by a propeller PIN (plus transistor) which is defined by LEDOnPin.
I started practicing LCD byte buffering, and i have one minor problem:
when i write the write to the code, i look at the compile current, and then look at the array i made, and there are no values in the designated addresses. Did i do something wrong? Also, when i use the repeat loop to insert the data (with a limit of 32 bytes : the 2 * 16 LCD), the data never shows up on the LCD. Otherwise, how's the rest of the code (it's short, i know. But i wanted to make sure)?
Binary(LCDtest).binary
TransmitLCD 3.spin
:blank:
I started practicing LCD byte buffering, and i have one minor problem:
when i write the write to the code, i look at the compile current, and then look at the array i made, and there are no values in the designated addresses. Did i do something wrong? Also, when i use the repeat loop to insert the data (with a limit of 32 bytes : the 2 * 16 LCD), the data never shows up on the LCD. Otherwise, how's the rest of the code (it's short, i know. But i wanted to make sure)?
Binary(LCDtest).binary
TransmitLCD 3.spin
:blank:
Attached Files
The binary you attached is pretty sure not the binary of TransmitLCD3.spin!
For this
byte char[320]
you would see 320 zero bytes in a row somewhere and for this
List byte $1F[320]
you would find 320 bytes with value $1F somewhere. I'd make TransmitLCD3.spin the top-file and always to a compile top. Otherwise you get what you see, which might mean that you compiled Debug_Lcd.spin for example.
is this by intention? You will never see something else but the content of char[0]-char[31]. At least I'd expect to have an offset which can be set, so that the display starts at other lines.
Why you don't see anything ... $1f might be undefined in the display. The useable characters usually start at $20 (=space). You can easily print out all the characters of the display to see which will show something and which not, as this is depending on the brand of the display anyways. Also above 128 you can find anything, for example chinese characters....
In other words: Try it with a character where you know that it should display something
Line byte "X"[320]
I just put those in there to illustrate what you would want the maximum length for one line to be. = 20 characters. I account for this in my code, making sure to leave the zero terminator because that is the flag for the end of the string, so the prop knows to stop outputting at that point.
OOOOOOOOOOOOOOOOOOO... I did not know that was out there..... that is VERY slick. It's in the obex I assume?
No, not yet. I wanted to make it an object on it's own which in the end is a memory map. Some portion of the 4GB address-space we can have using long should be
HUB-RAM
HUB-ROM
EEPROM
Memory map file
external RAM
....
So, for a program using this kind of virtual memory driver it would be totally transparent on which physical memory it's operating. Somehow I got distracted from this, but the as is version included in my private version of FSRW 2.6 is already very usefull.
It's available in the forum http://forums.parallax.com/showthread.php?117573-Virtual-Memory.
As you can see in the thread it's already used in an editor written by CassLan which implements a gap buffer.
I use it in my newCogOS for all kind of stuff. For example all the text messages and help pages for commands are put into virtual memory keeping HUB-RAM free for more important stuff.
I also started to code a home automation system using a 320x200x16 LCD touchscreen where all the background images, animations and icon files are stored in virtual memory. This keeps away tons of files from the filesystem and would also allow software-delivery by simply passing the swap-file....
I think I should add an blog-entry which explains how it currently works and what it's good for. If you have any questions, don't hesitate to ask.
How do you set an offset? Also, to clarify, i used $1F as an example, but had no intention that it would present other character. So, what is the highest hexadecimal number that shows english text and computer commands (i.e.- carriage return)?
And what do you mean by "over 128, you can find anything? Is that also referring to hexadecimal value?
What also do you mean by "Line byte "X"[320], if it can't exceed 128? I am confused about that.
Lastly, since my LCD is asynchronous serial, it can decifer hexadecimal by the ASCII chart?