I am evaluating the Ambiq Apollo3 MCU for potential future projects but a large part of our requirements centers around PWM performance. I have been pouring over the SDK and manual and have some code working to generate PWM on pin 18 pad 26, timer 0, Segment B and AUX output. B0OUT2 as per the datasheet, FNCSEL:0x02, CFGx:0x02 (basically pin 18 of Thing Plus with Artemis).
I am observing a few strange occurrences.
the PERIOD written to the register according to am_hal_ctimer_aux_period_set(). I can read back the PERIOD register CMPRAUXB0>>16 (or CMPRB3) and it is reads back as 0xFFF or 12bit (4096 steps). But the counter counts until 16bit (65536 steps) so as I step through the 4096 steps of my 12bit (CMPRB2) there is along period between the pulses because the counter is NOT resetting at match to CMPRAUXB0>>16 (or CMPRB3).
Randomly the PWM inverts so the short HIGH DUTY becomes a short LOW DUTY and nothing is changing other than updating CMPRB2 to the new DUTY. It seems to be random as it will go through a few cycles then invert and then hold for a while then invert. It does seem to only invert when in the smaller ranges of DUTY. I have code sweeping the range up and down (increasing then decreasing DUTY (CMPRB2)). I do not know what is causing this since the POL bit is not being touched, I can see glitches of HIGH as the DUTY is decreased with it fully inverting from time to time.
I don’t know if anyone else has been experimenting with generating PWM from the timers who could provide some insight.
This issue applies to all current Apollo devices (Apollo, Apollo2, Apollo2 Blue, Apollo3 Blue). A software implementation to address the issue is automatically handled with SDK revision 2.3.0 or later. However, if working with SDK revision 2.2.0 or earlier, then you should make a call to am_hal_ctimer_clear() before any Ctimer configuration such as am_hal_ctimer_config_single(), am_hal_ctimer_config(), or am_hal_ctimer_config_trigger().
Thank you for your reply. I apologize for taking so long to get back to this topic.
I have tried making a call to am_hal_ctimer_clear() prior to my call to am_hal_ctimer_config_single() and I am still getting the strange results. As I mentioned I can read the period and it’s reading as 12 bit but it’s behaving as 16 bit as well as the random inversion. Scoping the resulting waveform shows a PWM frequency of 183 Hz which is 16 bit and I should see 3KHz at 12bit. Because I am basically starting with the sparkfun analogWriteInit() and analogWrite() functions which basically call ap3_pwm_outputInit() and ap3_pwm_output(). I may be missing something but I really just changed the period to 12 bit and added a function to take the 0-255 linear input and do some math to output 12-bit logarithmic.
So I had some more time to play with this today and I came to realize that the built-in LED on the Artemis Thing Plus was an AUX timer output meaning while I was setting the period CMPR3B0 and duty CMPR2B0 for the CMPRAUXB0 register the timer would only reset to 0 after it reached the CMPR1B0 value. So while I now understand that a bit more I still get random inversions as it’s sweeping through the range. It is doing the function ap3_pwm_wait_for_pulse() to set the duty when it’s appropriate to avoid inversions but since the PWM is so fast by the time it detects a window to set the PWM it might have passed by the time it sets it? I’m surprised these don’t have double buffered registers like some others to allow you to set the DUTY whenever and it’s only updated when the timer is reset for this very reason?
Thanks guys, your postings helped me a lot (both in understanding, and the workaround). I also delved into the core and spent a while trying to figure things out, but could not.