基於AT91RM9200+linux平臺的MCP2510驅動

基於AT91RM9200+linux平臺的MCP2510驅動 2011-05-26 11:40:25

分類: LINUX

 
內核爲linux 2.6.30.4
在此內核裏,can設備被視爲網絡設備,目錄爲linux2.6.30.4/net/can,由於項目緊,對此並不熟悉,放棄這種方式。
採用 這種方式做的驅動。
把CAN設備視爲字符型驅動,添加到內核裏。
適用前需創建設備
mknod /dev/mcp251x c 253 0
 
由於MCP2510與ADS7846共用SPI總線,在項目進行的過程中發現SPI總線衝突引起觸摸屏死機,後來在觸摸屏的驅動裏新建了一個定時器,定時檢查ADS7846的狀態標誌,發現標誌有問題就恢復。解決了此問題。
 
static enum hrtimer_restart test_timer(struct hrtimer *handle)
{
struct ads7846 *ts = container_of(handle, struct ads7846, testtimer);
int value;
value = device_suspended(&ts->spi->dev);
hrtimer_start(&ts->testtimer, ktime_set(0, 50000*TS_POLL_DELAY),
     HRTIMER_MODE_REL);
if ((ts->irq_disabled == 1) && (ts->pending == 1) && (!get_pendown_state(ts)))
 {
 printk("i=%x, p=%x,v=%x\n",ts->irq_disabled,ts->pending,value);
 hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),HRTIMER_MODE_REL);
 }
return HRTIMER_NORESTART;
}
static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
 struct ads7846 *ts = container_of(handle, struct ads7846, timer);
 int  status = 0;
static bool flag = true;
 spin_lock(&ts->lock);
 if (unlikely(!get_pendown_state(ts) ||
       device_suspended(&ts->spi->dev))) {
  if (ts->pendown) {
   struct input_dev *input = ts->input;
   input_report_key(input, BTN_TOUCH, 0);
   input_report_abs(input, ABS_PRESSURE, 0);
   input_sync(input);
   ts->pendown = 0;
#ifdef VERBOSE
   dev_dbg(&ts->spi->dev, "UP\n");
#endif
  }
  /* measurement cycle ended */
  if (!device_suspended(&ts->spi->dev)) {
   ts->irq_disabled = 0;
   enable_irq(ts->spi->irq);
  }
  ts->pending = 0;
 } else {
  /* pen is still down, continue with the measurement */
  ts->msg_idx = 0;
  ts->wait_for_sync();
  status = spi_async(ts->spi, &ts->msg[0]);
  if (status)
   dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
 }
 spin_unlock(&ts->lock);
 if (flag)
  {
  hrtimer_start(&ts->testtimer, ktime_set(0, 50000*TS_POLL_DELAY),
     HRTIMER_MODE_REL);
  flag = false;
  }
 return HRTIMER_NORESTART;
}
 
在MCP2510發送數據時,需加緩衝時間,等上一個字節發完了再發。驗證可行。
static int mcp251x_hw_tx(struct spi_device *spi, int tx_buf_idx)
{
    struct mcp251x *chip = dev_get_drvdata(&spi->dev);
    uint8_t *buf = chip->spi_transfer_buf;
    struct can_frame *frame;
    int ret;
    int ext;
   int i = 0;
  
    dev_dbg(&spi->dev, "%s()\n", __FUNCTION__);
    if (down_interruptible(&chip->txblock))
     return -ERESTARTSYS;
    if (chip->txbout != chip->txbin) { 
  
 frame = &chip->txb[chip->txbout];
  
 //down(&chip->lock);
  
 if (frame->header.dlc > CAN_FRAME_MAX_DATA_LEN)
     frame->header.dlc = CAN_FRAME_MAX_DATA_LEN;
 if (frame->header.ide == 0)
     frame->header.eid = 0;
 /*  
 buf[0] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
 buf[1] = frame->header.id >> 3;
 buf[2] = ((frame->header.id << 5) & 0x07) |(frame->header.srr<<4)| (frame->header.ide << 3)
     | ((frame->header.eid >> 16) & 0x03);
 buf[3]  = (frame->header.eid >> 8) &0xff;
 buf[4]  = frame->header.eid & 0xff;
 buf[5] = (frame->header.rtr << 6) | frame->header.dlc;
 memcpy(buf + 6, frame->data, frame->header.dlc);
 */
 /*
 if(frame->header.eid >0)
  ext = true;
 else
  ext = false;
 */
 ext = frame->header.ide;
 //printk("ext = %d, eid = %x\n",ext, frame->header.eid);
 if (!ext)
  {
  printk("in=%d out=%d\n",chip->txbin,chip->txbout);
  chip->txbout = chip->txbin - 1;
  frame = &chip->txb[chip->txbout];
  }
  mdelay(5); //發送緩衝時間
 mcp251x_write_can(spi, tx_buf_idx, ext, (frame->header.id<<18) |frame->header.eid, frame->header.rtr
  , frame->data, frame->header.dlc);
// ret = spi_write(spi, buf, 6 + CAN_FRAME_MAX_DATA_LEN);
// if (ret < 0)
//     dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);
// up(&chip->lock);
 /* update pos of ring buffer */
 chip->txbout++;
 if (chip->txbout >= MCP251X_BUF_LEN)
     chip->txbout = 0;
 up(&chip->txblock);
 mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ |TXBCTRL_TXPRI(3-tx_buf_idx));
    }
else
 up(&chip->txblock);
    return 0;
}
 
目前,此係統運行穩定可靠。
同時希望高手給出更可靠的方案
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章