PDA

View Full Version : Counter and ASM Question



Mightor
08-29-2007, 02:42 AM
Hey there,

I'm trying to learn ASM for the prop. Right now I'm going through the Propeller Counters document. As far as I can understand you basically have two counters per cog. Does that mean that you could have two separate PWM generators per cog? I'd like to know if it is possible before I embark on my journey to modify the below into something that generates two different PWM signal on two separate pins. I don't want to strand my (asm)-ship before I've even set sail. So if it's doable, please let me know. I am not looking for the code, I'd like to try that myself, only to know if it can be done :)




{{
Demonstration of scaling Duty Cycle

}}

CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

VAR
long parameter

PUB go | x
cognew(@entry, @parameter)
repeat
'parameter := 50
repeat x from 0 to period ' linearly advance parameter from 0 to 100
parameter := x ' a constant here locks to x percent high
waitcnt(1000 + cnt) ' wait a little while before the next update

DAT
org

entry mov dira, diraval ' set APIN to output
mov ctra, ctraval ' establish counter A mode and APIN
mov frqa, #1 ' set counter to increment 1 each cycle

mov time, cnt ' record current time
add time, period ' establish next period

:loop rdlong value, par ' get an up to date duty cycle
waitcnt time, period ' wait until next period
neg phsa, value ' backup up phsa so that it
jmp #:loop ' loop for next cycle

diraval long |< 0 ' APIN direction (0)
ctraval long %00100 << 26 + 0 ' NCO/PWM APIN=0 {BPIN=1} <- not used
period long 100 ' 800kHz period ( clkfreq / period )
time res 1
value res 1




Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.

Steel
08-29-2007, 03:27 AM
yup. You are correct. There are 2 timers, and you can set each of them to the correct mode and have 2 PWM per cog...thus making 16 possible pwm signals. THANK YOU PARALLAX!

Mightor
08-30-2007, 03:35 AM
Well I figured it out and it works quite nicely now. I'd really like it if someone could have a look at the code and tell me if this is indeed the proper way to do it. Now, I know TIMTOWTDI (yeah, deSilva, I know Perl :), but some input would be greatly appreciated. I'd really like to know if there are clever tricks do this kind of thing. The counter application notes mention the ability use the counters so you can make the cog do other stuff as well. However, I am not sure how that would be possible since I seem to be in a loop most of the time.




{{
Demonstration of scaling Duty Cycle

}}

CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

VAR
long parameter

PUB go | x
cognew(@entry, @parameter)
repeat
'parameter := 50
repeat x from 0 to period ' linearly advance parameter from 0 to 100
parameter[0] := x ' a constant here locks to x percent high
parameter := period - x
waitcnt(1000 + cnt) ' wait a little while before the next update

DAT
org

entry mov dira, diraval ' set APIN to output
mov ctra, ctraval ' establish counter A mode and APIN
mov frqa, #1 ' set counter to increment 1 each cycle
mov ctrb, ctrbval ' establish counter B and
mov frqb, #1

mov time, cnt ' record current time
add time, period ' establish next period

:loop rdlong value, par ' get an up to date duty cycle
mov value2, par
add value2, #4 ' Get the address for the 2nd long
rdlong value2, value2 ' read the 2nd argument from the HUB
waitcnt time, period ' wait until next period
neg phsa, value
neg phsb, value2
jmp #:loop ' loop for next cycle

diraval long |< 2 + |< 3 ' APIN direction (0)
ctraval long %00100 << 26 + 2 ' NCO/PWM APIN=3
ctrbval long %00100 << 26 + 3 ' NCO/PWM APIN=4
period long 1000 ' 800kHz period ( clkfreq / period )
time res 1
value res 1
value2 res 1




Also, this is running at a breakneck speed of 800kHz, which is great when you're running this program in GEAR, but what kind of frequency should I be looking at when using PWM for a motor? 800kHz seems a little excessively fast. I am also going to need some diodes apart from the H bridge. What kind should I get? The max current the motors draw when stalled is about 1A. I saw on voti.nl (a local-ish online electronic shop) that the UF4007 is fast and can deal with 1A. Would this do the trick for me?

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.

deSilva
08-30-2007, 04:17 AM
Mightor said...
The counter application notes mention the ability use the counters so you can make the cog do other stuff as well. However, I am not sure how that would be possible since I seem to be in a loop most of the time.

Well, the PWM feature is indeed the worst example for this claim... But you COULD could do something else before WAITCNT... Having just 8 COGs can never compensate for the wealth of possibilties you have with a good interrupt system http://forums.parallax.com/images/smilies/smile.gif





mov time, cnt ' record current time
add time, period ' establish next period



Why "period" .. this is highly irrelevant in this place...
When you enter the loop you will first wait THIS time before any PHS is set.




diraval long |< 2 + |< 3 ' APIN direction (0)
ctraval long %00100 << 26 + 2 ' NCO/PWM APIN=3
ctrbval long %00100 << 26 + 3 ' NCO/PWM APIN=4



I should use constant NAMES rather "1" and "2"




period long 1000 ' 800kHz period ( clkfreq / period )


You can read the ckfreq value also in "PASM" - do you know how?

Mightor
08-30-2007, 11:58 AM
mov time, cnt ' record current time
add time, period ' establish next period



deSilva said...

Why "period" .. this is highly irrelevant in this place...
When you enter the loop you will first wait THIS time before any PHS is set.

Well, to be honest with you, I copied most of this code from the Propeller counter application notes code examples. I merely tweaked to be able to handle two PWM signals :) Why is it highly irrelevant? What would be more appropriate?





period long 1000 ' 800kHz period ( clkfreq / period )



deSilva said...
You can read the ckfreq value also in "PASM" - do you know how?

No, I do not. What would that allow me to do in this case? I picked 1000 because it allows me to see the waves very nicely in the GEAR simulator when it runs at 80MHz. In the Prop manual I see this:

Propeller manual said...
After issuing a CLKSET instruction, it is important to update the System Clock Frequency value by writing to its location in Main RAM (long 0): WRLONG freqaddr, #0. If the System Clock Frequency value is not updated, other objects will misbehave due to invalid clock frequency data.

My guess is that this has something to do with it, although tbh, I am not sure yet in what way :)

Thanks for looking at this stuff and giving me feedback, it's highly appreciated.

Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.

deSilva
08-31-2007, 12:32 AM
Mightor said...

Why "period" .. this is highly irrelevant in this place...
When you enter the loop you will first wait THIS time before any PHS is set.

Well, to be honest with you, I copied most of this code from the Propeller counter application notes code examples. I merely tweaked to be able to handle two PWM signals :) Why is it highly irrelevant? What would be more appropriate?[/code]

You see, you are entering the main loop at its WAIT-instruction, without presetting the PWM mechanism. So what is the use of waiting? Or how long? Why "period". Well it's a value as any value... Nevertheless it can also be a shorter or a longer time - what I wanted to say: No connection with the "period " in any way here. I myself would have coded:


mov time, cnt ' record current time
add time, period ' establish next period
JMP #:loopEntry

:loop rdlong value, par ' get an up to date duty cycle
mov value2, par
add value2, #4 ' Get the address for the 2nd long
rdlong value2, value2 ' read the 2nd argument from the HUB
waitcnt time, period ' wait until next period
:loopEntry
neg phsa, value
neg phsb, value2
jmp #:loop




But as it is generally frowned upon using "unstructured" constructs, you can now reshape the loop:


mov time, cnt ' record current time
add time, period ' establish next period

:loop
rdlong value, par ' get an up to date duty cycle
mov value2, par
add value2, #4 ' Get the address for the 2nd long
rdlong value2, value2 ' read the 2nd argument from the HUB
neg phsa, value
neg phsb, value2
waitcnt time, period ' wait until next period

jmp #:loop





Using the clock frequency stored in HUB cell 0 is easy
[code]
RDLONG t0, #0 ' read clock frequency
MOV t1, reqFreq
CALL #divide
MOV period, t0


reqFreq LONG 80_000 ' 80 kHz
I think it's 80kHz you are using, not 800...
You of course have to insert the standard 32/16 bit division routine..

However the values have now be harmonized with the values read from memory... At the moment you use "per thousend" which is quite transparent and will work (the duty cycle at least) independent of the clock speed.

But it is always a good idea to set the _PLLX to 4 from time to time , just to see whether one's program still runs with another clock...