Author-------Dansen-----xzd2734@163.com
Dsp 提供了hpi接口,可以用来和 Arm 通信,一年多前我刚接触Arm的工作就是要写一个hpi接口的驱动。最近真正需要把接口给用起来,又修改了一下代码,添加了中断,不过感觉还是不完美,再看看设备驱动程序这本书再来修改吧。
我们用的是c5416,增强型的8位hpi接口,先看看用到的寄存器吧。
HPI 有三个寄存器:地址寄存器 HPIA,控制寄存器 HPIC 以及数据寄存器 HPID。
接着是HPIC各个位的定义
X位不受写影响,读取是可以是0也可以是1
HPIC的高8位和低8位是一样的
BOB 该比特位只能由主机读写,C54X 无法访问。如果 BOB=1,表示 HPI 的 16 位传输中的第一个 8 位字节是低 8位;BOB=0,表示第一个 8 位字节为高 8 位。该比特位必须在读写数据和地址寄存器之前设置。
XHPIA 扩展地址使能位。XHPIA=1,主机写入的值被装入地址寄存器高位HPIA[n:16]. XHPIA=0, 主机写入的值被装入地址寄存器高位HPIA[15:0]. 只有主机可以读写。Dsp的内存地址从00000000---0003ffff 高位地址只是从0到3有效
HINT 该比特位主机和 C54X都可以读写。该比特决定了 C54X引脚 HINT 的状态。C54X可以利用该信号发送中断到主机。当 C54X 在复位状态时,HINT 比特位为 0,对应的 HINT 脚为高电平。当 C54X 将该比特位设置为 1 时,HINT 脚将变为低电平。注意,当主机和 C54X读取该比特位时,它将反映 HINT 引脚的状态,0 表示高电平,1 表示低电平。另外,该比特位只能由 C54X设置,由主机清除。主机将 1写到该比特位,将清除 HINT位,即 HINT 位为 0。
DSPINT 该比特位只能由主机写,并且 C54X 和主机都无法读取。当主机将 1 写到该比特位时,将产生一个中断到 C54X。如果 IMR 寄存器中的 HPINT 位(D9)被设置为 1,DSP 将响应该中断,执行相应的中断服务程序。
给出dsp c5416和arm s3c2410的接线图
关于HPI引脚的定义不再介绍,自己参考手册吧
由于初始化时把HPIC的BOB置为0,所以HBIL(A1)引脚为低时送的是高字节
其顺序必须是HBIL先低后高,所以必须先送高字节后送低字节。
通过此图可以计算Hpi的端口地址
HPIC_WriteH = hpi_vbase+0x00
HPIC_WriteL = hpi_vbase+0x02
HPIC_ReadH = hpi_vbase+0x10
HPIC_ReadL = hpi_vbase+0x12
HPIA_WriteH = hpi_vbase+0x04
HPIA_WriteL = hpi_vbase+0x06
HPIA_ReadH = hpi_vbase+0x14
HPIA_ReadL = hpi_vbase+0x16
HPID_AutoWriteH = hpi_vbase+0x08
HPID_AutoWriteL = hpi_vbase+0x0a
HPID_AutoReadH = hpi_vbase+0x18
HPID_AutoReadL = hpi_vbase+0x1a
HPID_WriteH = hpi_vbase+0x0c
HPID_WriteL = hpi_vbase+0x0e
HPID_ReadH = hpi_vbase+0x1c
HPID_ReadL = hpi_vbase+0x1e
理解了原理再写驱动就比较方便了
首先要设置HPIC,然后给HPIA写一个地址,接着就可以通过HPID读写数据了。
有地址自增和不自增两种方式,其地址是不一样的。
注意: 自增读时,先读后自增
自增写时,先自增后写 所以写的时候要注意地址
嘿嘿,要看源代码,到下一章去吧。
Author-------Dansen-----xzd2734@163.com
给出我写的源码,其中中断和几个变量是为了追球的任务特别添加的,基本不是通用的,还能继续改进的吧,不过暂时先这么用了。没有对中断中使用的共享变量进行保护啊,这是错误的地方,至少要关中断啊!再修改了!
/*
Dsp hpi interface with ARM 9 for s3c2410
Author--------Dansen----2007.09.05
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/ioport.h>
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
//#define HPI_DEBUG
#undef PDEBUG /* undef it, just in case */
#ifdef HPI_DEBUG
# ifdef __KERNEL__ /* This one if debugging is on, and kernel space */
# define PDEBUG(fmt, args...) printk( KERN_EMERG "hpi: " fmt, ## args)
# else /* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
# endif
#else
# define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif
#define HPI_BASEADDR 0x10000300 // BANK 2
#define HPI_MAJOR 200 /* dynamic major by default */
#define HPI_INT IRQ_EINT19
#define HPI_MAGIC 'K'
#define HPI_RESET _IO(HPI_MAGIC, 0)
#define Write_HPIC _IO(HPI_MAGIC, 1)
#define Read_HPIC _IO(HPI_MAGIC, 2)
#define Write_HPIA _IO(HPI_MAGIC, 3)
#define Read_HPIA _IO(HPI_MAGIC, 4)
#define Write_HPID_Auto _IO(HPI_MAGIC, 5)
#define Read_HPID_Auto _IO(HPI_MAGIC, 6)
#define Write_HPID _IO(HPI_MAGIC, 7)
#define Read_HPID _IO(HPI_MAGIC, 8)
#define Auto_HPID _IO(HPI_MAGIC, 9)
#define NoAuto_HPID _IO(HPI_MAGIC, 10)
#define Set_DSPINT _IO(HPI_MAGIC, 11)
#define Get_ball_found _IO(HPI_MAGIC, 12)
#define Get_ball_cy _IO(HPI_MAGIC, 13)
#define Get_ball_cx _IO(HPI_MAGIC, 14)
#define Disable_int _IO(HPI_MAGIC, 15)
#define Enable_int _IO(HPI_MAGIC, 16)
#define HPI_IOC_MAXNR 16
typedef struct hpi_device
{
int no_autoread;
int ball_found;
int ball_cy;
int ball_cx;
unsigned int buzy;
void * hpi_vbase;
char * HpiBaseBufRead;
char * HpiBaseBufWrite;
struct semaphore sem;
} HPI_DEV;
devfs_handle_t hpi_devfs;
HPI_DEV * hpi_dev;
int hpi_open (struct inode *inode, struct file *filp)
{
PDEBUG ("hpi device_open(%p,%p)/n", inode, filp);
if(hpi_dev->buzy)
{
printk("hpi device is in using/n");
return -1;
}
hpi_dev->buzy=1;
filp->private_data = hpi_dev;
MOD_INC_USE_COUNT;
enable_irq(HPI_INT);
return 0;
}
int hpi_release (struct inode *inode, struct file *filp)
{
disable_irq(HPI_INT);
MOD_DEC_USE_COUNT;
hpi_dev->buzy=0;
PDEBUG ("hpi device_release(%p,%p)/n", inode, filp);
return 0;
}
inline void HPIC_Write(u16 w)
{
unsigned char t1,t2;
t1 = (0xff00 & w) >>8;
t2 = (0x00ff & w);
outb(t1,hpi_dev->hpi_vbase+0x00);//写高字节
outb(t2,hpi_dev->hpi_vbase+0x02);//写低字节
}
inline u16 HPIC_Read(void)
{
unsigned char t1,t2;
t1=inb(hpi_dev->hpi_vbase+0x10);//读高字节
t2=inb(hpi_dev->hpi_vbase+0x12);//读低字节
return( (t1<<8) | t2);
}
inline void HPIA_Write(u16 w)
{
unsigned char t1,t2;
t1 = (0xff00 & w) >>8;
t2 = (0x00ff & w);
outb(t1,hpi_dev->hpi_vbase+0x04);//写高地址
outb(t2,hpi_dev->hpi_vbase+0x06); //写低地址
}
inline u16 HPIA_Read(void)
{
unsigned char t1,t2;
t1=inb(hpi_dev->hpi_vbase+0x14);//读高地址
t2=inb(hpi_dev->hpi_vbase+0x16);//读低地址
return( (t1<<8) | t2);
}
inline void HPID_AutoWrite(u16 w)
{
unsigned char t1,t2;
t1 = (0xff00 & w) >>8;
t2 = (0x00ff & w);
outb(t1,hpi_dev->hpi_vbase+0x08);
outb(t2,hpi_dev->hpi_vbase+0x0a);
}
inline u16 HPID_AutoRead(void)
{
unsigned char t1,t2;
t1=inb(hpi_dev->hpi_vbase+0x18);
t2=inb(hpi_dev->hpi_vbase+0x1a);
return( (t1<<8) | t2);
}
inline void HPID_Write(u16 w)
{
unsigned char t1,t2;
t1 = (0xff00 & w) >>8;
t2 = (0x00ff & w);
outb(t1,hpi_dev->hpi_vbase+0x0c);
outb(t2,hpi_dev->hpi_vbase+0x0e);
}
inline u16 HPID_Read(void)
{
unsigned char t1,t2;
t1=inb(hpi_dev->hpi_vbase+0x1c);
t2=inb(hpi_dev->hpi_vbase+0x1e);
return( (t1<<8) | t2);
}
inline void setdspint(void)//初始化dsp
{
HPIC_Write(HPIC_Read() | 0x0404);
}
inline void clearhostint(void)
{
HPIC_Write(HPIC_Read() | 0x0808);
}
static void hpi_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
HPI_DEV *dev = dev_id;
HPIA_Write(0x0000);
dev->ball_found = HPID_AutoRead();
dev->ball_cy = HPID_AutoRead();
dev->ball_cx = HPID_AutoRead();
}
ssize_t hpi_read (struct file *filp, char *buf,size_t count,loff_t *oppos)
{
HPI_DEV *dev = filp->private_data;
int i;
size_t ret ;
if (dev->no_autoread) count=2;
dev->HpiBaseBufRead=kmalloc(count, GFP_KERNEL);
if (!dev->HpiBaseBufRead) return -ENOMEM;
if (down_interruptible (&dev->sem))
{
kfree(dev->HpiBaseBufRead);
return -ERESTARTSYS;
}
for(i=0;i<count/2;i++)
{
if (dev->no_autoread)
((u16 *)dev->HpiBaseBufRead)[i]=HPID_Read();
else
((u16 *)dev->HpiBaseBufRead)[i]=HPI