Deriving PWM settings from frequency values ...

hitsware

Member
; Since the 082M cannot use 1000000 in calculation
; how does it calculate PWM values?
; I tried the below, but it gets more inaccurate as
; frequency increases.

w1=1000 ; frequency (cycles/second)
w2=62500/w1 ; period in terms of 16us clock
w3=16*w2 ; period for 1 us
w4=w3 -1
w5=w3/4 -1
w6=w3/16 -1
w7=w3/64 -1
 
Last edited:

hippy

Technical Support
Staff member
I don't have the answer but the equation for calculating a period value is ...

period = ( ( MHz * 250000 ) / ( frequency * pwmdiv ) ) - 1

Where MHz is the operating speed of the PICAXE ( usually 4 for M2, 8 for X2 ) and pwmdiv is 1, 4, 16 or 64.

Jeremy Leach wrote a number of 32-bit maths functions which may be of use.
 

hitsware

Member
;Thanks .... Same problem
;Higher frequency error
;Maybe I simply need 32 bit device ?
;I want to calculate pwm on the fly
;~ 40 to 4kHz (musically accurate)

w1=660 ;frequency
w2=w1*1 ;div=16
w3=w1*4 ;div=64
w4=62500/w2 -1 ;div=16
w5=62500/w3 -1 ;div=64
 

Buzby

Senior Member
If all you need is a set of musical notes, and not the frequencies between, then you may be better off precalculating for each note and storing the results in EEPROM.

Then your code just needs to 'look up' the results in the required note order.

We may be able to help more if you tell us what it is you are trying to do.

Cheers,

Buzby
 

hitsware

Member
Here's an example (BBCBasic using Windows api) of my work :
https://www.youtube.com/watch?v=ePhUBBGyVmI
I use 'just' intonation (integer math ratios) for tuning (though referanced to A @ 440Hz)
So I need to be able to compute the notes rather than use a lookup ........
(Or else have a giant lookup that would take the computation to make anyways :) )
Here's something I done with a MicroMite :
http://home.comcast.net/~mnjmiller/temper.mp3
The MicroMite (32 bit 5 pwm's(@ 2 freqs)) works well,
but I like the elegance of the 8 pin chips :)
 

AllyCat

Senior Member
Hi,

The problem with the "raw" 8-pin chip is not just that it has a very elementary 8-bit instruction set, but the PICaxe interpreter "overhead" makes it even slower for complex maths operations. Jeremy's (iterative) 32-bit divison routine converges remarkably quickly, but I don't think anybody has updated the code to an easily-usable form for the latest (M2) chips. Several others have also posted higher resolution maths routines in the "code snippets" section of the forum.

A few years ago, I wrote this double-word divison routine which might be suitable, but even the updated version in post #10 still takes around 70ms to execute with a 4 MHz clock. So maybe about 10 ms with the 32 MHz maximum clock of an 08M2. I have now devised a very similar routine that can use up to a 12-bit divisor and executes about 5 times faster, which I hope to "write up" soon.

Cheers, Alan.
 

hitsware

Member
Thank You ...
That's a little complicated for my style :cool:
Is there any simple way to write to the frequency registers with pokes ?
And is the 1 to 4 to 16 to 64 binding ?
I could live with squarewave only (though duty cycle is nice)
with 1 byte/octave and 2,4,8,16,32,64 prescalers......
preferably from ~ 20 to 2kHz
The ratio of 4 on the scalers is sort of musically awkward .
The scalers at all, it seems,(?) would be hard to manage
from a lookup table.
 

AllyCat

Senior Member
Hi,

They aren't "frequency" registers, they're (hardware) timers. That's why you need to invert (divide) the values (to convert from frequency to time period). I don't see how "poking" individual bytes to several different SFRs could be "simpler" than using the embedded PICaxe (word) command to do the same thing. :confused:

The 1 : 4 : 16 : 64 prescaling is defined by hardware counters on the chip.

I rather doubt if you'll find anything much simpler than my 6 lines (26 bytes) division module. The faster version is about twice the size.

Cheers, Alan.
 

hitsware

Member
> I don't see how "poking" individual bytes to several different SFRs could be "simpler"
> than using the embedded PICaxe (word) command to do the same thing.

POKE address, 1,4,16,64
(seems to me)
Would be simpler than
the 4 separate commands
PWMOUT, PWMOUT PWMDIV4 ... etc.
It would be equivalent if the 1,4,16,64 could be a variable
I.E..... PWMOUT PWMDIV divider, pin, period, dutycycles
 

AllyCat

Senior Member
Hi,

POKE address,1,4,16,64 will simply write the four values to consecutive locations in RAM.

The PWM.... commands generate a sequence of instructions equivalent to POKESFR converted_SFR_number, byte_value . AFAIK the SFR numbers used by the PICaxe PWM.... commands are not formally documented, but the 08M2 presumably uses the Capture-Compare (CCP1) registers with Timer2 (since Timer1 is used for time and servo functions). See page 184 onwards of the PIC12(L)F1840 data sheet.

It's also worth noting that the PE converts PWMDUTY... to over 30 bytes of program code.

Cheers, Alan.
 

westaust55

Moderator
In the absence if full information,
Any value in using the TUNE command with discrete single notes?
Guess it may not cover octaves in full desired range unless can also use SETFREQ to compensate.
See PICAXE manual 2 page 251 onwards.
 

hitsware

Member
> Any value in using the TUNE command with discrete single notes?

That could probably work, but defies just intonation (I think)
I've found that PWMOUT will accept numbers below 63,
(despite what the Wizard suggests) .... So using this :
.B........C.......D.......E........F......G.......A
256....240....216....192....180....160....144
128....120....108......96.....90......80.....72
.64......60......54......48.....45......40.....36
.32......30......27......24..............20.....18
.16......15...............12..............10......9
..8..........................6................5.......
..4..........................3.........................
..2....................................................
..1....................................................
And this:

eeprom (9,6,8,6, 6,3,4,3, 1,2,4)
do
for b0=0 to 3: read b0,b1
for b2=4 to 7: read b2,b3
random w8
b6=w8//3 +8
read b6,b7
b4=b1*b3*b7 -1
b5=b7*b4
pwmout pwmdiv64,2,b4,b5
pause 250
next b2:next b0
loop

I arrived at this:
http://home.comcast.net/~mnjmiller/picaxe_isle.mp3
:cool:
 

Technical

Technical Support
Staff member
; Since the 082M cannot use 1000000 in calculation
; how does it calculate PWM values?
To answer that question, it doesn't.
The pwmout command is processed by a dedicated silicon module in the PIC based around shift registers, so no calculations at all are carried out by the main processor to generate the pwmout stream.
 

AllyCat

Senior Member
Hi,

PWMOUT will accept numbers below 63,
(despite what the Wizard suggests)
Isn't it simply that normally it's more appropriate to change the division factor than use short PWM cycles?

But interestingly, it seems that PWMDIV64 is not a pre-defined number (as are "baudmode" and "port.pin", etc.), so it's not possible to use a lookup for "octave_number" and then: PWMOUT octave_number,2,b4,b5 etc..

However, presumably it is still possible to use something like:
Code:
ON octave_number GOSUB oct1,oct1,oct3,oct3 ... etc,
; .........
oct1: PWMOUT PWMDIV64,2,b4,b5      : RETURN
oct3: PWMOUT PWMDIV16,2,b4,b5      : RETURN
Cheers, Alan.
 

hitsware

Member
> Isn't it simply that normally it's more appropriate to change the division factor than use short PWM cycles?

It's because of the loss of ability to fine tune the frequency with low numbers.
The ratio of 255 to 254 is a lot differant than 3 to 2 :eek:
OK for me (in this case) as long as I'm not trying to tune to standard pitch or a
particular key ....

> ON octave_number GOSUB oct1,oct1,oct3,oct3 ... etc,
> ; .........
> oct1: PWMOUT PWMDIV64,2,b4,b5 : RETURN
> oct3: PWMOUT PWMDIV16,2,b4,b5 : RETURN

YES ! ..... :p ...... That'll do it !
 

oracacle

Senior Member
if you still need to get the numbers and don't don't wont use the suggested maths routines, then the other option would require the steep learning curve of the uM-FPU with both 32 and 64 bit variants available. both should be sub 10ms maths times one the data is onto the chip. providing the final answer never exceeds a the max values of the pwm comand
 

hitsware

Member
> if you still need to get the numbers and don't don't wont use the suggested maths routines,
> then the other option would require the steep learning curve of the uM-FPU
> with both 32 and 64 bit variants available. both should be sub 10ms maths times
> one the data is onto the chip. providing the final answer never exceeds a the max
> values of the pwm comand

Or one of these : http://geoffg.net/micromite.html

2 pwm frequencies

3 duty cycle on 1 frequency and 2 on the other frequency
 

oracacle

Senior Member
one of theses: http://micromegacorp.com/umfpu-v3.html
it can use it with about any PIC system providing it can handle either SPI or i2c, it wont output the PWM directly but is able to handle, byte, word and long word maths meaning that restriction on maths are removed. Also being floating point it can deal with decimal (it will allow you to round if you need to). there are some thing that may complicate initial design, like the steep learning curve and the fact its an extra part.

I used on in the macro rail to calculate depth of field, distances and number of steps for the stepper motor. I also used one to show a friend how quickly some fairly basic hardware and a simple-ish algorithm can find prime numbers a lot faster than the average human can.

you maybe able to use a user defined function (never done it myself) to help speed things up but you will always have the i2c overhead
 

hitsware

Member
Thank You All ! Works Nicely !

http://home.comcast.net/~mnjmiller/3isle3.mp3
Code:
eeprom (8,6,9,6, 2,5,3,4)
b9=85
do
	for b0=0 to 3: read b0,b1
		for b2=4 to 7: read b2,b3
			random w8
			b4=w8//3 
			b5=2840/b1/b3
			b6=b5 -1
			w9=2*b6 +2
			if b2=6 then serout 0,n2400,(b9):endif
			on b4 gosub left, right, center
			pause 250
		next b2: next b0
	loop
			left:
			pwmout 2,b6,w9
			pulsout 1, 200
			return
			right:
			pwmout pwmdiv4,2,b6,w9
			pulsout 4,200
			return
			center:
			pwmout pwmdiv16,2,b6,w9
			pulsout 1,200: pulsout 4,200
			return
 

Attachments

Top