Shop OBEX P1 Docs P2 Docs Learn Events
TACHYON O/S V3.0 JUNO - Furiously Fast Forth, FAT32+LAN+VGA+RS485+OBEX ROMS+FP+LMM+++ - Page 84 — Parallax Forums

TACHYON O/S V3.0 JUNO - Furiously Fast Forth, FAT32+LAN+VGA+RS485+OBEX ROMS+FP+LMM+++

18182848687109

Comments

  • MJB wrote: »
    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.
  • proplemproplem Posts: 233
    edited 2016-05-17 19:55
    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.

    Any interest?

    ... hacking Makefile ...
    kernel=Tachyon V2.8.spin
    
    %.spin:
    	/usr/local/bin/bstc.linux -p 2 ./20160514/$@
    
    %.H %.FTH:
    	/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/$@ > /dev/ttyUSB1'
    
    spinneret: spinneret1 spinneret2 spinneret3 spinneret3 spinneret4
    
    spinneret4: W5100.FTH EASYNET.FTH
    
    spinneret3:
    	echo "COMPACT" > /dev/ttyUSB1
    	echo "BACKUP" > /dev/ttyUSB1
    
    spinneret2: EXTEND.FTH SPINNERET.H SDCARD.FTH EASYFILE.FTH EEWORDS.FTH
    
    spinneret1: Tachyon\ V2.8.spin
    
    

    now typing
    make spinneret
    

    would result in
    /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'
    

  • proplem wrote: »
    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.

    Any interest?

    ... hacking Makefile ...
    kernel=Tachyon V2.8.spin
    
    %.spin:
    	/usr/local/bin/bstc.linux -p 2 ./20160514/$@
    
    %.H %.FTH:
    	/usr/bin/time -f 'downloaded in %e seconds' -o /dev/stdout sh -c 'cat ./20160514/$@ > /dev/ttyUSB1'
    
    spinneret: spinneret1 spinneret2 spinneret3 spinneret3 spinneret4
    
    spinneret4: W5100.FTH EASYNET.FTH
    
    spinneret3:
    	echo "COMPACT" > /dev/ttyUSB1
    	echo "BACKUP" > /dev/ttyUSB1
    
    spinneret2: EXTEND.FTH SPINNERET.H SDCARD.FTH EASYFILE.FTH EEWORDS.FTH
    
    spinneret1: Tachyon\ V2.8.spin
    
    

    now typing
    make spinneret
    

    would result in
    /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.

    Still the question: any interest in this?
  • 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:
    ccf9720b0d12480e21daa540459d4284  20160517/SPINNERET-V2.8.binary
    
    Or maybe the bst loader is a little old and i have to change the tool - any advice?
  • 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.

  • ElectrodudeElectrodude Posts: 1,614
    edited 2016-05-18 04:56
    @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.
    stty -F /dev/ttyUSB1 115200 -hupcl nl3
    
  • 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.
    Thanks Peter! I will try that tonight.
  • MJBMJB Posts: 1,235
    edited 2016-05-18 22:32
    proplem wrote: »
    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:
    ccf9720b0d12480e21daa540459d4284  20160517/SPINNERET-V2.8.binary
    
    Or maybe the bst loader is a little old and i have to change the tool - any advice?
    proplem wrote: »
    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:
    ccf9720b0d12480e21daa540459d4284  20160517/SPINNERET-V2.8.binary
    
    Or maybe the bst loader is a little old and i have to change the tool - any advice?

    I get 'invalid file' messages as well with PropTool and BST.
  • 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?

    Cheers!
  • 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 
    
  • D.P wrote: »
    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.

    Another Gem for the Glossary.

  • 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?
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2016-05-22 06:56
    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.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2016-05-22 16:31
    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.
  • Ok, get it functional first then I will look at a suitable mechanism we can use to replace it.
    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.

  • PaulRowntreePaulRowntree Posts: 150
    edited 2016-05-24 11:27
    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.
  • ErNaErNa Posts: 1,738
    For those interested in computer architectures, thisanalog-eetimes.com/news/notes-real-time-computing-architectures-0 should be of interest. Page 5 you find some words concerning Forth.
  • 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?

    Thanks, Heiko
  • MJBMJB Posts: 1,235
    proplem wrote: »
    ...
    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 ...
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2016-05-24 12:47
    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 :)
    proplem wrote: »
    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?

    Thanks, Heiko


  • 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

    are worth learning hard:-)

    Thanks again and again
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2016-05-24 14:01
    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.
    proplem wrote: »
    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

    are worth learning hard:-)

    Thanks again and again

Sign In or Register to comment.