Revision: 1252 Author: bvwelch Date: Thu Aug 27 09:58:42 2009 Log: changes for naming convention
http://code.google.com/p/jallib/source/detail?r=1252 Added: /trunk/include/external/can/can_mcp2515.jal ======================================= --- /dev/null +++ /trunk/include/external/can/can_mcp2515.jal Thu Aug 27 09:58:42 2009 @@ -0,0 +1,493 @@ +-- Title: External mcp2515 CAN controller +-- Author: William Welch Copyright (c) 2009, all rights reserved. +-- Compiler: 2.4 +-- +-- This file is part of jallib (http://jallib.googlecode.com) +-- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html) +-- +-- Description: -- The MCP2515 is an external CAN controller with Slave SPI +-- interface. The controller has 3 transmit buffers and 2 receive buffers. +-- +-- Note: uses SPI Master library and also needs a 'chip select' pin such as: +-- var bit can_sel is pin_B0 + +-- Three transmit buffers. Each transmit buffer has a control register, header +-- registers, length register and (up to ) eight bytes of payload. +const CAN_TXB0CTRL = 0x30 +const CAN_TXB0SIDH = 0x31 +const CAN_TXB0SIDL = 0x32 +const CAN_TXB0EID8 = 0x33 +const CAN_TXB0EID0 = 0x34 +const CAN_TXB0DLC = 0x35 +const CAN_TXB0D0 = 0x36 +const CAN_TXB0D1 = 0x37 +const CAN_TXB0D2 = 0x38 +const CAN_TXB0D3 = 0x39 +const CAN_TXB0D4 = 0x3A +const CAN_TXB0D5 = 0x3B +const CAN_TXB0D6 = 0x3C +const CAN_TXB0D7 = 0x3D + +const CAN_TXB1CTRL = 0x40 +const CAN_TXB1SIDH = 0x41 +const CAN_TXB1SIDL = 0x42 +const CAN_TXB1EID8 = 0x43 +const CAN_TXB1EID0 = 0x44 +const CAN_TXB1DLC = 0x45 +const CAN_TXB1D0 = 0x46 +const CAN_TXB1D1 = 0x47 +const CAN_TXB1D2 = 0x48 +const CAN_TXB1D3 = 0x49 +const CAN_TXB1D4 = 0x4A +const CAN_TXB1D5 = 0x4B +const CAN_TXB1D6 = 0x4C +const CAN_TXB1D7 = 0x4D + +const CAN_TXB2CTRL = 0x50 +const CAN_TXB2SIDH = 0x51 +const CAN_TXB2SIDL = 0x52 +const CAN_TXB2EID8 = 0x53 +const CAN_TXB2EID0 = 0x54 +const CAN_TXB2DLC = 0x55 +const CAN_TXB2D0 = 0x56 +const CAN_TXB2D1 = 0x57 +const CAN_TXB2D2 = 0x58 +const CAN_TXB2D3 = 0x59 +const CAN_TXB2D4 = 0x5A +const CAN_TXB2D5 = 0x5B +const CAN_TXB2D6 = 0x5C +const CAN_TXB2D7 = 0x5D + +-- There are two receive buffers -- RXB0 and RXB1. Note that RXB0 has +-- a 'higher priority' than RXB1. Also, you can set up RXB0 such that +-- it can 'roll over' into RXB1, if you don't want to keep the buffers +-- separate. + +-- Each receive buffer has a control register, header registers, length +-- register and (up to ) eight bytes of payload. +const CAN_RXB0CTRL = 0x60 +const CAN_RXB0SIDH = 0x61 +const CAN_RXB0SIDL = 0x62 +const CAN_RXB0EID8 = 0x63 +const CAN_RXB0EID0 = 0x64 +const CAN_RXB0DLC = 0x65 +const CAN_RXB0D0 = 0x66 +const CAN_RXB0D1 = 0x67 +const CAN_RXB0D2 = 0x68 +const CAN_RXB0D3 = 0x69 +const CAN_RXB0D4 = 0x6A +const CAN_RXB0D5 = 0x6B +const CAN_RXB0D6 = 0x6C +const CAN_RXB0D7 = 0x6D + +const CAN_RXB1CTRL = 0x70 +const CAN_RXB1SIDH = 0x71 +const CAN_RXB1SIDL = 0x72 +const CAN_RXB1EID8 = 0x73 +const CAN_RXB1EID0 = 0x74 +const CAN_RXB1DLC = 0x75 +const CAN_RXB1D0 = 0x76 +const CAN_RXB1D1 = 0x77 +const CAN_RXB1D2 = 0x78 +const CAN_RXB1D3 = 0x79 +const CAN_RXB1D4 = 0x7A +const CAN_RXB1D5 = 0x7B +const CAN_RXB1D6 = 0x7C +const CAN_RXB1D7 = 0x7D + +-- The controller has powerful MASK and FILTER registers for receiving +-- packets/frames. Since the CAN bus is a 'broadcast' medium, you will +-- likely want to filter out messages that are not useful. On the other +-- hand, in some cases, like a diagnostic mode, you may want to receive +-- any/all messages, and this can also be done via the MASK and/or FILTER +-- registers. + +-- RXB0, the 'high priority' buffer, has one mask and two filters. +-- N.B. The datasheet's naming convention for these is unfortunate and error +-- prone, so please be careful. + +-- RXB0 mask +const CAN_RXM0SIDH = 0x20 +const CAN_RXM0SIDL = 0x21 +const CAN_RXM0EID8 = 0x22 +const CAN_RXM0EID0 = 0x23 + +-- RXB0 filter #0 +const CAN_RXF0SIDH = 0x00 +const CAN_RXF0SIDL = 0x01 +const CAN_RXF0EID8 = 0x02 +const CAN_RXF0EID0 = 0x03 + +-- RXB0 filter #1 +const CAN_RXF1SIDH = 0x04 +const CAN_RXF1SIDL = 0x05 +const CAN_RXF1EID8 = 0x06 +const CAN_RXF1EID0 = 0x07 + +-- RXB1, the 'low priority' buffer, has one mask and four filters. +-- N.B. The datasheet's naming convention for these is unfortunate and error +-- prone, so please be careful. + +-- RXB1 mask +const CAN_RXM1SIDH = 0x24 +const CAN_RXM1SIDL = 0x25 +const CAN_RXM1EID8 = 0x26 +const CAN_RXM1EID0 = 0x27 + +-- RXB1 filter #2 +const CAN_RXF2SIDH = 0x08 +const CAN_RXF2SIDL = 0x09 +const CAN_RXF2EID8 = 0x0A +const CAN_RXF2EID0 = 0x0B + +-- RXB1 filter #3 +const CAN_RXF3SIDH = 0x10 +const CAN_RXF3SIDL = 0x11 +const CAN_RXF3EID8 = 0x12 +const CAN_RXF3EID0 = 0x13 + +-- RXB1 filter #4 +const CAN_RXF4SIDH = 0x14 +const CAN_RXF4SIDL = 0x15 +const CAN_RXF4EID8 = 0x16 +const CAN_RXF4EID0 = 0x17 + +-- RXB1 filter #5 +const CAN_RXF5SIDH = 0x18 +const CAN_RXF5SIDL = 0x19 +const CAN_RXF5EID8 = 0x1A +const CAN_RXF5EID0 = 0x1B + +-- CANCTRL register and fields +const CANCTRL = 0x0F +const CAN_MODE_NORMAL = 0x00 +const CAN_MODE_SLEEP = 0x20 +const CAN_MODE_LOOPBACK = 0x40 +const CAN_MODE_LISTENONLY = 0x60 +const CAN_MODE_CONFIG = 0x80 +const CAN_MODE_POWERUP = 0xE0 +const CAN_MODE_MASK = 0xE0 +const CAN_ABORT_TX = 0x10 +const CAN_MODE_ONESHOT = 0x08 +const CAN_CLKOUT_ENABLE = 0x04 +const CAN_CLKOUT_DISABLE = 0x00 +const CAN_CLKOUT_PS1 = 0x00 +const CAN_CLKOUT_PS2 = 0x01 +const CAN_CLKOUT_PS4 = 0x02 +const CAN_CLKOUT_PS8 = 0x03 + +-- Bit-rate and related registers and fields. Big topic. See datasheet. +-- CNF1 register and fields +const CAN_CNF1 = 0x2A +const CAN_SJW1 = 0x00 +const CAN_SJW2 = 0x40 +const CAN_SJW3 = 0x80 +const CAN_SJW4 = 0xC0 + +-- CNF2 register and fields +const CAN_CNF2 = 0x29 +const CAN_BTLMODE = 0x80 +const CAN_SAMPLE_1X = 0x00 +const CAN_SAMPLE_3X = 0x40 + +-- CNF3 and fields +const CAN_CNF3 = 0x28 +const CAN_SOF_ENABLE = 0x80 +const CAN_SOF_DISABLE = 0x00 +const CAN_WAKFIL_ENABLE = 0x40 +const CAN_WAKFIL_DISABLE = 0x00 + +-- There are 8 sources of interrupts inside the controller, and there is +-- a single interrupt 'pin' that you may choose to wire up to your project. +-- Alternatively you can poll using SPI commands. + +-- CANINTE register and fields +const CANINTE = 0x2B +const CAN_RX0IE = 0x01 +const CAN_RX1IE = 0x02 +const CAN_TX0IE = 0x04 +const CAN_TX1IE = 0x08 +const CAN_TX2IE = 0x10 +const CAN_ERRIE = 0x20 +const CAN_WAKIE = 0x40 +const CAN_MERRE = 0x80 + +-- CANINTF register and fields +const CANINTF = 0x2C +const CAN_RX0IF = 0x01 +const CAN_RX1IF = 0x02 +const CAN_TX0IF = 0x04 +const CAN_TX1IF = 0x08 +const CAN_TX2IF = 0x10 +const CAN_ERRIF = 0x20 +const CAN_WAKIF = 0x40 +const CAN_MERRF = 0x80 + +-- other misc registers +const CANSTAT = 0x0E +const CAN_TEC = 0x1C +const CAN_REC = 0x1D +const CAN_EFLG = 0x2D + +-- MCP2515 Instructions ( SPI interface ) +const CAN_WRITE_CMD = 0x02 +const CAN_READ_CMD = 0x03 +const CAN_BITMOD = 0x05 +const CAN_LOAD_TX0 = 0x40 +const CAN_LOAD_TX1 = 0x42 +const CAN_LOAD_TX2 = 0x44 +const CAN_RTS_TX0 = 0x81 +const CAN_RTS_TX1 = 0x82 +const CAN_RTS_TX2 = 0x84 +const CAN_RTS_ALL = 0x87 +const CAN_READ_RX0_DATA = 0x92 +const CAN_READ_RX1_DATA = 0x96 +const CAN_READ_STATUS_CMD = 0xA0 +const CAN_RX_STATUS_CMD = 0xB0 +const CAN_RESET_CMD = 0xC0 + +-- mcp2515 Reset instruction. +-- Puts the mcp2515 in Configuration Mode. +procedure can_reset() is + can_sel = 0 + spi_master_hw = CAN_RESET_CMD + can_sel = 1 +end procedure + +-- mcp2515 read status instruction +function can_read_status() return byte is + var byte data, dummy + can_sel = 0 + spi_master_hw = CAN_READ_STATUS_CMD + data = spi_master_hw + dummy = spi_master_hw + can_sel = 1 + return data +end function + +-- mcp2515 RX status instruction +function can_rx_status() return byte is + var byte data, dummy + can_sel = 0 + spi_master_hw = CAN_RX_STATUS_CMD + data = spi_master_hw + dummy = spi_master_hw + can_sel = 1 + return data +end function + +-- mcp2515 read instruction (single byte) +-- returns the current value of the specified register +function can_read(byte in addr) return byte is + var byte data + can_sel = 0 + spi_master_hw = CAN_READ_CMD + spi_master_hw = addr + data = spi_master_hw + can_sel = 1 + return data +end function + +-- mcp2515 write instruction (single byte) +-- writes the value to the specified register +procedure can_write(byte in addr, byte in data) is + can_sel = 0 + spi_master_hw = CAN_WRITE_CMD + spi_master_hw = addr + spi_master_hw = data + can_sel = 1 +end procedure + +-- set bit-rate and related can bus configuration. +-- see datasheet for details. +-- N.B. The chip must already be in 'configuration mode'. +procedure can_set_config(byte in p1, byte in p2, byte in p3) is + can_write(CAN_CNF1, p1) + can_write(CAN_CNF2, p2) + can_write(CAN_CNF3, p3) +end procedure + +-- set RX acceptance mask for buffer RXB0 +-- N.B. calling with 0,0,0,0 will pass all messages +procedure can_set_rxb0_mask(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXM0SIDH, sidh) + can_write(CAN_RXM0SIDL, sidl) + can_write(CAN_RXM0EID8, eid8) + can_write(CAN_RXM0EID0, eid0) +end procedure + +-- set RXB0 acceptance filter #0 +procedure can_set_rxb0_filter0(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXF0SIDH, sidh) + can_write(CAN_RXF0SIDL, sidl) + can_write(CAN_RXF0EID8, eid8) + can_write(CAN_RXF0EID0, eid0) +end procedure + +-- set RXB0 acceptance filter #1 +procedure can_set_rxb0_filter1(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXF1SIDH, sidh) + can_write(CAN_RXF1SIDL, sidl) + can_write(CAN_RXF1EID8, eid8) + can_write(CAN_RXF1EID0, eid0) +end procedure + +-- set RX acceptance mask for buffer RXB1 +-- N.B. calling with 0,0,0,0 will pass all messages +procedure can_set_rxb1_mask(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXM1SIDH, sidh) + can_write(CAN_RXM1SIDL, sidl) + can_write(CAN_RXM1EID8, eid8) + can_write(CAN_RXM1EID0, eid0) +end procedure + +-- set RXB1 acceptance filter #2 +procedure can_set_rxb1_filter2(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXF2SIDH, sidh) + can_write(CAN_RXF2SIDL, sidl) + can_write(CAN_RXF2EID8, eid8) + can_write(CAN_RXF2EID0, eid0) +end procedure + +-- set RXB1 acceptance filter #3 +procedure can_set_rxb1_filter3(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXF3SIDH, sidh) + can_write(CAN_RXF3SIDL, sidl) + can_write(CAN_RXF3EID8, eid8) + can_write(CAN_RXF3EID0, eid0) +end procedure + +-- set RXB1 acceptance filter #4 +procedure can_set_rxb1_filter4(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXF4SIDH, sidh) + can_write(CAN_RXF4SIDL, sidl) + can_write(CAN_RXF4EID8, eid8) + can_write(CAN_RXF4EID0, eid0) +end procedure + +-- set RXB1 acceptance filter #5 +procedure can_set_rxb1_filter5(byte in sidh, byte in sidl, byte in eid8, byte in eid0) is + can_write(CAN_RXF5SIDH, sidh) + can_write(CAN_RXF5SIDL, sidl) + can_write(CAN_RXF5EID8, eid8) + can_write(CAN_RXF5EID0, eid0) +end procedure + +-- send standard 11-bit CAN frame +-- Non-blocking -- function returns immediately if buffer is busy (in-use) +-- FIXME. this is ugly code +function can_send(byte in buf_no, word in std_id, byte in buf[8], byte in len) return bit is + var bit stat + var byte r_base, i + var word sidh, sidl + if buf_no == 0 then + r_base = CAN_TXB0CTRL + elsif buf_no == 1 then + r_base = CAN_TXB1CTRL + elsif buf_no == 2 then + r_base = CAN_TXB2CTRL + else + return 0 + end if + + -- buffer already in-use / busy? + stat = can_read(r_base) & 8 + if stat == 1 then + return 0 + end if + + -- FIXME this sets priority and other side-effects + can_write(r_base, 0) + + -- N.B. SIDH and SIDL bit-layout are weird (see datasheet) + sidh = std_id >> 3 + sidl = std_id & 7 + sidl = sidl << 5 + + can_write(r_base+1, sidh) + can_write(r_base+2, sidl) + can_write(r_base+3, 0) + can_write(r_base+4, 0) + can_write(r_base+5, len) + for 8 using i loop + var byte j + j = r_base + i + 6 + can_write(j, buf[i]) + end loop + + can_write(r_base, 8) -- request TX now/soonest + + return 1 +end function + +-- receive standard 11-bit CAN frame +-- Non-blocking -- function returns immediately if no message is available. +-- FIXME. N. B. This routine will automatically discard any extended frames! +-- FIXME. this is ugly code +function can_receive(byte in buf_no, word out std_id, byte out buf[8], byte out len) return bit is + var bit rtr, ide, stat, ex + var byte op, i + var byte sidh, sidl + + -- quick check to make sure we have a message waiting + if buf_no == 0 then + stat = can_read_status() & 1 + if stat == 0 then + return 0 + end if + elsif buf_no == 1 then + stat = can_read_status() & 2 + if stat == 0 then + return 0 + end if + else + return 0 -- illegal value for buf_no + end if + + -- N.B. At this point we have a message. We must read it, + -- even if we decide to discard it later. + if buf_no == 0 then + rtr = can_read(CAN_RXB0CTRL) & 8 + sidh = can_read(CAN_RXB0SIDH) + sidl = can_read(CAN_RXB0SIDL) + len = can_read(CAN_RXB0DLC) + op = CAN_READ_RX0_DATA + + elsif buf_no == 1 then + rtr = can_read(CAN_RXB1CTRL) & 8 + sidh = can_read(CAN_RXB1SIDH) + sidl = can_read(CAN_RXB1SIDL) + len = can_read(CAN_RXB1DLC) + op = CAN_READ_RX1_DATA + + end if + + -- fast read of the buffer + can_sel = 0 + spi_master_hw = op + for 8 using i loop + buf[i] = spi_master_hw + end loop + can_sel = 1 + + -- Remote Request frames do not include any data + if rtr != 0 then + len = 0 + end if + + -- discard 'extended frames' + -- FIXME + ide = sidl & 8 + if ide != 0 then + return 0 + end if + + -- form the 11-bit ID. See datasheet. + std_id = word(sidh) + std_id = std_id << 3 + sidl = sidl >> 5 + std_id = std_id | word(sidl) + + return 1 +end function + --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "jallib" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/jallib?hl=en -~----------~----~----~----~------~----~------~--~---
