thanks great
I see that I fire up my spinneret later with this version and try my webserver extensions/mods on top of it.
Maybe it works again ;-)
It would be great to pickup on where we left off with ajax and the js gauges example I ported to Tachyon, hope the issue is resolved in this build. Would be great, let me know if you need the js gauges source or anything else. The gauge project has gone dark, there was an attempt to rewrite the framework but is not active. Here is a very light weight gauge "library" I'm gonna explore with EasyNet.
I'm appreciating your help Peter and D.P.
It seems that building Tachyon for the different platforms is always a manual and sometimes time consuming work. On Linux we could implement a makefile based build process for the different platforms. Not very difficult and maybe time saving. This would also have the potential for a regression test and further automation maybe test automation.
My documentation efforts are also Linux and command line based and automatable. I could contribute in this direction.
I'm appreciating your help Peter and D.P.
It seems that building Tachyon for the different platforms is always a manual and sometimes time consuming work. On Linux we could implement a makefile based build process for the different platforms. Not very difficult and maybe time saving. This would also have the potential for a regression test and further automation maybe test automation.
My documentation efforts are also Linux and command line based and automatable. I could contribute in this direction.
/usr/local/bin/bstc.linux -p 2 ./20160514/Tachyon V2.8.spin
/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/EXTEND.FTH > /dev/ttyUSB1'
/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/SPINNERET.H > /dev/ttyUSB1'
/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/SDCARD.FTH > /dev/ttyUSB1'
/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/EASYFILE.FTH > /dev/ttyUSB1'
echo "COMPACT" > /dev/ttyUSB1
echo "BACKUP" > /dev/ttyUSB1
/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/W5100.FTH > /dev/ttyUSB1'
/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/EASYNET.FTH > /dev/ttyUSB1'
After executing the Makefile it didn't create a fix and ready spinneret. That's not like I imagine :-(
but i think there is potential! During writing the Makefile i wasn't able to manually download the files from DropBox - i was too fast. I already thought about putting some wget rules in the Makefile to automate getting the files. I tell you there is potential to save developers time which could better be invested into tachyon applications.
One thing that would have to be done is that tachyon answers with a result value which can be parsed and - in case of an error - breaks the make process.
Before going to bed I wanted to see the green Tachyon shine on black minicom and so I downloaded Peters SPINNERET-V2.binary and wanted to write it to my spinneret device. That failed also - grr.
/usr/local/bin/bstl.linux -p 2 ~/tachyon/20160517/SPINNERET-V2.8.binary
Brads SpinTool Loader v0.05 - Copyright 2008,2009 All rights reserved
Compiled for i386 Linux at 09:34:58 on 2009/07/03
Found a USB Serial Device
Binary Checksum Invalid!
I built the md5sum to compare with anybody out there:
So far so good on my AutoHelm project; Tachyon is smoothly reading data over the I2C, applying corrections, everything looks good. It is about 10x faster than spin, despite my awful Forth style.
I would like to put the I2C collection routines in a free-running cog to free up the main cog for watching the serial port etc. So far the codes do not seem to be updating the global data structures; I have the collection routine is a simple endless loop
: SAMPLE IMU_START BEGIN GetMag xyzDROP 10 ms AGAIN ; ok
' SAMPLE 6 RUN ok
The globals seem to see action once, but the values are then constant (and meaningless too).
Is there a trick to running I2C in a separate cog? Does the fact that I started I2C in the main cog (before the background cog was launched) cause problems?
Cheers!
: SAMPLE IMU_START BEGIN GetMag xyzDROP 10 ms AGAIN ; ok
' SAMPLE 6 RUN ok
The globals seem to see action once, but the values are then constant (and meaningless too).
Is there a trick to running I2C in a separate cog? Does the fact that I started I2C in the main cog (before the background cog was launched) cause problems?
Cheers!
Not a problem with I2C I would think but because a Tachyon cog only holds the top four items of the data stack you need to perhaps give it its own stack like this:
8 LONGS mystk
Then at the start of SAMPLE just:
mystk SP!
The 4 + 8 are more than adequate for practically any task as they only hold data.
@proplem, one problem with your Makefile might be that you aren't configuring your serial port. Not only are you not setting your baud, but you aren't disabling the hangup signal (HUPCL), which means your Propeller will get reset after every cat command terminates (not something you want!).
You might try something like this before doing any cat's. It sets the baud to 115200, disables hangup signal (i.e. don't reset the prop after every cat command), and hopefully adds some sort of delay after every line. I couldn't find any sort of documentation on how long the delay actually is - all I could find was that 0 was the shortest and 3 the longest.
Not a problem with I2C I would think but because a Tachyon cog only holds the top four items of the data stack you need to perhaps give it its own stack like this:
8 LONGS mystk
Then at the start of SAMPLE just:
mystk SP!
The 4 + 8 are more than adequate for practically any task as they only hold data.
Before going to bed I wanted to see the green Tachyon shine on black minicom and so I downloaded Peters SPINNERET-V2.binary and wanted to write it to my spinneret device. That failed also - grr.
/usr/local/bin/bstl.linux -p 2 ~/tachyon/20160517/SPINNERET-V2.8.binary
Brads SpinTool Loader v0.05 - Copyright 2008,2009 All rights reserved
Compiled for i386 Linux at 09:34:58 on 2009/07/03
Found a USB Serial Device
Binary Checksum Invalid!
I built the md5sum to compare with anybody out there:
Before going to bed I wanted to see the green Tachyon shine on black minicom and so I downloaded Peters SPINNERET-V2.binary and wanted to write it to my spinneret device. That failed also - grr.
/usr/local/bin/bstl.linux -p 2 ~/tachyon/20160517/SPINNERET-V2.8.binary
Brads SpinTool Loader v0.05 - Copyright 2008,2009 All rights reserved
Compiled for i386 Linux at 09:34:58 on 2009/07/03
Found a USB Serial Device
Binary Checksum Invalid!
I built the md5sum to compare with anybody out there:
Found the problem with the Spinneret binaries as for some reason things must have changed somewhere so that the Spin tool thought I had truncated the binary file as this is made from the hex file which spanned 0 to $7F00, so I changed that to $7FE0 and now it is happy. I use the top 16 bytes for the hex dump buffer btw.
This time I tested loading the binary and it works but I moved them all into its own SPINNERET folder in binaries plus I added a README which also mentions how you can load the 64k image via the microSD card.
: SAMPLE IMU_START BEGIN GetMag xyzDROP 10 ms AGAIN ; ok
' SAMPLE 6 RUN ok
The globals seem to see action once, but the values are then constant (and meaningless too).
Is there a trick to running I2C in a separate cog? Does the fact that I started I2C in the main cog (before the background cog was launched) cause problems?
Cheers!
Not a problem with I2C I would think but because a Tachyon cog only holds the top four items of the data stack you need to perhaps give it its own stack like this:
8 LONGS mystk
Then at the start of SAMPLE just:
mystk SP!
The 4 + 8 are more than adequate for practically any task as they only hold data.
That was the ticket Peter, thank you ! And the key is 'at the start of SAMPLE' !
It just occurred to me that if I am using the same I2C pins for the sensors as the EEPROM, I am bound to have trouble when I stick the dictionary up into the EEPROM space to save RAM... is this correct ? Is the fix just to use two other pins for the sensor bus and a pair of resistors?
I would like to create a cog-specific block of memory to avoid memory collisions, and I think storing the address in a COG register would be the cleanest approach. Are the 12 byte of the index=0 'general purpose' register available for my use? Are there any other cog-localized addresses available for users to work with ?
That was the ticket Peter, thank you ! And the key is 'at the start of SAMPLE' !
It just occurred to me that if I am using the same I2C pins for the sensors as the EEPROM, I am bound to have trouble when I stick the dictionary up into the EEPROM space to save RAM... is this correct ? Is the fix just to use two other pins for the sensor bus and a pair of resistors?
Cheers!
Say you have your sensor I2C bus on sck pin 15 and data on 16
When you want to read this bus:
16 15 I2CPINS --- set pins to my bus
--- my i2c routine here
EEPROM --- sets i2c pins back to eeprom
That was the ticket Peter, thank you ! And the key is 'at the start of SAMPLE' !
It just occurred to me that if I am using the same I2C pins for the sensors as the EEPROM, I am bound to have trouble when I stick the dictionary up into the EEPROM space to save RAM... is this correct ? Is the fix just to use two other pins for the sensor bus and a pair of resistors?
Cheers!
Say you have your sensor I2C bus on sck pin 15 and data on 16
When you want to read this bus:
16 15 I2CPINS --- set pins to my bus
--- my i2c routine here
EEPROM --- sets i2c pins back to eeprom
Hi D.P
Will this avoid conflict between 2 cogs, one that may be processing incoming code over the serial line (and uses the EEPROM to get to the Dictionary) and the other that is working with the sensor ?
As soon as one cog calls I2CSTART as part of any I2C transfer the routine will check to see if the bus is busy and if not it will set a busy flag and proceed. This means while it is proceeding that if another cog also tries to access the same bus it will cycle in I2CSTART until the bus is released by an I2CSTOP from the other cog.
However you can also use 2 other pins if you like as mentioned using I2CPINS and if that cog doesn't need to access the EEPROM then it doesn't need to switch back either nor is it strictly necessary. Normally if we do set up pins we also define them just as EEPROM is defined:
pub SENSORS 16 15 I2CPINS ;
I think though that sharing the pins will not prove to be any kind of problem really although when the dictionary in eeprom is being "searched" it basically reads in a block of up to 384 bytes if it can't find the word in the ram dictionary or in the cache. So that might be up to 4ms or so that the bus might be busy for although you will find that it is much less than this normally.
The cleverness of this system never ceases to amaze me. Thanks Peter! I realized this morning that a lockout had to be preventing collisions or else two cogs could never be independent after stuffing the eprom. Thank you!
As soon as one cog calls I2CSTART as part of any I2C transfer the routine will check to see if the bus is busy and if not it will set a busy flag and proceed. This means while it is proceeding that if another cog also tries to access the same bus it will cycle in I2CSTART until the bus is released by an I2CSTOP from the other cog.
I would like a cog to allocate a block of memory that will be directly accessed by the cog using an address. Several cogs, but not all, may have such buffers, so I don't want to waste RAM with 8 static buffers, and I don't need them to be named.
ORG and DS+ seem to be the right tools, but how do I find a safe place to point _org at with the ORG word before DS+ ? Several examples use BUFFERS ORG, but is this always safe?
The usual way to allocate a block of memory is simply:
256 BYTES mybuffer
or
64 LONGS mybuf
But if you want different variables all together in one contiguous block of memory without any opcodes between then it is best to allocate the memory as shown previously and then use that as the ORG like this:
mybuffer ORG
after which you can allocate storage with in byte units with DS
16 DS inbuf
16 DS outbuf
4 DS wrptr
etc
The BUFFERS area is the 2k byte area that is freed up from the Tachyon cog image and this area is used for up to 4 SD card files or they can be mixed or just used for anything else.
EDIT: a tad more info on how LONG/WORD/BYTE create data areas:
When a variable is defined it compiles an opcode in code space immediately followed by the data. This means that if you define a list of bytes for instance:
BYTE a,b,c,d
That the four variables will follow one another but each is preceded with the opcode for a variable which simply returns with the address of the next memory location. So if v1 returns with $4A71 then v2 would be $4A73 since it must be preceded with an opcode
BYTE v1,v2,v3,v4 ok
' v1 10 DUMP
0000_4A70: 81 00 81 00 81 00 81 00 72 4A 70 73 0A C1 B0 0C ........rJps.... ok
v1 .WORD 4A71 ok
v2 .WORD 4A73 ok
This means you can't clear all variables with a single 4 byte erase but if you use ORG and DS you can have the variables contiguous as the defined variable is now simply an address constant pointing to the data location:
4 BYTES mybuf ok
mybuf ORG ok
1 DS v1 ok
1 DS v2 ok
1 DS v3 ok
1 DS v4 ok
mybuf 10 DUMP
0000_4A74: 00 00 00 00 0C 0C 0C 7F 74 4A 00 00 0C 0C 0C 7F ........tJ...... ok
v1 .WORD 4A74 ok
v2 .WORD 4A75 ok
v3 .WORD 4A76 ok
v4 .WORD 4A77 ok
Be aware too that WORD is word aligned and LONG and DOUBLE are long aligned so the opcode precedes the data location and sometimes that is a little wasteful (for Tachyon) as some code locations will have to be skipped to place the opcode before the aligned location:
LONG v1,v2,v3,v4 ok
' v1 QD
0000_4A73: 81 00 00 00 00 0C BF B2 81 00 00 00 00 0C A2 C0 ................
0000_4A83: 81 00 00 00 00 0C 73 5A 81 00 00 00 00 72 4A 73 ......sZ.....rJs ok
v1 .WORD 4A74 ok
v2 .WORD 4A7C ok
v3 .WORD 4A84 ok
v4 .WORD 4A8C ok
Thanks Peter. I was hoping to have a way to do this without invoking namespaces, since each cog could need its own block. But perhaps the best way is to accept a bit of waster space in names, and have a CASE structure switched on COGID to create buffers as needed.
BTW this is to provide cog-specific space for a local variables extension.
Each cog can have it's own task "registers" as the default Tachyon cog has this register space from $0024 to $0124 which is pointed to by COGREG 7. So 7 COGREG@ = $0024 and you can change this in each Tachyon cog to point to an independent area. Some of these may be used by the system especially in the first 32 bytes but only the console task cog needs all the word and number buffers and even then there are still 32 bytes free at the end of the 256 bytes that are reserved.
Now these are regular variables but they use the REG word to index into this area so 0 REG returns $0024 in the main Tachyon console task. You can have more than 256 bytes if needed for the other cogs. To simulate a variable that has the same name and code but can have its own memory for each cog, try this:
: v1 $20 REG ;
: v2 $24 REG ;
: v3 $28 REG ;
Now that's not pretty but it will work and in the meantime I will think about how we can define them in a simpler manner.
Here's the register section for the Tachyon console.
0024(0003) 00 00 00 00 | registers long 0[64] 'Variables used by kernel + general-purpose
0124(0043) | org 0
0124(0000) | temp res 12 ' general purpose
0124(000C) | cntr res 4 ' hold CNT or temp
0124(0010) | uemit res 2 ' emit vector ? 0 = default
0124(0012) | ukey res 2 ' key vector
0124(0014) | keypoll res 2 ' poll user routines - low priority background task
0124(0016) | base res 2 ' current number base + backup location during overrides
0124(0018) | baudcnt res 4 ' SERIN SEROUT baud cnt value where baud = clkfreq/baudcnt ? each cog can have it's own
0124(001C) | uswitch res 4 ' target parameter used in CASE structures
0124(0020) | flags res 2 ' echo,linenums,ipmode,leadspaces,prset,striplf,sign,comp,defining
0124(0022) | keycol res 1 ' maintains column position of key input
0124(0023) | wordcnt res 1 ' length of current word (which is still null terminated)
0124(0024) | wordbuf res wordsz ' words from the input stream are assembled here
0124(004B) | numpad res numpadsz ' Number print format routines assemble digit characters here ? builds from end - 18,446,744,073,709,551,615
0124(0065) | padwr res 1 ' write index (builds characters down from lsb to msb in MODULO style)
0124(0066) | unum res 2 ' User number processing routine - executed if number failed and UNUM <> 0
0124(0068) | anumber res 4 ' Assembled number from input
0124(006C) | bnumber res 4
0124(0070) | digits res 1 ' number of digits in current number that has just been processed
0124(0071) | dpl res 1 ' Position of the decimal point if encountered (else zero)
0124(0072) | ufind res 2 ' runs extended dictionary search if set after failing precompiled dictionary search
0124(0074) | createvec res 2 ' If set will execute user create routines rather than the kernel's
0124(0076) | rxptr res 2 ' Pointer to the terminal receive buffer - read & write index precedes
0124(0078) | rxsz res 2 ' normally set to 256 bytes but increased during block load
0124(007A) | corenames res 2 ' points to core kernel names for optimizing search sequence
0124(007C) | oldnames res 2 ' backup of names used at start of TACHYON load
0124(007E) | names res 2 ' start of dictionary (builds down)
0124(0080) | prevname res 2 ' temp location used by CREATE
0124(0082) | fromhere res 2 ' Used by TACHYON word to backup current ?here? to determine code size at end of load
0124(0084) | here res 2 ' pointer to compilation area (overwrites VM image)
0124(0086) | codes res 2 ' current code compilation pointer (updates "here" or is reset by it)
0124(0088) | cold res 2 ' pattern to detect if this is a cold or warm start ($A55A )
0124(008A) | autovec res 2 ' user autostart address if non-zero - called from within terminal
0124(008C) | errors res 2
0124(008E) | linenum res 2
0124(0090) | delim res 2 ' the delimiter used in text input and a save location
0124(0092) | prompt res 2 ' pointer to code to execute when Forth prompts for a new line
0124(0094) | accept res 2 ' pointer to code to execute when Forth accepts a line to interpret (0=ok)
0124(0096) | prevch res 2 ' used to detect LF only sequences vs CRLF to perform auto CR
0124(0098) | lastkey res 1 ' written to directly from serialrx
0124(0099) | keychar res 1 ' override for key character
0124(009A) | spincnt res 1 ' Used by spinner to rotate busy symbol
0124(009B) | prefix res 1 ' NUMBER input prefix
0124(009C) | suffix res 1 ' NUMBER input suffix
0124(009D) | res 3
0124(00A0) | tasks res tasksz*8 ' (must be long aligned)
0124(00E0) | endreg res 0
What works now is an an array of 8 LONGS with each element being the address of the smaller local stack memory. Each cog uses its COGID to find its own buffer ... I had planned on using the temp REG space at 0-11 to point to the cog-specific buffer, but I found several routines (SAN, hypothenus...) that use it as scratch memory, so I went to the array of LONGs pointers in main RAM.
The ugliness now is that I allocate a buffer for each cog, regardless if it needs it or not. I will try to create it on first call to reserve some local space using a CASE statement that SWITCHes on COGID.
The indirection makes it slower than EXTEND.fth's locals, but I need the cog-independence. It makes equations, matrix manipulations much easier to write and read. Plus it can read/write intermediate values at any time.
What works now is an an array of 8 LONGS with each element being the address of the smaller local stack memory. Each cog uses its COGID to find its own buffer ... I had planned on using the temp REG space at 0-11 to point to the cog-specific buffer, but I found several routines (SAN, hypothenus...) that use it as scratch memory, so I went to the array of LONGs pointers in main RAM.
The ugliness now is that I allocate a buffer for each cog, regardless if it needs it or not. I will try to create it on first call to reserve some local space using a CASE statement that SWITCHes on COGID.
The indirection makes it slower than EXTEND.fth's locals, but I need the cog-independence. It makes equations, matrix manipulations much easier to write and read. Plus it can read/write intermediate values at any time.
This is my Locals Tachyon code. It simplifies code and coding that involves too much stack manipulations for my skill set.
It uses a single static buffer for all cogs' local stacks, and a short array that contains the addresses of each cog's stack inside the buffer; these could be merged to same som namespace memory. As written the local-based codes are ~5x slower than my stack-based code. Don't look for any one-line-wonders here. I think a factor of 2 could be gained if each cog kept a register pointer to it's local stack in the buffer, because it would remove one level of indirection. The other difference with respect to the locals in EXTEND.fth is that these can be read/written any time, making them good for intermediate results of calculations. Dynamic allocation by cogs that need the stack would be cool too.
This works for me now with cogs doing background tasks reading sensors and processing results, including trig functions, polynomials, and matrix math.
Free for anyone's use and comments; please keep original attribution in place Code size could be cut down by 50% by commenting out test/debugging words.
I'm having a firefighter model car with a damaged control unit that i want to replace with a Tachyon powered propeller solution.
There are motors for driving forward and backward, ladder up und down, ladder in and out, steer left and steer right, lights on off a loudspeaker etc - i know: everybody in this forum would be jealous for this funny project :-)))
I have 5 L293D integrated circuits mounted on a PPDB running tachyon.
: FW.FWD #P26 HIGH #P25 LOW #P27 HIGH ; \ move forward
: FW.BWD #P25 HIGH #P26 LOW #P27 HIGH ; \ move backward
: FW.STP #P27 LOW ; \ stop motion
Programming this way (every pin hardcoded) is not the right practice.
There is a lot of source code for different ic drivers in Peter's dropbox but i didn't see any source/forth code example where one ic is used more than once in an application - maybe I have overeseen - any advice where i could find and study a similar example (one object many instances) in forth?
...
I have 5 L293D integrated circuits mounted on a PPDB running tachyon.
: FW.FWD #P26 HIGH #P25 LOW #P27 HIGH ; \ move forward
: FW.BWD #P25 HIGH #P26 LOW #P27 HIGH ; \ move backward
: FW.STP #P27 LOW ; \ stop motion
Programming this way (every pin hardcoded) is not the right practice.
There is a lot of source code for different ic drivers in Peter's dropbox but i didn't see any source/forth code example where one ic is used more than once in an application - maybe I have overeseen - any advice where i could find and study a similar example (one object many instances) in forth?
Thanks, Heiko
sounds like a great fun project ...
have a look at the 'Introduction ...' there Peter shows how to deal with multiple counters.
Okay, here's the code we are going to use: (Note, a more complete version of this is incorporated into EXTEND.fth)
VARIABLE ctr
: CTR ( -- addr ) CTRA ctr C@ + ;
: CTR! ( val -- ) CTR COG! ;
: CTR@ ( -- val ) CTR COG@ ;
: A 0 ctr C! ;
: B 1 ctr C! ;
: CTRMODE ( n -- ) #26 SHL CTR@ $1F #26 SHL ANDN OR CTR! ;
: PLLDIV ( n -- ) #23 SHL CTR@ 7 #23 SHL ANDN OR CTR! ;
: APIN ( pin -- ) DUP MASK OUTPUTS CTR@ $1F ANDN OR CTR! ;
: BPIN ( pin -- ) DUP MASK OUTPUTS 9 SHL CTR@ $1F 9 SHL ANDN OR CTR! ;
: FRQ ( n -- ) FRQA ctr C@ + COG! ;
: NCO %00100 CTRMODE ;
: DUTY %00110 CTRMODE ;
So I've left out all the distracting comments, the names of the words should speak for themselves especially if you are familiar with the Propeller manual. For instance CTRMODE just needs a mode value and it will worry about setting the correct bits etc. Likewise APIN will make sure that the pin is an output and set the correct bits of the CTR. The idea is that we can set up a counter and then change things on the fly, even in interactive loops while we observe what is happening. My observation involves both an audio transducer and an oscilloscope. To select CTRA I just type A which does not need to be typed in again unless I change to B. To produce a tone on pin 19 use the NCO mode so type:
A 4 CTRMODE #100,000 FRQ #19 APIN
To produce a beating tone I use CTRB and set it up in similar fashion except for a slightly different frequency:
B 4 CTRMODE #100,100 FRQ #19 APIN
Now it's no longer a pure tone, we can hear the beat. Going one step further to make the beat vary we can type in a one-liner loop:
BEGIN #90,000 #20,000 ADO I FRQ LOOP KEY? AND UNTIL
This sounds really scary, even though I know what's happening. Hitting any key will exit the loop but the counters are still running so just type:
OFF A CTR! OFF B CTR!
This does nothing more than clear the counters and in fact there is a word called MUTE that does this. To do this easily next time we can enter what we just did into a new word along with the predefined words in EXTEND.fth:
: UFO
A #100,000 FRQ #19 APIN
B #100,100 FRQ #19 APIN
BEGIN #90,000 #20,000 ADO I FRQ LOOP KEY? AND UNTIL
A MUTE B MUTE
;
Anytime you type in UFO you can spook out some unsuspecting person, especially if you have this amp'd!
Here's a quick routine to “see” the beat frequency using an LED, give it a study
: PULSELED ( ledpin -- )
DUP \ duplicate the ledpin, now we have two copies of ledpin on the stack
A APIN \ select ctra and assign ledpin to APIN, APIN word just consumed one copy of ledpin off stack right?
#1000 HZ \ start ctra in NCO mode at 1000 hz, see the EXTEND.fth source for HZ definition
B APIN \ select ctrb assign ledpin to APIN, note both items we had on the stack are now gone
#1001 HZ \ start ctrb at 1001 hz
;
You turn the counters off as before with A MUTE B MUTE
you could do s.th. similar defining your motors as M1 .. Mx and then just M1 50 FWD , M3 0 BWD ...
Sounds like fun and if anything goes wrong and starts to smoke.....
There's probably nothing really wrong with setting highs and lows as you have done as it's straight to the point and gets the job done. The only thing I tend to do with names is keep them simple so that I can type them in easily in interactive mode and especially if I'm using a virtual keyboard on a phone or tablet. Try FORWARD BACK HALT GO etc and as MJB mentioned use a channel selector much like we select the console output to go to VGA for instance VGA PRINT" HELLO WORLD" CR CON. You can then name the motors according to function rather than just motor numbers.
Example:
DRIVE FORWARD LADDER FORWARD 500 ms HALT TURRET LEFT 200 ms HALT
where LEFT is an alias for FORWARD etc
Not sure what you mean though about using more than one IC in an application because I know that isn't so at all
I'm having a firefighter model car with a damaged control unit that i want to replace with a Tachyon powered propeller solution.
There are motors for driving forward and backward, ladder up und down, ladder in and out, steer left and steer right, lights on off a loudspeaker etc - i know: everybody in this forum would be jealous for this funny project :-)))
I have 5 L293D integrated circuits mounted on a PPDB running tachyon.
: FW.FWD #P26 HIGH #P25 LOW #P27 HIGH ; \ move forward
: FW.BWD #P25 HIGH #P26 LOW #P27 HIGH ; \ move backward
: FW.STP #P27 LOW ; \ stop motion
Programming this way (every pin hardcoded) is not the right practice.
There is a lot of source code for different ic drivers in Peter's dropbox but i didn't see any source/forth code example where one ic is used more than once in an application - maybe I have overeseen - any advice where i could find and study a similar example (one object many instances) in forth?
Yes! Thanks for your help MJB and Peter! You understood exactly what i wanted. This channel selector thing. How is this done? A global variable or is there more functionality?
Learning Forth is like being an adult person fallen back to the abilities of a baby. But code lines like this
DRIVE FORWARD LADDER FORWARD 500 ms HALT TURRET LEFT 200 ms HALT
No magic here, just set a variable which is then used by all the action words such as FORWARD and BACK etc. A bit like this (guessing):
BYTE chan
: DRIVE 0 chan C! ;
: LADDER 1 chan C! ;
: TURRET 2 chan C! ;
: CRANE 3 chan C! ;
: PUMP 4 chan C! ;
: FORWARD
chan C@ SWITCH
0 CASE #P26 HIGH #P25 LOW GO BREAK
1 CASE #P24 HIGH #P23 LOW GO BREAK
2 CASE #P22 HIGH #P21 LOW GO BREAK
3 CASE #P20 HIGH #P19 LOW GO BREAK
4 CASE #P18 HIGH #P17 LOW GO BREAK
;
But that is just guessing to give you an idea but it could be much much simpler than that too. The idea though is to make the words combine like an a natural language so that they make sense as in DRIVE FORWARD or TURRET LEFT which could just as well have passed the channel as a number on the stack but the variable means you don't have to keep repeating yourself as in DRIVE FORWARD 3 seconds DRIVE HALT 500 ms DRIVE BACK 3 seconds DRIVE HALT.
With the variable though you can just say DRIVE FORWARD 3 seconds HALT 500 ms BACK 3 seconds HALT
BTW, if a match is found in the case statement it will execute up to BREAK and then EXIT leaving the routine. The only time code gets executed after the last break is when there are no matches.
Yes! Thanks for your help MJB and Peter! You understood exactly what i wanted. This channel selector thing. How is this done? A global variable or is there more functionality?
Learning Forth is like being an adult person fallen back to the abilities of a baby. But code lines like this
DRIVE FORWARD LADDER FORWARD 500 ms HALT TURRET LEFT 200 ms HALT
Comments
It would be great to pickup on where we left off with ajax and the js gauges example I ported to Tachyon, hope the issue is resolved in this build. Would be great, let me know if you need the js gauges source or anything else. The gauge project has gone dark, there was an attempt to rewrite the framework but is not active. Here is a very light weight gauge "library" I'm gonna explore with EasyNet.
It seems that building Tachyon for the different platforms is always a manual and sometimes time consuming work. On Linux we could implement a makefile based build process for the different platforms. Not very difficult and maybe time saving. This would also have the potential for a regression test and further automation maybe test automation.
My documentation efforts are also Linux and command line based and automatable. I could contribute in this direction.
Any interest?
... hacking Makefile ...
now typing
would result in
but i think there is potential! During writing the Makefile i wasn't able to manually download the files from DropBox - i was too fast. I already thought about putting some wget rules in the Makefile to automate getting the files. I tell you there is potential to save developers time which could better be invested into tachyon applications.
One thing that would have to be done is that tachyon answers with a result value which can be parsed and - in case of an error - breaks the make process.
Still the question: any interest in this?
I built the md5sum to compare with anybody out there: Or maybe the bst loader is a little old and i have to change the tool - any advice?
I would like to put the I2C collection routines in a free-running cog to free up the main cog for watching the serial port etc. So far the codes do not seem to be updating the global data structures; I have the collection routine is a simple endless loop
The globals seem to see action once, but the values are then constant (and meaningless too).
Is there a trick to running I2C in a separate cog? Does the fact that I started I2C in the main cog (before the background cog was launched) cause problems?
Cheers!
Not a problem with I2C I would think but because a Tachyon cog only holds the top four items of the data stack you need to perhaps give it its own stack like this:
8 LONGS mystk
Then at the start of SAMPLE just:
mystk SP!
The 4 + 8 are more than adequate for practically any task as they only hold data.
You might try something like this before doing any cat's. It sets the baud to 115200, disables hangup signal (i.e. don't reset the prop after every cat command), and hopefully adds some sort of delay after every line. I couldn't find any sort of documentation on how long the delay actually is - all I could find was that 0 was the shortest and 3 the longest.
I get 'invalid file' messages as well with PropTool and BST.
This time I tested loading the binary and it works but I moved them all into its own SPINNERET folder in binaries plus I added a README which also mentions how you can load the 64k image via the microSD card.
It just occurred to me that if I am using the same I2C pins for the sensors as the EEPROM, I am bound to have trouble when I stick the dictionary up into the EEPROM space to save RAM... is this correct ? Is the fix just to use two other pins for the sensor bus and a pair of resistors?
Cheers!
Say you have your sensor I2C bus on sck pin 15 and data on 16
When you want to read this bus:
Will this avoid conflict between 2 cogs, one that may be processing incoming code over the serial line (and uses the EEPROM to get to the Dictionary) and the other that is working with the sensor ?
However you can also use 2 other pins if you like as mentioned using I2CPINS and if that cog doesn't need to access the EEPROM then it doesn't need to switch back either nor is it strictly necessary. Normally if we do set up pins we also define them just as EEPROM is defined:
pub SENSORS 16 15 I2CPINS ;
I think though that sharing the pins will not prove to be any kind of problem really although when the dictionary in eeprom is being "searched" it basically reads in a block of up to 384 bytes if it can't find the word in the ram dictionary or in the cache. So that might be up to 4ms or so that the bus might be busy for although you will find that it is much less than this normally.
Another Gem for the Glossary.
ORG and DS+ seem to be the right tools, but how do I find a safe place to point _org at with the ORG word before DS+ ? Several examples use BUFFERS ORG, but is this always safe?
256 BYTES mybuffer
or
64 LONGS mybuf
But if you want different variables all together in one contiguous block of memory without any opcodes between then it is best to allocate the memory as shown previously and then use that as the ORG like this:
mybuffer ORG
after which you can allocate storage with in byte units with DS
16 DS inbuf
16 DS outbuf
4 DS wrptr
etc
The BUFFERS area is the 2k byte area that is freed up from the Tachyon cog image and this area is used for up to 4 SD card files or they can be mixed or just used for anything else.
EDIT: a tad more info on how LONG/WORD/BYTE create data areas:
When a variable is defined it compiles an opcode in code space immediately followed by the data. This means that if you define a list of bytes for instance: That the four variables will follow one another but each is preceded with the opcode for a variable which simply returns with the address of the next memory location. So if v1 returns with $4A71 then v2 would be $4A73 since it must be preceded with an opcode
This means you can't clear all variables with a single 4 byte erase but if you use ORG and DS you can have the variables contiguous as the defined variable is now simply an address constant pointing to the data location:
Be aware too that WORD is word aligned and LONG and DOUBLE are long aligned so the opcode precedes the data location and sometimes that is a little wasteful (for Tachyon) as some code locations will have to be skipped to place the opcode before the aligned location:
BTW this is to provide cog-specific space for a local variables extension.
Now these are regular variables but they use the REG word to index into this area so 0 REG returns $0024 in the main Tachyon console task. You can have more than 256 bytes if needed for the other cogs. To simulate a variable that has the same name and code but can have its own memory for each cog, try this:
Now that's not pretty but it will work and in the meantime I will think about how we can define them in a simpler manner.
Here's the register section for the Tachyon console.
The ugliness now is that I allocate a buffer for each cog, regardless if it needs it or not. I will try to create it on first call to reserve some local space using a CASE statement that SWITCHes on COGID.
The indirection makes it slower than EXTEND.fth's locals, but I need the cog-independence. It makes equations, matrix manipulations much easier to write and read. Plus it can read/write intermediate values at any time.
It uses a single static buffer for all cogs' local stacks, and a short array that contains the addresses of each cog's stack inside the buffer; these could be merged to same som namespace memory. As written the local-based codes are ~5x slower than my stack-based code. Don't look for any one-line-wonders here. I think a factor of 2 could be gained if each cog kept a register pointer to it's local stack in the buffer, because it would remove one level of indirection. The other difference with respect to the locals in EXTEND.fth is that these can be read/written any time, making them good for intermediate results of calculations. Dynamic allocation by cogs that need the stack would be cool too.
This works for me now with cogs doing background tasks reading sensors and processing results, including trig functions, polynomials, and matrix math.
Free for anyone's use and comments; please keep original attribution in place Code size could be cut down by 50% by commenting out test/debugging words.
There are motors for driving forward and backward, ladder up und down, ladder in and out, steer left and steer right, lights on off a loudspeaker etc - i know: everybody in this forum would be jealous for this funny project :-)))
I have 5 L293D integrated circuits mounted on a PPDB running tachyon.
Programming this way (every pin hardcoded) is not the right practice.
There is a lot of source code for different ic drivers in Peter's dropbox but i didn't see any source/forth code example where one ic is used more than once in an application - maybe I have overeseen - any advice where i could find and study a similar example (one object many instances) in forth?
Thanks, Heiko
sounds like a great fun project ...
have a look at the 'Introduction ...' there Peter shows how to deal with multiple counters. you could do s.th. similar defining your motors as M1 .. Mx and then just M1 50 FWD , M3 0 BWD ...
There's probably nothing really wrong with setting highs and lows as you have done as it's straight to the point and gets the job done. The only thing I tend to do with names is keep them simple so that I can type them in easily in interactive mode and especially if I'm using a virtual keyboard on a phone or tablet. Try FORWARD BACK HALT GO etc and as MJB mentioned use a channel selector much like we select the console output to go to VGA for instance VGA PRINT" HELLO WORLD" CR CON. You can then name the motors according to function rather than just motor numbers.
Example:
DRIVE FORWARD LADDER FORWARD 500 ms HALT TURRET LEFT 200 ms HALT
where LEFT is an alias for FORWARD etc
Not sure what you mean though about using more than one IC in an application because I know that isn't so at all
Learning Forth is like being an adult person fallen back to the abilities of a baby. But code lines like this
DRIVE FORWARD LADDER FORWARD 500 ms HALT TURRET LEFT 200 ms HALT
are worth learning hard:-)
Thanks again and again
But that is just guessing to give you an idea but it could be much much simpler than that too. The idea though is to make the words combine like an a natural language so that they make sense as in DRIVE FORWARD or TURRET LEFT which could just as well have passed the channel as a number on the stack but the variable means you don't have to keep repeating yourself as in DRIVE FORWARD 3 seconds DRIVE HALT 500 ms DRIVE BACK 3 seconds DRIVE HALT.
With the variable though you can just say DRIVE FORWARD 3 seconds HALT 500 ms BACK 3 seconds HALT
BTW, if a match is found in the case statement it will execute up to BREAK and then EXIT leaving the routine. The only time code gets executed after the last break is when there are no matches.