I have been very bad, not writing blog post. I guess that will be habit I am never going to break.
This blog post is a quick write down what I did to get pwm output working on the Udoo.
Out of the box
Out of the box PWM the only usable PWM is the one on the Atmel, but I did not want to use that, it
feels wrong (also it is arduino based, so getting a decent PWM requires hacking, etc.). The
Freescale has it, so why not use that See
pinout. So looking around on the
install I did see a nice
/sys/class/pwm/ directory with the 4 pwm generators, however this was
completely non working for two reasons:
- The pinmux is wrong
- The entries do not seem to setup the right registers.
So looking around, I found this post basically
the only one I could find that talked about setting up PWM on the Udoo. But it gave a nice starting
point. Lets first try to compile that imx-utils repository. This failed, it is setup for
cross-compilation, and tries to link against framebuffer device. ( I only want the
A quick hack to the make file fixed this, the whole makefile now looks like:
1 2 3
The second problem when trying to get the tool to work is the processor detection, under ArchLinux (running 3.17 kernel) the right Revision is not exposed. A quick hack of the code to always load the imx6 version made things work. I might post this version later, mail me if interested.
So lets start setting up the PWM, first thing we need to do is setup the right pinmux. BEWARE THAT THIS PIN SHOULD NOT BE AN OUTPUT ON THE ATMEL, IF YOU DO THIS WILL DESTROY THE BOARD
This sets GPIO42 to PWM4 output. Check the pinout. Then I followed the steps from the forum post, setting up the PWM:
1 2 3 4
While I got some output from the PWM, it looked like utter sh??. It has a lot of high frequency components, and the output looks fully random. What could this be? (Sorry I forgot to take a photo of the output). Looking at the freescale manual IMX6DQRM.pdf it mentions several settings related to power? management: STOPEN stop mode enabled, DOZEN doze mode, WAITEN wait mode. By default if we hit any of these modes the PWM is stopped. I am not sure what Linux is doing, but lets be on the safe side and disable these.
And this instantly cleared up the PWM signal:
It is not perfect, there is still a lot of high frequency scruff on the signal, but it is clean enough. Now lets see if we can get a bit higher frequency going. Looking again at the datasheet, it looks like we can switch to highfreq clock,
And indeed the frequency goes up, now lets play with the prescaler a bit:
This gave me a nice stable 64kHz clock. (half from what I would expect based on the documentation, but that is an investigation for another time).
So to tie things together (I also inversed the PWM because my LED driver also inverts):
1 2 3 4 5 6 7 8 9 10
Now if I want to change the Light strength I call:
Changing the duty cycle.
There is one small thing we still need to tweak, the PWM has a 4 element queue before the ‘SAR’ (duty cycle) register, we need to make sure this fifo is not full before we insert an element. We can do this by checking the Status Register: (PWM4_PWMSR4). The lower 3 bits indicate the remaining space. Luckely, I never manage to hit this, so will fix this at a later stage when making a dedicated PWM application instead of using devregs. Maybe even a kernel driver?
This now gives me a very nice controllable PWM. I need to play a bit with improving ‘fading’ effects. Currently it takes 9 seconds to go from low to high.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
1 2 3 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36