PWM, updated object using overlapped cog counters
Tracy Allen
Posts: 6,664
A couple of weeks ago there was a question about generating conventional PWM at frequencies of 100kHz and above using the P1. I recalled an object I'd put in the OBEX that used the cog counters to accomplish that but found I hadn't quite gotten the details quite right. It should work okay at higher frequencies than is possible with a pasm loop, but as written it was not up to potential. I had some time today to pursue it a little more and to improve the dynamic range. It is a common issue of making the two counters end up at exactly the desired phase despite the lag between the two instructions that start them.
I also did a version that starts a pasm cog to set up the counters. In that case, the lag is only 4 clock ticks. The PWM is not any better or worse than the Spin-only version, but I think it allows more options for expansion.
Updated code at http://obex.parallax.com/object/482.
' counters are stopped as the following instructions execute to restart them phsa := 0 phsb := phsa + (42949673*percent)+(phaseStep*400) frqa := phaseStep frqb := phaseStep ' same frequency both channelsIt takes 400 clock ticks to execute the frqb := frequency command in Spin, and during those 400 clock ticks the phase advances (400*phaseStep). That is added to the desired phase offset between the two cog counters that are OR'd together to generate the PWM. 400 ticks at high frequency is quite a lot. Say, that is a complete trip through the phase accumulator at 200kHz when clkfreq=80MHz. But even at 1MHz and the above PWM works out okay (but with decreasing resolution of course).
I also did a version that starts a pasm cog to set up the counters. In that case, the lag is only 4 clock ticks. The PWM is not any better or worse than the Spin-only version, but I think it allows more options for expansion.
mov t1, f_step ' this is the phase increment at each clock tick shl t1, #2 ' allow 4 ticks during execution of the mov frqb,f_step instruction add t1, p_offset ' add the desired phase offset mov phsb, t1 ' apply it to ctrb mov frqa, f_step ' now start ctra mov frqb, f_step ' now start ctrb, ctra will already have 4 ticks
Updated code at http://obex.parallax.com/object/482.
Comments
That is what it is doing. Except that the implementation sets up the phase and counter registers earlier when frqb and frqa are equal to zero, then sets frqa and frqb to their final non-zero values to activate the pwm.
(I see a comment about stopping counters)