Hi Peter,
I got the WHEELCNT words working. After installing as a task it does not work.
LONG COUNTER \ hold the wheel count
[
pub WHEELCNT ( --- )
1 MASK 4 COG! --- setup for WAITCNT
A 1 APIN
1 FRQ
12 CTRMODE --- POSEDGE mode
0 COUNTER ! --- Zero counter
1 FLOAT
BEGIN
--- CLKFREQ 400000 / DELTA WAITCNT
WAITHI WAITLO
COUNTER ++
COUNTER @ DUP 56 = IF
0 COUNTER ! THEN . CR --- set pulse number here
AGAIN ;
Ken, the main problem I see is that you do a ". CR" in your WHEELCNT which will have an I/O conflict with the serial I/O in the main console cog. Make sure you remove that diagnostic code from within the loop.
btw - don't forget to enclose any code snippets you paste within the code tags (big C in the menu). You can always edit your post via the settings cog in the top right hand corner rather than reposting it again. Those square brackets don't cut it
Your code also looks strange in that it is doing all this CTRMODE stuff but is only implementing a counter in software, nothing to do with the hardware counter.
Perhaps try this version:
long COUNTER \ hold the wheel count
pub WHEELCNT ( --- )
1 MASK 4 COG! --- setup input mask for WAITXX
COUNTER ~ --- Zero counter
BEGIN
WAITHI WAITLO
COUNTER ++
COUNTER @ 56 = IF COUNTER ~ THEN
AGAIN
;
' WHEELCNT TASK? RUN
pub DSP BEGIN <CR> COUNTER @ . 4 SPACES KEY UNTIL ;
Ken, the code tags are for the forum itself which removes multiple spaces and recognises keywords and tags to format what would otherwise be plain text. To get it to ignore all of that so that our pasted code looks just like it does in the editor we can select it after it is pasted and then click on the big C in the forum edit menu "B I U S C T" etc at the top of your post.. It's not WYSIWYG until you post it but you can preview it or edit it after it has been posted thankfully.
Sorry to bug you Peter, thanks for the patience and the info on the forum posting. I installed the WHEELCNT.TASK and ran the test code all is well. I loaded the PWM.TASK and it worked fine also.
Here's the problem, when I load WHEELCNT.TASK and the PWM.TASK and run the counter test code the counter will not update but the PWM.TASK still works fine. My setup is a dc motor with an
encoder coming to the counter task. I can ramp the motor speed but I can't see the pulses on the terminal or scope.
Is there a tutorial explaining the new FOR...NEXT procedure in depth? Or just some examples covering the use of FROM, BY, I+ etc?
There's a bit here in my Tachyon blog but basically FOR NEXT like it always did and if you don't specify anything different the only other advantage is that it maintains an incrementing index "I" that starts from 0, just like in a DO LOOP. If you want your index to start from elsewhere then use "n FROM" before entering and if you want the index to step by a value other than the default of 1, then specify a signed number "n BY".
This is an example from the blog.
.. CR 100 FROM 5 BY 10 FOR I . SPACE NEXT
100 105 110 115 120 125 130 135 140 145 ok
Having a single FOR NEXT and doing away with DO LOOP +LOOP ADO BOUND means I have more room in the kernel for more important things. The FROM and BY words are outside of the cog kernel. LEAVE also causes FOR NEXT to exit.
There are additional words but I don't actually use them:
BY! ( change the step within a loop)
FOR! ( change the loop count )
FOR@ ( get the loop count )
I'm an electronics engineer based in Christchurch, New Zealand. In my spare time I've designed and built a small data acquisition and control system (which I've called DAQiri), with a view to using it as the control system for a scanning tunnelling microscope. The heart of the DAQiri system is a Propeller V1. The Propeller lines are divided into 4 groups and brought out to card slots. I've documented the hardware here: https://hackaday.io/project/27911-daqiri-a-data-acquisition-and-control-platform
While trying to decide what language to use (Spin? PASM? PropGCC?) I discovered Tachyon FORTH. I think it's just what I'm looking for - compact and fast! Now I just need to learn it
I've loaded v4.7 into DAQiri, and wrote some code to drive a stepper motor (a 28BYJ-48 driven by a ULN2003, via a TCA9535 I2C expansion IC):
--- utility function to write a byte to an I2C chip register
pub IO! ( data reg chip -- )
<i2c i2c! i2c! i2c! i2c>
;
--- Set I2C bus pins for stepper card, initialise TCA9535 ports 0 & 1 to output, set all outputs low
pub motor_init ( -- )
7 6 i2cpins
$00 $02 $40 io!
$00 $03 $40 io!
$00 $06 $40 io!
$00 $07 $40 io!
;
--- set motor phase outputs on port 0 of TCA9535
pub motor_phase ( phase -- )
$02 $40 io!
;
--- Turn on activity LED for motor 1, run for <steps> steps, with <speed> ms between phase outputs
pub motor_run ( speed steps -- )
3 high
for
$02 motor_phase
DUP ms
$04 motor_phase
DUP ms
$08 motor_phase
DUP ms
$10 motor_phase
DUP ms
$00 motor_phase
next
3 low
DROP
;
The motor spins quite happily, which is encouraging
Anyway, I've rather late to the Tachyon party but keen to catch up. Fantastic work Peter!
I'm an electronics engineer based in Christchurch, New Zealand. In my spare time I've designed and built a small data acquisition and control system (which I've called DAQiri), with a view to using it as the control system for a scanning tunnelling microscope. The heart of the DAQiri system is a Propeller V1. The Propeller lines are divided into 4 groups and brought out to card slots. I've documented the hardware here: https://hackaday.io/project/27911-daqiri-a-data-acquisition-and-control-platform
While trying to decide what language to use (Spin? PASM? PropGCC?) I discovered Tachyon FORTH. I think it's just what I'm looking for - compact and fast! Now I just need to learn it
I've loaded v4.7 into DAQiri, and wrote some code to drive a stepper motor (a 28BYJ-48 driven by a ULN2003, via a TCA9535 I2C expansion IC):
Hi Andrew, welcome to the Parallax forum and in particular to the Tachyon threads Good to hear you considered more than one option and ended up trying Tachyon out and it works for you!
Forth encourages factoring code not just into smaller reusable functions but also if well structured and named, into an application specific language too. By using words like "STEPS" and "PACE" you can imagine that if you also defined constants named FAST, SLOW, MEDIUM you can end up talking to Tachyon like this:
MEDIUM PACE 100 STEPS
and since PACE "falls through" to motor_init you don't even have to specifically call that function either.
Without changing the code too much here's a way you can factor and use your code. BTW, Tachyon allows fall-through code in that the end of a previous definition can fall through to the following code if you want it too. But unless you need to write to another TCA9535 there is probably no need for TCA! or even motor_init names either.
BTW, V5.2 NEON is the latest version and is more compact too as well as other enhancements. It is also very easy to add a keypad and LCD and even an SD card for logging etc. There's a quick binary to try out at that link.
--- utility function to write a byte to an I2C chip register
pub IO! ( data reg -- ) $40
pub TCA! ( data reg dev -- ) <I2C I2C! I2C! I2C! I2C> ;
word pacems
--- set the pace but also make sure the I/O is initiialized
pub PACE ( ms -- ) pacems W!
--- Set I2C bus pins for stepper card, initialise TCA9535 ports 0 & 1 to output, set all outputs low
pub motor_init ( -- ) 7 6 I2CPINS 0 2 IO! 0 3 IO! 0 6 IO! 0 7 IO! ;
--- set motor phase outputs on port 0 of TCA9535 and delay for programmed speed
pub STEP ( phase --) 2 IO40! pacems W@ ms ;
--- Turn on activity LED for motor 1, run for <steps> steps, at set ms pace between phase outputs
pub STEPS ( steps -- ) 3 HIGH FOR $02 STEP $04 STEP $08 STEP $10 STEP NEXT 0 STEP 3 LOW ;
{ Example:
5 PACE 100 STEPS
Try defining FAST and SLOW and OPTIMAL as constants like this:
2 == FAST
5 == MEDIUM
20 == SLOW
}
Hi Peter, we are currently active using telnet and see a response time of 14 send-receive packets per second. Is this what we have to expect or should easynet be faster?
Hi Peter, we are currently active using telnet and see a response time of 14 send-receive packets per second. Is this what we have to expect or should easynet be faster?
But what size packets are they? The Telnet socket is checked for receive data whenever the Tachyon console is ready to accept new data but transmit will wait until a 1kB buffer is filled or on a 1/128 timeout. If is is sending 14 packets per second then this would be roughly equivalent to 140k baud transmission. I will check a unit tonight and gather some more information.
Hi Peter, thanks for coming back immediately. That should be the point, the packet length is only 16 bytes now.
We ran into another pit: we want to have a gateway routing serial i/o to telnet and vice versa. We load the uart into a cog and had the interface running, but after about 5 minutes the communication showed spikey data. We found that the pointers to the uart send buffer txwr1 and txrd1 are 16 bit wide and use all bits counting upward, only when checking the pointers, the relevant bits are masked to stay within the buffer length of 0-31. This is done in uart and tachyon. We changed the code to store the masked pointers and from that time on the spikes didn't appear again.
We didn't look to find the origine of this behavior, as the solution works and we are busy to finish the project. But I guess, that comparing the rd/wr pointer doesn't work for all 16 bits values, maybe 16-bit two's-complement is not perfect?
Will show the source code and changes soon.
Some more information on the telnet behavior: We receive 16 bytes of information in one block send from a windows application. These bytes are forwarded to the serial port (115kb) to a second propeller. This propeller returns an answer, also 16 bytes and we measured the response time to be 3.8 ms. That is: the frequency for repeated communication is about 200 Hz. The answer again is send to LAN. After Windows receives the answer, the next request is started. A full cycle last about 50ms, corresponding to 20 Hz. When the windows application talkes to a linux telnet app, 100 hz are measured, what exactly correponds to the cycle time of the windows app.
We found the time-out routine and increase the divider shift from 7 to 10 but that didn't change a lot. Reducing the timeout time further ripped the message into parts and data was lost.
So it looks like Tachyon telnet needs 40 ms for an receive and send operation?
If the autosend variable is set it will transmit immediately on a LF so this might be the answer perhaps? I may not have time today to check the timing though.
In ?TELNET disable this line:
--- let 1/128 timeout handle characters or blocks
autosend C~
The variable autosend is set by default at startup, only ?TELNET turns it off.
Hi Peter, I can not imagine that your code can be optimized to multiply speed. So no chance to solve our problem without changing the solution. I could increase buffer size to get the throughput I need, but I would still miss real time requirements. The same is true if I wait for P2 ;-) Could it be, that tcp or udp is much faster? Or is there a way to move easynet to a separate COG?
I will look at it today. First thing is to verify your findings, second to isolate and time the processes, thirdly I will think about the best way to speed it up.
OK, thanks Peter. I'm sorry I can not focus on Tachyon, as it is what I ever wanted, but step by step I get a better idea. Make a shortcut on my browser to have quick access to forth and so get some acquaintance.. whenever I normally use a calculator https://skilldrick.github.io/easyforth/
Hi Peter, here a log of what happened:
We use Tachyon Forth V4.5 DAWN 450170727.1400
UART code looks like this:
'
'
' Transmit
'
fdtx jmpret txcode,rxcode ' run a chunk of receive code, then return
rdword fdtxwr,fdtxwrP ' read hub txwr to check for data
cmp fdtxwr,fdtxrd wz ' data available if wr<>rd?
if_z jmp #fdtx
mov ut3,fdtxrd ' get raw index
and ut3,fdtxsz ' wrap read index only when accessing data
add ut3,txbuff ' read data from txbuf
rdbyte txdata,ut3 ' get data
or txdata,fdstops ' ready byte to transmit
add fdtxrd,#1 ' update local tx read
and fdtxrd, fdtxsz THIS WE ADDED 2018.07.31 na
wrword fdtxrd,fdtxrdP ' update hub txrd
shl txdata,#1 ' insert start bit
mov txbits,#fdbits+1+1 ' data+start+stops
test fdmode,#%110 wz ' any special modes?
if_nz jmp #fdtxm
mov txcnt,cnt
:bit shr txdata,#1 wc
muxc outa,fdtxmask
add txcnt,bitticks ' ready next cnt
:wait jmpret txcode,rxcode 'run a chunk of receive code, then return
mov ut1,txcnt 'check if bit transmit period done
sub ut1,cnt
cmps ut1,#0 wc
if_nc jmp #:wait
djnz txbits,#:bit 'another bit to transmit?
jmp #fdtx 'byte done, transmit next byte
fdtxm
The change limited the pointer into the buffer to the actual value.
The corresponding change in EMIT1:
pub EMIT1 txwr1 W@ 1+ BEGIN DUP txrd1 W@ <> UNTIL 1- uart1 14 + W@ 1- AND txbuf1 + C! txwr1 DUP W@ 1+ uart1 14 + W@ 1- AND SWAP W! ;
\ pub EMIT1 txwr1 W@ 1+ $1F AND BEGIN DUP txrd1 W@ $1F AND <> UNTIL 1- $1F AND txbuf1 + C! txwr1 W++ ;
For some unknown reason, we found two EMIT1 versions, the second with the hard coded buffer length was active. I can imagine, this was to eliminate the problem we found, but it was not fixed. So we uncommented the first method and Q&D calculated the pointer to a modulo value in correspondence with the kernel asm.
That fixed the problem of spurios false messages.
pub KEY1 rxrd1 W@ rxwr1 W@ <> IF rxrd1 W@ rxbuf1 + C@ rxrd1 W@ 1+ uart1 10 + W@ 1- AND rxrd1 W! ELSE 0 THEN ;
pub LKEY1 BEGIN KEY1 DUP WHILE EMIT REPEAT CR ;
we next defined the word LKEY1 (loopedKey1) to read the buffer completely in one chunk.
During discussing all possible reasons, why we have such low throughput the question came up, if LKEY1 might be slow due to task switching when calling KEY1.
Hope this helps in locating the problem and it shows a little how we try to think forth.
Yes, I've been looking at this a bit but I probably need to set it up the same way as you are using it if you can send me the details. Do you also have a copy of the PC software that I can try this with?
Comments
I got the WHEELCNT words working. After installing as a task it does not work.
LONG COUNTER \ hold the wheel count
[
pub WHEELCNT ( --- )
1 MASK 4 COG! --- setup for WAITCNT
A 1 APIN
1 FRQ
12 CTRMODE --- POSEDGE mode
0 COUNTER ! --- Zero counter
1 FLOAT
BEGIN
--- CLKFREQ 400000 / DELTA WAITCNT
WAITHI WAITLO
COUNTER ++
COUNTER @ DUP 56 = IF
0 COUNTER ! THEN . CR --- set pulse number here
AGAIN ;
' WHEELCNT TASK? RUN
: DSP BEGIN COUNTER @ . CR KEY UNTIL ;
]
btw - don't forget to enclose any code snippets you paste within the code tags (big C in the menu). You can always edit your post via the settings cog in the top right hand corner rather than reposting it again. Those square brackets don't cut it
Your code also looks strange in that it is doing all this CTRMODE stuff but is only implementing a counter in software, nothing to do with the hardware counter.
Perhaps try this version:
Ken
Here's the problem, when I load WHEELCNT.TASK and the PWM.TASK and run the counter test code the counter will not update but the PWM.TASK still works fine. My setup is a dc motor with an
encoder coming to the counter task. I can ramp the motor speed but I can't see the pulses on the terminal or scope.
Ken..
Thanks,
Ken
Ken
There's a bit here in my Tachyon blog but basically FOR NEXT like it always did and if you don't specify anything different the only other advantage is that it maintains an incrementing index "I" that starts from 0, just like in a DO LOOP. If you want your index to start from elsewhere then use "n FROM" before entering and if you want the index to step by a value other than the default of 1, then specify a signed number "n BY".
This is an example from the blog.
Having a single FOR NEXT and doing away with DO LOOP +LOOP ADO BOUND means I have more room in the kernel for more important things. The FROM and BY words are outside of the cog kernel. LEAVE also causes FOR NEXT to exit.
There are additional words but I don't actually use them:
BY! ( change the step within a loop)
FOR! ( change the loop count )
FOR@ ( get the loop count )
I'm an electronics engineer based in Christchurch, New Zealand. In my spare time I've designed and built a small data acquisition and control system (which I've called DAQiri), with a view to using it as the control system for a scanning tunnelling microscope. The heart of the DAQiri system is a Propeller V1. The Propeller lines are divided into 4 groups and brought out to card slots. I've documented the hardware here: https://hackaday.io/project/27911-daqiri-a-data-acquisition-and-control-platform
While trying to decide what language to use (Spin? PASM? PropGCC?) I discovered Tachyon FORTH. I think it's just what I'm looking for - compact and fast! Now I just need to learn it
I've loaded v4.7 into DAQiri, and wrote some code to drive a stepper motor (a 28BYJ-48 driven by a ULN2003, via a TCA9535 I2C expansion IC):
The motor spins quite happily, which is encouraging
Anyway, I've rather late to the Tachyon party but keen to catch up. Fantastic work Peter!
Andrew
But what size packets are they? The Telnet socket is checked for receive data whenever the Tachyon console is ready to accept new data but transmit will wait until a 1kB buffer is filled or on a 1/128 timeout. If is is sending 14 packets per second then this would be roughly equivalent to 140k baud transmission. I will check a unit tonight and gather some more information.
We ran into another pit: we want to have a gateway routing serial i/o to telnet and vice versa. We load the uart into a cog and had the interface running, but after about 5 minutes the communication showed spikey data. We found that the pointers to the uart send buffer txwr1 and txrd1 are 16 bit wide and use all bits counting upward, only when checking the pointers, the relevant bits are masked to stay within the buffer length of 0-31. This is done in uart and tachyon. We changed the code to store the masked pointers and from that time on the spikes didn't appear again.
We didn't look to find the origine of this behavior, as the solution works and we are busy to finish the project. But I guess, that comparing the rd/wr pointer doesn't work for all 16 bits values, maybe 16-bit two's-complement is not perfect?
Will show the source code and changes soon.
We found the time-out routine and increase the divider shift from 7 to 10 but that didn't change a lot. Reducing the timeout time further ripped the message into parts and data was lost.
So it looks like Tachyon telnet needs 40 ms for an receive and send operation?
In ?TELNET disable this line:
The variable autosend is set by default at startup, only ?TELNET turns it off.
I will look at it today. First thing is to verify your findings, second to isolate and time the processes, thirdly I will think about the best way to speed it up.
We use Tachyon Forth V4.5 DAWN 450170727.1400
UART code looks like this:
The change limited the pointer into the buffer to the actual value.
The corresponding change in EMIT1:
For some unknown reason, we found two EMIT1 versions, the second with the hard coded buffer length was active. I can imagine, this was to eliminate the problem we found, but it was not fixed. So we uncommented the first method and Q&D calculated the pointer to a modulo value in correspondence with the kernel asm.
That fixed the problem of spurios false messages.
we next defined the word LKEY1 (loopedKey1) to read the buffer completely in one chunk.
During discussing all possible reasons, why we have such low throughput the question came up, if LKEY1 might be slow due to task switching when calling KEY1.
Hope this helps in locating the problem and it shows a little how we try to think forth.