hpi 驱动修改及一些杂碎

使用DSP和FPGA的视频图像处理卡每秒处理24帧图像,计算出目标物体(球)的位置(一般是通过颜色差异分解出物体),然后给ARM中断,ARM通过HPI口读取相关数据。
由于hpi并不是一种真正的字符设备,看起来又很像一种块设备,给定随机地址可以读取大块的dsp数据,这让我不知道怎么去实现,但是块设备的驱动程序我还没怎么看过,所以还是选择字符设备来实现,可是也不能像字符设备一样创建一个缓冲区,把接受到的数据放进去,因为主机从不被动接受数据,都是去主动读取,于是我想不管怎么样,读写就是先设定地址,然后把读写指定大小的数据就是了,对于中断,原来我想的是中断来了后,通过中断服务程序把指定的数据读到内核的一个buffer里,然后通知应用程序来取,不过不像串口那样数据不断累积,直到buffer满,由于我需要传输的数据是图像中物体的位置信息,每秒24帧,我只需要取当前的最新帧的数据就可以了,所以每次都是覆盖先前的数据的,所以该有一个标志位,在中断把数据取到内核时置1,在应用程序读走当前数据后再置0,这样它可以用来作为进程进入睡眠的条件。而我想如果把read函数改成中断驱动的话,那就不能再读别的数据了,而且由于每次传输的数据只有3个u16类型的数据,于是我就想不入用ioctl来读取这3个数据,并且把请求开启和关闭中断的功能也放到ioctl中去,保留原来的read和write,这样我通过read和write可以随意读写dsp的RAM,而又可以在需要是开启中断来获取每帧中目标的信息.
在读写的时候需要对资源进行保护,例如一个流式缓冲区,同一时间只允许一个进程在读或写,于是就用到了信号量或自旋锁来保护资源,自旋锁在单cpu的机器上是无效的,这里只讨论信号量。在内核用的都是互斥信号量,只能获取一次,一旦被一个进程先获取,另一个进程只能阻塞等待信号量被释放。
另一种阻塞的情况是没有数据可读或缓冲区满不能写的时候,进程进入睡眠状态,驱动程序一定是先判断条件,如果不满足,则释放信号量,不能持有信号量进入睡眠,不然进程容易死锁。
这里还是要用到自旋锁,因为中断是随时产生的,如果我在读取共享变量的过程中发生了中断,我读取得数据可能就不是同一帧中的,所以必须在读取共享变量是作保护,使用自旋锁.虽然自旋锁在单cpu情况下无效,不过其实我们用的只是它的关中断的功能.
spin_lock_irq(&dev->hpi_lock)在单cpu的情况下只是调用了cli关中断,所以如果不用自旋锁,只用关中断也是可以的.另外在用interruptible_sleep_on之前要释放锁,否则就是死锁,这样在中断中可以通过wake_up_interruptible唤醒进程,这样实时性应该比查询要好很多了吧.
spin_lock_irq(&dev->hpi_lock);
while(!dev->new_frame)
{
   spin_unlock_irq(&dev->hpi_lock);
   interruptible_sleep_on(&dev->hpi_queue);
   if(signal_pending(current))
      return -ERESTARTSYS;
   spin_lock_irq(&dev->hpi_lock);
}
dev->new_frame=0;
ret=copy_to_user((void *)arg,&dev->ball,sizeof(dev->ball))?-EFAULT : sizeof(dev->ball);
spin_unlock_irq(&dev->hpi_lock);
原本是想用wait_event_interruptible来使进程进入睡眠的,不过ms它不能让我在睡眠前释放锁.
基本就是这些了,通过获取的三个变量,来打造机器人的决策进程吧
class CBall
{
public:
 BALL_INFO m_ball_info;
 int angle;
 int  fd;
 void hpi_init();
};

void CBall::hpi_init(int portNo)
{
 if((fd=open("/dev/hpi",O_RDWR))<0)
 {
  perror("can not open device/n");
  exit(1);
 }
 ioctl(fd,HPI_RESET,0);
 ioctl(fd,Enable_int,0);
}
CBall类用来初始化和保存数据.
void* Get_ball_info(void*)//获取球的信息
{
 ioctl(m_data.m_ball.fd,Get_ball,&m_data.m_ball.m_ball_info);
 m_data.m_ball.angle=25*(2*m_data.m_ball.m_ball_info.cx-240)/240;
}

在main函数中创建一个新的线程用来从内核获取BALL_INFO数据结构
ret=pthread_create(&id3,NULL,Get_ball_info,NULL);
if(ret!=0)
{
   printf ("Create Get_ball_info pthread error!/n");
   exit (1);
}
当然还要有一个做决策的线程了.
主函数main如下:
 int main()
 {
  pthread_t id1,id2,id3;
        int ret;
        struct itimerval value, ovalue;
  
  m_data.m_drive.drive_init(1);//驱动初始化
  m_data.m_sensor.sensor_init(2);//传感器初始化
  m_data.m_ball.hpi_init();
  ret=pthread_create(&id1,NULL,Decision,NULL);//创建决策线程
  if(ret!=0)
  {
   printf ("Create Decision pthread error!/n");
   exit (1);
  }
  
  ret=pthread_create(&id2,NULL,Sensorlisten,NULL);//创建传感器串口监听线程
  if(ret!=0)
  {
   printf ("Create Sensorlisten pthread error!/n");
   exit (1);
  }
  
  ret=pthread_create(&id3,NULL,Get_ball_info,NULL);
  if(ret!=0)
  {
   printf ("Create Get_ball_info pthread error!/n");
   exit (1);
  }
       
        signal(SIGALRM, sigroutine);//创建定时器和定时函数
        value.it_value.tv_sec=0;
        value.it_value.tv_usec=200000;
        value.it_interval.tv_sec=0;
        value.it_interval.tv_usec=200000;
        setitimer(ITIMER_REAL, &value, &ovalue);

  pthread_join(id1,NULL);
  pthread_join(id2,NULL);
  pthread_join(id3,NULL);
}
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值