Shop OBEX P1 Docs P2 Docs Learn Events
PWM Capability — Parallax Forums

PWM Capability

th9xth9x Posts: 11
edited 2012-12-29 16:02 in Propeller 1
Hi,

So I have just stumbled across the P8X32 processor due to this site infact:

http://hackaday.com/2011/03/28/open-source-wireless-mesh-networking-energy-meter/

I digress, I have a possible project in mind, a fan controller. I have read the datasheet but I'm not sure I'm reading it right. I need to know how many PWM channels I can get, is it two per core ? Also how fast frequency wise can I drive them (more important), and what sort of resolution are they (less important) ?

They are just going to be used to drive buck converters, I would like to keep the component footprints small so higher frequency PWM is preferred.

Thanks.
--
Cam
«1

Comments

  • jmgjmg Posts: 15,173
    edited 2012-12-27 11:36
    th9x wrote: »
    I need to know how many PWM channels I can get, is it two per core ? Also how fast frequency wise can I drive them (more important), and what sort of resolution are they (less important) ?

    Cam

    Browse the OBEX ?
    This one looks useful ?
    http://obex.parallax.com/objects/359/

    PWMx8 : Provides up to 8 channels of fast PWM output per cog, generated by the Propeller's video circuitry.
  • th9xth9x Posts: 11
    edited 2012-12-27 11:57
    Wow thanks for the quick reply, looked like a very useful bit of code but too slow a frequency. My fault, I should have said in my first post, something upwards of 200Khz for the PWM frequency would be ideal. Resolution less important but 128 to 256 ish.

    From reading the code:
    '' This Propeller object provides up to eight leading-edge-aligned PWM channels
    '' with resolution determined by a defined constant. The maximum PWM frequency
    '' is the lesser of:
    ''
    ''    clkfreq / (13.5 * resolution) and 20.648881 / resolution MHz
    

    So my reckoning using the max clock of 80Mhz

    80,000,000/(13.5 * 256) = 23.148 Khz
    20.648881 / 256 = 0.0865 Mhz = 86.5 Khz

    So the lesser is 23.148Khz. Shame really liked the idea of 8 PWMs per core.

    Cam.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-27 12:18
    What other requirements do you have? Is it ok that PWM-channels have always the same frequency (in pairs)? How many PWM channels do you need?

    Then you can use the counters and a little piece of code, which gives you 2 PWMs per COG. 200kHz is 400 clock-cycles, which is 100 PASM instructions, so a COG dedicated to PWM-generation can not do much more. Resolution would be 400.

    Another possibility is to use 2 counters, 2 pins per PWM and an external XOR to have one PWM per COG. Difference is, that this would allow to run other code while the counters generate the PWM autonomously. Only changing the pulse width needs some caretaking code.
  • jmgjmg Posts: 15,173
    edited 2012-12-27 12:37
    MagIO2 wrote: »
    Another possibility is to use 2 counters, 2 pins per PWM and an external XOR to have one PWM per COG. Difference is, that this would allow to run other code while the counters generate the PWM autonomously. Only changing the pulse width needs some caretaking code.

    Expanding on this idea, it should be possible to have a shared (master) phase, from half a cog, and then other cogs can phase adjust from that, to allow 2 PWM per COG.

    Sync could be from either the Master Pin, or via CNT, which everyone can read.
    Then 8 channels would use be 4 1/2 COGs timers, and a whole chip could manage 15 channels..
  • th9xth9x Posts: 11
    edited 2012-12-27 12:40
    Oh I did get the wrong idea. I had assumed (no doubt due to dealing with more conventional processors) that the hardware counters could produce PWM without any other hardware or software. It appears I am at the bottom of the learning curve again. I was hoping for 12 PWM channels, and configurable in pairs to work at either 20Khz or 200Khz. I hoped for even faster than this though.
  • th9xth9x Posts: 11
    edited 2012-12-27 12:43
    jmg wrote: »
    it should be possible to have a shared (master) phase, from half a cog, and then other cogs can phase adjust from that

    So the master clock gives the frequency ? and the other clocks give the period ?
  • jmgjmg Posts: 15,173
    edited 2012-12-27 13:03
    th9x wrote: »
    So the master clock gives the frequency ? and the other clocks give the period ?

    Very close, you do need an external XOR per chan, as mentioned in #4, but now one timer is fixed as a master Freq, and that never changes.
    The other active COGs change the Phase, relative to that master, and that phase sets the PWM %, which can have any value 0..100%
    Prop counters are really 32 bit adders.

    There is no per-cycle maths needed, so you can resolve to what the timers can, (12.5ns), but to avoid jitter issues it would be best to stay Binary on the master clock. ( ie 312.500KHz @ 256 or 625.000 KHz @ 128 )
    SW intervention is needed only on a change in duty cycle.
    I had assumed (no doubt due to dealing with more conventional processors) that the hardware counters could produce PWM without any other hardware or software. It appears I am at the bottom of the learning curve again. I was hoping for 12 PWM channels, and configurable in pairs to work at either 20Khz or 200Khz. I hoped for even faster than this though.

    Prop 2 fixes that, with a true PWM mode, but a Prop 1 should allow full-range, 1 clk granularity on up to 15 channels (with an external HCT86 for every 4 chans )
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-27 14:00
    All counters will run at the same frequency. So, it's a master in the sense that it gives you a reference signal and all the other counters will be phase-shifted. The phase-shift together with the XOR gives you the PWM.
    So, if you need 2 different frequencies you need 2 masters ... removing counters from the PWM pool ;o)

    The nice thing with the masters is, that these never need any maintenance, just fire them up!

    16-2 => 14 PWM-channels @ 2 different frequencies
    16-3 => 13 PWM-channels @ 3 different frequencies
  • tonyp12tonyp12 Posts: 1,951
    edited 2012-12-27 14:56
    th9x
    though the 16 counters does have PDensityM (refered to as Duty), a high level is fixed at 12.5ns so only useful for RC circuits as it's to fast for much anything else.

    Using external gates you could use a few NCO (square wave) in different syncs to create the Pulse-WIDTH-Modified signal.
    Or simple use software as the Prop is fast and time-deterministic.
  • jmgjmg Posts: 15,173
    edited 2012-12-27 15:27
    th9x wrote: »
    Oh I did get the wrong idea. I had assumed (no doubt due to dealing with more conventional processors) that the hardware counters could produce PWM without any other hardware or software. It appears I am at the bottom of the learning curve again. I was hoping for 12 PWM channels, and configurable in pairs to work at either 20Khz or 200Khz. I hoped for even faster than this though.

    You can probably tolerate non phase aligned PWMs if you are driving FANs, so a variant of the example here (from page 7, NCO mode, Pin = PHSA[32] )

    http://www.parallaxsemiconductor.com/an001
    :loop      ' AN001 
        rdlong    value, par     'get an up to date pulse width from main memory 
        waitcnt   time, period   'wait until next period = 12.5ns granular 
        neg       phsa, value    'back up phsa so that it trips "value" cycles from now Pin = PHSA[32]
        jmp       #:loop         'loop for next cycle
    

    becomes something like
    :loop      ' expanded AN001 
        rdlong    PwmVal_Ch1, RegAdrCh1  'get an up to date pulse width from main memory 
        rdlong    PwmVal_Ch2, RegAdrCh2  'get an up to date pulse width from main memory 
        waitcnt   time, period           'wait until next period = 12.5ns granular , and granular from here 
        neg       phsa, PwmVal_Ch1       'back up phsa so that it trips "value" cycles from now, Pin = PHSA[32]
        neg       phsb, PwmVal_Ch2       'back up phsb so that it trips "value" cycles from now, Pin = PHSB[32]
        jmp       #:loop         'loop for next cycle    
    

    This reloads the adder output once every Period, and the Pin is the Adder MSB, so the reload value needs to be close to a MSB edge.
    For Period values of 256, we can say :
    a) A reload value of less than -256, will give PHSx[32] always hi, so is 100% Hi
    b) A reload value of less than 2^31-256, will give PHSx[32] always lo, so is 100% Lo

    You can reload close to either edge, for PWM; the example above reloads near the falling edge
    Within the reload range, the narrowest finite pulse width, will be a single clock Hi, or Low.
    Loading -255 will be 255 clocks Hi, and overflow right before the WAITCNT+NEG reloads a new -265 == single clk low.
    Loading -1 will output one clk-width high, and low for 255, until it reloads again.

    This makes the rising edge aligned with the NEG opcode, thus PHSB will be 4 clks later than PHSA.

    Both PHSx edges are also phased to the WAITCNT, so some housekeeping to do more than just CNT+Period, could start each COG with a more predictable phase between COGs

    In some systems, like LED drivers, such edge miss-align is considered a benefit as it avoids large current steps.

    On other designs, where you can expect a narrow-ish PWM range, (as in multi phase SMPS), then a deliberate coarse phase shift can reduce ripple current levels.
    eg if you expect your FAN PWM to be ~25% when stable, you can phase 4 cogs to be each ~25% shifted for best current profiles over 8 fans.
  • th9xth9x Posts: 11
    edited 2012-12-27 15:58
    OK, I understand the clocks and phase shifted clocks and therefore the need for the XOR. I take it you XOR master clock with phase shifted clock to generate the PWM ?

    The last post by "jmg" is still sinking in.

    Meanwhile can someone further explain this:
    though the 16 counters does have PDensityM (refered to as Duty), a high level is fixed at 12.5ns so only useful for RC circuits as it's to fast for much anything else.

    I don't really follow, the shortest high level duration is fixed @ 12.5ns ??
  • jmgjmg Posts: 15,173
    edited 2012-12-27 16:15
    th9x wrote: »
    Meanwhile can someone further explain this:
    "though the 16 counters does have PDensityM (refered to as Duty), a high level is fixed at 12.5ns so only useful for RC circuits as it's too fast for much anything else."
    I don't really follow, the shortest high level duration is fixed @ 12.5ns ??

    That is a different timer mode, less suited to Power Drivers, as it has more edges. - so it is not classic PWM.
  • th9xth9x Posts: 11
    edited 2012-12-27 17:12
    jmg wrote: »
    You can probably tolerate non phase aligned PWMs if you are driving FANs, so a variant of the example here (from page 7, NCO mode, Pin = PHSA[32] ) ........

    Again pardon my ignorance, for that's exactly what it is. I'm really just trying to evaluate if getting a development board is worth it for this project. Some final questions to condense my knowledge:

    • Using the "expanded AN001" method and a couple of master clocks at differing frequencies then I can have two PWM frequencies to pick from per pair of PWM outputs ?
    • Each pair of PWM outputs consumes a cog ?
    • I can have 1 COG doing master frequencies, without a processor overhead, and 7 COGs maintaining the phase shifted clocks and thay are waiting for most of their clock cycles ?
    • What frequency range can I have for the master clocks ?
    • I XOR the master clock with the phase shifted output to get my PWM ?
    • So isn't this dual master clock going to be complicated requiring more glue logic for XORing the signals ?

    Thanks so far for all the help. I can see now why this isn't a straight up spec for these devices, they seem more like an FPGA multi core device than conventional processor like.
  • MicksterMickster Posts: 2,694
    edited 2012-12-27 17:18
    Missed several posts.
  • th9xth9x Posts: 11
    edited 2012-12-27 17:27
    200Khz PWM is out of the bounds of most normal microprocessors, PICs AVRs etc, using it gives me smaller inductors, smaller caps, therefore smaller board size, and cheaper PCB costs. Higher switch losses but there seem to be plenty of capable devices. "Ideal" was probably the wrong word, ball park was probably a better choice. Some current buck regulators are using frequencies as high as 6Mhz that I have spotted, I know this is very likely out of the hobbyist reach at the moment and certainly mine, so I was aiming low. I would like to try up to 500Khz, but 200Khz gives me the sort of board size I was after. I'm just experimenting really.
  • MicksterMickster Posts: 2,694
    edited 2012-12-27 17:31
    th9x wrote: »
    Wow thanks for the quick reply, looked like a very useful bit of code but too slow a frequency. My fault, I should have said in my first post, something upwards of 200Khz for the PWM frequency would be ideal. Resolution less important but 128 to 256 ish.

    From reading the code:
    '' This Propeller object provides up to eight leading-edge-aligned PWM channels
    '' with resolution determined by a defined constant. The maximum PWM frequency
    '' is the lesser of:
    ''
    ''    clkfreq / (13.5 * resolution) and 20.648881 / resolution MHz
    

    So my reckoning using the max clock of 80Mhz

    80,000,000/(13.5 * 256) = 23.148 Khz
    20.648881 / 256 = 0.0865 Mhz = 86.5 Khz

    So the lesser is 23.148Khz. Shame really liked the idea of 8 PWMs per core.

    Cam.
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-12-27 18:34
    You would probably, actually, be fine with 32 levels of precision output, which will put you over 200KHz with the PLL8x driver, if you run at 96 or 104MHz (both of which have proven stable for everyone who has tried). I have a 12MHz crystal soldered to my quickstart board, and I use PLL8x with no issues.
  • jmgjmg Posts: 15,173
    edited 2012-12-27 18:46
    th9x wrote: »
    Again pardon my ignorance, for that's exactly what it is. I'm really just trying to evaluate if getting a development board is worth it for this project. Some final questions to condense my knowledge:


    [*]Using the "expanded AN001" method and a couple of master clocks at differing frequencies then I can have two PWM frequencies to pick from per pair of PWM outputs ?

    I'm not sure why you want different frequencies for Fan PWM ?
    [*]Each pair of PWM outputs consumes a cog ?
    Yes.
    [*]I can have 1 COG doing master frequencies, without a processor overhead, and 7 COGs maintaining the phase shifted clocks and thay are waiting for most of their clock cycles ?
    Yes, with external xor added case
    [*]What frequency range can I have for the master clocks ?
    In Master mode case, it would be best to stick with binary divides of 80MHz. At least to start with.
    [*]I XOR the master clock with the phase shifted output to get my PWM ?
    Yes, for the external xor case.
    [*]So isn't this dual master clock going to be complicated requiring more glue logic for XORing the signals ?

    Thanks so far for all the help. I can see now why this isn't a straight up spec for these devices, they seem more like an FPGA multi core device than conventional processor like.

    Yes, which was why I suggested the modified AN001, which does not need XORs . (or any master )

    I think you can tolerate phase not-aligned across PWM drives as they go to separate FANS, and in some cases that is a plus.
  • altosackaltosack Posts: 132
    edited 2012-12-27 22:06
    Hi Cam,

    I noticed that upthread you said that 200 KHz is not achievable with AVRs and PICs; for your required resolution of 256 (128 ?), it certainly is. I'm not sure if you need a through-hole chip or if you need the PWM outputs to be phased; here's a list of the capabilities of several possibilities:

                            PWM MHz     KHz @ 256   PWM outputs     Phased outputs    Package
    
    P8x32A (6.25 MHz Xtal)    100          391          14                14           DIP40
    dsPIC33FJ16GS502*        960/40      3750/156     10 (8/2)            8/2          SPDIP28
    dsPIC33FJ64GS406         960/40      3750/156     16 (12/4)          12/4          TQFP64 (0.5mm)
    dsPIC33FJ64MC202          80/40       313/156     12 (8/4)             4           SPDIP28
    dsPIC33EP64MC202         140/70       547/273     10 (6/4)            10           SPDIP28
    dsPIC33EP512MC506        140/70       547/273     24 (8/16)          8/16          TQFP64 (0.5mm)
    ATxmega64A4U              256          1000         18                 0           TQFP44 (0.8mm)
    
    *If you need 12 phased outputs in a through-hole package, you can use multiple of these chips with the PWM synchronized to each other.
    
    

    So, the propeller has the highest number of phased PWM outputs in a DIP package, which is one of the reasons I'm using it.
  • LawsonLawson Posts: 870
    edited 2012-12-28 08:49
    jmg wrote: »
    Browse the OBEX ?
    This one looks useful ?
    http://obex.parallax.com/objects/359/

    PWMx8 : Provides up to 8 channels of fast PWM output per cog, generated by the Propeller's video circuitry.

    Hm... doesn't look like there is much room to speed up the PWM8 object, but I don't see anything restricting the code to the current PWM pattern. I.e. It should work just fine outputting a dithered sequence of 16 4-bit pulses instead of one 8-bit pulse.

    Lawson
  • th9xth9x Posts: 11
    edited 2012-12-28 10:55
    jmg wrote: »
    I'm not sure why you want different frequencies for Fan PWM ?

    It's computer type fans I am after controlling so the two frequencies allow me to control 4 wire fans, which according to the specs need around 22-25Khz PWM signal and others can be two or three wire fans with my own buck convertor running faster to allow for small components.
    jmg wrote: »
    Yes, which was why I suggested the modified AN001, which does not need XORs . (or any master )
    I think you can tolerate phase not-aligned across PWM drives as they go to separate FANS, and in some cases that is a plus.

    Yes none aligned will be fine, I understood that about the modified AN001 example, I didn't grasp that it eliminated XOR's or a master clock. I really am green as grass when it comes to these propellor IC's, it isn't sinking in fast, I think I have established that what I am after is possible so a dev board should really be my next step. Much easier to learn by doing.

    If you will permit me another dumb question. Do I deduce from your comment the original AN001 code you posted does need a master clock and an external XOR ?
    altosack wrote: »
    Hi Cam,
    I noticed that upthread you said that 200 KHz is not achievable with AVRs and PICs; for your required resolution of 256 (128 ?), it certainly is.
    Sorry I always forget about dsPICs due to not using them much/at all. I did know about the ATXmegas, I think I just got a little excited about this whole different and exciting sounding world that has obviously been around a while but slipped by me and opened my mouth early, sorry.
    Lawson wrote: »
    Hm... doesn't look like there is much room to speed up the PWM8 object, but I don't see anything restricting the code to the current PWM pattern. I.e. It should work just fine outputting a dithered sequence of 16 4-bit pulses instead of one 8-bit pulse.

    Lawson

    Are you talking about what is sometimes called Bit Angle Modulation (BAM) or Binary Code Modulation ?
    You would probably, actually, be fine with 32 levels of precision output, which will put you over 200KHz with the PLL8x driver, if you run at 96 or 104MHz (both of which have proven stable for everyone who has tried). I have a 12MHz crystal soldered to my quickstart board, and I use PLL8x with no issues.
    Hmmm, ok thanks, you could be right in that I am probably being greedy with resolution, time for trying things out I think.
  • pik33pik33 Posts: 2,367
    edited 2012-12-28 11:32
    http://forums.parallax.com/showthread.php?141346-Yet-another-wave-player-now-NCO-based-and-noise-%28almost%29-free&highlight=wave

    Here you can find a wave player object using real 8-bit NCO PWM @ about 300 kHz - maybe this can help
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-28 12:02
    The PWM mentioned in AN001 needs no master clock and no XOR, but it needs the COG to take care of the PHSA-register according to your PWM frequency.

    The Counter has 32 bit. So, the higher the frequency, the lower the resolution and vice versa.

    8bit resolution gives you a frequency of 80_000_000 / 256 = 312500 Hz
    Overclocking to 100_000_000 gives you 390625 Hz
    7bit @ 80MHz allows 625000 Hz
  • jmgjmg Posts: 15,173
    edited 2012-12-28 12:03
    th9x wrote: »
    It's computer type fans I am after controlling so the two frequencies allow me to control 4 wire fans, which according to the specs need around 22-25Khz PWM signal and others can be two or three wire fans with my own buck convertor running faster to allow for small components.

    The AN001 method allows you to vary frequencies by COG pair, but of course the housekeeping is a little more complex, as the loaded Time-offset, is in clocks, not %.

    Yes none aligned will be fine, I understood that about the modified AN001 example, I didn't grasp that it eliminated XOR's or a master clock. I really am green as grass when it comes to these propellor IC's, it isn't sinking in fast, I think I have established that what I am after is possible so a dev board should really be my next step. Much easier to learn by doing.

    If you will permit me another dumb question. Do I deduce from your comment the original AN001 code you posted does need a master clock and an external XOR ?

    No, AN001 does not need XOR, in any form : it uses a skew on the Counter-Adder-edge, and a reload-every-cycle.
    My modify was simply to add a second timer load for dual PWM & note the phase skew; The code flow is identical.

    There are examples in OBEX based on AN001, so fire those up first.
  • th9xth9x Posts: 11
    edited 2012-12-28 12:10
    Right got it, AN001 eliminates XOR and master clock but has a higher CPU over head. Which is exactly what you MagIO2 mentioned in post #4. Pennies are starting to drop :)

    Think that pretty much covers the PWM ability of these chips, we have had software PWM, hardware PWM (using XOR) and a mixture of both hardware and software in the example last talked about.

    Thanks one and all !
  • jmgjmg Posts: 15,173
    edited 2012-12-28 14:19
    th9x wrote: »
    Right got it, AN001 eliminates XOR and master clock but has a higher CPU over head. Which is exactly what you MagIO2 mentioned in post #4. Pennies are starting to drop :)

    Think that pretty much covers the PWM ability of these chips, we have had software PWM, hardware PWM (using XOR) and a mixture of both hardware and software in the example last talked about.

    Thanks one and all !

    Yes, because you are pushing the switching frequency up, some hardware support is needed.
    There is a lot of code space spare, in the 1 Chan AN001, it has just 4 lines of active code, and in 2 Chan variant, that is just 6 lines.

    At PWM rate of /128, and (nominal) 4 clks per opcode, or 8..23 for Hub access (RDLONG) you have a time budget of up to 32 base opcode times. ( at /256, this grows to 64 base opcode times)

    You have plenty of code space per COG, and with care, you have enough time-space too, to implement the ideas mentioned like dithering.
    Google Rate Multipliers to get an idea on bit-density ( ie when to do a dither), and in a Prop, you can naturally dither fractions to N/32, N/16, N/8, N/4 etc, and at 80Mhz, and /128, the dither frequency is 19.53125 KHz, so still inaudible. ( and of very low energy, as it is LSB dither).
    N/32 dither would allow you to have 12 bit (averaged) PWM precision on a Switching Base of 625KHz
    Dither itself would cost as low as 2 opcodes excluding the fetch of the Dither itself.
    A ROR Dither,#1 gets a new LSB choice bit into CY, and then CY is used to load either PWM_Value, or PWM_Value+1 so that you load alternating choice of two PWM values. Over the 32 choices, this averages to give another 5 bits of PWM precision.
    For less dither choices, simple repeat the pattern in the rotated dither register.

    Loading (update) of the Dither value could need careful interleave of RDLONGs, but as it is a LSB decision, the phase of loading is likely to be tolerated. Certainly a motor will not notice any effect :)

    AN001 also does not pass Period as a Parameter, so the most-flexible high precision PWM would pass 5 values :

    Period (common to COG ) - Sets Period of PWM, in 12.5ns steps
    Base_PWM_A - sets base HI time in 12.5ns steps
    Base_PWM_B - sets base HI time in 12.5ns steps
    Fract_PWM_A - sets N/32 fractional dither for ChA - 32 bits as pattern, 5 bits as index
    Fract_PWM_B - sets N/32 fractional dither for ChB - 32 bits as pattern, 5 bits as index

    Simple RDLONG of all of those will be time-costly, so an optimal design may move to pack or index them.
  • th9xth9x Posts: 11
    edited 2012-12-28 14:36
    Ah dithering now understood. Something else I have never encountered before. Well not for PWM.

    So a RDLONG loads data from the hubs memory and it costs 8 to 23 clock ticks ? which is 2 to 6 opcode ticks ?
  • jmgjmg Posts: 15,173
    edited 2012-12-28 15:50
    th9x wrote: »
    Ah dithering now understood. Something else I have never encountered before. Well not for PWM.

    So a RDLONG loads data from the hubs memory and it costs 8 to 23 clock ticks ? which is 2 to 6 opcode ticks ?

    Yes, see page 24 of Propeller Manual v1.2.
    The worst case is 23 cy and a slot exists every 16, so a series of RDLONGs will be 23+16+16+16 , and of the following RDLONGS, each needs 8cy for itself, which means two 'free' Opcode slots are available (or it simply waits). 8+4+4 = 16
    WAITCNT is clk-granular, so you cannot place RDLONG after WAITCNT
    Those free opcode slots mean you might choose to pack parameter passing.
  • jmgjmg Posts: 15,173
    edited 2012-12-28 16:28
    If we do typical packing, as a rough sketch of pseudo code, we get along the lines of below, using these rules
    * Pack the Params, to reduce RDLONGs needed
    * two opcodes are placed between RDLONGs, time-free.
    * Pass Dither as an index, as this saves code in Main, and COG memory is 'free' on the PWM slaves.
    It also allows param packing.

    ' Min Time: Host has to know the Array_32_Long_Ch1,Array_32_Long_Ch2  base values
    ' Host then adds the fraction 0..31, to those base values & passes 9 bits
    ' -or- lines to add  PwmVal_Ch1,#Array_32_Long_Ch1 can be added here
    ' at a cost of +4 +4  (no carry into upper 16 bits)
    ; NOT INCLUDED - start-up code
    :loop      ' expanded AN001 - Dual PWM and N/32 Dither and Full param  
        rdlong    PwmVal_Ch1, RegAdrCh1     '+23 8..23  Pack Time(16b) + Fraction(5b.IDX + 9b.Reg Base)
    ' optional    add  PwmVal_Ch1,#Array_32_Long_Ch1   
        movd      RegAdr_ROR_A, PwmVal_Ch1  '    (4) patch index into Ch1 Dither table into ROR opcode
        ror       PwmVal_Ch1,#16            '    (4) Upper 16 bits are PWM_Time
        rdlong    PwmVal_Ch2, RegAdrCh2     '+16
    ' optional    add  PwmVal_Ch2,#Array_32_Long_Ch2   
        movd      RegAdr_ROR_B, PwmVal_Ch2  '    (4) patch index into Ch2 Dither table into ROR opcode
        ror       PwmVal_Ch2,#16            '    (4) Upper 16 bits are PWM_Time
        rdlong    PwmVal_Per, RegAdrCh2     '+16
        waitcnt   time, PwmVal_Per          '+6  +nC  wait until next period = 12.5ns granular , and granular from here 
    :RegAdr_ROR_A    
        ror       RegAdr_ROR_A,#1           '+4  CY = dither decision,A
    '.. tbd code to load PHSA with PwmVal_Ch1, or PwmVal_Ch1+1, based on CY
    :RegAdr_ROR_A    
        ror       RegAdr_ROR_B,#1           '+4  CY = dither decision,B
    '.. tbd code to load PHSB with PwmVal_Ch2, or PwmVal_Ch2+1, based on CY
        jmp       #:loop                    '+4  loop for next cycle
                                            '  = 73, at /128 have MAX of 128, 55 cy budget.
                                            '   { 81 with Add index offset in COG, 47 cy budget }
    :Array_32_Long_Ch1                                        
    ' 32 Long array, register Constant Patterns for Ch1, 
    :Array_32_Long_Ch2                                        
    ' 32 Long array, register Constant Patterns for Ch2, 
    ' These rotate in-place, for speed, so cannot share  
    
    

    and with one version of CY handling, and the index add done locally included, as we still have time-budget (I think ?)
    ' Min Time: Host has to know the Array_32_Long_Ch1,Array_32_Long_Ch2  base values
    ' Host then adds the fraction 0..31, to those base values & passes 9 bits
    ' -or- lines to add  PwmVal_Ch1,#Array_32_Long_Ch1 can be added here (shown)
    ' at a cost of +4 +4  (no carry into upper 16 bits)
    
    :loop      ' expanded AN001 
        rdlong    PwmVal_Ch1, RegAdrCh1     '+23 8..23  Pack Time(16b) + Fraction(5b.IDX )
        add       PwmVal_Ch1,#Ary_32L_Ch1   '    (4)  ' optional, if cycles tight ( Add 9b reg base ) 
        movd      RegAdr_ROR_A, PwmVal_Ch1  '    (4) free time pass index into A_Jitter table into opcode
        rdlong    PwmVal_Ch2, RegAdrCh2     '+16 (8) <- keep MOD16 from prev RDLONG
        add       PwmVal_Ch2,#Ary_32L_Ch2   '    (4) optional, if cycles tight  ( Add 9b reg base ) 
        movd      RegAdr_ROR_B, PwmVal_Ch2  '    (4) free time pass index into A_Jitter table into opcode
        rdlong    PwmVal_Per, RegAdrCh2     '+16 (8) <- keep MOD16 from prev RDLONG
        sar       PwmVal_Ch2,#16            '+4   Upper 16 bits are PWM_Time, ror or sar
        sar       PwmVal_Ch1,#16            '+4   Upper 16 bits are PWM_Time, ror or sar
        waitcnt   time, PwmVal_Per          '+6  +nC  wait until next period = 12.5ns granular , and granular from here 
    :RegAdr_ROR_A    
        ror       RegAdr_ROR_A,#1           '+4  CY = new dither decision, A
        addx      PwmVal_Ch1,#0             '+4  Add 1 based on CY Dither, reloads every PWM
        neg       PHSA, PwmVal_Ch1          '+4  back up phsa so that it trips "value" cycles from now
    :RegAdr_ROR_B    
        ror       RegAdr_ROR_B,#1           '+4  CY = new dither decision,B
        addx      PwmVal_Ch2,#0             '+4  Add 1 based on CY Dither, reloads every PWM
        neg       PHSB, PwmVal_Ch2          '+4  back up phsb so that it trips "value" cycles from now
        jmp       #:loop                    '+4  loop for next cycle
                                            '    97 with Add index offset in COG, 31 cy budget 
    :Ary_32L_Ch1                                       
    ' 32 Long array, register Constant Dither Patterns for Ch1, 
    :Ary_32L_Ch2                                       
    ' 32 Long array, register Constant Dither Patterns for Ch2, 
    ' These registers rotate in-place, for speed, so cannot share, so simply use 2 tables.   
    

    There will now be a fixed and stable 12cy skew between PWM edges, Ch1 and Ch2
    Size is 17 opcodes for loop, + 32L + 32L for patterns, and whatever Init code is needed.

    Result should be 2 chans of 12 bits of average PWM, (7b+5b) with 625KHz Freq
    Edit : option of sar for ror, to allow sign extend and the !MSB passes into the Pin, for values outside of period from a count boundary, the pin is static dc, H or L.
  • th9xth9x Posts: 11
    edited 2012-12-28 16:54
    OK, starting to get the idea now, I am still not completely familiar with the opcodes but enough to see the idea. You have packed duty and dither into the same 32bit variable just by bit shifting and adding, then bit shift them out again. Not sure what 9b.Reg Base is ?

    An idea of my own,,,, as the update of my PWM duty does not need to be every cycle things could be eased by alternating the between RDLONGing new Ch1 and Ch2 values, you think ? Although somewhat complicated by the dithering, but even then we could only refresh every 16th time.
Sign In or Register to comment.