内核为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;
}
目前,此系统运行稳定可靠。
同时希望高手给出更可靠的方案
阅读(3081) | 评论(0) | 转发(0) |