PWM Controller Register Guide

= PWM = There are two 16-bit up counters in the A10 SoC. Counters will reset when PWM_CH0_PERIOD/PWM_CH1_PERIOD has been reached. On initialization PWM_OUT is active high and starts counting from 0x0000.

The PWM divisor devides the 24MHz clock by 1-4096 depending on the PWM_CTRL register.

There are two output modes, cycle mode and pulse mode which are either, a square waveform or a postive/negative pulse, based on the frequency in the PWM_CH0_PERIOD/PWM_CH1_PERIOD register.

Observed behaviour on GR8 from NextThing
In this section, clock cycles refers to the 24 MHz divided by the current prescaler. With the default prescaler of 120, a clock cycle is 5 microseconds.

GR8 has two PWM channels.

In pulse mode, sending a pulse (time between starting and when the bit has been cleared) takes the time it should take + 1-2 clock cycles.

Writing the period register (between starting and the ready bit has been cleared) takes 3-4 clock cycles. If the register is written while the clock gating is off, the ready bit will stay busy until the clock gating is turned on (and 3-4 clock cycles have passed).

Time needed between disabling PWM and disabling the clock gate to make sure the PWM is actually turned off: 1-2 clock cycles. Otherwise the output signal may be stuck in the active state if it was turned off when the signal was active.

A pulse (regardless of single pulse or cycle mode) always starts with the inactive part, followed by the active part, contrary to what the user manual says.

The polarity register can always be written to, even when the clock gate is off, and will be applied immediately.

In cycle mode, writing 0 to EN and then 1 to EN resets the pulse, i.e. it will immediately perform the inactive part and then the active part and repeat. Same applies if 1 is written to MODE followed by 0. Note that at least 1 clock cycle should be slept between the two writes. By only temporarily disabling the clock gating, that rather just pauses the PWM.

In cycle mode, after a new value has been written to the period register, a complete pulse with the old parameters must first occur, regardless if the PWM is disabled and then enabled, prescaler is changed, clock gate is toggled. The new values are applied as soon as the active part of a complete pulse ends. If the PWM is enabled when the period register is written, it may thus take up two pulse lengths before the new settings are applied. Also note that if the prescaler is also changed in conjunction with the new period/duty values, for this complete pulse the old period/duty will be used with the new prescaler, which might lead to a very long period. The only way to clear the previous internal values without the need to wait one pulse with the previous settings seems to temporarily switch to pulse mode. After the period register has been written, sending a single pulse will use the new values immediately. After the single pulse has been sent and switching back to cycle mode, the new values are used (and not the old ones). So a simple workaround when changing the period register is to first write 0x00000000 to the period register (entire period is then one 1 clock cycle and active part is 0 clock cycles), switch to pulse mode and send a single pulse, write the desired value to the period register and then switch to cycle mode.

Note that with the prescaler of 72k, one clock cycle is 3 ms, which depending on use case, might be a long time. If one wants to perform an operation quicker than the timings according to the clock cycle timings mentioned above, one could temporarily change the prescaler to the smallest available. If the prescaler of 1 is available (like it is on GR8), one clock cycle is around 42 nanoseconds.

Info
PWM Base address: 0x01c20e00

PWM_CTRL
Default value: 0x00000000

Offset: 0x00

PWM_CH0_PERIOD
Default value: 0x00000000

Offset: 0x04

PWM_CH1_PERIOD
Default value: 0x00000000

Offset: 0x08

default map
md 0x01c20e00 3 01c20e00: 00000000 00000000 00000000   ...........

all to 1
mw 0x01c20e00 0xffffffff 3

md 0x01c20e00 3 01c20e00: 007f80ff 00ff00ff 00ff00ff   ............

all to 0
mw 0x01c20e00 0x00 3

md 0x01c20c00 3 01c20c00: 00000000 00000000 00000000   ............