|
本帖最后由 matson 于 2013-5-27 21:42 编辑
为了学习arm下的linux,入手了一块cubieboard,编写了一个pwm小驱动来练手。
由于新内核添加了pwm子系统,所以我练手用的kernel版本使用了当天最新的3.9.2(我是5月15日从kernel.org上下载的)u-boot使用cubieboard提供的,为了简化调试过程,我的系统仅仅在ramfs中运行,不挂载ubuntu的文件系统。
第一步:修改u-boot使其支持fdt(我的驱动初始化是基于fdt做的)。
1:在include/configs/sun4i.h档案中添加:
#define CONFIG_OF_LIBFDT
#define CONFIG_OF_CONTROL
#define CONFIG_OF_SEPARATE
2:在arch/arm/lib/bootm.c文件中,在if(images->ft_len)的判断之前加上
images->ft_addr = gd->fdt_blob;
images->ft_len = 2 *1024 *1024;
然后使用
make -j8 cubieboard CROSS_COMPILE=arm-none-linux-gnueabi-
指令编译(我的環境變量中已經是有arm-none-linux工具鏈的,假如你的沒有還需要
export PATH=$PATH:XXXX
XXXX表示你工具鏈的路徑
我的电脑是I7 8 线程的CPU所以可以使用-j8)
編譯的最後會報錯
make[2]:正在离开目录 `/home/workdir/u-boot-sunxi/u-boot-sunxi/spl'
make[2]: 正在进入目录 `/home/workdir/u-boot-sunxi/u-boot-sunxi/dts'
Makefile:30: *** Please define CONFIG_DEFAULT_DEVICE_TREE in your board header file。 停止。
make[2]:正在离开目录 `/home/workdir/u-boot-sunxi/u-boot-sunxi/dts'
make[1]: *** [u-boot.dtb] 错误 2
make[1]: *** 正在等待未完成的任务....
這個是因為u-boot中並沒有cubieboard的dts文件,不過這個不重要,只要
spl/sunxi-spl.bin 和u-boot.bin生成了就行了,dtb文件我們使用編譯內核生成的那個就行了。
第二步:修改linux3.9.2的源码使其能编译cubieboard并添加pwm驱动
下面使用的是git diff的输出结果来显示修改
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1cacda4..78a300f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1014,7 +1014,7 @@ config ARCH_MULTI_V7
bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)"
default y
select ARCH_MULTI_V6_V7
- select ARCH_VEXPRESS
+# select ARCH_VEXPRESS
select CPU_V7
config ARCH_MULTI_V6_V7
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..b07377a 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -227,7 +227,7 @@ else
MACHINE :=
endif
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0e0bfa0..6585db6 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -203,4 +203,9 @@ config PWM_VT8500
To compile this driver as a module, choose M here: the module
will be called pwm-vt8500.
+config PWM_SUNXI
+ tristate "sunxi PWM support"
+ depends on ARCH_SUNXI
+ help
+ Generic PWM framework driver for sunxi.
endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 94ba21e..852cbf6 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
obj-$(CONFIG_PWM_TWL) += pwm-twl.o
obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o
obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
+obj-$(CONFIG_PWM_SUNXI) += pwm-sunxi.o
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 8709a39..44ca175 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -7,4 +7,5 @@ config ARCH_SUNXI
select PINCTRL
select SPARSE_IRQ
select SUNXI_TIMER
- select PINCTRL_SUNXI
\ No newline at end of file
+ select PINCTRL_SUNXI
+ select PWM_SUNXI
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index f99f60d..d083f7b 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -44,6 +44,20 @@
allwinner,drive = <0>;
allwinner,pull = <0>;
};
+
+ gpio_pwm0: pwm0@0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "pwm0";
+ allwinner,drive = <4>;
+ allwinner,pull = <0>;
+ };
+
+ gpio_pwm1: pwm1@0 {
+ allwinner,pins = "PI3";
+ allwinner,function = "pwm1";
+ allwinner,drive = <4>;
+ allwinner,pull = <0>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/sunxi.dtsi b/arch/arm/boot/dts/sunxi.dtsi
index 8b36abe..ca1fd73 100644
--- a/arch/arm/boot/dts/sunxi.dtsi
+++ b/arch/arm/boot/dts/sunxi.dtsi
@@ -78,5 +78,17 @@
clock-frequency = <24000000>;
status = "disabled";
};
+
+ pwm0: pwm@0x01c20e04 {
+ compatible = "allwinner,sunxi-pwm";
+ reg = <0x01c20e04 0x4>;
+ id = <0>;
+ };
+
+ pwm1: pwm@0x01c20e08 {
+ compatible = "allwinner,sunxi-pwm";
+ reg = <0x01c20e08 0x4>;
+ id = <1>;
+ };
};
};
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 5cab825..b84e180 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -34,5 +34,16 @@
uart1: uart@01c28400 {
status = "okay";
};
+
+ pwm0: pwm@0x01c20e04 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_pwm0>;
+ status = "okay";
+ };
+ pwm1: pwm@0x01c20e08 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_pwm1>;
+ status = "okay";
+ };
};
};
ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y)
-MACHINE :=
+MACHINE := arch/arm/mach-sunxi
endif
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
添加檔案:
.config(基於arch/arm/configs/multi_v7_defconfig 修改)
build.sh(根據cubieborad sdk修改的簡易編譯腳本)
cubieboard.cpio.gz(ramfs壓縮包)
drivers/pwm/pwm-sunxi.c
./build.sh
在linux-3.9.2/output目錄中
我們可以看到我們需要的uImage 和sun4i-a10-cubieboard.dtb
cat u-boot.bin sun4i-a10-cubieboard.dtb > image.bin
使用上面的命令生成的鏡像,再燒寫時幾率導致dtb文件的尾部被截斷,
導致跑到start_kernel->setup_arch->dump_machine_table處掛掉
PS:我使用的是一個windows下的一個裸寫SD卡的小工具,並不是用
dd命令,那個工具是以sector問單位寫的(1 sector =512 Bytes)。
所以在文件尾部湊一個全為0的小文件
(dd if=/dev/zero of=pad bs=1024 count=1
cat u-boot.bin sun4i-a10-cubieboard.dtb pad> image.bin
)
製作啟動卡:
具體步驟可參照http://just4fun.cn/?p=643
這位朋友寫得非常好
大致步驟就是
重新格式化SD卡,
分2個區,第一個64M的fat32格式
第二個ext2/ext4格式(我這裡暫時不會用到)
linux下燒寫
在u-boot的目錄下(/dev/sda為讀卡器的設備名)
dd if=spl/sunxi-spl.bin of=/dev/sda bs=1024 seek=8
dd if=image.bin of=/dev/sda bs=1024 seek=32
然後將uImage拷貝到卡的第一個fat32格式的分區中,
將卡插入cubieboard的卡槽,上電啟動。
啟動並簡單的使用pwm模塊
在編譯時在drivers/pwm/pwm-sunxi.c文件的
#ifdef AW_PWM_DEBUG_SYSFS
上添加:#define AW_PWM_DEBUG_SYSFS
這樣我寫的驅動會在/sys/kernel目錄下創建sunxi_pwm目錄供調試pwm的功能使用
(這段代碼也可以作為其他驅動調用sunxi pwm驅動的示例)
在開啟調式功能後,進入系統後
echo "channel_numer duty_ns period_ns" > /sys/kernel/sunxi_pwm/start 啟動pwm
echo "channel_numer" > /sys/kernel/sunxi_pwm/stop 關閉pwm
示例:
echo "0 20 30" > /sys/kernel/sunxi_pwm/start (啟動pwm0 設置duty_ns = 20 ns period_ns = 30 ns)
這時pb2管腳會輸出占空比2/3的波形(pwm0是PB2管腳,pwm1為PI3管腳)
echo "0" > /sys/kernel/sunxi_pwm/stop (關閉pwm0)
這裡注明2點,第一我對輸入值的匹配分2個情況,
第一個是完全匹配,就是對寄存器的設置值完全和預期值一樣,
第二個是,在硬件無法設置剛好的duty_ns ,period_ns 值時,改為設置其他的值,
輸出的波形的占空比為duty_ns /period_ns的波形,
假如2個情況都滿足不了,就返回失敗。
附件中有我修改和添加的文件,以及在示波器上测量出的输出波形
|
|