Run Serial_LCD driver in its own cog?
hitolisolo
Posts: 11
Hello,
I've been trying to pick up Spin recently, but honestly I'm not finding it that easy.
Currently I'm trying to understand using the other cogs.
I'd like to launch an object (namely the LCD driver, at the moment) into its own cog.
However, from what I can follow I can only launch single methods into a cog (not an entire object - so that any and all of its methods would run in the other cog when called).
So is there a (somewhat) simple way to run the driver in its own cog?
Or do I need to write my own that's contained within a single function and update global/HUB variables within the other methods with the information to send?
Thanks for your help.
I've been trying to pick up Spin recently, but honestly I'm not finding it that easy.
Currently I'm trying to understand using the other cogs.
I'd like to launch an object (namely the LCD driver, at the moment) into its own cog.
However, from what I can follow I can only launch single methods into a cog (not an entire object - so that any and all of its methods would run in the other cog when called).
So is there a (somewhat) simple way to run the driver in its own cog?
Or do I need to write my own that's contained within a single function and update global/HUB variables within the other methods with the information to send?
Thanks for your help.
Comments
welcome to the propeller-world and -forum.
objects and cogs are different things.
You can have one object using more than one cog
you can have one cog executing code from more than one object.
objects are pieces of code that are stored in a second, third ... *.spin-file.
Now it depends on the code if other cogs are engaged or not.
starting a cog is always done through the command cognew.
There can be a great variant of locations where inside the code the command cognew is placed.
Wherever the command cognew is executed a new cog will be start running and will execute the code
named as the parameter
example
In the example above the new cog starts executing the code written in the Method "MyMethod"
all commands or other methods that are "called" from the code inside "MyMethod" will be executed in the new cog.
Some objects use an assemblerdriver. If this is the case the new cog executes only the assembler-code and no spincode.
Anyway SPIN-code is always executed by the calling cog.
Please attach your full code or at least post the exact name of the object that you are using.
The explanations will be easier to understand if the forum-members can refer to a certain object.
It will be helpful too if you describe what you want to do in the end.
It highly depends on the main-purpose which solution can be chosen or firts best.
I guess you have some problems
a) to wrap your brain about parallel executed code
b) your code behaves weird or unexpected
to help you more with this you should gives an overview of what you want to do in the end and describe with more details
what the actual problem is.
Another way to learn about objects and cogs is to read and work through the Propeller-Education KIT
click on help inside the propeller-tool and choose propeller education KIT (pdf)...
You don't need to have a PE-Kit hardware to learn from the labs.
Take a look into it and just start reading. If you have concrete questions on how adapating code to any other propeller-hardware
just post a question here
best regards
Stefan
Sure, write the driver in PASM which must be launched into its own cog.
Here's the key: for any object that uses IO, you can only control that IO from the cog that setup the pins you're using. For example, if you make P0 an output in COG0, manipulating the OUTA bit in COG1 won't do anything (until you make that bit an output in COG1 as well). For objects that use PASM, the Spin section is just an interface to the PASM code which is in the cog that setup the pins.
If you're using a Spin-only interface (perhaps a simple, 4-bit LCD driver), then you need to start that object in the cog where you want control. I've done this. I helped a guy with an HVAC project that uses an LCD with buttons; that interface needed to run while the system also received parameters from an RS-485 link. We solved this by running the LCD interface code in its own cog -- my LCD object was started in that cog so the IO lines were setup where they would be used. The system parameters where all globals in the hub which allowed the RS-485 and LCD cogs to see and manipulate them at the same time.
I take it that you are referring to a serial LCD rather than parallel and if so then you only need a single I/O pin and a few lines of Spin code to transmit the ASCII data serially. The code is trivial but you could look at the Simple Serial object and just use the few lines of transmit code. There is no need to run this in it's own cog unless your application software can't afford the time it takes to send a handful of characters serially. Most of the time we are talking about 16x2 displays and that means 32 characters tops with infrequent updates.
I could follow that much. Unfortunately, all the examples I could find in the PropTool documentation simply launched self contained methods (i.e. they didn't need more than the originally passed arguments).
I'd tried the PDF you mentioned, unfortunately I didn't see where they had an example of passing information to an already running cog.
And I'm thinking that's what I'll need to do.
Sorry I didn't realize how vague that came across.
I'd written a program for my Stamp to use as an interface for some old memory devices I have about.
However, it was taking the Stamp ~4 hours to read a single MB. So I ported the program to my Propeller (a QuickStart board) and Spin hoping for more speed.
The program actually works, it just doesn't have the speed I wanted. Reading 2 MBs took ~12 hours!
I tracked the speed loss to the code that updated the LCD [Parallax's 2x16 #27977] every byte (originally as debugging feedback, but I'd like to keep it if it won't cost that much in speed).
I'm using the Serial_Lcd.spin object I found in the propeller library folder. I copied the Hex and Bin functions from the Parallax Serial Terminal object into it to retain the formatting I had in the PBASIC version.
This is the function that kills the speed: With the lcd lines commented out as they currently are it read the 2 MBs within 6 minutes. So if my math is still decent that's just over 21 seconds to execute those lines (for the LCD).
Granted the lcd.clrln(1) is a pointless waste of time here and should be replaced with lcd.gotoxy(0, 1), however that shouldn't quite cut the time in half and 10+ seconds a byte is still awfully slow.
I'd like to get an independent cog to process/format the information and update the LCD, but I'm unsure how I can implement that (as even if Serial_Lcd used a cog to output the data, the Hex and Bin functions would be processed within my main cog - and I figure they're the next big hit to speed).
Perhaps the better question is, estimating ~176ms to read each byte without updating the LCD, is it even plausible to try updating the LCD that quickly?
The driver would have to be able to parse the hex and binary output faster, surely.
What do you do for the Rx pin? I don't have a spare pin to set it to. And I didn't think it had an option not to use one (although I'm unable to double check just now).
That's good to be aware of - thank you. I've never programmed anything in assembly before, though. Is there a good introduction to assembly programming somewhere?
Yes, I'm using the #27977 2x16 display from Parallax. I'm using the Serial_Lcd.spin file in the library folder (slightly modified) that itself uses the Simple Serial object. My problem is the code is taking ~21 seconds to update the LCD and I was hoping to update it with the individual byte address and data, but that took ~12 hours to read just 2 MBs. Since I'm using parallel buses would it be possible to have another cog monitor the I/O pins and automatically send the correct output to the LCD instead of calling that function from within my main cog?
One slight glitch with the program is when I first plug the board in, the Parallax Serial Terminal object - which I'm using to communicate with the computer - is supposed to send a byte to clear the screen at the end of the initialization function. However, for some reason it doesn't until I try to send something to it. At which time it appears to reboot, but does send the byte afterward. And it works like it should after that until it's unplugged and has to boot again. Any idea what might be causing that? And is there a reason the PST implies its buffer can't be set higher than 256?
Thanks for the suggestions everyone.
One possible improvement is, using a ringbuffer which is read from the code that currently calls ReadByte and written continuously by the ReadByte function which has to be turned into a loop. This could than be started in it's own COG.
I doubt that you'll read the whole 2MB output. So, does it maybe make sense to display a percentage bar (or number) instead?
In this case the function ReadByte simply increments a counter which is used by the LCD-output routine (which can run in a 3rd COG) to calculate and output the percentage.
The whole thing about sharing data between COGs is to use the same memory location in HUB-RAM and use that for passing data. As long as you stay in SPIN it is as easy as using the same variable.
If you don't work on secret code, it's best to archive it and attach the whole code to the post. Then we can show you much more possibilities to improve the code. From SD card the propeller can read ~1.6MB per second, so 6 min. is quite a long time!
Since the data passes quicker than it can actually be read, your idea of a progress bar is a good one.
I'll have a look at writing that up.
Also, updating the LCD elsewhere is causing more slow down. When I remove all the LCD updates I can get it down to two minutes / MB.
Granted that's still really slow when compared to your SD card.
So, you're half way on that road ;o)
The idea still is to use buffers and let LCD, Pc-sender/receiver and the RAM-driver work with this buffer more or less independently, because then you can start all of these tasks in separate COGs.
When optimizing, first thing to look at are the loops. For example you have loops counting up RAM addresses and calling the read function. For 1000 addresses this makes 1000 function calls, where each call adds time to the runtime. If you change the function to accept a variable address and the address-range and let it loop itself, there is only one function call.
There is another loop which has an if inside. I can't see that the variable you check is changed inside of the loop. In this case it would be better to have 2 different loops. One for the if-case and a slightly different one for the else-case. The if would then be outside the loop and would only be executed once instead of 1000times.
So do you have a description of what it is you are trying to do (rather than how you are doing it)?
As for the buffers, the Parallax Serial Terminal object seems to imply its buffer can't be set larger than 256, but it seems to use HUB RAM as a buffer - do you see a reason why I couldn't use any value as long as I have that much room in the HUB?
Yes, if I just wanted to store data an SD card would be a much simpler and faster, I'm sure, solution. I'm interfacing with these cartridges in order to recovered data from them (so switching to an SD card obviously won't work here).
I'm using a file in my Propeller library folder called Serial_Lcd.spin (with two extra functions) to interface with a 2x16 Serial LCD from Parallax (#27977). The exact (modified) file I'm using I attached a couple posts ago - here. The LCD was originally for debugging feedback, however I like having the status shown even though it's not really needed now.
While the transfer rate can probably be faster in the end, at the moment I'm losing data somewhere on occasion and a faster rate will only increase that (I think it's on the computer side, but I'm not certain, yet) and I'm content at the moment with what I'm getting (minus the huge delays caused by updating the LCD).
Finally, as my thread title suggests (and I thought I'd said this in a post of two directly), I'd like to be able to update my LCD more quickly (it's currently taking ~15 seconds to update a single line) and I thought being able to run the driver in its own cog (since I have extra) would help with that. It seems like it shouldn't take that long to send 16 characters to the LCD.