A 1 step into 1-wire.
I was looking after a 1-wire object, but couldn't find one.
I saw something in the dropbox, but it was a mix of spin and forth.
So I started my own development of a 1-wire in forth.
Now I have it running and spitting 3 temperaturer back on me.
I have had a lot of fun, and it is almost like assembler.
Have a look at the object.
It seeks the 1-wire and returns the id numbers of the chips with crc8 check.
Then it send the temperature back on the console.
Hi Frida,
Peter also has a basic 1W.fth implementation, that I extended with ROM search.
I didn't have time to do extensive testing and higher level functions.1W-MJB.fth.txt
Will take a look at your code later.
I now solved my problem: the BEGIN AGAIN loop didn't jump back to the BEGIN line.
I putted the loop in a word with jimmyloop which calls the jimmy word with some cleaned up code.
Now everything works and the robot can detect light and drive to a bright spot.
LONG lightl
LONG lightsensleft
: lightleft
#8 HIGH
#250 ms
#8 LOW
#8 PININP
0 lightl !
BEGIN
lightl @ 1 + lightl !
\ lightl @ . CR
\ #8 PIN@ . CR
#8 PIN@
0=
UNTIL
lightl @ lightsensleft !
;
The light value is stored in lightsensleft after call. For the right sensor just use lightsensright as a name and then two sensors can be readed out!
And set your pin number in the code. Higher counter numbers mean darker light and lower numbers brighter light.
That is all.
I use a senselight word which looks like this:
: senselight
BEGIN
lightleft
lightright
AGAIN
;
It's called from the main program to run in another cog:
' senselight TASK? RUN
So the robot can drive and measure light at the same time.
A 1 step into 1-wire.
I was looking after a 1-wire object, but couldn't find one.
I saw something in the dropbox, but it was a mix of spin and forth.
So I started my own development of a 1-wire in forth.
Now I have it running and spitting 3 temperaturer back on me.
I have had a lot of fun, and it is almost like assembler.
Have a look at the object.
It seeks the 1-wire and returns the id numbers of the chips with crc8 check.
Then it send the temperature back on the console.
Thanks for the contribution Frida, the 1wire search routines were started but weren't implemented at the time so this is a welcome addition.
Just had a look at the DropBox file 1Wire.fth (and the webdoc) which was last updated 2 years ago not long after I had introduced Tachyon. The reason I looked was because you said it had a mix of "spin and forth" which just wouldn't be, which it isn't. But just having a quick look at your code it could be simplified somewhat, for instance just comparing the the 1wire reset word:
You have:
[FONT=courier new]pub OW_RESET ( -- t/f )
ow_pin OUTPUTS \ ow_pin low
#487 us \ ~500 us
ow_pin INPUTS \ ow_pin high
#66 us \ ~77 us
ow_pin IN
IF
0 \ return false
ELSE
-1 \ return true
THEN
#487 us \ ~500 us
;
[/FONT]
The original does the same thing and is much simpler:
[FONT=courier new]pub 1WRESET ( -- ack )
DQ@ OUTCLR 1 ms DQ@ INPUTS
#80 us
DQ@ IN 0=
#400 us
;[/FONT]
BTW, the use of the word OUTPUTS is more of a special operation and it is usually much better to use OUTSET or OUTCLR or similar as they set/clear the pin while ensuring it is an output without any extra overhead but IMO it helps us to see that the pin is cleared low. TRUE and FALSE are also the same thing as -1 and 0 if you want to convey the thought that it is returning a flag instead of a value.
1wire devices cannot detect nor do they need precise timings so neither is there any need to try to overly trim timing in code and besides if it were important then the only real way to check timing is to measure it. The specification calls for a low pulse of 480us "minimum" so it doesn't matter if we use a 1ms or 100ms pulse to reset it and in fact it is better to add in a margin.
The "us" word isn't perfect if you have very small values as there is overhead in the instruction itself as this test reveals:
LAP 0 us LAP .LAP 3.800us ok
0 LAP us LAP .LAP 2.800us ok
LAP 10 us LAP .LAP 20.800us ok
LAP 1 us LAP .LAP 10.600us ok
LAP 100 us LAP .LAP 111.600us ok
LAP 500 us LAP .LAP 512.200us ok
I may revisit the delay words to see if I can trim their timing a bit but they have to do a multiply to calculate the number of waitcnts against the system clock. They look like this:
: ms ?DUP 0EXIT 80,000 UM* DROP DELTA ;
: us ?DUP 0EXIT 80 UM* DROP DELTA ;
So it becomes more than redundant to say 0 us for instance as this operation will take 3.8us to accomplish nothing and 1 us still has to perform several operations to end up taking 10.6us doing it.
Anyway, thanks again for the contribution, I think Brian Riley would be happy with that since he has a whole network of 1-wire devices. Seeing you are warmed up, we look forward to more
I wrote a little program for my mouse bot.
The bot should search light with it's phototransistors. I did a run with motor driver battery unplugged:
Propeller .:.:--TACHYON--:.:. Forth V24140928.1630
Clock frequency = 80,000,000
NAMES: $5B01...745E for 6493 (102 bytes added)
CODE: $0000...3DBF for 9314 (577 bytes added)
CALLS: 0420 vectors free
RAM: 7490 bytes free
jimmy light measure
turn right
driveahead
driveahead
driveahead
...
It just repeats the "driveahead" message over and over again. Without jumping back to the BEGIN statement.
It should print out the "light measure" message after "driveahead" by jumping back to "BEGIN", but it never does this.
Maybe I messed up something with my IF/ELSE/THEN stuff?
I just have no idea what is going on there.
Sorry jay, missed this post somehow. I've just gone and refactored and reformatted your code so I can see (and you) what's going on. If you do this yourself when you write code it will be a lot easy to test, read, and modify. Keeping each word small and named appropriately and descriptively (not_that_descriptively_that_you_are_saying_whole_sentences_though) means that when you use the word elsewhere it should not even need a comment as the word DriveAhead already tells you what it's doing.
I'm not sure if you need to do a -1 = IF as it looks like they are actual values and not flags and normally IF will accept any non-zero as a true but in this case it has to be at the maximum value of -1 or $FFFF_FFFF.
You could also run jimmy in it's own cog with ' jimmy 6 RUN for instance (plus maybe some stack allocation) and that way you examine the sensors and variables from the serial console to see what is going on as well.
However I don't see where "turned" is being cleared after you set it, that doesn't look right. I will continue to have a look at this code but this bit may be enough for you to debug the rest. Don't forget to post a little video or something later on if you can.
[FONT=courier new]TACHYON
: jimmybot.FTH ." Jimmy the mouse bot main program " ;
[~
{
The main control program for Jimmy the mouse bot.
Refactored and reformatted - pbj
}
--- just make the motor control words fairly basic for clarity comapred to other actions
ALIAS driveahead FORWARD
ALIAS drivebackw REVERSE
ALIAS drivestop HALT
ALIAS turnleft LEFT
ALIAS turnright RIGHT
DECIMAL
LONG irleft,irright,irfront,turned
LONG lightsensleft,lightsensright
: TurnLeft
." turn left " CR
HALT 1 second
LEFT 1 second
HALT
;
: TurnRightRev \ left side blocked, go backwards and right
." turn backwards right " CR
HALT 1 second
REVERSE 500 ms
RIGHT 1 second
HALT
;
: TurnRight
." turn right " CR
HALT 1 second
RIGHT 1 second
HALT
;
: TurnLeftRev \ left side blocked, go backwards and left
." turn backwards left " CR
HALT 1 second
REVERSE 500 ms
LEFT 1 second
HALT
;
: BackLeft
." backwards and left " CR
HALT 1 second
REVERSE 500 ms
LEFT 1 second
HALT
turned ~~
;
: BackRight
." backwards right " CR
HALT 1 second
REVERSE 500 ms
RIGHT 1 second
HALT
turned ~~
;
: DriveAhead
." driveahead " CR
FORWARD 500 ms
HALT
;
: DriveBack \ no way to turn, drive backwards
." backwards " CR
HALT 1 second
REVERSE 500 ms
HALT
;
: WhichWay?
\ measure light on left and right side
lightleft lightsensleft !
lightright lightsensright !
lightsensleft @ lightsensright @
< IF \ left side is brighter, turn left
irleft @ -1 = IF TurnLeft ELSE TurnRightRev THEN
ELSE \ right side is brighter, turn right
irright @ -1 = IF TurnRight ELSE TurnLeftRev THEN
THEN
sensorfront irfront ! \ store sensor data
irfront @ -1 = IF DriveAhead THEN \ front free, drive ahead
;
: Blocked!
irfront @ irleft @ OR
-1 = irleft @ -1 = AND IF BackLeft THEN
irfront @ irright @ OR
-1 = irright @ -1 = AND IF BackRight THEN
turned @ 0= IF DriveBack THEN
;
: jimmy
initpwm
\ test IR LEDs
tirfront tirleft tirright
\ test motors
FORWARD 500 ms
REVERSE 500 ms
\ beeperok
5 seconds
BEGIN
sensorfront irfront ! \ store sensor data
5 ms sensorleft irleft !
5 ms sensorright irright !
turned ~
irfront @
-1 = IF
\ front free
." light measure " CR
WhichWay?
ELSE \ front blocked somewhere
Blocked!
THEN
AGAIN
;
]~
END
[/FONT]
Well I must be blind, (maybe because I am old! ) but I can only find under MISC MODULES SpinOneWire.fth in your dropbox.
But I got the webdoc file. Now I have something to study.
Well I must be blind, (maybe because I am old! ) but I can only find under MISC MODULES SpinOneWire.fth in your dropbox.
But I got the webdoc file. Now I have something to study.
Yikes, that's a Spin file that got in there somehow and got renamed to a .fth file, how did that happen?? Oh well, time to clean up the folders I guess......
I started looking at the SEARCH command at the time but it looked too messy plus I wasn't really using these 1-wire devices so that part got pushed to the bottom of the pile, until you came along and fixed it up.
BTW, I've moved the "us" word to EXTEND and added in some compensation so after all the checks etc it's timing is good for 21us upwards but anything smaller will just cause it to exit early and still take around 11us. Only other way to get it better than that would be to make an opcode of it in the PASM kernel, but there's no room for that anyway.
I am? Why? There is a lot of clever and innovative work going on in this thread. I have not participated here at all, though I see my name has come up here a few times.
I can hear it now (WHAT ABOUT FFT)
Well. I have not given up hope of casting my simple minded FFT into Forth one day. It won't be for Tachyon though. Perhaps gforth on my PC. Just so I get some idea how to work this language.
I am? Why? There is a lot of clever and innovative work going on in this thread. I have not participated here at all, though I see my name has come up here a few times.
Well. I have not given up hope of casting my simple minded FFT into Forth one day. It won't be for Tachyon though. Perhaps gforth on my PC. Just so I get some idea how to work this language.
If you really have a fast FFT in PASM, then why bother converting to a much slower FORTH.
Then let's just make a PASM blop to load in a COG and feed it from Tachyon.
If somebody needs fast FFT in Tachyon, then I think THAT's the way to go.
Define a HUB array, put the data, give length + array-address to COG - check for sync - and be happy with the result in the defined HUB result array.
Shouldn't be very difficult.
I am a beginner in forth. So first I spell it out line by line until I understand what is going on.
When I understand it, then I can do 1 liners also.
I have changed my OW_RESET a bit.
old:
pub OW_RESET ( -- t/f )
ow_pin OUTPUTS \ ow_pin low
#487 us \ ~500 us
ow_pin INPUTS \ ow_pin high
#66 us \ ~77 us
ow_pin IN
IF
0 \ return false
ELSE
-1 \ return true
THEN
#487 us \ ~500 us
;
new:
pub OW_RESET ( -- t/f )
ow_pin OUTPUTS \ ow_pin low
#487 us \ ~500 us
ow_pin INPUTS \ ow_pin high
#66 us \ ~77 us
ow_pin IN NOT
#487 us \ ~500 us
;
I also changed:
pub OW_WRITE_X ( 0|1 -- )
ow_pin OUTPUTS
NOP NOP NOP \ ~1.2 us
IF
ow_pin INPUTS
THEN
#49 us \ ~60.4 us
ow_pin INPUTS
NOP NOP NOP \ ~1.2 us
;
and
pub OW_READ_X ( -- 0|FF )
ow_pin OUTPUTS \ ow_pin low
NOP NOP NOP \ ~1.2 us
ow_pin INPUTS \ ow_pin high
NOP NOP NOP \ ~1.2 us
\ 1 us \ ~10.6 us \timing wrong with 4 elements on datastack
\ 0 us \ ~3.8 us -- ~4.2 us \ this works with more or nothing on datastack
ow_pin IN \ ow_pin read
#39 us \ ~50.6 us
;
First I used 1 us, but it vent wrong with 4 data on the stack. Then I used 0 us, and it worked. After some test I now use NOP NOP NOP and get 1.2 us.
I have done a lot of lap xx lap .LAP to find the right delay time. When I do lap 0 us lap .LAP I got 3.8 us with a empty stack, but when I do lap 0 us lap .LAP with 4 or more data on the stack I got 4.2 us.
Now I can do CRC8 on the scratchpad registers also. Now I wil test on a long wire, to se if it still works.
If you really have a fast FFT in PASM, then why bother converting to a much slower FORTH. Then let's just make a PASM blop to load in a COG and feed it from Tachyon.
Yes, but no, but yes, but...
If I ever actually needed an FFT that was actually fast I would probably use somebody else's cleverer and faster code on a faster processor. All depends what the requirements might be.
My rude and crude FFT was not about that. It was about solving a puzzle that had bugged me for a couple of decades or more. That is about how long it was between seeing my first FFT source code, in BASIC for the Atari 520, and starting to have even the slightest idea how it works. It was a deep mystery.
Luckily, with input from this forum, I finally saw the light. The challenge then was to write my own FFT from scratch in C. Just to see if I could do it. And then to do that in Spin. And then to do that in PASM.
By strange happen stance a couple of people here have made use of the resulting FFT on the Propeller.
So it goes with the translation to Forth. It's about learning enough Forth to actually be able to make a simple program like that.
It has been said here that I should not comment on Forth until I actually know what I'm talking about. Quite rightly so. So that is the challenge I have set myself, a significant, slightly complex piece of logic in Forth. Useful or not.
I agree. If one wants a speedy FFT for Forth on the Propeller the PASM part of my FFT can be extracted and used as you describe. There is at least one other PASM FFT http://propeller.wikispaces.com/FFT. Perhaps an even faster option, I have never tried it.
Some people spend hours on crossword puzzles or soduku or just watching TV. Me, I waste my time messing around with bits of code.
My apologies for this little diversion to the Tachyon thread.
If I ever actually needed an FFT that was actually fast I would probably use somebody else's cleverer and faster code on a faster processor. All depends what the requirements might be.
My rude and crude FFT was not about that. It was about solving a puzzle that had bugged me for a couple of decades or more. That is about how long it was between seeing my first FFT source code, in BASIC for the Atari 520, and starting to have even the slightest idea how it works. It was a deep mystery.
Luckily, with input from this forum, I finally saw the light. The challenge then was to write my own FFT from scratch in C. Just to see if I could do it. And then to do that in Spin. And then to do that in PASM.
By strange happen stance a couple of people here have made use of the resulting FFT on the Propeller.
So it goes with the translation to Forth. It's about learning enough Forth to actually be able to make a simple program like that.
It has been said here that I should not comment on Forth until I actually know what I'm talking about. Quite rightly so. So that is the challenge I have set myself, a significant, slightly complex piece of logic in Forth. Useful or not.
I agree. If one wants a speedy FFT for Forth on the Propeller the PASM part of my FFT can be extracted and used as you describe. There is at least one other PASM FFT http://propeller.wikispaces.com/FFT. Perhaps an even faster option, I have never tried it.
Some people spend hours on crossword puzzles or soduku or just watching TV. Me, I waste my time messing around with bits of code.
My apologies for this little diversion to the Tachyon thread.
Wrangling with writing an efficient FFT in Forth? Not the kind of thing I would recommend for anyone to do for several reasons but it is certainly not the way to learn Forth. If you are very familiar and comfortable both with Forth and FFTs then you would be in a better position to see how you would shape Forth in such a way that made writing the FFT more natural and at the same time efficient. Unfortunately I think if you attempt to dive into the deep end of rough waters for your first lesson you may not dive again. Once bitten, twice shy, and the problem is the approach in the first place and what your motivation for doing it this way is.
No, Forth was born out of a need for bare metal control (radio telescopes) with high level abstraction without losing anything in-between. The interactive shell/compiler is another layer that is a bonus as well. But when it comes to FFTs these things need to be compiled to the bare machine code to have any hope but this is not what Tachyon does, nor can it do much with the limited resources of the Prop itself. But it is possible to write an optimizing compiler in Tachyon that could reduce something like an FFT down to PASM which would then have to be loaded into it's own cog. Of course, writing the compiler would not really be worth the trouble unless it was running on an ARM where code space is not limited to 512 instructions, so therefore the FFT in PASM is all that is required.
The way Frida is learning Tachyon Forth is a very good way as you can jump into small chunks of code and test them, even optimize them in different ways to get a feel for the merits of various approaches. So I would recommend that if you really want to play with your FFT that you incorporate your PASM version into Tachyon and perhaps even interface to the wave player to see if it's fast enough to do anything useful.
But it is possible to write an optimizing compiler in Tachyon that could reduce something like an FFT down to PASM which would then have to be loaded into it's own cog.
I like this idea. It is the model that was used by Lisp programmers as well. You use Forth (Lisp) to craft a domain-specific language that makes it easy to talk about the things you're interested in. I think this is probably what you've already done with things like network stacks and HTTP request handling. FFT could be another example but one where you really want to generate machine code rather than just interpreted words. It would be really interesting to see an example of how this would be done.
I like this idea. It is the model that was used by Lisp programmers as well. You use Forth (Lisp) to craft a domain-specific language that makes it easy to talk about the things you're interested in. I think this is probably what you've already done with things like network stacks and HTTP request handling. FFT could be another example but one where you really want to generate machine code rather than just interpreted words. It would be really interesting to see an example of how this would be done.
I have written one-pass CPLD compilers in Forth that proved very compact, efficient, and flexible! It's the approach taken that makes a difference.
An optimizing compiler would be better served operating on the source as a file, so a system with an SD card can take that source and perform multiple passes as required and generate the output files back to the SDFS. If this is the case then it is no trouble to implement any mix of infix as well as postfix notation and register addressing and it can still benefit from still being Forth in the use of "macros" etc. The compiler would be loaded as necessary and then "forgotten" after a compile with the binary available as a runtime object. This reminds me that I have to get a move on with my runtime object handlers as I already have the assembler anyway but an optimizing compiler to PASM would be a bonus. These runtime objects can be stored on file anywhere really, in a small system they would be in the upper 32K of a large EEPROM for instance, otherwise SDFS, or even SPI Flash which I plan to integrate transparently with the SDFS as a drive.
The compiler would be loaded as necessary and then "forgotten" after a compile with the binary available as a runtime object.
How does "forget" work? I thought that the dictionary in Forth was organinzed like a stack and that "forget" just pops some definitions off the stack making the space formerly occupied by them available. Is that right? Is it also possible to forget things down further in the stack? I'm imagining that your compiler would produce additional dictionary words and so the compiler itself would not be on the top of the dictionary stack when the compilation was finished. How do you remove the compiler words but keep the compiler generated code? Or do I have this all wrong? :-)
This reminds me that I have to get a move on with my runtime object handlers as I already have the assembler anyway but an optimizing compiler to PASM would be a bonus. These runtime objects can be stored on file anywhere really, in a small system they would be in the upper 32K of a large EEPROM for instance, otherwise SDFS, or even SPI Flash which I plan to integrate transparently with the SDFS as a drive.
Are you talking about an optimizing compiler that would compile Tachyon Forth words into native PASM code? That would be cool!
Wrangling with writing an efficient FFT in Forth? Not the kind of thing I would recommend for anyone to do for several reasons but it is certainly not the way to learn Forth.
It seems I did not express myself clearly enough and the main point of my post was lost.
I was trying to say that "efficient" is not the point of the exercise. "FFT" is not the point of the exercise. The point of my little goal is to learn enough Forth to be able to create some small but non-trivial function.
I totally agree with you, as Braino has also pointed out, diving into something like an FFT is not a good way to start getting to grips with a new language. So that is not what is going on here. It's simply the "final exam" I have set myself for this course of study.
Starting with baby steps. Whatever program I had in mind they all have the same fundamental needs: Data, variables, arrays, arithmetic operations, sequential statements, conditional statements, iteration constructs, sub functions and so on.
If I ever master those simple concepts in Forth I'll then be trying to put it all together into something bigger.
How does "forget" work? I thought that the dictionary in Forth was organinzed like a stack and that "forget" just pops some definitions off the stack making the space formerly occupied by them available. Is that right?
Hi David
yes - that's basically it.
There is another related option in pub vs. pri definitions, where the vectors of private words can be reclaimed, which makes theminvisible to later modules and reclaims some dictionar space and vectors.
Is it also possible to forget things down further in the stack?
I'm imagining that your compiler would produce additional dictionary words and so the compiler itself would not be on the top of the dictionary stack when the compilation was finished. How do you remove the compiler words but keep the compiler generated code? Or do I have this all wrong? :-)
that's why Peter was talking about 'batch' compilation reading the source from file and storing the output, the binary COG module, on file as well.
think of compile <source >bin
which loads in the compiler, runs the job and frees memory after.
No words need to be created this way. maybe temp stuff, that can be removed, when unloading (forgetting) the loaded compiler module.
then at later time the created module can be loaded from SD into a COG and run there.
If there were more memory plus memory management (big RAM + GC ;-) ) then it can be done different as you were thinking, the LISP way.
Are you talking about an optimizing compiler that would compile Tachyon Forth words into native PASM code? That would be cool!
sounds like it ... ;-)
but I think a real first step into this direction is the assembler.
Imagine:
Heaters FFT PASM code slightly modified to match the special Tachyon-PASM syntax in it's file on SD.
This is run through the Tachyon Assembler and creates a COG image on SD (kind of SD OBEX)
Which now can be loaded into a COG and run whenever you like.
Hi David
yes - that's basically it.
There is another related option in pub vs. pri definitions, where the vectors of private words can be reclaimed, which makes theminvisible to later modules and reclaims some dictionar space and vectors.
that's why Peter was talking about 'batch' compilation reading the source from file and storing the output, the binary COG module, on file as well.
think of compile <source >bin
which loads in the compiler, runs the job and frees memory after.
No words need to be created this way. maybe temp stuff, that can be removed, when unloading (forgetting) the loaded compiler module.
then at later time the created module can be loaded from SD into a COG and run there.
If there were more memory plus memory management (big RAM + GC ;-) ) then it can be done different as you were thinking, the LISP way.
sounds like it ... ;-)
but I think a real first step into this direction is the assembler.
Imagine:
Heaters FFT PASM code slightly modified to match the special Tachyon-PASM syntax in it's file on SD.
This is run through the Tachyon Assembler and creates a COG image on SD (kind of SD OBEX)
Which now can be loaded into a COG and run whenever you like.
Here's a color coded ASCII dump "memory map" which gives you a pretty good view of how memory is used in an almost fully loaded system with networking. The code grows up in memory while the dictionary grows down towards and I've used the same color for matching code and dictionary sections. This was done a few months ago before I implemented the SDWORDS which moves everything from the dictionary into the SDFS as an indexed rapid search, so all that dictionary memory you see is now free except for 1K plus whatever gets added afterwards.
But here is a very quick memory map listing starting from low memory:
56A0 NETWORK WORDS xxxx WIZNET WORDS xxxx EASYFILE WORDS xxxx SDCARD WORDS xxxx HARDWARE WORDS xxxx EXTEND WORDS xxxx KERNEL WORDS 7440 SOCKET BUFFERS 7500 FILE BUFFERS 7D00 RECEIVE BUFFERS 7F60 CONSOLE STACK
I have been thinking of implementing code addressing into virtual memory although I haven't run out of memory yet since I implemented SDWORDS, but later I may need it what with optimizing compilers and the like! It may even use a similar scheme to SDWORDS where I cache whole sectors of code that are read from an SDWORDS.TBC (Tachyon Byte Code) file. Normally this code would be like application code, it mostly references code in RAM with a smaller percentage of the application. So you could load up the optimizing compiler, run it, without having to "forget it" even though it's sitting in RAM, it is really in virtual memory in the SDWORDS.TBC file. So even the network servers and clients could be handled this way too, the few milliseconds to cache it is nothing. Just an idea but it sounds doable.
No....My observation is that humans can believe in all kind of weird non-existent stuff: God, the devil, heaven, hell, capitalism, communism, society, punk rock, integers, e, PI, quantum mechanics, TV news, it's endless.... All figments of the human imagination that change a persons behaviour in many ways.
No....My observation is that humans can believe in all kind of weird non-existent stuff: God, the devil, heaven, hell, capitalism, communism, society, punk rock, integers, e, PI, quantum mechanics, TV news, it's endless.... All figments of the human imagination that change a persons behaviour in many ways.
Let's just say that "In Chip we trust".
Sorry, I think I hijacked Peter's thread. Let's get back to talking about Tachyon which is much more interesting than all of this philosophical junk. :-)
Phil, you're referring to the P2 thread that's only been around for 7 months. I think the previous P2 thread was around for a few years and had half a million views, or maybe it was only 300,000.
Propeller .:.:--TACHYON--:.:. Forth V24140928.1630
Clock frequency = 80,000,000
NAMES: $5C89...745E for 6101 (3715 bytes added)
CODE: $0000...34EC for 7447 (7212 bytes added)
CALLS: 0450 vectors free
RAM: 10141 bytes free
MODULES LOADED:
18C0: EXTEND.fth Primary extensions to TACHYON kernel - 141027-1000
BOOT: EXTEND.boot
----------------------------------------------------------------
1 1 a ok
2 2 b ok
3 3 c --> C <-- not found
ok
.S Data Stack (6)
$0000.0003 - 3
$0000.0003 - 3
$0000.0002 - 2
$0000.0002 - 2
$0000.0001 - 1
$0000.0001 - 1
$0000.0000 - 0 ok
What are a and b doing?
There is a fault in my 1 wire seek rotine, a new will follow soon.
Hi Frida,
\ from EXTEND
( Select the desired target CTR A or B before use )
pub A ctr C~ ;
pub B 1 ctr C! ;
A and B set the active counter.
since a and b are not defined the input reader makes the word upper case and tries again.
it finds A and B and does as commanded.
since there is no "C" and "c" is not defined as well you get the error.
The stack shows your 1 1 2 2 3 3 values
so all is fine ;-)
btw: 1-Wire - did you see the code that I postet? --- and my PM
There is a fault in my 1 wire seek rotine, a new will follow soon.
As MJB pointed out "all is fine". In some Forths they are case insensitive which is mainly to cater to the C crowd I feel and so they accept lower case alphas in hex numbers. I could allow this I guess but what to make number processing more efficient especially during a large source code load I specify that all numbers must be recognizable in that they start with a valid decimal digit so DEADBEEF will not be recognized as a number. Instead with would prepend a 0 or a radix prefix such as $ or # or % to force it to be processed as a number. This latter method is preferred for all non-decimal numbers.
In fact if you prefix a number it will preprocess it rather than scanning the dictionary for a match, failing, then trying to convert it as it normally would with a number. So my convention at present for source code is to set the default base to decimal and make sure all non-decimal numbers are prefixed.
So the hex digit A would then be entered as $A or $0A or even 0Ah if you like. Because this preprocessor forces it to become a number it is quite flexible in what it will allow in the way of "separators", that's why you will see ports as #P26 for instance, because we can and it's so much clearer to see it's P26.
I notice too that the .S routine is printing a dummy zero at the end of the list, this was a bug in an earlier version but if you recompile your system from current sources it will print clean.
BTW, I appreciate the work you are putting into the 1-wire routines, especially the search function!
I downloaded Tachyon V2.4.spin, and changed baud to 115200, but only get a blue screen like windoze.
Unfortunately I deleted the old version before I tryed the new one.
Tachyon V2.3.spin works, so now I have to start all over again.
Comments
Peter also has a basic 1W.fth implementation, that I extended with ROM search.
I didn't have time to do extensive testing and higher level functions.1W-MJB.fth.txt
Will take a look at your code later.
I putted the loop in a word with jimmyloop which calls the jimmy word with some cleaned up code.
Now everything works and the robot can detect light and drive to a bright spot.
I wrote a little code to detect light with this circuit: http://learn.parallax.com/activitybot/build-light-sensor-circuits
The light value is stored in lightsensleft after call. For the right sensor just use lightsensright as a name and then two sensors can be readed out!
And set your pin number in the code. Higher counter numbers mean darker light and lower numbers brighter light.
That is all.
I use a senselight word which looks like this:
It's called from the main program to run in another cog:
So the robot can drive and measure light at the same time.
Thanks for the contribution Frida, the 1wire search routines were started but weren't implemented at the time so this is a welcome addition.
Just had a look at the DropBox file 1Wire.fth (and the webdoc) which was last updated 2 years ago not long after I had introduced Tachyon. The reason I looked was because you said it had a mix of "spin and forth" which just wouldn't be, which it isn't. But just having a quick look at your code it could be simplified somewhat, for instance just comparing the the 1wire reset word:
You have:
The original does the same thing and is much simpler:
BTW, the use of the word OUTPUTS is more of a special operation and it is usually much better to use OUTSET or OUTCLR or similar as they set/clear the pin while ensuring it is an output without any extra overhead but IMO it helps us to see that the pin is cleared low. TRUE and FALSE are also the same thing as -1 and 0 if you want to convey the thought that it is returning a flag instead of a value.
1wire devices cannot detect nor do they need precise timings so neither is there any need to try to overly trim timing in code and besides if it were important then the only real way to check timing is to measure it. The specification calls for a low pulse of 480us "minimum" so it doesn't matter if we use a 1ms or 100ms pulse to reset it and in fact it is better to add in a margin.
The "us" word isn't perfect if you have very small values as there is overhead in the instruction itself as this test reveals:
LAP 0 us LAP .LAP 3.800us ok
0 LAP us LAP .LAP 2.800us ok
LAP 10 us LAP .LAP 20.800us ok
LAP 1 us LAP .LAP 10.600us ok
LAP 100 us LAP .LAP 111.600us ok
LAP 500 us LAP .LAP 512.200us ok
I may revisit the delay words to see if I can trim their timing a bit but they have to do a multiply to calculate the number of waitcnts against the system clock. They look like this:
: ms ?DUP 0EXIT 80,000 UM* DROP DELTA ;
: us ?DUP 0EXIT 80 UM* DROP DELTA ;
So it becomes more than redundant to say 0 us for instance as this operation will take 3.8us to accomplish nothing and 1 us still has to perform several operations to end up taking 10.6us doing it.
Anyway, thanks again for the contribution, I think Brian Riley would be happy with that since he has a whole network of 1-wire devices. Seeing you are warmed up, we look forward to more
Sorry jay, missed this post somehow. I've just gone and refactored and reformatted your code so I can see (and you) what's going on. If you do this yourself when you write code it will be a lot easy to test, read, and modify. Keeping each word small and named appropriately and descriptively (not_that_descriptively_that_you_are_saying_whole_sentences_though) means that when you use the word elsewhere it should not even need a comment as the word DriveAhead already tells you what it's doing.
I'm not sure if you need to do a -1 = IF as it looks like they are actual values and not flags and normally IF will accept any non-zero as a true but in this case it has to be at the maximum value of -1 or $FFFF_FFFF.
You could also run jimmy in it's own cog with ' jimmy 6 RUN for instance (plus maybe some stack allocation) and that way you examine the sensors and variables from the serial console to see what is going on as well.
However I don't see where "turned" is being cleared after you set it, that doesn't look right. I will continue to have a look at this code but this bit may be enough for you to debug the rest. Don't forget to post a little video or something later on if you can.
But I got the webdoc file. Now I have something to study.
Yikes, that's a Spin file that got in there somehow and got renamed to a .fth file, how did that happen?? Oh well, time to clean up the folders I guess......
I started looking at the SEARCH command at the time but it looked too messy plus I wasn't really using these 1-wire devices so that part got pushed to the bottom of the pile, until you came along and fixed it up.
BTW, I've moved the "us" word to EXTEND and added in some compensation so after all the checks etc it's timing is good for 21us upwards but anything smaller will just cause it to exit early and still take around 11us. Only other way to get it better than that would be to make an opcode of it in the PASM kernel, but there's no room for that anyway.
Then let's just make a PASM blop to load in a COG and feed it from Tachyon.
If somebody needs fast FFT in Tachyon, then I think THAT's the way to go.
Define a HUB array, put the data, give length + array-address to COG - check for sync - and be happy with the result in the defined HUB result array.
Shouldn't be very difficult.
When I understand it, then I can do 1 liners also.
I have changed my OW_RESET a bit.
old: new: I also changed: and First I used 1 us, but it vent wrong with 4 data on the stack. Then I used 0 us, and it worked. After some test I now use NOP NOP NOP and get 1.2 us.
I have done a lot of lap xx lap .LAP to find the right delay time. When I do lap 0 us lap .LAP I got 3.8 us with a empty stack, but when I do lap 0 us lap .LAP with 4 or more data on the stack I got 4.2 us.
Now I can do CRC8 on the scratchpad registers also. Now I wil test on a long wire, to se if it still works.
Have fun.
maybe you want to compare with this:1WireMJB-2014-11-11.fth.txt
If I ever actually needed an FFT that was actually fast I would probably use somebody else's cleverer and faster code on a faster processor. All depends what the requirements might be.
My rude and crude FFT was not about that. It was about solving a puzzle that had bugged me for a couple of decades or more. That is about how long it was between seeing my first FFT source code, in BASIC for the Atari 520, and starting to have even the slightest idea how it works. It was a deep mystery.
Luckily, with input from this forum, I finally saw the light. The challenge then was to write my own FFT from scratch in C. Just to see if I could do it. And then to do that in Spin. And then to do that in PASM.
By strange happen stance a couple of people here have made use of the resulting FFT on the Propeller.
So it goes with the translation to Forth. It's about learning enough Forth to actually be able to make a simple program like that.
It has been said here that I should not comment on Forth until I actually know what I'm talking about. Quite rightly so. So that is the challenge I have set myself, a significant, slightly complex piece of logic in Forth. Useful or not.
I agree. If one wants a speedy FFT for Forth on the Propeller the PASM part of my FFT can be extracted and used as you describe. There is at least one other PASM FFT http://propeller.wikispaces.com/FFT. Perhaps an even faster option, I have never tried it.
Some people spend hours on crossword puzzles or soduku or just watching TV. Me, I waste my time messing around with bits of code.
My apologies for this little diversion to the Tachyon thread.
Wrangling with writing an efficient FFT in Forth?
No, Forth was born out of a need for bare metal control (radio telescopes) with high level abstraction without losing anything in-between. The interactive shell/compiler is another layer that is a bonus as well. But when it comes to FFTs these things need to be compiled to the bare machine code to have any hope but this is not what Tachyon does, nor can it do much with the limited resources of the Prop itself. But it is possible to write an optimizing compiler in Tachyon that could reduce something like an FFT down to PASM which would then have to be loaded into it's own cog. Of course, writing the compiler would not really be worth the trouble unless it was running on an ARM where code space is not limited to 512 instructions, so therefore the FFT in PASM is all that is required.
The way Frida is learning Tachyon Forth is a very good way as you can jump into small chunks of code and test them, even optimize them in different ways to get a feel for the merits of various approaches. So I would recommend that if you really want to play with your FFT that you incorporate your PASM version into Tachyon and perhaps even interface to the wave player to see if it's fast enough to do anything useful.
I have written one-pass CPLD compilers in Forth that proved very compact, efficient, and flexible! It's the approach taken that makes a difference.
An optimizing compiler would be better served operating on the source as a file, so a system with an SD card can take that source and perform multiple passes as required and generate the output files back to the SDFS. If this is the case then it is no trouble to implement any mix of infix as well as postfix notation and register addressing and it can still benefit from still being Forth in the use of "macros" etc. The compiler would be loaded as necessary and then "forgotten" after a compile with the binary available as a runtime object. This reminds me that I have to get a move on with my runtime object handlers as I already have the assembler anyway but an optimizing compiler to PASM would be a bonus. These runtime objects can be stored on file anywhere really, in a small system they would be in the upper 32K of a large EEPROM for instance, otherwise SDFS, or even SPI Flash which I plan to integrate transparently with the SDFS as a drive.
I was trying to say that "efficient" is not the point of the exercise. "FFT" is not the point of the exercise. The point of my little goal is to learn enough Forth to be able to create some small but non-trivial function.
I totally agree with you, as Braino has also pointed out, diving into something like an FFT is not a good way to start getting to grips with a new language. So that is not what is going on here. It's simply the "final exam" I have set myself for this course of study.
Starting with baby steps. Whatever program I had in mind they all have the same fundamental needs: Data, variables, arrays, arithmetic operations, sequential statements, conditional statements, iteration constructs, sub functions and so on.
If I ever master those simple concepts in Forth I'll then be trying to put it all together into something bigger.
yes - that's basically it.
There is another related option in pub vs. pri definitions, where the vectors of private words can be reclaimed, which makes theminvisible to later modules and reclaims some dictionar space and vectors. that's why Peter was talking about 'batch' compilation reading the source from file and storing the output, the binary COG module, on file as well.
think of compile <source >bin
which loads in the compiler, runs the job and frees memory after.
No words need to be created this way. maybe temp stuff, that can be removed, when unloading (forgetting) the loaded compiler module.
then at later time the created module can be loaded from SD into a COG and run there.
If there were more memory plus memory management (big RAM + GC ;-) ) then it can be done different as you were thinking, the LISP way. sounds like it ... ;-)
but I think a real first step into this direction is the assembler.
Imagine:
Heaters FFT PASM code slightly modified to match the special Tachyon-PASM syntax in it's file on SD.
This is run through the Tachyon Assembler and creates a COG image on SD (kind of SD OBEX)
Which now can be loaded into a COG and run whenever you like.
Here's a color coded ASCII dump "memory map" which gives you a pretty good view of how memory is used in an almost fully loaded system with networking. The code grows up in memory while the dictionary grows down towards and I've used the same color for matching code and dictionary sections. This was done a few months ago before I implemented the SDWORDS which moves everything from the dictionary into the SDFS as an indexed rapid search, so all that dictionary memory you see is now free except for 1K plus whatever gets added afterwards.
But here is a very quick memory map listing starting from low memory:
0024 REGISTERS
0124 VECTORS
0929 KERNEL CODE
1880 EXTEND CODE
208A HARDWARE CODE
2AA0 SDCARD CODE
2F54 EASYFILE CODE
3962 WIZNET CODE
40A0 NETWORK CODE
4E80 <FREE SPACE FOR APP>
56A0 NETWORK WORDS
xxxx WIZNET WORDS
xxxx EASYFILE WORDS
xxxx SDCARD WORDS
xxxx HARDWARE WORDS
xxxx EXTEND WORDS
xxxx KERNEL WORDS
7440 SOCKET BUFFERS
7500 FILE BUFFERS
7D00 RECEIVE BUFFERS
7F60 CONSOLE STACK
I have been thinking of implementing code addressing into virtual memory although I haven't run out of memory yet since I implemented SDWORDS, but later I may need it what with optimizing compilers and the like! It may even use a similar scheme to SDWORDS where I cache whole sectors of code that are read from an SDWORDS.TBC (Tachyon Byte Code) file. Normally this code would be like application code, it mostly references code in RAM with a smaller percentage of the application. So you could load up the optimizing compiler, run it, without having to "forget it" even though it's sitting in RAM, it is really in virtual memory in the SDWORDS.TBC file. So even the network servers and clients could be handled this way too, the few milliseconds to cache it is nothing. Just an idea but it sounds doable.
In case you haven't noticed, Tachyon is more popular than the Prop2 (measured in number of thread views). Compare:
to your 145K views.
-Phil
Hmmm...It's arguable if God exists. But the idea as always been really popular and written about a lot.
But I know what you mean.
No....My observation is that humans can believe in all kind of weird non-existent stuff: God, the devil, heaven, hell, capitalism, communism, society, punk rock, integers, e, PI, quantum mechanics, TV news, it's endless.... All figments of the human imagination that change a persons behaviour in many ways.
Let's just say that "In Chip we trust".
What are a and b doing?
There is a fault in my 1 wire seek rotine, a new will follow soon.
A and B set the active counter.
since a and b are not defined the input reader makes the word upper case and tries again.
it finds A and B and does as commanded.
since there is no "C" and "c" is not defined as well you get the error.
The stack shows your 1 1 2 2 3 3 values
so all is fine ;-)
btw: 1-Wire - did you see the code that I postet? --- and my PM
As MJB pointed out "all is fine". In some Forths they are case insensitive which is mainly to cater to the C crowd I feel and so they accept lower case alphas in hex numbers. I could allow this I guess but what to make number processing more efficient especially during a large source code load I specify that all numbers must be recognizable in that they start with a valid decimal digit so DEADBEEF will not be recognized as a number. Instead with would prepend a 0 or a radix prefix such as $ or # or % to force it to be processed as a number. This latter method is preferred for all non-decimal numbers.
In fact if you prefix a number it will preprocess it rather than scanning the dictionary for a match, failing, then trying to convert it as it normally would with a number. So my convention at present for source code is to set the default base to decimal and make sure all non-decimal numbers are prefixed.
So the hex digit A would then be entered as $A or $0A or even 0Ah if you like. Because this preprocessor forces it to become a number it is quite flexible in what it will allow in the way of "separators", that's why you will see ports as #P26 for instance, because we can and it's so much clearer to see it's P26.
I notice too that the .S routine is printing a dummy zero at the end of the list, this was a bug in an earlier version but if you recompile your system from current sources it will print clean.
BTW, I appreciate the work you are putting into the 1-wire routines, especially the search function!
seems problematic.
Unfortunately I deleted the old version before I tryed the new one.
Tachyon V2.3.spin works, so now I have to start all over again.