打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
A Hardware PWM implementation for Cubie and Allwinner A10
A Hardware PWM Implementation for Cubie and Allwinner A10
by David H. Wilkins - Aug-23-2013 - posted in HardwareLinuxPWM
Cubieboard-1 - powered by the Allwinner A10 Arm SOC
When I received my first Allwinner A10 board it lacked support for hardware PWM. Without a driver for hardware PWM it’s very hard to use this very powerful SOC for controlling motors
This article describes the design of one such hardware pwm driver interface.
The Arduino has a simple to use PWM interface and other implementations should strive to have a similarly developer friendly interface. The “analogWrite” Arduino interface is both easy to understand and implement. For instance the following code implements a 50% duty cycle on digital pin 5:
12pinMode(5,OUTPUT); // Declare pin 5 as outputanalogWrite(5,128); // Output a valud between 0 (off) and 255 (full on)
One problem with the Arduino interface is the learning curve required to venture beyond the primary interface. For instance, the above code doesn’t specify the PWM period. Many motors (servos..) function best within a specific PWM period.
This implementation doesn’t allow specification of the signal polarity either. If the hardware interface requires an inverted signal, then duty will have to be computed as 1/duty manually.
12345678910111213141516171819void TimerOne::setPeriod(long microseconds) // AR modified for atomic access{ long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum oldSREG = SREG; cli(); // Disable interrupts for 16 bit register access ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode SREG = oldSREG; TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock}
*example code from Timer One Library for Arduino
The Linux OS and expanded ram of the cubieboard make possible a much more rich interface than the arduino affords. File based programming interfaces are available to extend the PWM control to many more languages. One possible implementation might include the following interface (examples in shell script):
/sys/class/pwm-sunxi/pwmX
This is the sysfs directory that contains the PWM interface. X is the PWM channel. The Allwinner A10 has 2
period (r/w)
period that makes up a cycle. Can be expressed as hz, khz, ms, or us. Whole numbers only. Examples: echo 10hz > /sys/class/pwm-sunxi/pwm0/periodecho 1khz > /sys/class/pwm-sunxi/pwm0/period
echo 100ms > /sys/class/pwm-sunxi/pwm0/period
echo 100us > /sys/class/pwm-sunxi/pwm0/period
echo 150khz > /sys/class/pwm-sunxi/pwm0/period
duty (r/w)
portion of the period above that is “active” or on. Same units as duty.
echo 100ms > /sys/class/pwm-sunxi/pwm0/period # Period is 100 milliseconds
echo 25ms > /sys/class/pwm-sunxi/pwm0/duty # 25% duty
echo 50ms > /sys/class/pwm-sunxi/pwm0/duty # 50% duty
echo 75ms > /sys/class/pwm-sunxi/pwm0/duty # 75% duty
duty_percent (r/w)
duty expressed as a percentage. Whole numbers only
echo 100ms > /sys/class/pwm-sunxi/pwm0/period # Period is 100 milliseconds
echo 25 > /sys/class/pwm-sunxi/pwm0/duty_percent # 25% duty
echo 50 > /sys/class/pwm-sunxi/pwm0/duty_percent # 50% duty
echo 75 > /sys/class/pwm-sunxi/pwm0/duty_percent # 75% duty
polarity (r/w)
Polarity of the pin during the duty portion. Note that the opposite state will be for the non-duty portion.
1 = high, 0 = low
pulse (r/w)
Output one pulse at the specified period and duty
echo 1 > /sys/class/pwm-sunxi/pwm0/puls # Output 1 pulse when run is 1
pin (r/o)
Name of the A10 pin this pwm outputs on. This is hardwired and informational only. Example:
cat /sys/class/pwm-sunxi/pwm0/pin # output: PB2
run (r/w)
Enable the PWM with the previously set parameters. Example:
echo 1 > /sys/class/pwm-sunxi/pwm0/run # Start the pwm interface
echo 0 > /sys/class/pwm-sunxi/pwm0/run # Stop the pwm interface
So, the above interface as a Linux kernel module can implement a 50% duty cycle hardware pwm with the following code:
12echo 50 > /sys/class/pwm-sunxi/pwm0/duty_percentecho 1 > /sys/class/pwm-sunxi/pwm0/run
Or a 25% duty cycle at 250hz with the following code:
123echo 250hz > /sys/class/pwm-sunxi/pwm0/periodecho 50 > /sys/class/pwm-sunxi/pwm0/duty_percentecho 1 > /sys/class/pwm-sunxi/pwm0/run
Or a 25% duty cycle at 500hz with negative polarity with the following code:
1234echo 500hz > /sys/class/pwm-sunxi/pwm0/periodecho 50 > /sys/class/pwm-sunxi/pwm0/duty\_percentecho 0 > /sys/class/pwm-sunxi/pwm0/polarityecho 1 > /sys/class/pwm-sunxi/pwm0/run
So, the design goal of a simple interface is achieved, with incremental functionality requiring only incremental amounts of additional code.
Next article – developing the pwm-sunxi pwm module
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
干货 | LS1028A如何输出pwm方波?
全志平台通读写寄存器的方法
内核里的gpiolib在终端上命令操作gpio口
首页 » 全志/Allwinnertech/V3S/A64/H6/A20/A33/F1C100s » 在A33上抛掉安卓层,在根文件系统层操作调试过程(也就是做了安卓用户层的工作)
Banana Pi BPI-R3 评测:详细信息和功能--第四部分
迅為iMX6UL開發板驅動
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服