说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计
现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:APP+Frameworks+JNI+HAL+Driver
整个系统设计,大致分为三篇文章介绍完毕,包括:
一、驱动设计篇
二、系统API接口篇
三、APP功能实现篇
---------------------------------------------------(一)驱动设计篇-----------------------------------------------------------------
在前面介绍过iTop4412的字符驱动的编写方法,所以这里不详细介绍驱动的编写流程了,附上传送门:http://www.cnblogs.com/pngcui/p/4766504.html
FM调频收音机芯片这里使用的是TEA5767HN模块,使用I2C进行通信,所以我们第一步肯定就是找到芯片的datasheet,找到芯片的设备地址,即0xC0
同时需要在datasheet中找到I2C的通信协议
这里需要注意的是,标准的I2C协议并没有这么简洁,不过该datasheet中这么写了,那么我们就根据他来写代码吧
附上标准的I2C通信协议:
写操作:START+器件地址+ACK+写寄存器地址+ACK+写数据+ACK+STOP
读操作:START+(器件地址+写标志位)+ACK+写寄存器地址+ACK+(器件地址+读标志位)+ACK+读数据+STOP
START信号:当SCL为高期间,SDA由高到低的跳变
STOP信号: 当SCL为高期间,SDA由低到高的跳变
有了I2C的通信协议,我们接下来就需要选取开发板的pin脚,去连接TEA5767HN芯片了。
由于板子上camera接口没有被占用,所以我们在原理图上找到camrea接口,即j27
我这里选取了CAM_HREF脚与CAM_PCLK脚分别作为I2C的SDA与SCL线,接下来我们需要到kernel的gpio的配置文件中找到这两个引脚的定义
{ EXYNOS4212_GPJ0(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D6 by pngcui
{ EXYNOS4212_GPJ0(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D7 by pngcui
{ EXYNOS4212_GPJ0(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_PCLK by pngcui
{ EXYNOS4212_GPJ0(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D1 by pngcui
{ EXYNOS4212_GPJ0(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D2 by pngcui
{ EXYNOS4212_GPJ0(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D4 by pngcui
{ EXYNOS4212_GPJ0(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_D3 by pngcui
{ EXYNOS4212_GPJ0(7), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_VSYNC by pngcui
{ EXYNOS4212_GPJ1(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //I2C_SCL7 by pngcui
{ EXYNOS4212_GPJ1(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM2M_RST by pngcui
{ EXYNOS4212_GPJ1(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //CAM_HREF by pngcui
{ EXYNOS4212_GPJ1(3), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, //I2C_SDA7 by pngcui
{ EXYNOS4212_GPJ1(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, //NC-CAM2M_PWDN low=0v high=0.3v bu pngcui
这里需要注意的是,里面的注释与板子上的引脚是对应不起来的,所以最好还是事先写个测试程序,再使用万用表测试一下,引脚是否对应上了。
到这里,我们就可以使用gpio_set_value函数去控制I2C的两根线了,接下来,就是正式的驱动程序的编写了!!!
1.在平台文件中配置设备信息
参考:http://www.cnblogs.com/pngcui/p/4766504.html
2.注册驱动信息
1 struct platform_driver tea5767_driver = {
2 .probe = tea5767_probe,
3 .remove = tea5767_remove,
4 .shutdown = tea5767_shutdown,
5 .suspend = tea5767_suspend,
6 .resume = tea5767_resume,
7 .driver = {
8 .name = DRIVER_NAME,
9 .owner = THIS_MODULE,
10 }
11 };
12
13 /* init the driver */
14 static int __init tea5767_init(){
15
16 int err;
17
18 printk("tea5767 init start...n");
19
20 err = platform_driver_register(&tea5767_driver);
21
22 printk("state is %dnn",err);
23
24 return 0;
25 }
26
27 /* cleanup the driver */
28 static void __exit tea5767_exit(){
29
30 int i;
31
32 printk("tea5767 exit ..and free gpion");
33 gpio_free(SCL);
34 gpio_free(SDA);
35
36 platform_driver_unregister(&tea5767_driver);
37 }
38
39 MODULE_LICENSE("Dual BSD/GPL");
40 MODULE_AUTHOR("PNGCUI");
41
42 module_init(tea5767_init);
43 module_exit(tea5767_exit);
注:include/linux/init.h中说明了驱动函数的加载顺序,附详细说明链接:http://blog.csdn.net/maopig/article/details/7375933
3.当平台文件中的配置的name与驱动中的name匹配成功之后,会自动进入驱动程序的probe函数中
1 static int tea5767_probe(struct platform_device *pdv){
2 int ret,i;
3 printk("tea5767_probe start..n");
4
5 pll = default_pll;
6
7
8 for(i=0; i 10 ret = gpio_request(tea5767_gpios[i], "tea5767"); 11 if (ret < 0) { 12 printk("%s: request GPIO %d for tea5767 failed, ret = %dn", DEVICE_NAME,i, ret); 13 goto exit; 14 } 15 else{ 16 printk("%s: request GPIO %d for tea5767 success, ret = %dn", DEVICE_NAME,i, ret); 17 s3c_gpio_cfgpin(tea5767_gpios[i], S3C_GPIO_OUTPUT); 18 gpio_set_value(tea5767_gpios[i], 0); 19 //gpio_free(tea5767_gpios[i]); 20 } 21 22 } 23 24 //使能芯片 25 //mute=1&stby=1 26 write_data[0]=0xac; 27 write_data[1]=0x7a; 28 write_data[2]=0xd0; 29 write_data[3]=0x57; 30 write_data[4]=0x00; 31 32 tea5767_write(); 33 tea5767_read(); 34 35 //初始化芯片 36 //设置为mute=1&freq=87400&stby=0 37 write_data[0]=0xa9; 38 write_data[1]=0x9d; 39 write_data[2]=0xa0; 40 write_data[3]=0x17; 41 write_data[4]=0x00; 42 tea5767_write(); 43 tea5767_read(); 44 45 ret = misc_register(&tea5767_dev); 46 if(ret<0) 47 { 48 printk("tea5767:register device failed!n"); 49 goto exit; 50 } 51 52 return 0; 53 54 exit: 55 misc_deregister(&tea5767_dev); 56 return ret; 57 } 在这个函数中,可以进行一些初始化芯片的操作,使能芯片等,这里又需要查看芯片的datasheet中具体寄存器代表的含义了 写模式: 读模式: 这里我总结在这里: /* *读入数据5byte -----------8---------------4------------------2-----------------1------------|----8----------------4---------------2--------------------1---- *1st byte:MUTE(静音=1) SM(自动搜索=1) PLL13 PLL12 -|- PLL11 PLL10 PLL9 PLL8 *2nd byte:PLL7 PLL6 PLL5 PLL4 -|— PLL3 PLL2 PLL1 PLL0 *3rd byte:SUD(SearchUp=1) SSL1(Search stop) SSL0(Search stop) HLSI(LO) -|- MS(单声道=1) MR(右声道静音=1) ML(左声道静音=1) SWP1(端口1为高=1) *4th byte:SWP2(端口2为高=1) STBY(待机=1) BL(US/Europe=0) XTAL(时钟频率) -|- SMUTE(soft mute) HCC(High Cut) SNC(立体音噪音消除1) SI(SWPORT1做ready flag 为1) *5th byte:PLLREF(时钟频率) DTC(de-emphasis time) - - -|- - - - - */ /* *读出数据5byte -----------8-----------------4------------------2-----------------1----------|----8----------------4---------------2-----------------1------ *1st byte:RF(发现电台=1) BLF(搜索到头=1) PLL13 PLL12 -|- PLL11 PLL10 PLL9 PLL8 *2nd byte:PLL7 PLL6 PLL5 PLL4 -|— PLL3 PLL2 PLL1 PLL0 *3rd byte:STEREO(立体声=1) IF6(中频计数结果) IF5(同前) IF4(同前) -|- IF3(同前) IF2(同前) IF1(同前) IF0(同前) *4th byte:LEV3(信号ADC) LEV2(同前) LEV1(同前) LEV0(同前) -|- CI3(芯片标记) CI2(同前) CI1(同前) 0 *5th byte:0 0 0 0 -|- 0 0 0 0
上一篇:基于讯为4412开发板的Android开发流程
下一篇:基于iTop4412的FM收音机系统设计(二)
推荐阅读




推荐帖子
- 限度降低Ćuk稳压器的辐射
- 拓扑非常适合用于从正电源电压生成负输出电压。许多系统都需要负电源电压,以便读取某些传感器发出的信号。因此,可能需要为信号链提供(例如)+5V和–5V,或者甚至+15V和–15V电压。负电源电压也用于安全切换某些开关元件,例如碳化硅(SiC)。 拓扑也称为2L反相拓扑,因为其电源路径中需要使用两个电感。图1为?uk拓扑的电路图。 在选择合适的开关稳压器IC时,需要确保其中包含负电源电压反馈引脚,这非常重要。ADI公司拥有大
-
fish001
模拟与混合信号
- C8051F系列单片机串口应用问题
- 近日学习C8051F340系列单片机的应用,遇到一段串口发送接收程序,有一个地方看不懂,即:在串口发送和接收前,要置P3口的状态,使用交叉开关后的串口Rx和Tx不是都在P1口中吗,关P3口什么事啊?请高手指点,我进行了调试,不对P3口置位还真不行,程序如下: #include"c8051f340.h" #include"intrins.h" #defineNOP_nop_();_nop_();_nop_();_nop_();_nop_();_
-
ling.wo
嵌入式系统
- stm32l053r8 定时器 uart串口
- l053r8中的例程,uart-compolling和timebase,分开各自好使,为什么我把timebase融合到uart-compolling里面,timebase,就不能产生时间中断;当我把uart-compolling融合到timebase中的时候串口失效。stm32l053r8定时器uart串口
-
mrfeet
stm32/stm8
- EEWORLD大学堂----直播回放:TI 无线风光可穿戴研讨会
-
hi5
综合技术交流
- 收到suoma的苹果了
- 前几天suoma发了一个苹果贴,就支持了一下。快递的速度很快,两天就收到了。买的是大个的,18个一盒,每个还单独包装了,很细心。削了一个,口感很不错,很甜。 最后帮suoma推荐一下,大家可以去看看。 http://bbs.eeworld.com.cn/thread-503244-1-1.html 收到suoma的苹果了
-
dcexpert
淘e淘
- 【米尔MYC-JX8MPQ评测】+QT调用OpenCV库进行测试
- 我们编译完成OpenCV库之后还是需要测试下,切最终在下位机中进行测试,所以我选择了使用QT进行一个交叉编译,把使用QT图形界面把OpenCV跑起来。 QT的环境不用动,还是使用我们之前配置好的。上次也把库弄好了,这次我们下载一个QT+OpenCV的历程交叉编译测试下即可。 还是老规矩,新建一个测试工程。还是一个最简单的测试demo。 直接看代码,此最简单的就是用opencv打开一个图片,没有对图像做其他处理。
-
流行科技
开发板测评专版
实战 培训 开发板 精华推荐
最新视频课程更多
- 兆易GD32307E-START免费测评试用
- 有奖直播【如何在几分钟之内完成高效可靠的USB PD电源设计――PI Expert™分步教程】(9:30开始入场)
- 有奖直播报名|瑞萨RA MCU家族成员快速增长,助力打造安全稳定的工业控制系统
- 是德科技有奖问答活动之四,使用实时示波器进行串扰分析,答题闯关赢好礼!
- 【中秋佳节话中秋】吃吃月饼聊聊天,还有抢楼好礼送给你!
- 上演你的“ADI实验室电路”DIY!
- 直击富士通在线展会,答题赢好礼
- 联想栗子工业智能开发板抢先首发!免费申请进行时~另有12 月 22 日深圳技术沙龙邀您莅临!
- TE Connectivity利用传感和连接解决方案,赋能电动汽车发展 参与有好礼!
- PI带您走进物联网时代!下载资料赢好礼