Is there any more example code for the COG timers? I have studied the wave playing example and sort of understand it (been wading through the Parallax docs), would be good to
have some other other examples though ... i.e pulse PWM, motor control, Freq/Duty measurement etc ... the timers are so powerful, I would like to get my head around them ...
Is there any more example code for the COG timers? I have studied the wave playing example and sort of understand it (been wading through the Parallax docs), would be good to
have some other other examples though ... i.e pulse PWM, motor control, Freq/Duty measurement etc ... the timers are so powerful, I would like to get my head around them ...
Cheers,
Bernie
There's the PWM code that's built in for 8 channels although it's a fairly easy matter to make it 32 channels so that you can choose arbitrary pins to suit. There's also the DAC function which could just as easily have a VOLTS function frontend to make it easier to set a voltage. So besides these and the frequency generation words that you can play with I think that it's easy enough to go to the next step of measuring etc. Have you had a look at the Introduction page? If you have something specific in mind I can work on that.
I actually have the W5200 code and FAT32 file + virtual memory available soon. It's all been dragging out as a WIP until I start feeling the whip itself after which I get the job finished. Let me know if there are specific chips that need interfacing such as the RTCs and Bluetooth etc.
There's the PWM code that's built in for 8 channels although it's a fairly easy matter to make it 32 channels so that you can choose arbitrary pins to suit. There's also the DAC function which could just as easily have a VOLTS function frontend to make it easier to set a voltage. So besides these and the frequency generation words that you can play with I think that it's easy enough to go to the next step of measuring etc. Have you had a look at the Introduction page? If you have something specific in mind I can work on that.
Hmmm, been looking at the PWM code ... very confused. Code is:
org _RUNMOD
_PWM mov deltaR,tos ' use supplied delta value from tosmov target,tos
add target,cntmov R1,#0
pwmlp mov X,REG0 ' read base address of tableadd X,R1 ' add in read indexrdbyte X,X
shl X,REG1 ' shift up to pwmpinsmovouta,X ' update outputsadd R1,#1and R1,#$FFwaitcnt target,deltaR
jmp #pwmlp
PWM byte _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,13,XOP,xLOADMOD,EXIT
It seems to me that your only using the cog timer for a delay right? all io is bit-bashed rather than using outa,outb?
Also, I don't see how the above loop ends ... and ther is no jump to next or drop at the end of the code ... where does it go to?
Seems I am missing a big chunk of information here ... also "org _RUNMOD" confuses me as it is used above each PASM code module, doesn't that mean they will all be assembled at the same place in memory?
My head hurts.....
EDIT: Why is the code I post all mashed up ... tried copy/pasting through different editors but still rubbish ..
Hmmm, been looking at the PWM code ... very confused. Code is:
org _RUNMOD
_PWM mov deltaR,tos ' use supplied delta value from tosmov target,tos
add target,cntmov R1,#0
pwmlp mov X,REG0 ' read base address of tableadd X,R1 ' add in read indexrdbyte X,X
shl X,REG1 ' shift up to pwmpinsmovouta,X ' update outputsadd R1,#1and R1,#$FFwaitcnt target,deltaR
jmp #pwmlp
PWM byte _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,13,XOP,xLOADMOD,EXIT
It seems to me that your only using the cog timer for a delay right? all io is bit-bashed rather than using outa,outb?
Also, I don't see how the above loop ends ... and ther is no jump to next or drop at the end of the code ... where does it go to?
Seems I am missing a big chunk of information here ... also "org _RUNMOD" confuses me as it is used above each PASM code module, doesn't that mean they will all be assembled at the same place in memory?
My head hurts.....
EDIT: Why is the code I post all mashed up ... tried copy/pasting through different editors but still rubbish ..
Bernie
COG memory is very limited and Tachyon squeezes the VM and stacks in there and there's no room really left over for specialized operations that really require PASM. That's where RUNMOD comes in as I sacrifice 16 to 24 longs for specialized modules which are compiled to run at that address but only one module can be loaded at a time. These specialized modules include SPI, I2C, SD, and PWM etc. The PWM module is designed to run in it's own cog as it's an endless loop where another cog/task can control the parameters. Of course the PWM cog doesn't need all the Tachyon VM in it after that but it's easy to load the module in the normal fashion.
So PWM doesn't use the counters, only WAITCNT but you mentioned PWM in your list which is different to duty-cycle modulation ( fixed pulse width, variable frequency).
As for your head hurting can I suggest a Pepperjack Cab Sav. If that doesn't work then increase the dose.
Getting an Asus TF300T tomorrow. Any tips on using the RN-42 with Blueterm?
The DS3231 is compatible enough with the MCP79410 that you should be able to use it as is, just change the device address. The first 7 registers are compatible although the 79410 does uses some of the otherwise unused bits for control purposes but that won't affect the 3231. Try it and let me know how is goes.
The device address can be changed either in the source code: $DE == @rtc
to
$B0 == @rtc
Or you can write directly to the constant at runtime with:
$B0 ' @rtc 1+ !
The RN42 should just work in slave mode and you should be able to change it's default baudrate to 230400.
I'm starting to get close to finishing the FAT32 file support, I've just been getting my head around where everything is and how it works by Googling bits of information and interacting with the code and card to check it all out. I know a FAT32 driver has been written but I haven't referenced it at all which may sound a bit odd seeing that the code is all there. The thing is I would have to get my head around the code and I'd much rather get my head around FAT32 and SDHC cards themselves, that way I can produce a nice clean interface and so far it's been working out that way. The code size is under 1.5K at present and probably will not increase too much more. Here's a capture of a quick session I did in mounting a card, checking the card info and performing a couple of operations on it and even accessing a file as virtual memory (me in red).
[FONT=courier new][COLOR=#ff0000]MOUNT [/COLOR]
655F_06B0: SYSLINUX FAT32
Sectors = 7,725,056 ok
[COLOR=#ff0000]SD [/COLOR]
Card inserted
MFG 27
OEM PH
Product ID SD04G
REV20
S/N 655F06B0
DATE 2011/4
CRC 5B
CSD REGISTER
*SDHC CARD*
TACC 100ns
NSAC 0bps
TRANS 50MHz
BLKLEN 512
SIZE 3,775 Mbytes
________________
ok
[COLOR=#ff0000]ls [/COLOR]
UBNKERN . UBNINIT . UBNPATHL.TXT AUTORUN .INF MD5SUM .TXT UBNFILEL.TXT LDLINUX .SYS SYSLINUX.CFG
MENU .C32 ok
[COLOR=#ff0000]DIR [/COLOR]
UBNKERN . .....a 0000404027/01/201220:44:044,658,096
UBNINIT . .....a 0000640027/01/201220:44:0620,068,855
UBNPATHL.TXT .....a 0000FFC0 07/02/201211:37:0687
AUTORUN .INF .....a 0001014009/11/201100:59:44170
MD5SUM .TXT .....a 0024AE80 27/01/201220:49:5412,511
UBNFILEL.TXT .....a 0024AF40 07/02/201211:41:365,866
LDLINUX .SYS rhs..a 0024AF80 07/02/201211:41:3632,256
SYSLINUX.CFG .....a 0024AFC0 07/02/201211:41:421,107
MENU .C32 .....a 0024B000 07/02/201211:41:4256,164 ok
[COLOR=#ff0000]cat AUTORUN.INF[/COLOR]...opened at 00010140
[autorun]
open=mint4win.exe --cdmenu --skipmd5check
icon=mint4win.exe,0
label=Install Linux Mint
[Content]
MusicFiles=false
PictureFiles=false
VideoFiles=false
ok[/FONT]
[COLOR=#ff0000]OPEN SYSLINUX.CFG[/COLOR]...opened at 0024AFC0 ok
[COLOR=#ff0000]@FILE XADR 80 DUMP[/COLOR]
7600: 6465666175 6C 7420 6D 65 6E 75 2E 633332 default menu.c32
7610: 0A 7072 6F 6D 70742030 0A 6D 65 6E 752074 .prompt 0.menu t
7620: 6974 6C 652055 4E 657462 6F 6F 7469 6E 0A itle UNetbootin.
7630: 7469 6D 65 6F 757420313030 0A 0A 6C 6162 timeout 100..lab
7640: 65 6C 2075 6E 657462 6F 6F 7469 6E 646566 el unetbootindef
7650: 6175 6C 74 0A 6D 65 6E 7520 6C 616265 6C 20 ault.menu label
7660: 4465666175 6C 74 0A 6B 6572 6E 65 6C 20 2F Default.kernel /
7670: 7562 6E 6B 6572 6E 0A 61707065 6E 642069 ubnkern.append i
ok
since Peter was busy I continued my experiments and now I understand partly,
why it could only work in this special case.
I am revectoring KEY via ukey to read from a string.
which can only work at the end of the input line, when the input loop comes back to calling KEY again.
@Peter
based on your new STRING words I wanted to build an EVAL
which works - almost fine.
BUT:
1. maybe it would be better to suppress the echo of the evaluated string and show just the result
(could be done using NULLOUT & CON see below )
2. if used multiple times in one line or inside a loop, only the last EVAL seems to get executed.
seems I still miss s.th. important
\
pub (EVALSTR) ( strAddr -- )
C@++DUP0=IFDROP ukey W~$0D THEN ; ok
ok
pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr )
' (EVALSTR) ukey W! ; ok
{ without output
pub (EVALSTR) ( strAddr -- )
C@++DUP0=IFDROPCON$0D THEN ;
\ just deliver one char after the other, on last one add $0D to get it executed and set reader back to CONsole
pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr )
NULLOUT \ suppress output
' (EVALSTR) ukey W! ;
}
" 1 1 + . "EVAL ok
11+ . 2 ok
" 2 2 + . "EVAL ok
22+ . 4 ok
" : TT1 $17 . ; "$20STRINGTESTSTR ok
TESTSTREVAL ok
: TT1$17 . ; ok
TT117 ok
ok
\ let's define a WORD, that generates other words ... ( I worked many years with LISP ;-) - so I love EVAL )
: TTT06ADO"0"I+TESTSTR4+C! "0"I+TESTSTR8+C! TESTSTR .STRCRTESTSTR [COLOR=#020FC0][B]EVAL [/B][/COLOR]LOOP
; ok
ok
TTT : TT0$10 . ;
: TT1$11 . ;
: TT2$12 . ;
: TT3$13 . ;
: TT4$14 . ;
: TT5$15 . ;
ok
: TT5$15 . ; ok
so I tried the following modifications, which at least seem to work on the input line.
But it is still not possible to put this inside a loop or definition of a word.
in other words - I can not compile it.
Since now I had to define EVAL as IMMEDIATE to work at least this far.
pub (EVALSTR) ( strAddr -- )
C@++ DUP 0= IF DROP CON $0D THEN ;
\ just deliver onechar after the other, onlastoneadd $0D toget it executed andset reader back to CONsole
pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr )
[COMPILE] GRAB
\ NULLOUT \ suppress output
' (EVALSTR) ukey W! ;
IMMEDIATE
" 1 1 + . " EVAL " 2 2 + . " EVAL " 3 3 + . " EVAL 1 1 +
I assume I need to take a completely different approach for EVAL to do what I imagine.
I'm starting to get close to finishing the FAT32 file support, I've just been getting my head around where everything is and how it works by Googling bits of information and interacting with the code and card to check it all out. I know a FAT32 driver has been written but I haven't referenced it at all which may sound a bit odd seeing that the code is all there. The thing is I would have to get my head around the code and I'd much rather get my head around FAT32 and SDHC cards themselves, that way I can produce a nice clean interface and so far it's been working out that way. The code size is under 1.5K at present and probably will not increase too much more. Here's a capture of a quick session I did in mounting a card, checking the card info and performing a couple of operations on it and even accessing a file as virtual memory (me in red).
[FONT=courier new][COLOR=#ff0000]MOUNT [/COLOR]
655F_06B0: SYSLINUX FAT32
Sectors = 7,725,056 ok
[COLOR=#ff0000]SD [/COLOR]
Card inserted
MFG 27
OEM PH
Product ID SD04G
REV20
S/N 655F06B0
DATE 2011/4
CRC 5B
CSD REGISTER
*SDHC CARD*
TACC 100ns
NSAC 0bps
TRANS 50MHz
BLKLEN 512
SIZE 3,775 Mbytes
________________
ok
[COLOR=#ff0000]ls [/COLOR]
UBNKERN . UBNINIT . UBNPATHL.TXT AUTORUN .INF MD5SUM .TXT UBNFILEL.TXT LDLINUX .SYS SYSLINUX.CFG
MENU .C32 ok
[COLOR=#ff0000]DIR [/COLOR]
UBNKERN . .....a 0000404027/01/201220:44:044,658,096
UBNINIT . .....a 0000640027/01/201220:44:0620,068,855
UBNPATHL.TXT .....a 0000FFC0 07/02/201211:37:0687
AUTORUN .INF .....a 0001014009/11/201100:59:44170
MD5SUM .TXT .....a 0024AE80 27/01/201220:49:5412,511
UBNFILEL.TXT .....a 0024AF40 07/02/201211:41:365,866
LDLINUX .SYS rhs..a 0024AF80 07/02/201211:41:3632,256
SYSLINUX.CFG .....a 0024AFC0 07/02/201211:41:421,107
MENU .C32 .....a 0024B000 07/02/201211:41:4256,164 ok
[COLOR=#ff0000]cat AUTORUN.INF[/COLOR]...opened at 00010140
[autorun]
open=mint4win.exe --cdmenu --skipmd5check
icon=mint4win.exe,0
label=Install Linux Mint
[Content]
MusicFiles=false
PictureFiles=false
VideoFiles=false
ok[/FONT]
[COLOR=#ff0000]OPEN SYSLINUX.CFG[/COLOR]...opened at 0024AFC0 ok
[COLOR=#ff0000]@FILE XADR 80 DUMP[/COLOR]
7600: 6465666175 6C 7420 6D 65 6E 75 2E 633332 default menu.c32
7610: 0A 7072 6F 6D 70742030 0A 6D 65 6E 752074 .prompt 0.menu t
7620: 6974 6C 652055 4E 657462 6F 6F 7469 6E 0A itle UNetbootin.
7630: 7469 6D 65 6F 757420313030 0A 0A 6C 6162 timeout 100..lab
7640: 65 6C 2075 6E 657462 6F 6F 7469 6E 646566 el unetbootindef
7650: 6175 6C 74 0A 6D 65 6E 7520 6C 616265 6C 20 ault.menu label
7660: 4465666175 6C 74 0A 6B 6572 6E 65 6C 20 2F Default.kernel /
7670: 7562 6E 6B 6572 6E 0A 61707065 6E 642069 ubnkern.append i
ok
Can't wait but I will.
Perfect for logging, writing and running profiles for my Tachyon/Forth machine.
COG memory is very limited and Tachyon squeezes the VM and stacks in there and there's no room really left over for specialized operations that really require PASM. That's where RUNMOD comes in as I sacrifice 16 to 24 longs for specialized modules which are compiled to run at that address but only one module can be loaded at a time. These specialized modules include SPI, I2C, SD, and PWM etc. The PWM module is designed to run in it's own cog as it's an endless loop where another cog/task can control the parameters. Of course the PWM cog doesn't need all the Tachyon VM in it after that but it's easy to load the module in the normal fashion.
So PWM doesn't use the counters, only WAITCNT but you mentioned PWM in your list which is different to duty-cycle modulation ( fixed pulse width, variable frequency).
As for your head hurting can I suggest a Pepperjack Cab Sav. If that doesn't work then increase the dose.
Will do ... although I had to replace the Pepperjack with a Local Merlot ..... distinct lack of Oz wines over here ....
By the way, what I am trying to do is this:
My interest is Electric Cars ... currently I am building one based on a 200HP Industrial motor running at 650V. (Biggest problem is the cost of the controller ... even when I got the power module off eBay)
That is all good, but for my next project I would like to use a BLDC motor being driven by a Prop1 (in sensorless mode) or maybe a Prop2 if I run out of resources .... seems to me I can get the cost of the controller right down ...
So I would like to start the coding based on the Prop1 and see how far I get ... and obviously I would like to do this in Tachyon Forth ..
.... So I am thinking for the 3 Phase PWM, maybe I could use 3 cogs running a low level PWM word that could be phase shifted relative to each other .... (using timers)
Another cog would interface to the sensorless circuitry (zero-crossing detector) and would self modify the phase shifting .. (phase shift is normally 60deg in a six step BLDC)
Be interested in what you think of that approach and what the best words would be to achieve the building blocks ..
NB: I have seen the 32 channel PWM code that Parallax have coded up to do this sort of thing in pure assembly, but surely we can use cog timers for this ....
Will do ... although I had to replace the Pepperjack with a Local Merlot ..... distinct lack of Oz wines over here ....
By the way, what I am trying to do is this:
My interest is Electric Cars ... currently I am building one based on a 200HP Industrial motor running at 650V. (Biggest problem is the cost of the controller ... even when I got the power module off eBay)
That is all good, but for my next project I would like to use a BLDC motor being driven by a Prop1 (in sensorless mode) or maybe a Prop2 if I run out of resources .... seems to me I can get the cost of the controller right down ...
So I would like to start the coding based on the Prop1 and see how far I get ... and obviously I would like to do this in Tachyon Forth ..
.... So I am thinking for the 3 Phase PWM, maybe I could use 3 cogs running a low level PWM word that could be phase shifted relative to each other .... (using timers)
Another cog would interface to the sensorless circuitry (zero-crossing detector) and would self modify the phase shifting .. (phase shift is normally 60deg in a six step BLDC)
Be interested in what you think of that approach and what the best words would be to achieve the building blocks ..
NB: I have seen the 32 channel PWM code that Parallax have coded up to do this sort of thing in pure assembly, but surely we can use cog timers for this ....
Cheers,
Bernie
I can't see how a 32 channel PWM could be implemented by counters or even without a cog involved. It could be possible to use the video register though for 8 channels and I'm not sure if that's been done yet but it would still need a cog dedicated to it. The present PWM runs 8-bit PWM up to around 5kHz which means it's updating every 781ns as it needs to read from a table in hub ram (slow) which can be updated by another cog. Sure you could place the table in COG RAM but how do you change it without upsetting the PWM updates? I could update the 8-bit method to read in a long each time if I want to speed it up but I'd have to time the hub access to make sure it's synchronized too.
Remember the Prop design philosopy, the cog is the peripheral, you don't have UARTs, SPI, I2C, ADC, DAC, DMA, VGA, A/V, PWM etc hardwired in, but each cog can do just that. Although each cog is a CPU, it's not necessarily THE CENTRAL processing unit and unlike prima donnas they are humble and flexible enough to be what they need to be ("be a radio"! Okay!)
BTW, Pepperjack is a very lovely red for sure but it's kinda like my baseline red Life is too short to drink cheap wine I say!
I can't see how a 32 channel PWM could be implemented by counters or even without a cog involved. It could be possible to use the video register though for 8 channels and I'm not sure if that's been done yet but it would still need a cog dedicated to it. The present PWM runs 8-bit PWM up to around 5kHz which means it's updating every 781ns as it needs to read from a table in hub ram (slow) which can be updated by another cog. Sure you could place the table in COG RAM but how do you change it without upsetting the PWM updates? I could update the 8-bit method to read in a long each time if I want to speed it up but I'd have to time the hub access to make sure it's synchronized too.
Remember the Prop design philosopy, the cog is the peripheral, you don't have UARTs, SPI, I2C, ADC, DAC, DMA, VGA, A/V, PWM etc hardwired in, but each cog can do just that. Although each cog is a CPU, it's not necessarily THE CENTRAL processing unit and unlike prima donnas they are humble and flexible enough to be what they need to be ("be a radio"! Okay!)
BTW, Pepperjack is a very lovely red for sure but it's kinda like my baseline red Life is too short to drink cheap wine I say!
No, I don't want or need 32 channels, just quoting some example code that was entirely bit bashed PASM code ...
All I need is 3Phase PWM that is gated by the commutation circuitry ..I was thinking of using a cog each for the 3 PWM, and stopping/starting cogs to gate them ..not sure if this is the best approach.
As you know BLDC is usually a six step waveform across the 3 phases, 60deg apart, and each step could be either a duty cycle controlled PWM of fully on or fully off. The commutation determines when the start of these steps happens.
So there will be 6 (3 complementary ) outputs (timers in PWM mode) and three inputs .... the three inputs really need to go through a comparator , which for the P1 looks like I will need external ones, looks like the P2 could do this with it's comparator on each pin.
So, I am going to build some interface circuitry on the Prop Proto board and would like to play around with some interfacing code and the PWM stuff ..
As far as the current PWM word, I may have some suggestions to modify it to allow gating ... that would help my application .. (instead of Cog on/off stuff)
No, I don't want or need 32 channels, just quoting some example code that was entirely bit bashed PASM code ...
All I need is 3Phase PWM that is gated by the commutation circuitry ..I was thinking of using a cog each for the 3 PWM, and stopping/starting cogs to gate them ..not sure if this is the best approach.
As you know BLDC is usually a six step waveform across the 3 phases, 60deg apart, and each step could be either a duty cycle controlled PWM of fully on or fully off. The commutation determines when the start of these steps happens.
So there will be 6 (3 complementary ) outputs (timers in PWM mode) and three inputs .... the three inputs really need to go through a comparator , which for the P1 looks like I will need external ones, looks like the P2 could do this with it's comparator on each pin.
So, I am going to build some interface circuitry on the Prop Proto board and would like to play around with some interfacing code and the PWM stuff ..
As far as the current PWM word, I may have some suggestions to modify it to allow gating ... that would help my application .. (instead of Cog on/off stuff)
Thanks,
Bernie
for the table driven PWM code Peter gives:
This version is set to run up to 8 channels of 8-bit PWM at 1kHz (Tested to 5kHz)
so this would work for a slow motor
and as you write, COG on/off is slow and not a good option.
Updating the PWM tables even in tha PASM version takes
New kernel module method to speed-up updates = 233us total
which gives you a 4kHz update rate - if this is fast enough depends on your motor dynamics.
At what RPM do you run?
Adding gating to the PWM-Code module inside the Tachyon core shouldn't be to difficult.
org _RUNMOD
_PWM mov deltaR,tos ' use supplied delta value from tosmov target,tos
add target,cntmov R1,#0
pwmlp
mov X,REG0 ' read base address of tableadd X,R1 ' add in read indexrdbyte X,X
[SIZE=3][B]' here you can read and check a HUB variable with a gate MASKrdbyte R2,REG3 ' use e.g. REG3 to hold the gate mask HUB address for all 8 channelsand X,R2[/B][/SIZE] ' [B][SIZE=3]mask the PWM [/SIZE][/B]- depending on positive or negative logic might need to be invertedshl X,REG1 ' shift up to pwmpinsmovouta,X ' update outputsadd R1,#1and R1,#$FF
pwmwait waitcnt target,deltaR
jmp #pwmlp
PWM byte _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,1[SIZE=5][B]5[/B][/SIZE],XOP,xLOADMOD,EXIT ' adapt PASM line count
It took me quite some time to figure out, what STRING is really doing.
So I commented the code - hope it is right.
If not please correct somebody / Peter ...
\ commented by Markus Baer MJB ( for my understanding - hope this is correct )
pub STRING ( str max -- ) \ Specify max size ofstringelse use 0forstring length
[COMPILE] GRAB \ execute input before STRING
?DUP 0= IF DUP STRLEN 1+ THEN SWAP ( max str ) \ max is STRLEN+1if max given was 0
codes W@ 4 ALIGN codes W! ALLOCATED ( size str ) \ make long aligned, adjust here
( since the string literal isin the place where we want to create the STRING variable, we need to save the string somewhere further up in the buffer.
CREATE not only compiles the VARB byte code, but also appends an EXIT
because of this we can not move the stringconstto the final place yet,
but we need to move up 1char more )
HERE 5 + OVER STRLEN 1+ <CMOVE \ move out of the way
$80 HERE C! \ set the attribute byte, first byteof the STRING header
DUP HERE 1+ C! \ store the size in the second byteofSTRING header
HERE 4 + STRLEN HERE 2+ C! \ calc the null terminated string len and store it in third byteofSTRING header
3 ALLOT \ allocate space for the 3 header bytes, adjust here
[COMPILE] CREATE \ since CREATE is immediate we need to prefix with [COMPILE]
\ CREATE creates a variable, that returns its address to TOS
( now we need to move the string literal value to the right position replacing the EXITbyte code compiled inby CREATE, which we don't need )
HERE 1+ DUP STRLEN 1+ OVER 1- SWAP CMOVE
( now move the here pointer to the endof the stringby allocating the requested length orif this was 0then the length of the stringconst plus the 0endbyte.
HERE 3 - C@ ALLOT
;
IMMEDIATE \ make this an immediate so the STRINGis created direcly
reverse engineering Peter's code raises my insight, and I hope, TACHYON 3.0 will not be too different inside and I have to relearn all again ...
sorry - I just can't get the comments aligned correctly
so this would work for a slow motor
and as you write, COG on/off is slow and not a good option.
Updating the PWM tables even in tha PASM version takes
which gives you a 4kHz update rate - if this is fast enough depends on your motor dynamics.
At what RPM do you run?
Adding gating to the PWM-Code module inside the Tachyon core shouldn't be to difficult.
org _RUNMOD
_PWM mov deltaR,tos ' use supplied delta value from tosmov target,tos
add target,cntmov R1,#0
pwmlp
mov X,REG0 ' read base address of tableadd X,R1 ' add in read indexrdbyte X,X
[SIZE=3][B]' here you can read and check a HUB variable with a gate MASKrdbyte R2,REG3 ' use e.g. REG3 to hold the gate mask HUB address for all 8 channelsand X,R2[/B][/SIZE] ' [B][SIZE=3]mask the PWM [/SIZE][/B]- depending on positive or negative logic might need to be invertedshl X,REG1 ' shift up to pwmpinsmovouta,X ' update outputsadd R1,#1and R1,#$FF
pwmwait waitcnt target,deltaR
jmp #pwmlp
PWM byte _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,1[SIZE=5][B]5[/B][/SIZE],XOP,xLOADMOD,EXIT ' adapt PASM line count
Hi MJB,
Thanks. I do actually need much faster PWM ... in the order of 10..15Khz, which is why I was wondering about using the Cog timers in PWM mode with complementary outputs and gating those some how,
rather than doing bit-bashing as per Peter's code ..
My other requirement is to have a cog act as a re-triggerable mono-stable as part of the commutation side ... I wonder if that can also be done using a Cog timer.
Thanks. I do actually need much faster PWM ... in the order of 10..15Khz, which is why I was wondering about using the Cog timers in PWM mode with complementary outputs and gating those some how,
rather than doing bit-bashing as per Peter's code ..
a very simple method for gating would be setting the pins to inputs with pullup or pull downs as appropriate, while the counter-PWM continues
My other requirement is to have a cog act as a re-triggerable mono-stable as part of the commutation side ... I wonder if that can also be done using a Cog timer.
B.
you can easily implement a SW monoflop - if timing is sufficient.
I use a COG to implement a legacy bus interface - kind a SW CPLD.
Reaction is 25 .. 50 ns for the most time critical transition.
a very simple method for gating would be setting the pins to inputs with pullup or pull downs as appropriate, while the counter-PWM continues
I don't think that would work, I need to turn those outputs on or off when they are not PWM outputs. I wonder about changing the pwm mode in a way that they go high or low?
you can easily implement a SW monoflop - if timing is sufficient.
Can you elaborate with some Pseudo code on how that would work?
@bmentink: would something like http://obex.parallax.com/object/482 work for you (3ctrx variant)? It may need some work but everything is done inside the prop (there is at least one other implementation available).
Can you elaborate with some Pseudo code on how that would work?
B.
a monoflop is very simple.
e.g.:
output is low
trigger
set output high
set timer variable / manual countdown counter with value for impuls time
looplabel
... on retrigger event reload counter variable with original value ...
djnz looplabel
set output low
using waitcnt will not work, since there must be s.th. to check for retrigger signal
so you can just use a simple tight polling loop.
I don't see how counters could be used for this.
@bmentink: would something like http://obex.parallax.com/object/482 work for you (3ctrx variant)? It may need some work but everything is done inside the prop (there is at least one other implementation available).
an interresting question might be:
Is PWM really needed to drive the motor - or would duty mode be useful as well?
It can be easily generated with the counters.
the important feature is to generate the appropriate average current within the time interval.
Inductivity averages it - so I wonder if the exact phase of PWM is a must have. ...???
a monoflop is very simple.
e.g.:
output is low
trigger
set output high
set timer variable / manual countdown counter with value for impuls time
looplabel
... on retrigger event reload counter variable with original value ...
djnz looplabel
set output low
using waitcnt will not work, since there must be s.th. to check for retrigger signal
so you can just use a simple tight polling loop.
I don't see how counters could be used for this.
Thanks, that makes sense .. I could not work out how it could work with a cog counter either ..
I need three of these, so guess I could use one cog to do all three in PASM as above ..
an interresting question might be:
Is PWM really needed to drive the motor - or would duty mode be useful as well?
It can be easily generated with the counters.
the important feature is to generate the appropriate average current within the time interval.
Inductivity averages it - so I wonder if the exact phase of PWM is a must have. ...???
I think PWM is needed as duty mode would give some interesting motor noises as you sped up and down due to motor resonances .. I think you do need a constant frequency.
I though PWM mode (NCO mode) generated a constant frequency, with variable duty .... am I wrong?
Thanks, that makes sense .. I could not work out how it could work with a cog counter either ..
I need three of these, so guess I could use one cog to do all three in PASM as above ..
I think PWM is needed as duty mode would give some interesting motor noises as you sped up and down due to motor resonances .. I think you do need a constant frequency.
I though PWM mode (NCO mode) generated a constant frequency, with variable duty .... am I wrong?
Bernie, if you want to see what the different modes do then hook-up a scope and sit at the terminal and try the modes. It's very simple and all the words are there (in EXTEND.fth) to allow you to change things easily and of course interactively.
Yes of course I will do that ... just someone has stolen my Prop board for that express purpose ... to play with Forth ( a new convert) ... so I am giving him some head ..
When I get the board back I will be into it ... just thought I could get a quick answer back wile i wait ..
I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?
I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?
TNX in advance .... cheers ... BBR
\ Adjust and dump the current Tachyon binary image in Intel hex format for conversion at the PC end to a bin file
\ The bin file should be renamed as .binary to suit the Prop tool
I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?
TNX in advance .... cheers ... BBR
The BINARYDUMP word will dump the whole 32K less the top 32 bytes in Intel hex format with the correct Spin header checksum so you can run a HEX2BIN or equivalent on the PC end. Just make sure that the binary is named with the .binary extension so the Prop tool can handle it.
The discussions on i/o redirection came to me today as I was editing my BBR_Extensions.fth file for the umpteenth time ... and I wondered if I could apply our ever-so-slippery "variable constant" technique to the same end result ...
The discussions on i/o redirection came to me today as I was editing my BBR_Extensions.fth file for the umpteenth time ... and I wondered if I could apply our ever-so-slippery "variable constant" technique to the same end result ...
.... it worked ... the serial LCD on Pin2 displayed the string (.LSTR word invokes LCD does a string print and returns the CONsole)
Hi Brian,
I'm scrathing my head as to why it is done this way which looks awkward plus I'm not sure what .LSTR does that's different from the normal ." word or even the .STR or TYPE$ words. However I don't really see the need for redirection unless I had multiple serial displays and that would be easy enough too. The rewritable constant is actually redundant if you see how I would handle a couple of different serial devices using SEROUT:
[SIZE=3][FONT=courier new]: LCDEMIT #P2 SEROUT ;
\ Set baudrate for the LCD and select the txd pin used
: LCD ' LCDEMIT uemit W! #19200 SERBAUD ;
: TTYEMIT #P7 SEROUT ;
: TELETYPE ' TTYEMIT uemit W! #300 SERBAUD ;
\ Test out these words
LCD ." HELLO WORLD" CON
TELETYPE ." HELLO WORLD, THIS IS " .VER CON[/FONT][/SIZE]
It's also more desirable to set the baudrate once when the output device is selected as baudrate is a redundant and time-consuming calculation that ends up repeating for every character that's sent.
If I had multiple LCDs I might add a parameter to LCD and invoke it like this:
#P2 LCD ." HELLO WORLD" #P7 LCD ." HELLO WORLD FROM ME TOO" CON
There's even this version of the LCD and TELETYPE snippet that uses a common output word that uses a variable to hold the pin.
[SIZE=3][FONT=courier new]
BYTE serout
: SEROUT2 serout C@ SEROUT ;
\ Set baudrate for the LCD andselect the txd pin used
: LCD ' SEROUT2 uemit W! #19200 SERBAUD #P2 serout C! ;
: TELETYPE ' SEROUT2 uemit W! #300 SERBAUD #P7 serout C! ;[/FONT][/SIZE]
Comments
Is there any more example code for the COG timers? I have studied the wave playing example and sort of understand it (been wading through the Parallax docs), would be good to
have some other other examples though ... i.e pulse PWM, motor control, Freq/Duty measurement etc ... the timers are so powerful, I would like to get my head around them ...
Cheers,
Bernie
Bluetooth: RN-42 http://www.parallax.com/StoreSearchResults/tabid/768/txtSearch/Rn-42/List/0/SortField/4/ProductID/890/Default.aspx
Getting an Asus TF300T tomorrow. Any tips on using the RN-42 with Blueterm?
Hmmm, been looking at the PWM code ... very confused. Code is:
org _RUNMOD _PWM mov deltaR,tos ' use supplied delta value from tos mov target,tos add target,cnt mov R1,#0 pwmlp mov X,REG0 ' read base address of table add X,R1 ' add in read index rdbyte X,X shl X,REG1 ' shift up to pwmpins mov outa,X ' update outputs add R1,#1 and R1,#$FF waitcnt target,deltaR jmp #pwmlp PWM byte _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,13,XOP,xLOADMOD,EXIT
It seems to me that your only using the cog timer for a delay right? all io is bit-bashed rather than using outa,outb?
Also, I don't see how the above loop ends ... and ther is no jump to next or drop at the end of the code ... where does it go to?
Seems I am missing a big chunk of information here ... also "org _RUNMOD" confuses me as it is used above each PASM code module, doesn't that mean they will all be assembled at the same place in memory?
My head hurts.....
EDIT: Why is the code I post all mashed up ... tried copy/pasting through different editors but still rubbish ..
Bernie
COG memory is very limited and Tachyon squeezes the VM and stacks in there and there's no room really left over for specialized operations that really require PASM. That's where RUNMOD comes in as I sacrifice 16 to 24 longs for specialized modules which are compiled to run at that address but only one module can be loaded at a time. These specialized modules include SPI, I2C, SD, and PWM etc. The PWM module is designed to run in it's own cog as it's an endless loop where another cog/task can control the parameters. Of course the PWM cog doesn't need all the Tachyon VM in it after that but it's easy to load the module in the normal fashion.
So PWM doesn't use the counters, only WAITCNT but you mentioned PWM in your list which is different to duty-cycle modulation ( fixed pulse width, variable frequency).
As for your head hurting can I suggest a Pepperjack Cab Sav. If that doesn't work then increase the dose.
The DS3231 is compatible enough with the MCP79410 that you should be able to use it as is, just change the device address. The first 7 registers are compatible although the 79410 does uses some of the otherwise unused bits for control purposes but that won't affect the 3231. Try it and let me know how is goes.
The device address can be changed either in the source code:
$DE == @rtc
to
$B0 == @rtc
Or you can write directly to the constant at runtime with:
$B0 ' @rtc 1+ !
The RN42 should just work in slave mode and you should be able to change it's default baudrate to 230400.
Now my head hurts because this wine is not available in the USA!
Gonna have to place an Intl order
[FONT=courier new][COLOR=#ff0000]MOUNT [/COLOR] 655F_06B0: SYSLINUX FAT32 Sectors = 7,725,056 ok [COLOR=#ff0000]SD [/COLOR] Card inserted MFG 27 OEM PH Product ID SD04G REV 20 S/N 655F06B0 DATE 2011/4 CRC 5B CSD REGISTER *SDHC CARD* TACC 100ns NSAC 0bps TRANS 50MHz BLKLEN 512 SIZE 3,775 Mbytes ________________ ok [COLOR=#ff0000]ls [/COLOR] UBNKERN . UBNINIT . UBNPATHL.TXT AUTORUN .INF MD5SUM .TXT UBNFILEL.TXT LDLINUX .SYS SYSLINUX.CFG MENU .C32 ok [COLOR=#ff0000]DIR [/COLOR] UBNKERN . .....a 00004040 27/01/2012 20:44:04 4,658,096 UBNINIT . .....a 00006400 27/01/2012 20:44:06 20,068,855 UBNPATHL.TXT .....a 0000FFC0 07/02/2012 11:37:06 87 AUTORUN .INF .....a 00010140 09/11/2011 00:59:44 170 MD5SUM .TXT .....a 0024AE80 27/01/2012 20:49:54 12,511 UBNFILEL.TXT .....a 0024AF40 07/02/2012 11:41:36 5,866 LDLINUX .SYS rhs..a 0024AF80 07/02/2012 11:41:36 32,256 SYSLINUX.CFG .....a 0024AFC0 07/02/2012 11:41:42 1,107 MENU .C32 .....a 0024B000 07/02/2012 11:41:42 56,164 ok [COLOR=#ff0000]cat AUTORUN.INF[/COLOR]...opened at 00010140 [autorun] open=mint4win.exe --cdmenu --skipmd5check icon=mint4win.exe,0 label=Install Linux Mint [Content] MusicFiles=false PictureFiles=false VideoFiles=false ok[/FONT] [COLOR=#ff0000]OPEN SYSLINUX.CFG[/COLOR]...opened at 0024AFC0 ok [COLOR=#ff0000]@FILE XADR 80 DUMP[/COLOR] 7600: 64 65 66 61 75 6C 74 20 6D 65 6E 75 2E 63 33 32 default menu.c32 7610: 0A 70 72 6F 6D 70 74 20 30 0A 6D 65 6E 75 20 74 .prompt 0.menu t 7620: 69 74 6C 65 20 55 4E 65 74 62 6F 6F 74 69 6E 0A itle UNetbootin. 7630: 74 69 6D 65 6F 75 74 20 31 30 30 0A 0A 6C 61 62 timeout 100..lab 7640: 65 6C 20 75 6E 65 74 62 6F 6F 74 69 6E 64 65 66 el unetbootindef 7650: 61 75 6C 74 0A 6D 65 6E 75 20 6C 61 62 65 6C 20 ault.menu label 7660: 44 65 66 61 75 6C 74 0A 6B 65 72 6E 65 6C 20 2F Default.kernel / 7670: 75 62 6E 6B 65 72 6E 0A 61 70 70 65 6E 64 20 69 ubnkern.append i ok
why it could only work in this special case.
I am revectoring KEY via ukey to read from a string.
which can only work at the end of the input line, when the input loop comes back to calling KEY again.
so I tried the following modifications, which at least seem to work on the input line.
But it is still not possible to put this inside a loop or definition of a word.
in other words - I can not compile it.
Since now I had to define EVAL as IMMEDIATE to work at least this far.
pub (EVALSTR) ( strAddr -- ) C@++ DUP 0= IF DROP CON $0D THEN ; \ just deliver one char after the other, on last one add $0D to get it executed and set reader back to CONsole pub EVAL ( strAddr -- \ evaluate the FORTH sentence in the null-teminated string starting at strAddr ) [COMPILE] GRAB \ NULLOUT \ suppress output ' (EVALSTR) ukey W! ; IMMEDIATE " 1 1 + . " EVAL " 2 2 + . " EVAL " 3 3 + . " EVAL 1 1 +
I assume I need to take a completely different approach for EVAL to do what I imagine.
Can't wait but I will.
Perfect for logging, writing and running profiles for my Tachyon/Forth machine.
Will this be available in V2.1? or 3.x only?
Pre thanks Peter.
Will do ... although I had to replace the Pepperjack with a Local Merlot ..... distinct lack of Oz wines over here ....
By the way, what I am trying to do is this:
My interest is Electric Cars ... currently I am building one based on a 200HP Industrial motor running at 650V. (Biggest problem is the cost of the controller ... even when I got the power module off eBay)
That is all good, but for my next project I would like to use a BLDC motor being driven by a Prop1 (in sensorless mode) or maybe a Prop2 if I run out of resources .... seems to me I can get the cost of the controller right down ...
So I would like to start the coding based on the Prop1 and see how far I get ... and obviously I would like to do this in Tachyon Forth ..
.... So I am thinking for the 3 Phase PWM, maybe I could use 3 cogs running a low level PWM word that could be phase shifted relative to each other .... (using timers)
Another cog would interface to the sensorless circuitry (zero-crossing detector) and would self modify the phase shifting .. (phase shift is normally 60deg in a six step BLDC)
Be interested in what you think of that approach and what the best words would be to achieve the building blocks ..
NB: I have seen the 32 channel PWM code that Parallax have coded up to do this sort of thing in pure assembly, but surely we can use cog timers for this ....
Cheers,
Bernie
here my attempt at a generalization of it.
comments and optimizations welcome.
\ ============= BUFFER =========================== \ usage size BUFFER BufName pub BUFFER ( size -- \ create a circular buffer of size bytes, \ 4 bytes size, R-index, W-index and VAR byte code preceed buffer address ) [COMPILE] GRAB \ force evaluation auf previous input 3 ALLOT \ space for size, Rind, Wind DUP HERE 3 - C! \ store buffer length HERE 2- C~ \ make sure it is 0 - maybe not needed HERE 1- C~ \ make sure it is 0 [COMPILE] CREATE \ create a variable which returns the buffer start address ALLOT \ allocate size bytes needed which are automatically 0 ?? ; IMMEDIATE pub BUFEMPTY ( bufAddr -- flag ) DUP 3 - C@ SWAP 2- C@ = ; { #10 BUFFER mBuf mBuf 5 - 20 DUMP mBuf BUFEMPTY . } pub BUFSIZE ( bufAddr -- size ) 4 - C@ ; { mBuf BUFSIZE . } pri BUFR ( bufAddr -- rIndex ) 3 - ; \ address of buffer read index pri BUFW ( bufAddr -- wIndex ) 2- ; \ address of buffer write index { mBuf BUFR . mBuf BUFW . } pri BUFR@ ( bufAddr -- rIndex ) BUFR C@ ; \ value of buffer read index pri BUFR@@ ( bufAddr -- rByte ) DUP BUFR@ + C@ ; \ byte of buffer at read index pri BUFW@ ( bufAddr -- wIndex ) BUFW C@ ; \ value of buffer write index pri BUFW@! ( wByte bufAddr -- ) DUP BUFW@ + C! ; \ store byte to buffer at write index { mBuf BUFR@ . mBuf BUFW@ . 12 mBuf BUFW@! mBuf 4 - 20 DUMP } pub BUFFREE ( bufAddr -- flag ) DUP BUFSIZE ( bufAddr size ) OVER BUFW - ( bufAddr size-wPtr ) SWAP BUFR + ; { mBuf BUFFREE . } pub BUFFULL ( bufAddr -- flag ) BUFFREE 0= ; { mBuf BUFFULL . } pub BUFRD ( bufAddr -- byte ) DUP BUFR@@ SWAP ( byte bufAddr ) \ get the value at buffer read pos DUP BUFR C++ DUP BUFR@ OVER ( byte bufAddr rIndex bufAddr ) BUFSIZE = IF BUFR C~ ELSE DROP THEN ; pub BUFWR ( byte bufAddr -- ) SWAP OVER BUFW@! ( bufAddr ) \ write the value to buffer at write pos DUP BUFW C++ DUP BUFW@ OVER ( bufAddr wIndex bufAddr ) BUFSIZE = IF BUFW C~ ELSE DROP THEN ; { 1 mBuf BUFWR 2 mBuf BUFWR mBuf 4 - 20 DUMP mBuf BUFRD . mBuf BUFRD . 1 5 ADO I mBuf BUFWR LOOP mBuf 4 - 20 DUMP 3 mBuf BUFWR mBuf 4 - 20 DUMP 4 mBuf BUFWR mBuf 4 - 20 DUMP 5 mBuf BUFWR mBuf 4 - 20 DUMP 6 mBuf BUFWR mBuf 4 - 20 DUMP 17 mBuf BUFWR mBuf 4 - 20 DUMP 17 mBuf BUFWR mBuf 4 - 20 DUMP } pub BUFCLR ( bufAddr -- ) \ clear buffer DUP BUFR C~ DUP BUFW C~ DUP BUFSIZE ERASE ; { mBuf 4 - 20 DUMP mBuf BUFCLR mBuf 4 - 20 DUMP } pub BUFCNT ( bufAddr -- count ) DUP BUFSIZE ( bufAddr size ) SWAP BUFFREE - ; { mBuf BUFFREE . mBuf BUFCNT . }
I can't see how a 32 channel PWM could be implemented by counters or even without a cog involved. It could be possible to use the video register though for 8 channels and I'm not sure if that's been done yet but it would still need a cog dedicated to it. The present PWM runs 8-bit PWM up to around 5kHz which means it's updating every 781ns as it needs to read from a table in hub ram (slow) which can be updated by another cog. Sure you could place the table in COG RAM but how do you change it without upsetting the PWM updates? I could update the 8-bit method to read in a long each time if I want to speed it up but I'd have to time the hub access to make sure it's synchronized too.
Remember the Prop design philosopy, the cog is the peripheral, you don't have UARTs, SPI, I2C, ADC, DAC, DMA, VGA, A/V, PWM etc hardwired in, but each cog can do just that. Although each cog is a CPU, it's not necessarily THE CENTRAL processing unit and unlike prima donnas they are humble and flexible enough to be what they need to be ("be a radio"! Okay!)
BTW, Pepperjack is a very lovely red for sure but it's kinda like my baseline red
No, I don't want or need 32 channels, just quoting some example code that was entirely bit bashed PASM code ...
All I need is 3Phase PWM that is gated by the commutation circuitry ..I was thinking of using a cog each for the 3 PWM, and stopping/starting cogs to gate them ..not sure if this is the best approach.
As you know BLDC is usually a six step waveform across the 3 phases, 60deg apart, and each step could be either a duty cycle controlled PWM of fully on or fully off. The commutation determines when the start of these steps happens.
So there will be 6 (3 complementary ) outputs (timers in PWM mode) and three inputs .... the three inputs really need to go through a comparator , which for the P1 looks like I will need external ones, looks like the P2 could do this with it's comparator on each pin.
So, I am going to build some interface circuitry on the Prop Proto board and would like to play around with some interfacing code and the PWM stuff ..
As far as the current PWM word, I may have some suggestions to modify it to allow gating ... that would help my application .. (instead of Cog on/off stuff)
Thanks,
Bernie
and as you write, COG on/off is slow and not a good option.
Updating the PWM tables even in tha PASM version takes which gives you a 4kHz update rate - if this is fast enough depends on your motor dynamics.
At what RPM do you run?
Adding gating to the PWM-Code module inside the Tachyon core shouldn't be to difficult.
org _RUNMOD _PWM mov deltaR,tos ' use supplied delta value from tos mov target,tos add target,cnt mov R1,#0 pwmlp mov X,REG0 ' read base address of table add X,R1 ' add in read index rdbyte X,X [SIZE=3][B]' here you can read and check a HUB variable with a gate MASK rdbyte R2,REG3 ' use e.g. REG3 to hold the gate mask HUB address for all 8 channels and X,R2[/B][/SIZE] ' [B][SIZE=3]mask the PWM [/SIZE][/B]- depending on positive or negative logic might need to be inverted shl X,REG1 ' shift up to pwmpins mov outa,X ' update outputs add R1,#1 and R1,#$FF pwmwait waitcnt target,deltaR jmp #pwmlp PWM byte _WORD,(@_PWM+s)>>8,@_PWM+s,_BYTE,1[SIZE=5][B]5[/B][/SIZE],XOP,xLOADMOD,EXIT ' adapt PASM line count
So I commented the code - hope it is right.
If not please correct somebody / Peter ...
\ commented by Markus Baer MJB ( for my understanding - hope this is correct ) pub STRING ( str max -- ) \ Specify max size of string else use 0 for string length [COMPILE] GRAB \ execute input before STRING ?DUP 0= IF DUP STRLEN 1+ THEN SWAP ( max str ) \ max is STRLEN+1 if max given was 0 codes W@ 4 ALIGN codes W! ALLOCATED ( size str ) \ make long aligned, adjust here ( since the string literal is in the place where we want to create the STRING variable, we need to save the string somewhere further up in the buffer. CREATE not only compiles the VARB byte code, but also appends an EXIT because of this we can not move the string const to the final place yet, but we need to move up 1 char more ) HERE 5 + OVER STRLEN 1+ <CMOVE \ move out of the way $80 HERE C! \ set the attribute byte, first byte of the STRING header DUP HERE 1+ C! \ store the size in the second byte of STRING header HERE 4 + STRLEN HERE 2+ C! \ calc the null terminated string len and store it in third byte of STRING header 3 ALLOT \ allocate space for the 3 header bytes, adjust here [COMPILE] CREATE \ since CREATE is immediate we need to prefix with [COMPILE] \ CREATE creates a variable, that returns its address to TOS ( now we need to move the string literal value to the right position replacing the EXIT byte code compiled in by CREATE, which we don't need ) HERE 1+ DUP STRLEN 1+ OVER 1- SWAP CMOVE ( now move the here pointer to the end of the string by allocating the requested length or if this was 0 then the length of the string const plus the 0 end byte. HERE 3 - C@ ALLOT ; IMMEDIATE \ make this an immediate so the STRING is created direcly
reverse engineering Peter's code raises my insight, and I hope, TACHYON 3.0 will not be too different inside and I have to relearn all again ...sorry - I just can't get the comments aligned correctly
Hi MJB,
Thanks. I do actually need much faster PWM ... in the order of 10..15Khz, which is why I was wondering about using the Cog timers in PWM mode with complementary outputs and gating those some how,
rather than doing bit-bashing as per Peter's code ..
My other requirement is to have a cog act as a re-triggerable mono-stable as part of the commutation side ... I wonder if that can also be done using a Cog timer.
B.
a very simple method for gating would be setting the pins to inputs with pullup or pull downs as appropriate, while the counter-PWM continues
you can easily implement a SW monoflop - if timing is sufficient.
I use a COG to implement a legacy bus interface - kind a SW CPLD.
Reaction is 25 .. 50 ns for the most time critical transition.
I don't think that would work, I need to turn those outputs on or off when they are not PWM outputs. I wonder about changing the pwm mode in a way that they go high or low?
Can you elaborate with some Pseudo code on how that would work?
Thanks,
B.
e.g.:
output is low
trigger
set output high
set timer variable / manual countdown counter with value for impuls time
looplabel
... on retrigger event reload counter variable with original value ...
djnz looplabel
set output low
using waitcnt will not work, since there must be s.th. to check for retrigger signal
so you can just use a simple tight polling loop.
I don't see how counters could be used for this.
there are some more:
http://obex.parallax.com/object/211 (looks slow)
search OBEX for PWM or MOTOR
an interresting question might be:
Is PWM really needed to drive the motor - or would duty mode be useful as well?
It can be easily generated with the counters.
the important feature is to generate the appropriate average current within the time interval.
Inductivity averages it - so I wonder if the exact phase of PWM is a must have. ...???
Thanks, that makes sense .. I could not work out how it could work with a cog counter either ..
I need three of these, so guess I could use one cog to do all three in PASM as above ..
I think PWM is needed as duty mode would give some interesting motor noises as you sped up and down due to motor resonances .. I think you do need a constant frequency.
I though PWM mode (NCO mode) generated a constant frequency, with variable duty .... am I wrong?
Bernie, if you want to see what the different modes do then hook-up a scope and sit at the terminal and try the modes. It's very simple and all the words are there (in EXTEND.fth) to allow you to change things easily and of course interactively.
Yes of course I will do that ... just someone has stolen my Prop board for that express purpose ... to play with Forth ( a new convert) ... so I am giving him some head ..
When I get the board back I will be into it ... just thought I could get a quick answer back wile i wait ..
I need to generate a HEX file from Tachyon Forth that can be loaded and burnt to EEPROM. Which of the various "dump" words produces a bootable hex file?
TNX in advance .... cheers ... BBR
The BINARYDUMP word will dump the whole 32K less the top 32 bytes in Intel hex format with the correct Spin header checksum so you can run a HEX2BIN or equivalent on the PC end. Just make sure that the binary is named with the .binary extension so the Prop tool can handle it.
The discussions on i/o redirection came to me today as I was editing my BBR_Extensions.fth file for the umpteenth time ... and I wondered if I could apply our ever-so-slippery "variable constant" technique to the same end result ...
#P15 CONSTANT #SO \ declare #SO and set default : SO! ( serpin -- ) ' #SO 1+ ! ; : LCDEMIT #19200 SERBAUD #SO SEROUT ; : LCD ' LCDEMIT uemit W! ;
I typed
#P2 SO! " HELLO WORLD" .LSTR
.... it worked ... the serial LCD on Pin2 displayed the string (.LSTR word invokes LCD does a string print and returns the CONsole)Hi Brian,
I'm scrathing my head as to why it is done this way which looks awkward plus I'm not sure what .LSTR does that's different from the normal ." word or even the .STR or TYPE$ words. However I don't really see the need for redirection unless I had multiple serial displays and that would be easy enough too. The rewritable constant is actually redundant if you see how I would handle a couple of different serial devices using SEROUT:
[SIZE=3][FONT=courier new]: LCDEMIT #P2 SEROUT ; \ Set baudrate for the LCD and select the txd pin used : LCD ' LCDEMIT uemit W! #19200 SERBAUD ; : TTYEMIT #P7 SEROUT ; : TELETYPE ' TTYEMIT uemit W! #300 SERBAUD ; \ Test out these words LCD ." HELLO WORLD" CON TELETYPE ." HELLO WORLD, THIS IS " .VER CON[/FONT][/SIZE]
It's also more desirable to set the baudrate once when the output device is selected as baudrate is a redundant and time-consuming calculation that ends up repeating for every character that's sent.
If I had multiple LCDs I might add a parameter to LCD and invoke it like this:
#P2 LCD ." HELLO WORLD" #P7 LCD ." HELLO WORLD FROM ME TOO" CON
There's even this version of the LCD and TELETYPE snippet that uses a common output word that uses a variable to hold the pin.
[SIZE=3][FONT=courier new] BYTE serout : SEROUT2 serout C@ SEROUT ; \ Set baudrate for the LCD and select the txd pin used : LCD ' SEROUT2 uemit W! #19200 SERBAUD #P2 serout C! ; : TELETYPE ' SEROUT2 uemit W! #300 SERBAUD #P7 serout C! ;[/FONT][/SIZE]