最开始选择HI3531A,然后需要支持CAN设备以为是一件很简单的事情。本着一个Linux内核的老鸟心态,觉得应该这个是小儿科的东西。在网上搜索了一下发现很多人都有使用mcp2515的芯片,特别是还有某培训机构写了一篇很详细的文章,当时以为是一件简单的事情。然后打开Linux内核的源码,找到了mcp251x.c的文件,在头文件注释里面看到一段话:

  Your platform definition file should specify something like:
 
  static struct mcp251x_platform_data mcp251x_info = {
          .oscillator_frequency = 8000000,
          .board_specific_setup = &mcp251x_setup,
          .power_enable = mcp251x_power_enable,
          .transceiver_enable = NULL,
  };
 
  static struct spi_board_info spi_board_info[] = {
          {
                  .modalias = "mcp2510",
 			// or "mcp2515" depending on your controller
                  .platform_data = &mcp251x_info,
                  .irq = IRQ_EINT13,
                  .max_speed_hz = 2*1000*1000,
                  .chip_select = 2,
          },
  };
心想这个好简单,就是实现这两个结构体的定义。

结果这是噩梦的开始,海思根本没有按照spi的标准框架来实现。或是实现了我没看懂,所以纠结了很久。最后在spidev_info.c中找到了添加接口,结果还是不正常。然后各种调试使用示波器,后面发现是海思在实现上面有bug。修改好了能实现probe成功了。

probe成功后发现没法设置波特率,当然很多外面的文档都没用提到这个问题。关键问题是中断没法被初始化,所谓中断就是MCP2515的INT管脚需要接入到Linux内核通知线程中断函数注册:

	ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
				   flags, DEVICE_NAME, priv);
	if (ret) {
		dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
		if (pdata->transceiver_enable)
			pdata->transceiver_enable(0);
		close_candev(net);
		goto open_unlock;
	}
这个地方的问题其实很简单,主要解决的是中断沿的问题。需要把mcp2515的中断管脚拉到设备的IO中断口上来。然后在驱动注册的时候初始化外部中断。然后修改中断沿模式。这几个问题都解决了就可以正常识别mcp2515了。使用canuntil测试能正常send。


Logo

更多推荐