硬件说明
TEA5767 + AT24c08
要使用耳机收听,不加功放芯片,声音非常小。

这2个芯片都支持 3.3 或 5.0 电源支持
连线比较简单,sda scl 接到 2440 对应的 排针上,找出一路 3.3v GND ,这里我是从 com 口上接出。
如下接线图,tea5767 at24c08 来自于,之前用 51 单片机做的 FM 收音机,因为电平不同,就把 51 单片机取下来了。
1602 因为 2440 开发板,没有这么多可用 GPIO 这次就不接了。

中间的转换板是我自己焊的,是一个 5V 转 3.3V 和 LED 台灯 和 排针连接工具。 用的是 asm1117 3.3 。
制作中出现过一个严重的问题,led 灯全烧了,之前用 笔记本上面的 usb 供电,led 灯虽然说是亮些,但是没有烧过。
这次新买了一个 台达5v 5a 电源,接上线后全烧了。加了一个100欧,限流电阻后正常了。

编译环境
ubunto 12
arm-linux-gcc 4.3.2

使用说明
本项目基于 linux4.3.36 (2.6 内核肯定是不能用,3.1 之后的也许可以,如果不能用请自行修改)
首先要配置内核启用 i2c 的支持
make menuconfig
-> Device Drivers
   -> I2C support
      -> I2C support (I2C [=y])
         -> I2C Hardware Bus support

-> Device Drivers
    -> I2C support
       -> I2C support (I2C [=y])

基本上有难度的是 at24c08 的 mmap 实现。 不是普通的读写。 这样做,程序写起来比较简单。

打开 fm 应用程序后,打开 tea5767 和 at24c08 对 at24c08 进行 mmap 映射为 unsigned long 来表现,电台的 频率, 单位是 Khz (因为小数不容易存)。
搜到台以后, 把台的频率(单位是Khz)保存到 mmap 中, 退出的时候,在写回 at24c08 。简化了程序。

内核驱动中需要注意的是, mmap 的 内存要求是物理地址连续,所以使用 dma_alloc_writecombine 分配。

请把 项目中的所有文件,下载到本地,修改 Makefile 中的 内核路径,除非你的和我的一样,这样就不用修改了。
执行
在项目目录中 执行 make
生成 4个 ko 文件 和 fm 应用程序。 把这5个文件复制到,开发板上,或 nfs 中。

启动开发板,请一定要注意,内核有 i2c 硬件支援,然后加载4个ko 文件。
insmod tea5767/tea5767.ko
insmod tea5767/tea5767_dev.ko
insmod tea5767/at24cxx.ko
insmod tea5767/at24cxx_dev.ko

执行测试 fm 程序
tea5767/fm

输入 s 按回车 自动搜台
搜完毕后,自动打开第1个台
可以按 n 切换下一台
可以按 p 切换上一台
可以按 q 退出
可以按 h 查看帮助信息
可以按 t 进行测试模式 这里收听一个 北京台 99.6Mhz

主要发下 at24c08 的 mmap 实现

#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h> //主设备号
static int major;
//类描述为创建设备使用
static struct class *cls;
//i2c client 发送接收数据使用
static struct i2c_client *at24cxx_client; //互斥锁
static struct mutex at24cxx_mutex; //i2c table 和 board 中进行比较 相同调用 probe
static struct i2c_device_id at24cxx_id_table[] = {
{"at24c08", },
{}
}; //mmap 使用内存
static unsigned char *at24cxx_buf;
//物理地址 使用和 lcd fb 一样的分配内存的方法 dma_alloc_writecombine
static dma_addr_t at24cxx_phys; #define AT24cxx_BUF_SIZE 64 static int at24cxx_mmap(struct file *file, struct vm_area_struct *vma)
{
u64 len = vma->vm_end - vma->vm_start;
len = min(len, AT24cxx_BUF_SIZE);
//no cache
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return vm_iomap_memory(vma, at24cxx_phys, len);
} static int at24cxx_open(struct inode *note, struct file *f)
{
//打开时 填充 mmap 的buf
int i;
memset(at24cxx_buf, , AT24cxx_BUF_SIZE);
for(i=; i<AT24cxx_BUF_SIZE; i++)
{
at24cxx_buf[i] = i2c_smbus_read_byte_data(at24cxx_client, i);
}
return ;
} static int at24cxx_release(struct inode *note, struct file *f)
{
//写 mmap 中的数据回 at24c08
int i;
for(i=; i<AT24cxx_BUF_SIZE; i++)
{
i2c_smbus_write_byte_data(at24cxx_client, i, at24cxx_buf[i]);
mdelay();
}
return ;
} static struct file_operations at24cxx_ops = {
.owner = THIS_MODULE,
.open = at24cxx_open,
.release = at24cxx_release,
.mmap = at24cxx_mmap,
}; //当idtab中比较相同以后调用这个
static int at24cxx_probe(struct i2c_client *client,const struct i2c_device_id *dev)
{
//初始化锁
mutex_init(&at24cxx_mutex);
//设给全局变量
at24cxx_client = client;
//创建字库设备
cls = class_create(THIS_MODULE, "at24cxx");
major = register_chrdev(, "at24cxx", &at24cxx_ops);
device_create(cls, NULL, MKDEV(major, ), NULL, "at24cxx"); //vmalloc 分配的物理地址连续
at24cxx_buf = dma_alloc_writecombine(NULL, AT24cxx_BUF_SIZE, &at24cxx_phys, GFP_KERNEL);
return ;
} static int at24cxx_remove(struct i2c_client *client)
{
device_destroy(cls, MKDEV(major, ));
class_destroy(cls);
unregister_chrdev(major, "at24cxx");
dma_free_writecombine(NULL, AT24cxx_BUF_SIZE, at24cxx_buf, at24cxx_phys);
return ;
} static struct i2c_driver at24cxx_drv = {
.driver = {
.name = "at24cxx",
.owner = THIS_MODULE,
},
.probe = at24cxx_probe,
.remove = at24cxx_remove,
.id_table = at24cxx_id_table,
}; static int at24cxx_init(void)
{
i2c_add_driver(&at24cxx_drv);
return ;
} static void at24cxx_exit(void)
{
i2c_del_driver(&at24cxx_drv);
} module_init(at24cxx_init);
module_exit(at24cxx_exit);
MODULE_LICENSE("GPL");

GIT 项目地址 https://github.com/nejidev/tea5767_at24c08_fm_radio_linux

TEA5676 + AT24C08 FM收音机 搜台 存台 mmap 实现读写的更多相关文章

  1. 51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

    先看效果图: 显示 频道CH , 频率 100.0Mhz 欢迎信息,1602 内置日文平假名, 正好用来显示博主名称. 焊接前,已经万能面包板上试验成功. 焊接完成以后,1602 的D0 - D7 接 ...

  2. 图像里的"白噪声"——电视机搜不到台时雪花斑点的形成原因

    作者:❄️固态二氧化碳❄️ (主页) 链接:图像里的"白噪声"--电视机搜不到台时雪花斑点的形成原因 - 固态二氧化碳的博客 - CSDN博客 来源:CSDN博客 发表时间:201 ...

  3. FM收音机 RDS的强大功能

    FM收音机 RDS的强大功能 分类: MTK2011-04-26 16:06 14889人阅读 评论(6) 收藏 举报 交通公告体育音乐娱乐教育 前言 随着发展,会有越来越多的电台具有RDS广播功能, ...

  4. 与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器

    原文:与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器 [索引页][源码下载] 与众不同 windows phon ...

  5. 基于iTop4412的FM收音机系统设计(一)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  6. Codeforces977D ---Divide by three, multiply by two 深搜+map存出现的数

    传送门:点我 题意:给定n长度的序列,重排成后一个数是前一个数除以三,或者后一个数是前一个数乘二,要求输出这个序列. 思路:大力深搜,对每个数搜除3的和乘2的是否出现过,然后继续搜下去.如果有一个数搜 ...

  7. 基于iTop4412的FM收音机系统设计(三)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  8. 基于iTop4412的FM收音机系统设计(二)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  9. 2019-8-31-dotnet-控制台-Hangfire-后台定时任务

    title author date CreateTime categories dotnet 控制台 Hangfire 后台定时任务 lindexi 2019-08-31 16:55:58 +0800 ...

随机推荐

  1. C++ this指针详解(精辟)

    this 是 C++ 中的一个关键字,也是一个 const 指针,它指向当前对象,通过它可以访问当前对象的所有成员. 所谓当前对象,是指正在使用的对象.例如对于stu.show();,stu 就是当前 ...

  2. 瑞星:以虚拟化安全“Hold住”企业用户

    自从云计算的概念诞生的哪一天起,就吸引了无数人的目光.自从2006年开始,云计算经过了雾里看花的朦胧.众说纷纭的迷茫,到现在各类应用与服务呈现出了百花齐放的姿态,引领着信息科技迈入了新纪元,而服务器虚 ...

  3. JDBC原理之层次结构

    目录 JDBC的层次结构 前言 Collection角色 Statement角色 ResultSet角色 JDBC工作的基本流程 JDBC的层次结构 前言 JDBC API提供了以下接口和类: Dri ...

  4. spring学习笔记四:spring常用注解总结

    使用spring的注解,需要在配置文件中配置组件扫描器,用于在指定的包中扫描注解 <context:component-scan base-package="xxx.xxx.xxx.x ...

  5. MOOC(1)-使用pycharm新建Django项目、开发post接口

    https://www.cnblogs.com/liqu/p/9308966.html 1.安装Django的两种方式: > 1) pip install django 2)下载离线安装包,进入 ...

  6. 爬虫时伪装header信息

    在爬虫时,一般需要伪装Agent信息,放在header中 1.header不是必传参数,在需要的时候进行伪装 2.header = {"User-Agent": "Moz ...

  7. haproxy笔记之六:负载均衡MySQL服务的配置示例

    #--------------------------------------------------------------------- # Global settings #---------- ...

  8. Java编程风格节选

    3.3 import语句 3.3.1 import不要使用通配符 即,不要出现类似这样的import语句:import java.util.*; 3.3.2 不要换行 import语句不换行,列限制( ...

  9. 【转载】[基础知识]【网络编程】TCP/IP

    转自http://mc.dfrobot.com.cn/forum.php?mod=viewthread&tid=27043 [基础知识][网络编程]TCP/IP iooops  胖友们楼主我又 ...

  10. python入门机器学习,3行代码搞定线性回归

    本文着重是重新梳理一下线性回归的概念,至于几行代码实现,那个不重要,概念明确了,代码自然水到渠成. “机器学习”对于普通大众来说可能会比较陌生,但是“人工智能”这个词简直是太火了,即便是风云变化的股市 ...