Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4263582
  • 博文数量: 776
  • 博客积分: 13014
  • 博客等级: 上将
  • 技术积分: 10391
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-22 17:00
文章分类

全部博文(776)

文章存档

2015年(55)

2014年(43)

2013年(147)

2012年(20)

2011年(82)

2010年(429)

分类: LINUX

2015-09-04 07:08:06

/>

CAN + OpenWrt

This adapter is outdated. Please use the

Used parts

OpenWrt Router BR-6104K
CAN Controller MCP2515 + Tranceiver MCP2551
7805 and some caps and resitors

Why using a BR-6104K and OpenWrt ?

I'm still waiting getting my
The schematic is trivial. You can find a lot examples using google. There is only one sticking point: the MCP2551 tranceiver needs 5V, but the SoC is using 3V3.So you need a voltage divider (R1/R2).

The ADM5120 SoC doesn't have a SPI interface but there is still a way by using SPI bitbanging thru GPIO. I was skeptic if the speed is high enough (roughly 340kHz SPI - the designated CAN bandwidth 250kHz). The MCP2515 provides a small hardware receiving FIFO (2 entries) and the socket CAN layer a 10 entries wide sending FIFO. This should be enough for small bursts.
Sure this is not sufficient for industrial applications, but the main purpose here is a RailRoad interface.

Connecting the CAN Controllers to the BR-6104K - software part

OpenWrt environment

OpenWrt provides all needed parts: an actual Kernel with SPI GPIO bitbanging and the MCP251x modul.

The software part is a little bit tricky.

SPI Interface

First you have to patch
The CAN controller is connected to following ports:
ADM5120_GPIO_P3L1 GPIO17 -> MISO
ADM5120_GPIO_P3L0 GPIO18 -> MOSI
ADM5120_GPIO_P4L1 GPIO20 -> SCK
ADM5120_GPIO_P4L0 GPIO21 -> CS
RESET Button GPIO2 -> INT
Another part is the board defintion:
#include <linux/spi/spi_gpio.h> #include <inux/can/platform/mcp251x.h> ... static struct mcp251x_platform_data mcp251x_info = { .oscillator_frequency = 16E6, .board_specific_setup = NULL, .power_enable = NULL, .transceiver_enable = NULL, }; static struct spi_gpio_platform_data br61xx_gpio_spi = { .sck = 20, .mosi = 18, .miso = 17, .num_chipselect = 1, /* number of chip selects for spi gpio master */ }; static struct platform_device spi_gpio_device = { .name = "spi_gpio", .id = 1, /* Bus number */ .dev.platform_data = &br61xx_gpio_spi, }; static struct spi_board_info mcp2515_spi_gpio_board_info [] = { { .modalias = "mcp2515", .max_speed_hz = 10000000, .bus_num = 1, .chip_select = 0, .platform_data = &mcp251x_info, .mode = SPI_MODE_0, .controller_data = (void *) 21, }, }; static struct platform_device *br61xx_devices[] __initdata = { &spi_gpio_device, }; void __init br61xx_generic_setup(void) { ... spi_register_board_info(mcp2515_spi_gpio_board_info,ARRAY_SIZE(mcp2515_spi_gpio_board_info)); adm5120_add_device_gpio_buttons(ARRAY_SIZE(br61xx_gpio_buttons), br61xx_gpio_buttons);

Interrupt

The MCP2515 kernel module
static irqreturn_t mcp251x_can_hardirq(int irq, void *dev_id) { struct mcp251x_priv *priv = dev_id; struct spi_device *spi = priv->spi; unsigned long flags; unsigned int intc_reg_int_level; // ADM5120 IRQs can only be level, not edge so we are going // switch level and only use high to low trigger spin_lock_irqsave(&level_register_lock, flags); intc_reg_int_level = intc_read_reg(INTC_REG_INT_LEVEL) ^ BIT(4); intc_write_reg(INTC_REG_INT_LEVEL, intc_reg_int_level); // dev_info(&spi->dev, " mcp251x INT level 0x%X \n",intc_reg_int_level); // we ignore raising edge - we have already xored // if (intc_reg_int_level & BIT(4)) if (intc_reg_int_level &= 0x10) { // dev_info(&spi->dev, " mcp251x INT high -> IRQ_HANDLED\n"); spin_unlock_irqrestore(&level_register_lock, flags); return IRQ_HANDLED; } else { // dev_info(&spi->dev, " mcp251x INT low -> IRQ_WAKE_THREAD\n"); spin_unlock_irqrestore(&level_register_lock, flags); return IRQ_WAKE_THREAD; } } ... static int mcp251x_open(struct net_device *net) { ... ret = request_threaded_irq(spi->irq, mcp251x_can_hardirq, mcp251x_can_ist, // pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING, pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_NONE, DEVICE_NAME, priv); After compiling an installing can,can-dev,can-raw and mcp251x the ports should look like this:
root@OpenWrt:~# cat /sys/kernel/debug/gpio 
GPIOs 0-3, adm5120 gpio0:
 gpio-0   (power               ) out hi
 gpio-2   (MCP251x /INT        ) in  hi

GPIOs 8-22, adm5120 gpio1:
 gpio-8   (wan_lnkact          ) out hi
 gpio-9   (wan_speed           ) out hi
 gpio-11  (lan1_lnkact         ) out hi
 gpio-12  (lan1_speed          ) out hi
 gpio-14  (lan2_lnkact         ) out hi
 gpio-15  (lan2_speed          ) out hi
 gpio-17  (spi_gpio.1          ) in  lo
 gpio-18  (spi_gpio.1          ) out lo
 gpio-20  (spi_gpio.1          ) out lo
 gpio-21  (spi1.0              ) out hi
dmesg should show something like this:
[   17.648000] can: controller area network core (rev 20090105 abi 8)
[   17.656000] NET: Registered protocol family 29
[   17.704000] CAN device driver interface
[   17.748000] can: raw protocol (rev 20090105)
[   17.956000] mcp251x spi1.0: CANSTAT 0x80 CANCTRL 0x07
[   17.956000] mcp251x spi1.0: probed
After starting the controller:
/usr/sbin/ip link set can0 type can bitrate 250000
/sbin/ifconfig can0 up
dmesg should show:
[   39.108000] mcp251x spi1.0:  INTC_REG_IRQ_ENABLE was = 0x212
[   39.108000] mcp251x spi1.0:  INTC_REG_IRQ_ENABLE now = 0x212
[   39.120000] mcp251x spi1.0:  GPIO2 IRQ initialized: IRQ 12
[   39.160000] mcp251x spi1.0: CNF: 0x01 0xb5 0x01
You also should see the corresponding interrupts:
root@OpenWrt:~# cat /proc/interrupts 
           CPU0       
  2:          0      MIPS  cascade [INTC]
  7:     113752      MIPS  timer
  9:         35      INTC  uart-pl010
 12:          0      INTC  mcp251x
 17:      18955      INTC  eth0, eth1
ERR:          0
BTW: The number of interrupts is always even for the mcp251x because of the workaround.

A look at the interface:
root@OpenWrt:/# ip -s -d link show can0
8: can0:  mtu 16 qdisc pfifo_fast state UNKNOWN qlen 10
    link/can 
    can state ERROR-ACTIVE restart-ms 0 
    bitrate 250000 sample-point 0.875 
    tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
    mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
    clock 8000000
    re-started bus-errors arbit-lost error-warn error-pass bus-off
    0          0          0          0          0          0         
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0      
    TX: bytes  packets  errors  dropped carrier collsns 
    0          0        0       0       0       0     


Now we are ready to use the CAN, e.g. controlling a Railroad
.
Reduced to the max

Impressum:
管理员在2009年8月13日编辑了该文章文章。
-->
阅读(3536) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~