- 论坛徽章:
- 0
|
引用 SAMSUNG_S3C2410串口驱动
引用
Akem
的
SAMSUNG_S3C2410串口驱动
今天写了一个2410的串口驱动.在此总结一下.也当作一次复习. 废话不多说了.进入正题.
2410支持3个COM口,在u-boot中已经打开了COM1, 所以现在要打开COM2口.以模块方式加载驱动程序.并在COM2口打印测试. 开发板上有两个串口接口,所以要用两台PC机进行测试.一台作为宿主机COM1,一台测试串口读写COM2.
在开发板已经下载了Linux2.4内核.通过NFS文件系统.和宿主机进行开发通信.也就是说在PC机上进行开发和交叉编译,把目标文件通过NFS加载到开发版上运行
操作步骤:
串口数据发送
1. 设置串口工作在中断和轮训模式
2. 设置串口的数据位长度, 停止位, 是否有奇偶校验位
3. 设置串口收发数据波特率
4. 将数据写到发送寄存器
5. 检测状态寄存器相关位判断是否发送完成
串口数据读取
1. 设置串口工作在中断和轮询模式
2. 设置串口收发数据位长度, 停止位, 是否有奇偶校验
3. 设置串口收发数据的波特率
4. 检测状态寄存器是否有数据
5. 读取数据
代码
----------------------------------------------------------------------
utrs_driver.h 配置相关寄存器
-------------------------------------------------------------------------------
#include
/* 通过2410手册得到的串口寄存器地址 ,驱动要设置的相关寄存器 */
/* 控制寄存器: 设置数据位, 停止位, 校验位 0x50004000*/
#define UART_ULCON1 __REG(0x50004000 + 0x00)
/* 设置串口工作模式, UCON1是第二串口,偏移量0x04设置中断轮询模式 */
#define UART_UCON1 __REG(0x50004000 + 0x04)
/* 设置接收寄存器, 发送数据偏移量0x24是L模式 */
#define UART_URXH1 __REG(0x50004000 + 0x24)
/* 设置接收寄存器, 发送和接收状态,偏移量0x20是L模式 */
#define UART_UTXH1 __REG(0x50004000 + 0x20)
/* 设置串口通讯波特率寄存器 */
#define UART_UBRDIV1 __REG(0x50004000 + 0x28)
/* 设置接受状态偏移量0x10设置清空buffer */
#define UART_UTRSTAT1 __REG(0x50004000 + 0x10)
int s3c2410_serial_open(void);
int s3c2410_serial_release(void);
int s3c2410_serial_read(unsigned char *buf, int count);
int s3c2410_serial_write(unsigned char *buf, int count);
---------------------------------------------------------------------------------------
utrs_driver.c 驱动模块
---------------------------------------------------------------------------------------
#include
#include
#include
#include
#include"utrs_driver.h"
/* 打开串口并且初始化 */
int s3c2410_serial_open(void)
{
UART_UCON1 = 0x05; /* 初始化控制寄存器的 [3 : 0] 读写模式为中断轮询 */
UART_ULCON1 = 0x03; /* 初始化线控制寄存器 [1 : 0] 读写为8-bit即一个字符 */
UART_UBRDIV1 = 26; /* 初始化串口波特率 26 为115200 */
return 0;
}
int s3c2410_serial_release(void)
{
return 0;
}
/* 接收模块 */
int s3c2410_serial_read( unsigned char *buf, int count )
{
int i;
unsigned char ch;
for(i = 0; i
#include
#include
#include"utrs_driver.h"
int s3c2410_serial_init(void)
{
unsigned char str[200] = "HELLO FUCK!\r\n";
unsigned char ch;
int len;
len = strlen(str);
printk("init moule!\n");
s3c2410_serial_open(); /* 打开串口 */
s3c2410_serial_release();
s3c2410_serial_write(str, len); /* 相串口里写数据, 此时COM2连接的PC会打印出HELLO FUCK! */
while(ch != '#')
{
s3c2410_serial_read(&ch, 1); /* 在COM2的PC上输入数据会写入到接收寄存器, 在宿主机打印 */
/* 寄存器是以一个字节读写 */
printk("%c",ch); /* 把在COM2端写入的数据打印到主机 */
}
return 0;
}
void s3c2410_serial_cleanup(void)
{
printk("clean moule!\n");
}
int init_module(void) /* 加载模块 */
{
s3c2410_serial_init();
return 0;
}
void cleanup_module(void) /* 卸载模块 */
{
s3c2410_serial_cleanup();
}
-------------------------------------------------------------------------------------------
驱动程序是在内核启动时,通过系统脚本创建设备文件的,而应用程序要和驱动打交道就必须通过打开相应的设备文件进行操作。上述的例子不能算是一个完整的驱动程序,因为是通过模块加载的方式对设备进行操作,并没有创建设备文件。也就是说要手工的进行加载。以下的例子是通过创建真实设备文件的形式,所以是货真价实的驱动程序。
----------------------------------------------------------------------------------------------------------------
utrs_driver.h
----------------------------------------------------------------------------------------------------------------
#include
#define UART_ULCON1 __REG(0x50004000 + 0x00)
#define UART_UCON1 __REG(0x50004000 + 0x04)
#define UART_URXH1 __REG(0x50004000 + 0x24)
#define UART_UTXH1 __REG(0x50004000 + 0x20)
#define UART_UBRDIV1 __REG(0x50004000 + 0x28)
#define UART_UTRSTAT1 __REG(0x50004000 + 0x10)
----------------------------------------------------------------------------------------------------------------
utrs_driver.c
----------------------------------------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "utrs_driver.h"
#define DEVICE_NAME "akem" //设备文件名
#define BUTTON_MAJOR 232 //主设备号
/* 打开驱动inode结构在内部表示文件,file结构是打开上面传来的文件描述符fd对应的file结构,file结构都指向单个inode */
static int akem_open(struct inode *inode, struct file * file)
{
/* 设置寄存器 */
UART_UCON1 = 0x05;
UART_ULCON1 = 0x03;
printk("Kernel : in open,we do nothing......\n");
return 0;
}
/* 从设备读取数据,上层的read函数会调用到这里,file是read的fd对应的结构, ppos是系统回调 */
static int akem_read(struct file * file, char * buff, size_t count, loff_t *ppos)
{
int i;
unsigned char ch;
for(i = 0; i
#include
#include
#include
#define BOUNDRATE 111 /* 设置伯特率命令参数 */
int main(void)
{
int fd;
int ret = 0;
char buf[100] = "HELLO FUCK!\n\r";
char ch;
fd = open("/temp/akem", O_RDWR); /* open会直接调用到驱动里的akem_open */
if(fd == -1)
{
perror("open");
exit(1);
}
ret = ioctl(fd, BOUNDRATE, 115200); /* 设置伯特律115200 */
ret = write(fd, buf, strlen(buf)); /* write会调用驱动里的akem_write */
if(ret == -1)
{
perror("write error");
exit(1);
}
while(ch != '#')
{
read(fd, &ch,1);
printf("%c",ch);
fflush(stdout);
}
close(fd);
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/7971/showart_548176.html |
|