The OS saw the FT232 part, but the Propeller Tool doesn't see the device (pressing F7), which seems a bit odd to me. I do run my loads off a separate supply and make certain grounds are common. The I/O from the Prop ties to the 5v circuitry via some 1K resistors, which seems to work just fine.
I'll poke around a bit and see what I can find out with my scope, regarding the 'dead' Props. Perhaps there's something obvious, but at $25 a piece, they're not worth putting a whole lot of effort into troubleshooting!
The Prop tool waits for a response from the Prop as part of the boot loader sequence and if it doesn't get it then it doesn't "see" it. I like to add a status LED + resistor pulled up on the SCL line P28 so that I can see the Prop responding to a reset, which is to check the serial line first otherwise check the EEPROM. When my app is running it can blink the status LED when the bus is otherwise quiet so I know it's alive.
Anyway, finding the problem now may save not just more money again, but your time, your hair, your sanity.......
I've been adhering to your 3 rules pretty faithfully! When I get a spare moment, I will fire up the scope and check these 'dead' Props out to see if there's anything obvious. At $25 a piece, they aren't worth (to me) spending more than a few minutes troubleshooting!
In my attempt at getting an AUTORUN properly executed, I've tried the following with the below code (the main routine):
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
AUTORUN WxExt
This doesn't seem to be enough to make it work correctly. I'm not fully understanding the big picture of AUTORUN, I guess!
In my attempt at getting an AUTORUN properly executed, I've tried the following with the below code (the main routine):
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
AUTORUN WxExt
This doesn't seem to be enough to make it work correctly. I'm not fully understanding the big picture of AUTORUN, I guess!
If you turn off autorun ( AUTORUN NONE ) and on reset you can type WxExt before doing anything to get it to run then there should not be a problem with AUTORUN. I'm guessing you haven't initialized some setting such as baudrate etc. Avoid initializing anything during source code load, even though that's handy, it doesn't help when you reboot. You did do a BACKUP command, didn't you?
4 == speed-i \ Wind speed index
8 == dir-i \ Wind direction index
#12 == temp-i \ Temperature index
#16 == Lrain-i \ Longterm Rainfall index
#40 == date-i \ Day of year index
#45 == tod-i \ Time of day index
#48 == rain-I \ Today's rain index
#P9 == WX-RXD \ Incoming data pin.
#P0 4 MASKS CONSTANT DigVal
#P4 2 MASKS CONSTANT DigSel
\ variables containing wind speed by digit.
LONG dig100s
LONG dig10s
LONG dig1s
\ variables containing wind direction by digit.
LONG dir100s
LONG dir10s
LONG dir1s
pub GetData ( -- ) \ Read serial port and place WX data into array SERBUF.
!SP datastk SP!
#2400 SERBAUD \ Ultimeter comm set to 2400 baud.
BEGIN
BEGIN 9 SERIN "$" = UNTIL \ Wait for beginning of header.
DROP \ Got header start; proceed with empty stack
SERBUF
BEGIN
9 SERIN DUP $0D <>
WHILE
NIP SWAP DUP 1+ ROT ROT C!
REPEAT NIP C! DROP
AGAIN
;
' GetData TASK? RUN \ Set GetData to run in background on its own cog.
: SERBUF@ SERBUF CR #80 DUMP ;
pub ASC2HEX ( char -- hexchar ) \ Convert ASCII hex byte to hex.
DUP $3A <
IF $30 -
ELSE $37 -
THEN
;
pub ConvField ( idx -- decvalue ) \ Index into the serial buffer and convert a field to decimal.
SERBUF + \ Point to 1st char in field.
0 4 FOR
SWAP C@++ ASC2HEX \ Get/convert char to hex.
ROT 4 SHL OR \ Put char into 1st hex posn.
NEXT NIP
;
\ The routines below control the LEDs on the compass rose, for 8 positions.
pub rose0 0 LOW 1 LOW 2 LOW ;
pub rose1 0 HIGH 1 LOW 2 LOW ;
pub rose2 0 LOW 1 HIGH 2 LOW ;
pub rose3 0 HIGH 1 HIGH 2 LOW ;
pub rose4 0 LOW 1 LOW 2 HIGH ;
pub rose5 0 HIGH 1 LOW 2 HIGH ;
pub rose6 0 LOW 1 HIGH 2 HIGH ;
pub rose7 0 HIGH 1 HIGH 2 HIGH ;
pub W-DIR ( n --- ) \ Light LED at position n degrees on compass rose.
SWITCH
1 45 SWITCH>< IF rose1 BREAK
46 90 SWITCH>< IF rose2 BREAK
91 135 SWITCH>< IF rose3 BREAK
136 180 SWITCH>< IF rose4 BREAK
181 225 SWITCH>< IF rose5 BREAK
226 270 SWITCH>< IF rose6 BREAK
271 315 SWITCH>< IF rose7 BREAK
316 360 SWITCH>< IF rose0 BREAK
0 0 SWITCH>< IF rose0 BREAK
;
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
\ ' WxExt TASK? RUN \ Run main routine in its own cog.
I've posted lots of good code for you that shows you have to cut that code by half, even that W-DIR and multiple rose definition looks complex but really reduces to just one line as I have shown. Simple but functional is always best.
BTW, that line:
' GetData TASK? RUN \ Set GetData to run in background on its own cog.
is only set at compile time, isn't this one of those things I mentioned that need to be in the startup word?
EDIT: Found one of the many posts with suggestions and W-DIR and rose0...rose7 is replaced with a simple:
pub W-DIR ( n --- ) \ Light LED n on compass rose.
1- 45 / 1+ 7 AND 7 OUTCLR OUTSET ;
That's one little suggestion and I'm sure there were many others.
I think Peter talks about something like this ... ;-)
But it is perfectly OK to start slow and verbose.
His comment to my implementation of the MAX7219.fth was also that is was way to verbose to him.
He likes those 'genious' oneliners that take me half an hour to disect and understand ;-)
- AND in doing so I learn a lot and slowly try to immitate his style.
Markus
pub rose0 0 LOW 1 LOW 2 LOW ;
pub rose1 0 HIGH 1 LOW 2 LOW ;
pub rose2 0 LOW 1 HIGH 2 LOW ;
pub rose3 0 HIGH 1 HIGH 2 LOW ;
pub rose4 0 LOW 1 LOW 2 HIGH ;
pub rose5 0 HIGH 1 LOW 2 HIGH ;
pub rose6 0 LOW 1 HIGH 2 HIGH ;
pub rose7 0 HIGH 1 HIGH 2 HIGH ;
\ can be replaced by
pub rose ( n -- ) 7 OUT ;
\
pub W-DIR ( n --- ) \ Light LED at position n degrees on compass rose.
SWITCH
1 45 SWITCH>< IF rose1 BREAK
46 90 SWITCH>< IF rose2 BREAK
91 135 SWITCH>< IF rose3 BREAK
136 180 SWITCH>< IF rose4 BREAK
181 225 SWITCH>< IF rose5 BREAK
226 270 SWITCH>< IF rose6 BREAK
271 315 SWITCH>< IF rose7 BREAK
316 360 SWITCH>< IF rose0 BREAK
0 0 SWITCH>< IF rose0 BREAK
;
\ unfortunately your octant counts are not starting with 0 at 0..45
pub W-DIR ( n --- ) \ Light LED at position n degrees on compass rose.
45 / rose ; would be the simple solution
\ 45 / 1+ 7 AND rose ; \ should do it more or less
The OUT word requires a mask as you only want to affect a group of pins so it's just as easy to say <new> <mask> OUTCLR OUTSET which only affects those pins. My W-DIR word takes into account the octant offset too so that it works just like you want it too (if that's the way you want it) and lights up the LEDS, all in one line. Anything more, why, it's just too...ooo verbose!
pub W-DIR ( n --- ) \ Light LED n on compass rose.
1- 45 / 1+ 7 AND 7 OUTCLR OUTSET ;
@MJB: I think there is a bug in OUT anyway as for some reason it uses a SHROUT and I just checked it and it's not working properly.
The OUT word requires a mask as you only want to affect a group of pins so it's just as easy to say <new> <mask> OUTCLR OUTSET which only affects those pins. My W-DIR word takes into account the octant offset too so that it works just like you want it too (if that's the way you want it) and lights up the LEDS, all in one line. Anything more, why, it's just too...ooo verbose!
pub W-DIR ( n --- ) \ Light LED n on compass rose.
1- 45 / 1+ 7 AND 7 OUTCLR OUTSET ;
well ... that's exactly what I meant up there. ROFL
He likes those 'genious' oneliners that take me half an hour to disect and understand ;-)
@MJB: I think there is a bug in OUT anyway as for some reason it uses a SHROUT and I just checked it and it's not working properly.
yes - now as you mention it...
I saw it and wondered subconsciously - but did not think about.
"The genius one-liners" ... I love that! Though I've been dabbling with FORTH for several decades (on-and-off), my start was with MVPForth, which, as I recall, was an ANSI FORTH and much of my coding ways need to be re-learned to 'master' Tachyon. For me to jump right in and code with 'genius one-liners' isn't going to happen at this stage. Like Markus, I prefer the straight forward and verbose method until I have things working properly. Making each word definition simple for me to understand and building upon them, seems to help me through the development process a bit more easily. Once there, the code can be 'prettied' up and thinned down, especially when embedded resources are at a premium!
I've made the change to W-DIR, to include Peter's 'genius one-liner' and it works just great! I can't say I understand it quite yet, but will take the time to do so once I get this project buttoned up and on the wall.
The ' GetData TASK? RUN hasn't been put into a startup word yet, since I wanted to get a better handle on turning things over to an AUTORUN, so everything runs on power-up. One thing I noticed that might take a bit of re-thinking on my part is the initial population of the data array. This doesn't happen right away, since the Wx station only reports about every 20 minutes. It seems that I need to initially hold off on the main program execution until that array is populated, since the parsing routines don't account for an all-zeroes condition that the array starts out with.
Regarding AUTORUN and multiple tasks ... the GetData word needs to run in its own task, which doesn't present a problem to me at this point. What I'm wondering about is the main program that will run with AUTORUN. Does it need to be in its own task? If so, what considerations to I need to take into account before turning it loose in this manner?
While the multitude of the routines are tested and ready, I've been a bit confused by what needs to happen inside the routine that is set to AUTORUN ... stacks & their size ... registers for the assigned task cores, etc.
There is nothing magical about AUTORUN and instead of typing in a word to get it to run you just tell the system to do it for you. However the system finds and runs EXTEND.boot at startup which starts up the background timer cog and then checks the autorun vector and verifies that the code still exists before running it. There is no need to worry about anything else except your application and no need to run it in another cog either unless that is what you want to do. However for debugging purposes it is good to be able to talk to the main console cog but there are a variety of ways of doing this. Also if you need to abort the autorun you can hold down ^A after a reset (manual or serial break) until the system responds.
If my data requires initialization on a cold start (first time) then I have a variable like "firstrun" for instance that I check for a pattern such as $A55A or something but if it isn't then I execute code to load up the variables I need to set after which I set the firstrun variable to the match pattern and run BACKUP. It's much better though to make the system tolerant of uninitialized data though and the LONG/WORD/BYTE words will initially zero that data.
This is my new main routine that I submit to AUTORUN:
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
7219INIT
' GetData TASK? RUN \ Set GetData to run in background on its own cog.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
At the bottom of the file containing this routine, I have the following:
AUTORUN WxExt
?BACKUP
REBOOT
What happens is:
The compass rose is getting updated, but the 7219 module is not. I also notice that I no longer have access to the console following a reboot, which would be nice to have.
This is my new main routine that I submit to AUTORUN:
<snip>
What happens is:
The compass rose is getting updated, but the 7219 module is not. I also notice that I no longer have access to the console following a reboot, which would be nice to have.
There are better ways of separating digits but here's one of them for reference using U/MOD ( n div -- rem quo ):
So putting that into action we can extract the digits and write directly into the display rather than bothering with those holding variables such as dig100s etc.
EDIT: changed 100 U/MOD to 10 U/MOD
: GetSpeed ( -- ) \ Pull value from array and extract digits for display.
speed-i ConvField DUP Wspeed !
10 U/MOD 10 U/MOD
3 7219WR 2 7219WR 1 7219WR --- write digits
;
: GetDir ( -- ) \ Pull direction value from array & parse for display.
dir-i ConvField DUP Wdir !
10 U/MOD 10 U/MOD ( units tens hundreds )
8 7219WR 7 7219WR 6 7219WR --- write digits
;
so you no longer need 7219OUT either and you can get rid of digs100 etc.
Then we can finish off with:
: WxExt.task
!SP 7219INIT
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir \ Put speed & direction values to 7219 module.
AGAIN
;
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
' GetData 6 RUN \ Set GetData to run in background on its own cog.
' WxExt.task 5 RUN
;
AUTORUN WxExt
?BACKUP
So I just specified the cogs I wanted directly and made a task out of the main loop so that cog 0 can continue running the console. The initialization for the MAX7219 must go in the same cog that accesses it as each cog has its own direction registers.
BTW, you may have been setting the SPI pins for the MAX7219 during compile but not in any init routine I could see so this is probably your problem after reboot. Add it to the 7219INIT:
pub 7219INIT
&14.15.15.13 SPIPINS ( ce.miso.mosi.clk --- ) \ dummy miso
1 $C 7219WR \ 7219RUN \ Put shutdown register in 'RUN' mode.
$FF 9 7219WR \ codeB \ Set 7219 for Code-B decode
7 $B 7219WR \ Set scan limit to # of displayed digits (all 8 in this case).
$F 4 7219WR $F 5 7219WR \ blank digits 4 & 5 for space between direction & speed.
;
AVOID special actions during compile - even though they are great for testing - you need to have them available during reboot
NOTES: GetData is a bit of a waste as it is used infrequently with a tiny string of data every 10 mins or so and it could just as well process and display the data after receiving it.
If you run your main task in the console COG then the console is unavailable since the
BEGIN ... AGAIN
loop never exits.
but you can run this low resource display routine either in
KEYPOLL or in a TIMER routine.
no time to show right now ...
Yes, this is true too as I use KEYPOLL for my network servers etc. TIMER is great too but only if everything gets done in under 1ms (more likely 700us) otherwise the task's WAITCNT won't time out again for another 55.33secs. Doing it as a KEYPOLL is great because all the I/O is directly accessible from the console cog too. In which case this is the change to the code:
: WxExt.task
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir \ Put speed & direction values to 7219 module.
;
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
' GetData 6 RUN \ Set GetData to run in background on its own cog.
7219INIT
' WxExt.task +POLL
;
This all looks very helpful. Thank you both! I want to take more time to understand the code you've suggested, Peter. This also brings a question to mind: would you consider creating a "Forth Encyclopedia" for Tachyon? It would sure go a long way toward helping folks that are either new to Tachyon, new to FORTH, or both.
This all looks very helpful. Thank you both! I want to take more time to understand the code you've suggested, Peter. This also brings a question to mind: would you consider creating a "Forth Encyclopedia" for Tachyon? It would sure go a long way toward helping folks that are either new to Tachyon, new to FORTH, or both.
That simplified code isn't as simple as I think as my original version I did that parsed the serial stream and inserted spaces in the right places to allow the text interpreter to just go and do its job. Anyway, you can also see that with a handful of general-purpose routines you can have "the lot" rather than duplicating your effort everytime you want that little bit extra. This is not about coding or programming per se but about seeing the problem in such a light that it becomes "simple" and then the solution and how to go about it becomes very clear, no matter what language you end up programming it in.
So now, a "Forth Encyclopedia" for Tachyon you say? If I started that I might not get too much else done, including improvements etc. Then there's the imminent P2, well FPGA at least and I intend to devote some time for this. If however this Tachyon documentation was really a group effort then I would be willing to fill in and correct sections if need be, otherwise it's a big task to do it alone. Coding and testing is easy, documentation, hmmmm, that's hard
BTW, this is the simplified version of your code if you didn't get it on dropbox. I defined a dummy word called DEMO beforehand so that it would compile a version that I could test without the serial port operating.
TACHYON [~
\ FORTH support routines for Ultimeter 100 Wall display using Tachyon FORTH on the Propeller.
FORGET ULTIMETER.fth
pub ULTIMETER.fth PRINT" ULTIMETER 100 Wall display by K6MLE (PBJ) 150910-0000 " ;
--- Breadboard ---
#P14 == 7219CE
#P15 == 7219MOSI
#P13 == 7219CLK
pub 7219WR ( val reg -- )
8 SHL OR SPIWR16 DROP
7219CE HIGH
;
pub 7219INIT
&14.12.15.13 SPIPINS ( ce.miso.mosi.clk --- ) \ dummy 19 for MISO - also sets pins as outputs
1 $C 7219WR \ 7219RUN \ Put shutdown register in 'RUN' mode.
$FF 9 7219WR \ codeB \ Set 7219 for Code-B decode
7 $B 7219WR \ Set scan limit to # of displayed digits (all 8 in this case).
$F 4 7219WR $F 5 7219WR \ blank digits 4 & 5 for space between direction & speed.
;
80 BYTES SERBUF
#P9 == WX-RXD \ Incoming data pin.
#P0 4 MASKS == DigVals
#P4 2 MASKS == DigSel
10 LONGS datastk
--- Create an array of words that hold the 16-bit values read from all the fields
13 WORDS fields
--- now create the field names
fields ORG
2 DS @speed --- 1. Wind Speed Peak over last 5 min. (0.1 kph)
2 DS @dir --- 2. Wind Direction of Wind Speed Peak (0-255)
2 DS @temp --- 3. Current Outdoor Temp (0.1 deg F)
2 DS @lrain --- 4. Rain Long Term Total (0.01 in.)
2 DS @bp --- 5. Current Barometer (0.1 mbar)
2 DS @bdv --- 6. Barometer Delta Value(0.1 mbar)
2 DS @bcfl --- 7. Barometer Corr. Factor(LSW)
2 DS @bcfh --- 8. Barometer Corr. Factor(MSW)
2 DS @odhum --- 9. Current Outdoor Humidity (0.1%)
2 DS @date --- 10. Date (day of year)
2 DS @tod --- 11. Time (minute of day)
2 DS @rain --- 12. Today's Rain Total (0.01 inches)*
2 DS @windavg --- 13. 5 Minute Wind Speed Average (0.1kph)*
: ASC2HEX ( char -- hexchar ) \ Convert ASCII hex byte to hex.
$30 - DUP 9 > 7 AND -
;
: ConvField ( idx -- value ) \ Index into the serial buffer and convert a field to a value
SERBUF + \ Point to 1st char in field.
0 4 FOR
SWAP C@++ ASC2HEX \ Get/convert char to hex.
ROT 4 SHL OR \ Put char into 1st hex posn.
NEXT NIP
;
--- Rather than accessing fields individually just convert everything and store their values in the "fields" array.
: ConvFields
4 BEGIN DUP SERBUF + C@ $1F > WHILE DUP ConvField OVER 4 - 2/ fields + W! 4 + REPEAT
DROP
;
: W-DIR ( n --- ) \ Light LED n on compass rose.
1- 45 / 1+ 7 AND 7 OUTCLR OUTSET
;
--- display value as 3 digits from index position
: DISPLAY ( value idx -- )
10 U/MOD 10 U/MOD
4TH 2+ 7219WR 3RD 1+ 7219WR SWAP 7219WR
;
--- Read serial port and place WX data into array SERBUF.
: ?ULTIMETER
!SP datastk SP!
7219INIT
#2400 SERBAUD \ Ultimeter comm set to 2400 baud.
BEGIN
IFDEF DEMO
--- test by writing direcly to serbuf etc
" ULTW0031003702CE0069----000086A00001----011901CC00000005" SERBUF COPY$
--- 0123456789-123456789-123456789-123456789-123456789-123456789-
--- 49 55 718
}
IFNDEF DEMO
BEGIN 9 SERIN "$" = UNTIL \ Wait for beginning of header.
SERBUF 1-
BEGIN
1+ --- increment buffer address
9 SERIN --- get a char
DUP 3RD C! --- buffer it
$0D = --- and exit on a CR
UNTIL
DROP
}
ConvFields --- convert all the values in the string and write to fields array
@dir W@ W-DIR
@speed W@ 1 DISPLAY
@dir W@ 6 DISPLAY
AGAIN
;
- Main routine to display wind speed & direction on wall display.
: ULTIMETER ( -- )
' ?ULTIMETER 6 RUN
;
--- diagnostics ---
--- just use a very short name for having a quick look at the serial buffer
: sb SERBUF #80 DUMP CR fields $20 DUMP ;
~] END
AUTORUN ULTIMETER
?BACKUP
This all looks very helpful. Thank you both! I want to take more time to understand the code you've suggested, Peter. This also brings a question to mind: would you consider creating a "Forth Encyclopedia" for Tachyon? It would sure go a long way toward helping folks that are either new to Tachyon, new to FORTH, or both.
Thanks MJB! That's a very helpful listing. Perhaps when things settle down for me project-wise, I can make some additions. I wouldn't be at all opposed to creating something like a Tachyon encyclopedia myself, but it would probably be best if it were a community effort. The framework I'd use is very similar to the infamous Derick & Baker work published back in the early '80's.
On another newbie note: what is the preference of using a colon versus PUB to define a new word? They appear somewhat interchangeable.
On another newbie note: what is the preference of using a colon versus PUB to define a new word? They appear somewhat interchangeable.
: is the Forth way, which is there in Tachyon as well.
pub / pri are the Tachyon way to define new words (looks like SPIN) which can express the intent of public / private
Since Tachyon Forth headers are stored in name space rather than code space this allows headers to be selectively removed without disrupting code. In fact the headers don't even need link fields but they all have attribute bits to indicate IMMEDIATE, SMUDGE, code type, etc. Code space grows up in memory while name space grows down until they meet in which case there is no more memory left although if this happens there are already solutions to deal with this.
So sometimes for reasons such as reclaiming memory or for security concerns we want to remove headers but we can only do this after compilation as the headers are used in a similar way to a symbol table. To remove them we need a way of identifying them and since it was desirable to make Tachyon more readable to Spin users I decided to use the pub and pri in place of a colon with pri setting the "private" bit in the header's attributes.
Everything still works the same but when we run RECLAIM it will strip out all the headers with the "private" attribute and repack them as it goes thus freeing up and reclaiming memory. Colon definitions are the same as pub definitions.
Perhaps this post could go into the "Tachyon encyclopedia"
BTW, the structure of the header and attributes bits are:
HEADER
1 Count byte - This speeds up searching the dictionary both in comparing and in jumping to the next string
2 Name string
3 Attribute byte (8th bit set also terminates name string as strings can be terminated by a null or >$7F )
4 (1st bytecode, 2nd bytecode) or 16-bit absolute address if CALL16
ATTRIBUTES
7 indicates this is an attribute (delimits the start of a null terminated name)
6 smudge bit - set to deactivate word during definition
5 lexicon immediate bit
3 private (can be removed from the dictionary)
2..0 code type (single opcode, double opcode, XCALL, CALL16)
Oh the pain, the pain.
There are so so many ways to do this and keeping in mind that you are asking for this to run in individual cogs (what a waste) here are but a few.
1. The simple dedicated cog and code soft blinky
: BLINKY1 BEGIN 0 HIGH 200 ms 0 LOW 200 ms AGAIN ;
: BLINKY2 BEGIN 1 HIGH 400 ms 1 LOW 400 ms AGAIN ;
: BLINKY3 BEGIN 2 HIGH 50 ms 2 LOW 50 ms AGAIN ;
' BLINKY1 TASK? RUN
' BLINKY2 TASK? RUN
' BLINKY3 TASK? RUN
Here's a SPLAT shot of that working:
2. Use a counter in each cog and return back to IDLE (so it is ready to run some real code)
3. This one uses global variables so that you can change speed and leds on the fly from the console
8 BYTES leds
8 WORDS speed
: BLINKY BEGIN COGID leds + C@ DUP HIGH COGID 2* speed + W@ DUP ms SWAP LOW ms AGAIN ;
--- setup some leds and speeds
0 leds 6 + C! 200 speed 6 2* + W!
1 leds 5 + C! 400 speed 5 2* + W!
2 leds 4 + C! 50 speed 4 2* + W!
--- now start up just 3 cogs - usually 6,5,4
3 FOR ' BLINKY TASK? RUN NEXT
--- you can of course create words to handle the settings thus
: BLINKY! ( speed led cog -- )
SWAP OVER leds + C!
2* speed + W!
;
--- to use BLINKY! --- 50 2 4 BLINKY!
The SPLAT shot for method 3 which shows they are all synchronized as we started them at the same time in the FOR NEXT loop
As mentioned there are much better ways of doing this but because the task is simple there is no need for more stack space or indeed for a copy of task registers.
Thanks, Peter! If you could endure just a bit more pain, I'd be curious to see how you incorporate the addition of stack space and copying the task registers.
Thanks, Peter! If you could endure just a bit more pain, I'd be curious to see how you incorporate the addition of stack space and copying the task registers.
Something specific is what's needed here, MJB. I'm unclear how multiple cogs are set up with stack space and copying the task registers. Seeing how it's done for something simple like the LED question I posed, will help me apply it to my situation.
As for the 'Encyclopedia' ... here is a typical entry from Derick and Baker:
ROT
ROT ( value1 \ value2 \ value3 \ -- value2 \ value3 \ value1 )
Brings the third 16-bit stack item to the top of the stack, while moving the first and second items one deeper in the stack.
Definition: : ROT >R SWAP >R SWAP ;
Usage: ( example of usage here )
My suggestion is to use this, or something similar, as a template for each Tachyon-specific entry, thus giving the newcomer an idea of the tools (words) that are available and how to use them.
Something specific is what's needed here, MJB. I'm unclear how multiple cogs are set up with stack space and copying the task registers. Seeing how it's done for something simple like the LED question I posed, will help me apply it to my situation.
As for the 'Encyclopedia' ... here is a typical entry from Derick and Baker:
ROT
ROT ( value1 \ value2 \ value3 \ -- value2 \ value3 \ value1 )
Brings the third 16-bit stack item to the top of the stack, while moving the first and second items one deeper in the stack.
Definition: : ROT >R SWAP >R SWAP ;
Usage: ( example of usage here )
My suggestion is to use this, or something similar, as a template for each Tachyon-specific entry, thus giving the newcomer an idea of the tools (words) that are available and how to use them.
I don't think MJB is talking about a glossary but rather a collection of code snippets and tips and even the rationale behind the decisions that led to its implementation etc.
When it comes to a glossary however the Derick and Baker method of "Definition" is interesting as I think that confuses and clutters. Also I think that where possible the labels on the stack notation should reflect their purposes such as "src" "dst" "cnt" etc.
I did start up a glossary a while ago but it's a lot of work to do it properly. Here's an example of an entry:
But there was the "Kufanya kazi na Tachyon Forth" document I started up and made editing open to anyone with the link. The title is in Swahili in response to Jonny Mac's mumblings that trying to learn Tachyon Forth was like saying "Swahili is easy", so my response. Anyone can ask questions etc in that document and I will do my best to answer it and document it in such a way that the overall document has structure and can be used as a reference. It is quite alright to link to there to the glossary and the Encyclopedia and other documents.
Documentation is necessary but since it is hard to keep up to date let alone document in the first place I decided from the beginning to make the source code as "documents" and include descriptions and diagrams etc. For sure more detail can be added but at least I have something other than just code and verbose and obvious comments and if I create an application I try to make sure that there is sufficient information in there that anyone could follow along.
Because Forth has no strict syntax rules I try to shape the application so that the names and the way they are used are more natural for that application. In fact the applications and drivers I have published should give a lot of background information and insight into how Tachyon can be used. Due to the dictionary being accessible and the system interactive it becomes far easier to test out and modify these applications by anyone with even a basic knowledge of Forth.
I like your glossary entry for EMIT, better than the example from Derick and Baker. The formatting, while very nice to the eye, seems a bit challenging. That's mostly because I'm unfamiliar with the physical editing process to put it into that format (boxes, etc.). I was also thinking that limiting the glossary to high level definitions might be a good place to start, since newbies aren't going to be delving down too far into the dictionary as they learn and write code. As more of a need for expansion of the glossary arises, the additional words can be added.
Regarding our recent exchange about multiple cores blinking separate LED's at different rates, I wanted to point you back to my 'problem': I'm unclear how multiple cogs are set up with stack space and copying the task registers. Seeing how it's done for something simple like the LED question I posed, will help me apply it to my situation.
I sincerely hope this isn't very painful for you to post! It will be very helpful to this old fellow!
Comments
The OS saw the FT232 part, but the Propeller Tool doesn't see the device (pressing F7), which seems a bit odd to me. I do run my loads off a separate supply and make certain grounds are common. The I/O from the Prop ties to the 5v circuitry via some 1K resistors, which seems to work just fine.
I'll poke around a bit and see what I can find out with my scope, regarding the 'dead' Props. Perhaps there's something obvious, but at $25 a piece, they're not worth putting a whole lot of effort into troubleshooting!
Anyway, finding the problem now may save not just more money again, but your time, your hair, your sanity.......
In my attempt at getting an AUTORUN properly executed, I've tried the following with the below code (the main routine):
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
AUTORUN WxExt
This doesn't seem to be enough to make it work correctly. I'm not fully understanding the big picture of AUTORUN, I guess!
If you turn off autorun ( AUTORUN NONE ) and on reset you can type WxExt before doing anything to get it to run then there should not be a problem with AUTORUN. I'm guessing you haven't initialized some setting such as baudrate etc. Avoid initializing anything during source code load, even though that's handy, it doesn't help when you reboot. You did do a BACKUP command, didn't you?
But then again you could just post your code
FORGET MAX7219.fth
pub MAX7219.fth PRINT" MAX7219/7221 8-7-Segment LED Driver by MJB V0.1 150714-1800 " ;
\ Breadboard
&14.12.15.13 SPIPINS ( ce.miso.mosi.clk --- ) \ dummy 19 for MISO
#14 == 7219CE
#15 == 7219MOSI
#13 == 7219CLK
\ #12 == DUMMY
7219CE PINSET
7219MOSI PINSET
7219CLK PINCLR
pub 7219DP ( BCD -- BCDDP ) --- add in DP
$80 OR ;
pub 7219WR ( val reg -- )
8 SHL OR SPIWR16 DROP
7219CE PINSET
;
pub codeB ( -- ) \ Set 7219 for Code-B decode
$FF 9 7219WR
;
pub scan8 ( -- ) \ Set scan limit to # of displayed digits (all 8 in this case).
7 $B 7219WR
;
pub blank45 ( -- ) \ blank digits 4 & 5 for space between direction & speed.
$F 4 7219WR $F 5 7219WR
;
pub 7219RUN ( -- ) \ Put shutdown register in 'RUN' mode.
1 $C 7219WR
;
pub 7219INIT
7219RUN codeB scan8 blank45
;
\ FORTH support routines for Ultimeter 100 Wall display using Tachyon FORTH on the Propeller.
FORGET ULTIMETER
pub ULTIMETER ;
\ CREATE SERBUF 60 ALLOT \ Serial input buffer
#80 BYTES SERBUF
4 == speed-i \ Wind speed index
8 == dir-i \ Wind direction index
#12 == temp-i \ Temperature index
#16 == Lrain-i \ Longterm Rainfall index
#40 == date-i \ Day of year index
#45 == tod-i \ Time of day index
#48 == rain-I \ Today's rain index
#P9 == WX-RXD \ Incoming data pin.
#P0 4 MASKS CONSTANT DigVal
#P4 2 MASKS CONSTANT DigSel
LONG Wspeed
LONG Wdir
#10 LONGS datastk
#10 LONGS mainstk
#128 BYTES mainregs
\ variables containing wind speed by digit.
LONG dig100s
LONG dig10s
LONG dig1s
\ variables containing wind direction by digit.
LONG dir100s
LONG dir10s
LONG dir1s
pub GetData ( -- ) \ Read serial port and place WX data into array SERBUF.
!SP datastk SP!
#2400 SERBAUD \ Ultimeter comm set to 2400 baud.
BEGIN
BEGIN 9 SERIN "$" = UNTIL \ Wait for beginning of header.
DROP \ Got header start; proceed with empty stack
SERBUF
BEGIN
9 SERIN DUP $0D <>
WHILE
NIP SWAP DUP 1+ ROT ROT C!
REPEAT NIP C! DROP
AGAIN
;
' GetData TASK? RUN \ Set GetData to run in background on its own cog.
: SERBUF@ SERBUF CR #80 DUMP ;
pub ASC2HEX ( char -- hexchar ) \ Convert ASCII hex byte to hex.
DUP $3A <
IF $30 -
ELSE $37 -
THEN
;
pub ConvField ( idx -- decvalue ) \ Index into the serial buffer and convert a field to decimal.
SERBUF + \ Point to 1st char in field.
0 4 FOR
SWAP C@++ ASC2HEX \ Get/convert char to hex.
ROT 4 SHL OR \ Put char into 1st hex posn.
NEXT NIP
;
\ The routines below control the LEDs on the compass rose, for 8 positions.
pub rose0 0 LOW 1 LOW 2 LOW ;
pub rose1 0 HIGH 1 LOW 2 LOW ;
pub rose2 0 LOW 1 HIGH 2 LOW ;
pub rose3 0 HIGH 1 HIGH 2 LOW ;
pub rose4 0 LOW 1 LOW 2 HIGH ;
pub rose5 0 HIGH 1 LOW 2 HIGH ;
pub rose6 0 LOW 1 HIGH 2 HIGH ;
pub rose7 0 HIGH 1 HIGH 2 HIGH ;
pub W-DIR ( n --- ) \ Light LED at position n degrees on compass rose.
SWITCH
1 45 SWITCH>< IF rose1 BREAK
46 90 SWITCH>< IF rose2 BREAK
91 135 SWITCH>< IF rose3 BREAK
136 180 SWITCH>< IF rose4 BREAK
181 225 SWITCH>< IF rose5 BREAK
226 270 SWITCH>< IF rose6 BREAK
271 315 SWITCH>< IF rose7 BREAK
316 360 SWITCH>< IF rose0 BREAK
0 0 SWITCH>< IF rose0 BREAK
;
: GetSpeed ( -- ) \ Pull value from array and parse digits for display.
speed-i ConvField Wspeed !
Wspeed @ 100 / dig100s ! \ grab 100's digit
Wspeed @ dig100s @ 100 * - 10 / dig10s ! \ grab 10's digit
Wspeed @ dig100s @ 100 * - dig10s @ 10 * - dig1s ! \ grab 1's digit
;
: GetDir ( -- ) \ Pull direction value from array & parse for display.
dir-i ConvField Wdir !
Wdir @ 100 / dir100s ! \ grab 100's digit
Wdir @ dir100s @ 100 * - 10 / dir10s ! \ grab 10's digit
Wdir @ dir100s @ 100 * - dir10s @ 10 * - dir1s ! \ grab 1's digit
;
: 7219OUT ( -- ) \ Place wind speed & direction to 8-digit display, with DP @ posn 2.
dig1s @ 1 7219WR dig10s @ 7219DP 2 7219WR dig100s @ 3 7219WR
dir1s @ 6 7219WR dir10s @ 7 7219WR dir100s @ 8 7219WR
;
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
\ ' WxExt TASK? RUN \ Run main routine in its own cog.
\ AUTORUN WxExt
\ ?BACKUP
\ REBOOT
\ !SP mainstk SP!
\ $24 mainregs $80 CMOVE
\ mainregs 7 COGREG!
This is working when I start it manually. What remains is to make it run on power-up.
BTW, that line: is only set at compile time, isn't this one of those things I mentioned that need to be in the startup word?
EDIT: Found one of the many posts with suggestions and W-DIR and rose0...rose7 is replaced with a simple: That's one little suggestion and I'm sure there were many others.
I think Peter talks about something like this ... ;-)
But it is perfectly OK to start slow and verbose.
His comment to my implementation of the MAX7219.fth was also that is was way to verbose to him.
He likes those 'genious' oneliners that take me half an hour to disect and understand ;-)
- AND in doing so I learn a lot and slowly try to immitate his style.
Markus
The OUT word requires a mask as you only want to affect a group of pins so it's just as easy to say <new> <mask> OUTCLR OUTSET which only affects those pins. My W-DIR word takes into account the octant offset too so that it works just like you want it too (if that's the way you want it) and lights up the LEDS, all in one line. Anything more, why, it's just too...ooo verbose!
@MJB: I think there is a bug in OUT anyway as for some reason it uses a SHROUT and I just checked it and it's not working properly.
well ... that's exactly what I meant up there. ROFL yes - now as you mention it...
I saw it and wondered subconsciously - but did not think about.
I've made the change to W-DIR, to include Peter's 'genius one-liner' and it works just great! I can't say I understand it quite yet, but will take the time to do so once I get this project buttoned up and on the wall.
The ' GetData TASK? RUN hasn't been put into a startup word yet, since I wanted to get a better handle on turning things over to an AUTORUN, so everything runs on power-up. One thing I noticed that might take a bit of re-thinking on my part is the initial population of the data array. This doesn't happen right away, since the Wx station only reports about every 20 minutes. It seems that I need to initially hold off on the main program execution until that array is populated, since the parsing routines don't account for an all-zeroes condition that the array starts out with.
While the multitude of the routines are tested and ready, I've been a bit confused by what needs to happen inside the routine that is set to AUTORUN ... stacks & their size ... registers for the assigned task cores, etc.
If my data requires initialization on a cold start (first time) then I have a variable like "firstrun" for instance that I check for a pattern such as $A55A or something but if it isn't then I execute code to load up the variables I need to set after which I set the firstrun variable to the match pattern and run BACKUP. It's much better though to make the system tolerant of uninitialized data though and the LONG/WORD/BYTE words will initially zero that data.
: WxExt ( -- ) \ Main routine to display wind speed & direction on wall display.
7219INIT
' GetData TASK? RUN \ Set GetData to run in background on its own cog.
BEGIN
dir-i ConvField W-DIR \ Light up direction LED on compass rose.
GetSpeed GetDir 7219OUT \ Put speed & direction values to 7219 module.
AGAIN ;
At the bottom of the file containing this routine, I have the following:
AUTORUN WxExt
?BACKUP
REBOOT
What happens is:
The compass rose is getting updated, but the 7219 module is not. I also notice that I no longer have access to the console following a reboot, which would be nice to have.
There are better ways of separating digits but here's one of them for reference using U/MOD ( n div -- rem quo ):
So putting that into action we can extract the digits and write directly into the display rather than bothering with those holding variables such as dig100s etc.
EDIT: changed 100 U/MOD to 10 U/MOD
so you no longer need 7219OUT either and you can get rid of digs100 etc.
Then we can finish off with:
So I just specified the cogs I wanted directly and made a task out of the main loop so that cog 0 can continue running the console. The initialization for the MAX7219 must go in the same cog that accesses it as each cog has its own direction registers.
BTW, you may have been setting the SPI pins for the MAX7219 during compile but not in any init routine I could see so this is probably your problem after reboot. Add it to the 7219INIT:
AVOID special actions during compile - even though they are great for testing - you need to have them available during reboot
NOTES: GetData is a bit of a waste as it is used infrequently with a tiny string of data every 10 mins or so and it could just as well process and display the data after receiving it.
I have a much simplified version which just that and it is very easy to follow.
but you can run this low resource display routine either in
KEYPOLL or in a TIMER routine.
no time to show right now ...
Yes, this is true too as I use KEYPOLL for my network servers etc. TIMER is great too but only if everything gets done in under 1ms (more likely 700us) otherwise the task's WAITCNT won't time out again for another 55.33secs. Doing it as a KEYPOLL is great because all the I/O is directly accessible from the console cog too. In which case this is the change to the code:
That simplified code isn't as simple as I think as my original version I did that parsed the serial stream and inserted spaces in the right places to allow the text interpreter to just go and do its job. Anyway, you can also see that with a handful of general-purpose routines you can have "the lot" rather than duplicating your effort everytime you want that little bit extra. This is not about coding or programming per se but about seeing the problem in such a light that it becomes "simple" and then the solution and how to go about it becomes very clear, no matter what language you end up programming it in.
Have you ever read "Thinking Forth"? I recommend it.
So now, a "Forth Encyclopedia" for Tachyon you say? If I started that I might not get too much else done, including improvements etc. Then there's the imminent P2, well FPGA at least and I intend to devote some time for this. If however this Tachyon documentation was really a group effort then I would be willing to fill in and correct sections if need be, otherwise it's a big task to do it alone. Coding and testing is easy, documentation, hmmmm, that's hard
BTW, this is the simplified version of your code if you didn't get it on dropbox. I defined a dummy word called DEMO beforehand so that it would compile a version that I could test without the serial port operating.
as a little step into this direction I started a Google-Docs document as a collection of Peter's
useful Tachyon snippets.
most copied fron the Tachyon thread, where they are a bit hard to find.
everybody is invited to help collect, organize, extend, comment ...
and sure Peter's time is best spend in extending TACHYON ... (and writing all those helpful comments here ...) thanks
On another newbie note: what is the preference of using a colon versus PUB to define a new word? They appear somewhat interchangeable.
Regards,
Michael
K6MLE
pub / pri are the Tachyon way to define new words (looks like SPIN) which can express the intent of public / private
So sometimes for reasons such as reclaiming memory or for security concerns we want to remove headers but we can only do this after compilation as the headers are used in a similar way to a symbol table. To remove them we need a way of identifying them and since it was desirable to make Tachyon more readable to Spin users I decided to use the pub and pri in place of a colon with pri setting the "private" bit in the header's attributes.
Everything still works the same but when we run RECLAIM it will strip out all the headers with the "private" attribute and repack them as it goes thus freeing up and reclaiming memory. Colon definitions are the same as pub definitions.
Perhaps this post could go into the "Tachyon encyclopedia"
BTW, the structure of the header and attributes bits are:
using 3 cogs; each to control an LED; blink each LED at a different rate.
?
Thanks!
There are so so many ways to do this and keeping in mind that you are asking for this to run in individual cogs (what a waste) here are but a few.
1. The simple dedicated cog and code soft blinky
Here's a SPLAT shot of that working:
2. Use a counter in each cog and return back to IDLE (so it is ready to run some real code)
3. This one uses global variables so that you can change speed and leds on the fly from the console
The SPLAT shot for method 3 which shows they are all synchronized as we started them at the same time in the FOR NEXT loop
As mentioned there are much better ways of doing this but because the task is simple there is no need for more stack space or indeed for a copy of task registers.
why don't you just have a look at the TACHYON Encyclopedia ?
As for the 'Encyclopedia' ... here is a typical entry from Derick and Baker:
ROT
ROT ( value1 \ value2 \ value3 \ -- value2 \ value3 \ value1 )
Brings the third 16-bit stack item to the top of the stack, while moving the first and second items one deeper in the stack.
Definition: : ROT >R SWAP >R SWAP ;
Usage: ( example of usage here )
My suggestion is to use this, or something similar, as a template for each Tachyon-specific entry, thus giving the newcomer an idea of the tools (words) that are available and how to use them.
I don't think MJB is talking about a glossary but rather a collection of code snippets and tips and even the rationale behind the decisions that led to its implementation etc.
When it comes to a glossary however the Derick and Baker method of "Definition" is interesting as I think that confuses and clutters. Also I think that where possible the labels on the stack notation should reflect their purposes such as "src" "dst" "cnt" etc.
I did start up a glossary a while ago but it's a lot of work to do it properly. Here's an example of an entry:
But there was the "Kufanya kazi na Tachyon Forth" document I started up and made editing open to anyone with the link. The title is in Swahili in response to Jonny Mac's mumblings that trying to learn Tachyon Forth was like saying "Swahili is easy", so my response. Anyone can ask questions etc in that document and I will do my best to answer it and document it in such a way that the overall document has structure and can be used as a reference. It is quite alright to link to there to the glossary and the Encyclopedia and other documents.
Documentation is necessary but since it is hard to keep up to date let alone document in the first place I decided from the beginning to make the source code as "documents" and include descriptions and diagrams etc. For sure more detail can be added but at least I have something other than just code and verbose and obvious comments and if I create an application I try to make sure that there is sufficient information in there that anyone could follow along.
Because Forth has no strict syntax rules I try to shape the application so that the names and the way they are used are more natural for that application. In fact the applications and drivers I have published should give a lot of background information and insight into how Tachyon can be used. Due to the dictionary being accessible and the system interactive it becomes far easier to test out and modify these applications by anyone with even a basic knowledge of Forth.
Regarding our recent exchange about multiple cores blinking separate LED's at different rates, I wanted to point you back to my 'problem': I'm unclear how multiple cogs are set up with stack space and copying the task registers. Seeing how it's done for something simple like the LED question I posed, will help me apply it to my situation.
I sincerely hope this isn't very painful for you to post!