以下是红外串口的电路图,有图可知,要想用ATMEL芯片的IO口模拟实现串口功能,需要以下4个条件:
1、38K调制方波
2、RXD接收引脚
3、TXD发射引脚
4、定时器,用于bit位计时
串口时序参照上图所示。这里我们以红外串口通信波特率为1200bps为例,进行实现。
波特率为1200bps时,每个比特位的占用的时间为833us
驱动代码实现采用platform_device与platform_driver那一套,字符设备驱动框架。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "at91sam9g25_pwm.h"
#define AT91_PWM_MR 0x00 /*Mode Register*/
#define PWM_CLK_DIVA(n) (n)
#define PWM_PREA(n) (n << 8)
#define AT91_PWM_ENA 0x04 /*Enable Register*/
#define AT91_PWM_DIS 0x08 /*Disable Register*/
#define AT91_PWM_SR 0x0C /*Status Register*/
#define AT91_PWM_IER 0x10 /*Interrupt Enable Register*/
#define AT91_PWM_IDR 0x14 /*Interrupt Disable Register*/
#define AT91_PWM_IMR 0x18 /*Interrupt Mask Register*/
#define AT91_PWM_ISR 0x1C /*Interrupt Status Register*/
#define AT91_PWM_CMR(ch_num) (0x200 + ch_num * 0x20 + 0x00) /*Channel Mode Register*/
#define PWM_CPRE_MCKDIV1 0x00
#define PWM_CALG_LEFT 0x00
#define PWM_CPOL_HIGH (1 << 9)
#define PWM_CPD (1 << 10)
#define AT91_PWM_CDTY(ch_num) (0x200 + ch_num * 0x20 + 0x04) /*Channel Duty Cycle Register*/
#define AT91_PWM_CPRD(ch_num) (0x200 + ch_num * 0x20 + 0x08) /*Channel Period Register*/
#define AT91_PWM_CCNT(ch_num) (0x200 + ch_num * 0x20 + 0x0C) /*Channel Counter Register*/
#define AT91_PWM_CUPD(ch_num) (0x200 + ch_num * 0x20 + 0x10) /*Channel Update Register*/
/*错误类型*/
#define DRV_NO_ERROR (0) //正常
#define DRV_ERROR_DEV (-1) //设备打开失败
#define DRV_ERROR_INPUT_ARGS (-2) //输入参数错误
#define DRV_ERROR_OPT_FAILED (-3) //操作失败
#define DRV_ERROR_OPT_NOT_OVER (-4) //操作未结束
#define DRV_ERROR_DEV_BUSY (-5) //设备忙
/*操作类型*/
#define DRV_OPTTYPE_SET (0x1000) //设置
#define DRV_OPTTYPE_GET (0x1100) //读取
#define DRV_OPTTYPE_INIT (0x1200) //初始化
/*常用类型*/
#define DRV_TRUE 1
#define DRV_FALSE 0
/*设备状态定义*/
#define DRV_STATUS_IDLE 0x10
#define DRV_STATUS_BUSY 0x11
#define DRV_STATUS_TX 0x12
#define DRV_STATUS_RX 0x13
/*其他*/
#ifndef NULL
#define NULL ((void*)0)
struct iouart_platform_data
{
u32 tx_pin;
u32 rx_pin;
u32 tx_pin_base;
u32 rx_pin_base;
u32 tx_pin_port;
u32 rx_pin_port;
u32 rx_pin_irq;
u32 tc_irq;
u32 flags;
u32 pwm_pin;
u32 pwm_port;
void __iomem *tc_base;
void __iomem *pwm_base;
struct resource *tc_res;
struct resource *pwm_res;
};
#define IOUART_BUF_LEN (4*1024) //发送、接收缓冲区最大长度
struct ring_t
{
unsigned char buf[IOUART_BUF_LEN];
unsigned int index; //对于rx来说,index表示待读取数据首地址索引,对于tx来说,表示待发送数据首地址索引
unsigned int len; //对于rx来说,len表示当前未读取的数据长度,对于tx来说,表示未发送的数据长度
unsigned char bitStep;
unsigned char parity;
unsigned char byte;
};
struct iouart_dev_t
{
struct ring_t rx; //接收缓冲区
struct ring_t tx; //发送缓冲区
spinlock_t lock; //自旋锁
wait_queue_head_t tx_waitqueue; //发送等待队列
int trans_status; //通讯状态
struct platform_device *pdev;
};
/*****************irda设备定义****************/
static struct resource irda_uart_resource[] =
{
[0] =
{
.start = AT91SAM9X5_BASE_TC3,
.end = AT91SAM9X5_BASE_TC3 + 0x40 - 1,
.flags = IORESOURCE_MEM,
},
[1] =
{
.start = AT91SAM9X5_BASE_PWMC,
.end = AT91SAM9X5_BASE_PWMC + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
};
static struct iouart_platform_data irda_uart_data =
{
.tx_pin = AT91_PIN_PC2,
.rx_pin = AT91_PIN_PB13,
.tx_pin_base = AT91_PIN_PC0,
.rx_pin_base = AT91_PIN_PB0,
.tx_pin_port = AT91_PIOC,
.rx_pin_port = AT91_PIOB,
.flags = TX_ENABLE | RX_ENABLE | PWM_ENABLE ,//| TX_PIN_OPENDRAIN,
.pwm_pin = AT91_PIN_PB18,
.pwm_port = PWM1,
.rx_pin_irq = AT91SAM9X5_ID_PIOAB,
.tc_irq = AT91SAM9X5_ID_TCB,
};
/****************平台设备与驱动************************/
static struct platform_device iouart_device[] =
{
[0] =
{
.name = "irda",
.id = 0,
.dev =
{
.platform_data = &irda_uart_data,
.release = iouart_release,
},
.resource = irda_uart_resource,
.num_resources = ARRAY_SIZE(irda_uart_resource),
},
};
static struct platform_driver iouart_driver[] =
{
[0] =
{
.probe = iouart_probe,
.remove = iouart_remove,
.driver =
{
.name = "irda",
.owner= THIS_MODULE,
},
},
};
static struct file_operations iouart_ops =
{
.owner = THIS_MODULE,
.open = iouart_open,
.release = iouart_close,
.read = iouart_read,
.write = iouart_write,
};
static int major = 0; //主设备号
static struct class *iouart_class; //class
static long l_rxIrqIsr[4] = {0,0,0,0}; //针对rx pin中断的isr保留值?
static int __init iouart_init(void)
{
int ret = 0,m,n,k;
/*注册字符设备*/
ret = register_chrdev(major,DEV_NAME,&iouart_ops);
if(ret < 0)
{
printk(KERN_INFO "iouart_init: register char dev failed !\n");
return -1;
}
/*获取动态分配主设备号*/
if(major == 0)
{
major = ret;
}
/*注册dev class*/
iouart_class = class_create(THIS_MODULE,DEV_NAME);
if(IS_ERR(iouart_class))
{
printk(KERN_INFO "iouart_init: class create failed !\n");
goto fail0;
}
/*注册platform_device*/
for(m = 0; m < ARRAY_SIZE(iouart_device); m++)
{
ret = platform_device_register(&iouart_device[m]);
if(ret < 0)
{
printk(KERN_INFO "iouart_init: platform register device failed !\n");
goto fail1;
}
}
/*注册platform driver*/
for(n = 0; n < ARRAY_SIZE(iouart_driver); n++)
{
ret = platform_driver_register(&iouart_driver[n]);
if(ret < 0)
{
printk(KERN_INFO "iouart_init: platform register driver failed !\n");
goto fail2;
}
}
return 0;
fail2:
for(k = 0; k < n; k++)
{
platform_driver_unregister(&iouart_driver[k]);
}
fail1:
for(k = 0; k < m; k++)
{
platform_device_unregister(&iouart_device[k]);
}
class_destroy(iouart_class);
fail0:
unregister_chrdev(major,DEV_NAME);
return -1;
}
static void __exit iouart_exit(void)
{
int i;
for(i = 0; i < ARRAY_SIZE(iouart_driver); i++)
{
platform_driver_unregister(&iouart_driver[i]);
}
for(i = 0; i < ARRAY_SIZE(iouart_device); i++)
{
platform_device_unregister(&iouart_device[i]);
}
class_destroy(iouart_class);
unregister_chrdev(major,DEV_NAME);
}
module_init(iouart_init);
module_exit(iouart_exit);
MODULE_AUTHOR("luke.zhao");
MODULE_LICENSE("Dual BSD/GPL");
struct platform_device *get_pdev_by_iminor(unsigned int minor)
{
return &iouart_device[minor];
}
static int iouart_probe(struct platform_device *pdev)
{
struct device *dev;
struct iouart_platform_data *pdata;
dev_t dev_no;
int ret = 0;
pdata = pdev->dev.platform_data;
/*获取资源及分配*/
pdata->tc_res = platform_get_resource(pdev,IORESOURCE_MEM,0);
if(!pdata->tc_res)
{
printk(KERN_INFO "iouart_probe : platform_get_resource : tc_res failed !\n");
return -ENXIO;
}
if(!request_mem_region(pdata->tc_res->start,resource_size(pdata->tc_res),pdev->name))
{
printk(KERN_INFO "iouart_probe : request_mem_region : tc_res failed !\n");
return -EBUSY;
}
pdata->tc_base = ioremap(pdata->tc_res->start,resource_size(pdata->tc_res));
if(!pdata->tc_base)
{
printk(KERN_INFO "iouart_probe : tc_base ioremap :tc_res failed !\n");
ret = -ENOMEM;
goto fail0;
}
if((pdata->flags & PWM_ENABLE) > 0)
{
pdata->pwm_res = platform_get_resource(pdev,IORESOURCE_MEM,1);
if(!pdata->pwm_res)
{
printk(KERN_INFO "iouart_probe : platform_get_resource : pwm_res failed !\n");
ret = -ENXIO;
goto fail0;
}
if(!request_mem_region(pdata->pwm_res->start,resource_size(pdata->pwm_res),pdev->name))
{
printk(KERN_INFO "iouart_probe : request_mem_region : pwm_res failed !\n");
ret = -EBUSY;
goto fail0;
}
pdata->pwm_base = ioremap(pdata->pwm_res->start,resource_size(pdata->pwm_res));
if(!pdata->pwm_base)
{
printk(KERN_INFO "iouart_probe : pwm_base ioremap : pwm_res failed !\n");
ret = -EACCES;
goto fail1;
}
}
/*硬件设备初始化*/
iouart_hw_enable(pdata);
/*创建dev*/
dev_no = MKDEV(major,pdev->id);
dev = device_create(iouart_class,&pdev->dev,dev_no,NULL,pdev->name);
if(IS_ERR(dev))
{
printk(KERN_INFO "iouart_probe: device create failed !\n");
ret = -EACCES;
goto fail2;
}
return 0;
fail2:
iounmap(pdata->tc_base);
if((pdata->flags & PWM_ENABLE) > 0)
{
iounmap(pdata->pwm_base);
}
fail1:
if((pdata->flags & PWM_ENABLE) > 0)
{
release_mem_region(pdata->pwm_res->start,resource_size(pdata->pwm_res));
}
fail0:
release_mem_region(pdata->tc_res->start,resource_size(pdata->tc_res));
return ret;
}
static int iouart_remove(struct platform_device *pdev)
{
struct iouart_platform_data *pdata;
dev_t dev_no;
pdata = pdev->dev.platform_data;
// printk(KERN_INFO "iouart_remove start !\n");
/*注销设备*/
dev_no = MKDEV(major,pdev->id);
device_destroy(iouart_class,dev_no);
/*硬件禁止*/
iouart_hw_disable(pdata);
/*释放资源*/
iounmap(pdata->tc_base);
if((pdata->flags & PWM_ENABLE) > 0)
{
iounmap(pdata->pwm_base);
}
if((pdata->flags & PWM_ENABLE) > 0)
{
release_mem_region(pdata->pwm_res->start,resource_size(pdata->pwm_res));
}
release_mem_region(pdata->tc_res->start,resource_size(pdata->tc_res));
// printk(KERN_INFO "iouart_remove end !\n");
return 0;
}
static int iouart_open(struct inode *inode, struct file *filp)
{
int ret;
long rxIrqIsr;
unsigned int minor = iminor(inode);
struct iouart_dev_t *iouart_dev;
struct platform_device *pdev;
struct iouart_platform_data *pdata;
pdev = get_pdev_by_iminor(minor);
if(pdev == NULL)
{
printk(KERN_INFO "iouart_open : get_pdev_by_iminor failed !\n");
return -EACCES;
}
/*分配esam dev数据结构体内存*/
iouart_dev = kmalloc(sizeof(struct iouart_dev_t),GFP_KERNEL);
if(!iouart_dev)
{
printk(KERN_INFO "iouart_open : kmalloc iouart_dev failed !\n");
return -ENOMEM;
}
/*初始化esam dev数据结构体*/
memset(&iouart_dev->rx,0,sizeof(struct ring_t));
memset(&iouart_dev->tx,0,sizeof(struct ring_t));
iouart_dev->pdev = pdev;
iouart_dev->trans_status = DRV_STATUS_RX;
pdata = iouart_dev->pdev->dev.platform_data;
spin_lock_init(&iouart_dev->lock);
init_waitqueue_head(&iouart_dev->tx_waitqueue);
/*申请中断*/
ret = request_irq(pdata->tc_irq,iouart_func_timer_interrupt,IRQF_SHARED,iouart_dev->pdev->name,iouart_dev);
if(ret < 0)
{
printk(KERN_INFO "iouart_open : request_irq_timer failed ! ret = %d\n",ret);
kfree(iouart_dev);
return ret;
}
ret = request_irq(pdata->rx_pin_irq,iouart_func_rxio_interrupt,IRQF_SHARED,iouart_dev->pdev->name,iouart_dev);
if(ret < 0)
{
printk(KERN_INFO "iouart_open : request_irq_rxio failed ! ret = %d\n",ret);
free_irq(pdata->tc_irq,iouart_dev);
kfree(iouart_dev);
return ret;
}
/*存储iouart_dev结构体到private_data*/
filp->private_data = iouart_dev;
/*清中断标志*/
rxIrqIsr = get_rxirq_isr(pdata->rx_pin_port);
rxIrqIsr &=~(1 << (pdata->rx_pin - pdata->rx_pin_base));
set_rxirq_isr(pdata->rx_pin_port,rxIrqIsr);
/*触发接收中断*/
at91_sys_write((pdata->rx_pin_port+PIO_IER),(1 << (pdata->rx_pin - pdata->rx_pin_base)));
return 0;
}
static int iouart_close(struct inode *inode, struct file *filp)
{
struct iouart_dev_t *iouart_dev = (struct iouart_dev_t*)(filp->private_data);
struct iouart_platform_data *pdata;
pdata = iouart_dev->pdev->dev.platform_data;
free_irq(pdata->tc_irq,iouart_dev);
free_irq(pdata->rx_pin_irq,iouart_dev);
/*禁止接收中断*/
at91_sys_write((pdata->rx_pin_port+PIO_IDR),(1 << (pdata->rx_pin - pdata->rx_pin_base)));
kfree(iouart_dev);
return 0;
}
static ssize_t iouart_read(struct file *filp, char __user *buf, size_t len, loff_t *loffp)
{
int cpyLen,i;
struct iouart_dev_t *iouart_dev = (struct iouart_dev_t*)filp->private_data;
/*计算读取长度*/
cpyLen = (iouart_dev->rx.len > len) ? len : iouart_dev->rx.len;
/*从接收缓冲区中读取数据到buf*/
for(i = 0; i < cpyLen; i++)
{
put_user(iouart_dev->rx.buf[(iouart_dev->rx.index + i) % IOUART_BUF_LEN],&buf[i]);
}
/*重新计算接收缓冲区参数*/
spin_lock_irq(&iouart_dev->lock);
iouart_dev->rx.index += cpyLen;
iouart_dev->rx.index %= IOUART_BUF_LEN;
iouart_dev->rx.len -= cpyLen;
spin_unlock_irq(&iouart_dev->lock);
return cpyLen;
}
static ssize_t iouart_write(struct file *filp, const char __user *buf, size_t len, loff_t *loffp)
{
int validLen,i,currentLen,currentIndex,currentMaxBufLen;
struct iouart_dev_t *iouart_dev = (struct iouart_dev_t*)filp->private_data;
/*计算当前能写的字节长度*/
currentLen = iouart_dev->tx.len;
currentIndex = iouart_dev->tx.index;
currentMaxBufLen = IOUART_BUF_LEN;
validLen = currentMaxBufLen - currentLen;
if(len > validLen)
goto exit0;
/*循环将buf中的数据写入发送缓冲区*/
for(i = 0; i < len; i++)
{
get_user(iouart_dev->tx.buf[(iouart_dev->tx.index + iouart_dev->tx.len+i)% IOUART_BUF_LEN],&buf[i]);
}
/*重新计算发送缓冲区的参数*/
spin_lock_irq(&iouart_dev->lock);
iouart_dev->tx.len += len;
spin_unlock_irq(&iouart_dev->lock);
if(iouart_dev->tx.len == 0)
goto exit0;
/*启动发送*/
if(iouart_dev->trans_status == DRV_STATUS_RX)
{
iouart_start_send(iouart_dev);
}
/*等待数据发送完成*/
// interruptible_sleep_on(&iouart_dev->tx_waitqueue);
return len;
exit0:
return 0;
}
这里的代码主要是实现IO模拟串口收发数据的过程,主要是硬件初始化、中断、定时器等。
static void iouart_hw_enable(struct iouart_platform_data *pdata)
{
/*PWM使能*/
if((pdata->flags & PWM_ENABLE) > 0)
{
at91_sys_write(AT91_PMC_PCER, 1 << 18); //使能PWM的CLOCK
at91_set_C_periph(pdata->pwm_pin,1); //配置PWM1
at91_pwm_write(pdata->pwm_base,AT91_PWM_CMR(pdata->pwm_port),PWM_CPRE_MCKDIV1 | PWM_CALG_LEFT); //MCK=100M
at91_pwm_write(pdata->pwm_base,AT91_PWM_CDTY(pdata->pwm_port),1316);
at91_pwm_write(pdata->pwm_base,AT91_PWM_CPRD(pdata->pwm_port),2631); //period = MCK / 2603 = 38K
at91_pwm_write(pdata->pwm_base,AT91_PWM_ENA,(1 << pdata->pwm_port)); //使能PWM1
}
/*IO管脚配置*/
if((pdata->flags & TX_ENABLE) > 0)
{
if((pdata->flags & TX_PIN_OPENDRAIN) > 0)
at91_set_multi_drive(pdata->tx_pin,((pdata->flags & TX_PIN_OPENDRAIN) > 0 ? 1 : 0));
at91_set_gpio_output(pdata->tx_pin,1); //TX pin
}
if((pdata->flags & RX_ENABLE) > 0)
{
at91_set_gpio_input(pdata->rx_pin,1); //RX pin
at91_set_deglitch(pdata->rx_pin,1);
}
at91_sys_write((pdata->rx_pin_port+PIO_AIMER),(1 << (pdata->rx_pin-pdata->rx_pin_base)));
at91_sys_write((pdata->rx_pin_port+PIO_FELLSR),(1 << (pdata->rx_pin-pdata->rx_pin_base))); //data pin下降沿触发中断
at91_sys_write((pdata->rx_pin_port+PIO_IDR),(1 << (pdata->rx_pin-pdata->rx_pin_base))); //禁止io中断
/*enable transfer timer*/
at91_sys_write(AT91_PMC_PCER, 1 << 17); //使能TC的CLOCK
at91_tc_write(pdata->tc_base,AT91_TC_CMR,AT91_TC_TIMER_CLOCK3 | AT91_TC_CPCSTOP | \
AT91_TC_WAVE | AT91_TC_WAVESEL_UP ); // MCK/32= 100/32 = 3.125MHZ
at91_tc_write(pdata->tc_base,AT91_TC_IER,AT91_TC_CPCS); //中断使能
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_CLKEN); //定时器使能
}
static void iouart_hw_disable(struct iouart_platform_data *pdata)
{
if((pdata->flags & PWM_ENABLE) > 0)
{
/*disable pwm clk*/
at91_pwm_write(pdata->pwm_base,AT91_PWM_DIS,(1 << pdata->pwm_port)); //禁止PWM
}
/*disable esam rxio*/
at91_sys_write((pdata->rx_pin_port+PIO_IDR),(1 << (pdata->rx_pin-pdata->rx_pin_base))); //接收中断禁止
/*disable transfer timer*/
at91_tc_write(pdata->tc_base,AT91_TC_IDR,AT91_TC_CPCS); //中断禁止
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_CLKDIS); //定时器禁止
}
static unsigned int get_rxirq_isr(int pin_port)
{
unsigned int retValue;
retValue = at91_sys_read(pin_port+PIO_ISR);
retValue &= at91_sys_read(pin_port+PIO_IMR);
switch(pin_port)
{
case AT91_PIOA:
{
l_rxIrqIsr[0] |= retValue;
return l_rxIrqIsr[0];
}
case AT91_PIOB:
{
l_rxIrqIsr[1] |= retValue;
return l_rxIrqIsr[1];
}
case AT91_PIOC:
{
l_rxIrqIsr[2] |= retValue;
return l_rxIrqIsr[2];
}
case AT91_PIOD:
{
l_rxIrqIsr[3] |= retValue;
return l_rxIrqIsr[3];
}
default:
{
break;
}
}
return 0;
}
static void set_rxirq_isr(int pin_port,long rxIrqIsr)
{
switch(pin_port)
{
case AT91_PIOA:
{
l_rxIrqIsr[0] = rxIrqIsr;
break;
}
case AT91_PIOB:
{
l_rxIrqIsr[1] = rxIrqIsr;
break;
}
case AT91_PIOC:
{
l_rxIrqIsr[2] = rxIrqIsr;
break;
}
case AT91_PIOD:
{
l_rxIrqIsr[3] = rxIrqIsr;
break;
}
default:
{
break;
}
}
}
static void iouart_start_send(struct iouart_dev_t *dev)
{
struct iouart_dev_t *iouart_dev = dev;
struct iouart_platform_data *pdata = iouart_dev->pdev->dev.platform_data;
/*禁止IO中断*/
at91_sys_write((pdata->rx_pin_port+PIO_IDR),(1 << (pdata->rx_pin-pdata->rx_pin_base)));;
spin_lock_irq(&iouart_dev->lock);
iouart_dev->trans_status = DRV_STATUS_TX;
iouart_dev->tx.byte = iouart_dev->tx.buf[iouart_dev->tx.index];
iouart_dev->tx.index++;
iouart_dev->tx.index %= IOUART_BUF_LEN;
iouart_dev->tx.len--;
iouart_dev->tx.bitStep = 0;
iouart_dev->tx.parity = 0;
spin_unlock_irq(&iouart_dev->lock);
/*启动发送*/
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
}
//注意,此处由于是io中断,所有的中断号共享一个isr,所以所有的rx_pin中断有可能全在这里处理了。
static irqreturn_t iouart_func_rxio_interrupt(int irq, void *dev_id)
{
unsigned int rxIrqIsr;
struct iouart_dev_t *iouart_dev = (struct iouart_dev_t *)dev_id;
struct iouart_platform_data *pdata = iouart_dev->pdev->dev.platform_data;
/*读取中断标志*/
rxIrqIsr = get_rxirq_isr(pdata->rx_pin_port);
if((rxIrqIsr & (1 << (pdata->rx_pin - pdata->rx_pin_base))) > 0)
{
rxIrqIsr &=~(1 << (pdata->rx_pin - pdata->rx_pin_base));
if(iouart_dev->trans_status == DRV_STATUS_RX)
{
/*禁止IO中断*/
at91_sys_write((pdata->rx_pin_port+PIO_IDR),(1 << (pdata->rx_pin-pdata->rx_pin_base))); //禁止io中断
/*设置检查状态*/
iouart_dev->rx.bitStep = 0x00;
iouart_dev->tx.parity = 0;
iouart_dev->rx.byte = 0x00;
/*开启检查起始位的定时器*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT/2);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
}
}
/*保存中断值,共下一个rx中断查询使用*/
set_rxirq_isr(pdata->rx_pin_port,rxIrqIsr);
return IRQ_NONE;
}
static irqreturn_t iouart_func_timer_interrupt(int irq, void *dev_id)
{
long retval;
struct iouart_dev_t *iouart_dev = (struct iouart_dev_t *)dev_id;
struct iouart_platform_data *pdata = iouart_dev->pdev->dev.platform_data;
/*读取中断状态*/
retval = at91_tc_read(pdata->tc_base,AT91_TC_SR);
retval &= at91_tc_read(pdata->tc_base,AT91_TC_IMR);
if((retval & AT91_TC_CPCS) > 0)
{
if(iouart_dev->trans_status == DRV_STATUS_RX)
{
iouart_timer_rx(iouart_dev);
}
else if(iouart_dev->trans_status == DRV_STATUS_TX)
{
iouart_timer_tx(iouart_dev);
}
else
{
printk(KERN_INFO "iouart_func_timer_interrupt : wrong status !\n");
}
}
return IRQ_NONE;
}
void iouart_timer_tx(struct iouart_dev_t *iouart_dev)
{
unsigned int rxIrqIsr;
struct iouart_platform_data *pdata = iouart_dev->pdev->dev.platform_data;
switch(iouart_dev->tx.bitStep)
{
case 0: //发送起始位
{
at91_set_gpio_value(pdata->tx_pin,0);
iouart_dev->tx.bitStep++;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
break;
}
case 9: //发送校验位,本口是固定偶校验
{
if(iouart_dev->tx.parity == 0)
{
at91_set_gpio_value(pdata->tx_pin,0);
}
else
{
at91_set_gpio_value(pdata->tx_pin,1);
}
iouart_dev->tx.bitStep++;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
break;
}
case 10: //发送固定1位停止位
{
at91_set_gpio_value(pdata->tx_pin,1);
iouart_dev->tx.bitStep++;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
break;
}
case 11: //表示1字节发送完成
{
if(iouart_dev->tx.len > 0)
{
iouart_dev->tx.byte = iouart_dev->tx.buf[iouart_dev->tx.index];
iouart_dev->tx.index++;
iouart_dev->tx.index %= IOUART_BUF_LEN;
iouart_dev->tx.len--;
iouart_dev->tx.bitStep = 0;
iouart_dev->tx.parity = 0;
at91_set_gpio_value(pdata->tx_pin,1);
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
}
else
{
iouart_dev->trans_status = DRV_STATUS_RX;
/*清中断标志*/
rxIrqIsr = get_rxirq_isr(pdata->rx_pin_port);
rxIrqIsr &=~(1 << (pdata->rx_pin - pdata->rx_pin_base));
set_rxirq_isr(pdata->rx_pin_port,rxIrqIsr);
/*允许IO中断*/
at91_sys_write((pdata->rx_pin_port+PIO_IER),(1 << (pdata->rx_pin-pdata->rx_pin_base)));
/*唤醒发送等待队列*/
// wake_up_interruptible(&iouart_dev->tx_waitqueue);
}
break;
}
default: //发送BIT0~BIT8
{
if((iouart_dev->tx.byte & (1 << (iouart_dev->tx.bitStep - 1))) > 0)
{
at91_set_gpio_value(pdata->tx_pin,1);
iouart_dev->tx.parity = 1 - iouart_dev->tx.parity;
}
else
{
at91_set_gpio_value(pdata->tx_pin,0);
}
iouart_dev->tx.bitStep++;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
break;
}
}
}
void iouart_timer_rx(struct iouart_dev_t *iouart_dev)
{
unsigned int rxIrqIsr;
struct iouart_platform_data *pdata = iouart_dev->pdev->dev.platform_data;
switch(iouart_dev->rx.bitStep)
{
case 0: //检查起始位是否正常
{
if(at91_get_gpio_value(pdata->rx_pin) == 0)
{
iouart_dev->rx.bitStep++;
iouart_dev->rx.parity = 0;
iouart_dev->rx.byte = 0;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
}
else
{
// printk("接收起始位错误!\n");
goto exit1;
}
break;
}
case 9: //接收校验位
{
if(at91_get_gpio_value(pdata->rx_pin) == 0) //检测到低电平
{
if(iouart_dev->rx.parity > 0)
{
// printk("校验位错误!\n");
goto exit1;
}
}
else //检测到高电平
{
if(iouart_dev->rx.parity == 0)
{
// printk("校验位错误!\n");
goto exit1;
}
}
iouart_dev->rx.bitStep++;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
break;
}
case 10: //接收停止位,1字节接收完成
{
if(at91_get_gpio_value(pdata->rx_pin) > 0 && iouart_dev->rx.len < IOUART_BUF_LEN) //检测到高电平
{
iouart_dev->rx.buf[(iouart_dev->rx.index + iouart_dev->rx.len)%IOUART_BUF_LEN] = iouart_dev->rx.byte;
iouart_dev->rx.len++;
}
goto exit1;
}
default: //接收数据位
{
if(at91_get_gpio_value(pdata->rx_pin) == 0) //检测到低电平
{
iouart_dev->rx.byte &= ~(1 << (iouart_dev->rx.bitStep - 1));
}
else //检测到高电平
{
iouart_dev->rx.byte |= (1 << (iouart_dev->rx.bitStep - 1));
iouart_dev->rx.parity = 1 - iouart_dev->rx.parity;
}
iouart_dev->rx.bitStep++;
/*timer start*/
at91_tc_read(pdata->tc_base,AT91_TC_SR);
at91_tc_write(pdata->tc_base,AT91_TC_RC,IOUART_TIMER_COUNT);
at91_tc_write(pdata->tc_base,AT91_TC_CCR,AT91_TC_SWTRG);
break;
}
}
return;
exit1:
iouart_dev->rx.bitStep = 0x00;
iouart_dev->rx.parity = 0x00;
iouart_dev->rx.byte = 0x00;
/*清中断标志*/
rxIrqIsr = get_rxirq_isr(pdata->rx_pin_port);
rxIrqIsr &=~(1 << (pdata->rx_pin - pdata->rx_pin_base));
set_rxirq_isr(pdata->rx_pin_port,rxIrqIsr);
/*允许IO接收中断*/
at91_sys_write((pdata->rx_pin_port+PIO_IER),(1 << (pdata->rx_pin-pdata->rx_pin_base)));
}
好了红外串口IO模拟实现代码就是这样,以上代码发送与接收使用的是同一个定时器中断,因此只能实现半双工通信,要想实现全双工通信,则必须使用两个定时器,不过半双工一般就够用了。希望这个代码对小伙伴们有点用,此代码写于4年前。