Overview of Counters on the Propeller
So @RoyEltham and @whixr are always telling me to go back and listen to previous First Spin episodes, especially for topics such as counters on the Propeller. They're used for things such as PWM, sigma-delta modulation (ADC and DAC), and probably curing cancer by the sound of it! I thought I'd write out what I understand about them and maybe give myself a reference. And uber thanks to Roy for his help when I got stuck:
So each cog has two counters - CTRA and CTRB. Each counter has a FRQx and PHSx (and also PLLx) associated with it. The counter itself can control/monitor up to 2 I/O pins and with every clock cycle, whatever value is in FRQx adds to the running total in PHSx.
Put another way, the PHSx register is the accumulator that stores the counter's current value. The FRQx register holds the value that is added to the accumulator whenever an "accumulate condition" is TRUE. The accumulate condition is determined by the mode of operation set by CTRMODE. Pass go, collect $200.
Using CTRA (physically typing this out in code) sets the mode that the counter operates under with the below four categories - CTRMODE, PLLDIV, BPIN, and APIN - and the locations of these are shown within a 32 bit command (ie bits 30..26 or 5..0):
So the bits under APIN determine when the target Propeller pin will turn on.
First, some background for APIN options (0, PHSx[31], PHSx-Carry):
So say you're doing binary and you're adding to this 32bit number to fill up all of the bits. Then you add 1 to this number; it will clear the lower bits and turns the topmost one ON (like 011 to 100 below).
Example: 000 > 001 > 010 > 011 > 100 > 101 > 111
With an APIN mode of PHSx[31] - whenever that top bit is turned on, the target pin will be ON. You can see that the top bit is on half of the time, therefore the target pin is ON half of the time, off half of the time.
Now say you're dealing with an APIN of PHSx-Carry:
If you accumulate past the maximum of what the 32bit number can hold, say you keep accumulating to get to 33bits, then a "carry flag" is set. And as soon as another operation is done, the carry flag will be cleared/set by something else.
Example: 000 > 001 > 010 > 011 > 100 > 101 > 111 > Flag > 000 > 001 >...
Say you have a large value in FRQx, each time you add that large value to PHSx, you might overflow what 32bits can represent, and so set the carry bit. So the target pin would stay ON for as long as you keep overflowing. But at some point it will get to a point where you will add and it won't overflow that time. The target pin would then turn OFF.
Example. Say $F000_0000 is in FRQx. The first time you add it to PHSx, it won't carry (in a 32bit value), so the pin will be low. The next time you add it will carry so the pin will be high. But now the value in PHSx is $E000_000 and you add $F000_0000 and it overflows so it stays high, and does so for 14 more times. You can adjust the value in FRQx to have a certain ratio for on vs off (duty cycle style).
This would also theoretically make the pin turn on and off really quickly if it took a while for accumulation and wrap to occur.
And then if APIN is 0, that means that there's no output and that the particular mode is going to READ the target pin.
You see that sometimes BPIN has a setting in it. Essentially if you are driving APIN, if you configure BPIN, then BPIN'll always be the inverse of APIN. But if you setup the counters to read the pins and count pin actions, then you can use logic operations with APIN and BPIN. Examples:
You can have it count each time that APIN is high OR BPIN is high.
Or all of the times that A does not equal B etc.
Interestingly, when BPIN is the inverse of APIN, that's what they call "differential mode". And single-ended is just driving APIN.
(Refer to AppNote Diagram 1) So when you have wrapping of PHSx[31] in any mode (as determined by FRQx accumulating in PHSx), that result goes into the PLL, and the PLL output option determines how often APIN toggles on and off.
Let's say PLL input is 4Mhz (most reliable is 4-8MHz). The PLL will always take the input rate (4MHz in this case) and multiply it by 16. And then you will get PLL output options in 1x, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, and 1/128 options:
(Input x 16)/PLLDIV where PLL DIV = 1, 2, 4, 8, 16, 32, 128. (And even then, technically, the real value in PLLDIV is 0-7 where 0 = 128 and 7 = 1).
The 3bit field PLLDIV you code selects one of these eight PLL outputs and the PLL output you choose will go to APIN so the APIN will toggle at that rate.
You might ask how do you calculate FRQx so that PHSx wraps around at the rate you want (whether 4Mhz or 8Mhz):
80Mhz system clock, 32 bit value
4Mhz = 80mhz / x where x = 20
So 2^32 / x = 2^32 / 20 = value to put into FRQx
So now we know what you put in PLLDIV, what it does for the modes. We know when APIN is on depending on what is placed in that field. We also know what BPIN can be used for. I originally wanted to divide this into one big post, but then that'd force folks to look at different posts when one reference link is more beneficial. So apologies for the length of this post!!