Controller Area Network - CAN BUS Project

Post here to let others know of a project you're working on.

Moderators: Chuckt, Garth, bitfogav

Post Reply [phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable
User avatar
bitfogav
Moderator
Moderator
Posts: 915
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Controller Area Network - CAN BUS Project

Post by bitfogav » Sat Oct 15, 2011 10:00 am

Hi guys, Just thought I would let you know what im up to lately :)

Some of you my know that I work in the motor industry, and spend most of my time fault finding on vehicle electronics.
There are several data buses used on motor vehicles today but Im going to talk about the Controller area network (CAN bus).

CAN is a serial two-wire bus system, rebust and reliable with fast communication up to 1Mbps and its used to send data messages all over the vehicle to many Control units, which then will carry out different functions based on the data that was received. Anyway thats a basic insight, if you would like to know more then just ask :)

I recently came across a Microcontroller by Microchip MCP2515, this microchip is a CAN interface controller with SPI connection to a PIC, so ive spent a few days working on a small project trying to interface this MCP2515 to a PIC.

Im hoping that I can make a small circuit board which I can connect into the CAN bus and read the data from the system.

User avatar
brad
Site Admin
Site Admin
Posts: 2578
Joined: Fri Mar 26, 2010 10:30 pm
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable

Re: Controller Area Network - CAN BUS Project

Post by brad » Mon Oct 17, 2011 8:51 pm

That's cool bitfogav!

Hows the progress with this project? designed a circuit board yet? Can we expect some video footage on youtube of the project?

As for me, I am still very busy working on the house and then when I get some spare time, I have been learning how to program for the iphone using objective c. It would be great to be able to make some sort of project that can connect to the expansion port of an iphone and make some software that can interface with it.

It is quite a fun experience using xcode (which is Apple developer software) and is an amazing piece of kit. much nicer to use compared to visual basic!

User avatar
bitfogav
Moderator
Moderator
Posts: 915
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Re: Controller Area Network - CAN BUS Project

Post by bitfogav » Thu Oct 20, 2011 9:16 am

Im just trying to put a Module together for Swordfish(basic) at the moment for the MCP2515 CAN interface, once thats done I shall put a circuit together and share and a video once all is finished :)

Im interested in the iphone stuff you are doing Brad, Could you share some of the info? things you need? links etc? :)

User avatar
brad
Site Admin
Site Admin
Posts: 2578
Joined: Fri Mar 26, 2010 10:30 pm
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable

Re: Controller Area Network - CAN BUS Project

Post by brad » Fri Oct 21, 2011 6:29 am

I'll get a few links put together and will have to start a new thread documenting some info :)

I have to say though, it has been the hardest programming language that I have ever tried to get my head around. But I guess like any problem, you eventually figure it out and it all seems easy after that!

User avatar
bitfogav
Moderator
Moderator
Posts: 915
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Re: Controller Area Network - CAN BUS Project

Post by bitfogav » Sun Oct 30, 2011 9:05 pm

Will look forward to your iPhone stuff Brad :) heres the Swordfish Module that ive put together for the MCP2515, the module takes care of the SPI interface aswell, so the user has only got to set his/hers MCU pins of the specific microchip they are using..

Example of setting your specific MCU pins in the main code:

Code: Select all

// override the MCP2515 module values for PIC 18F2455...
#option SPI_SCK = PORTB.1
#option SPI_SDI = PORTB.0
#option SPI_SDO = PORTC.7
#option MCP_CSN = PORTB.4
#option MCP_INT = PORTB.5

// set MCP2515 module CAN baudrate
#option CAN_BAUDRATE = 125 


NB, the module is fully working but does not contain the send/receive CAN message functions, And does not initialise the mcp2515, more to come. So take this has an example module of the mcp2515:

Code: Select all

{
*****************************************************************************
*  Name    : MCP2515 Module                                                 *
*  Author  : Gavin Wiggett                                                  *
*  Notice  : Licensed Bitfogav			                                     *
*          : All Rights Reserved                                            *
*  Date    : 11/10/2011                                                     *
*  Notes   : Microchip MCP2515 - CAN Interface with Serial SPI	           *
*          : SPI is taken care off by the Module - user set MCU pins        *
*                                                                           *
*  Version : 1.0                                                            *
*          : The module is designed to use software Reset to Reset MCP2515  *
*****************************************************************************
} 
 
Module MCP2515 

Include "MCP2515_def"       ' user lib Definitions support module for MCP2515

// map registers to SSP(x)
#if _mssp = 0
   #error _device + " does not support MSSP"

// single SSP...
#elseif _mssp = 1

// default module option - user options will override these values...
#option SPI_SCK = PORTC.3   ' SPI clock to MCP2515 pin (PDIP/SOIC 13)
#option SPI_SDI = PORTC.4   ' SPI SDI master in/slave out from MCP2515 pin (PDIP/SOIC 15)
#option SPI_SDO = PORTC.5   ' SPI SDO master out/slave in to MCP2515 pin (PDIP/SOIC 14)
#option MCP_CSN = PORTA.5   ' SPI chip select to MCP2515 pin (PDIP/SOIC 16)
#option MCP_INT = PORTC.6   ' MCP2515 INT pin (PDIP/SOIC 12) 

// validate SCK pin...
#if IsOption(SPI_SCK) And Not IsValidPortPin(SPI_SCK) 
   #error SPI_SCK, "Invalid option. SCK must be a valid port pin."
#endif

// validate SDI pin...
#if IsOption(SPI_SDI) And Not IsValidPortPin(SPI_SDI) 
   #error SPI_SDI, "Invalid option. SDI must be a valid port pin."
#endif

// validate SDO pin...
#if IsOption(SPI_SDO) And Not IsValidPortPin(SPI_SDO) 
   #error SPI_SDO, "Invalid option. SDO must be a valid port pin."
#endif

// validate CS pin...
#if IsOption(MCP_CSN) And Not IsValidPortPin(MCP_CSN) 
   #error MCP_CSN, "Invalid option. CS must be a valid port pin."
#endif

// validate CS pin...
#if IsOption(MCP_INT) And Not IsValidPortPin(MCP_INT) 
   #error MCP_INT, "Invalid option. INT must be a valid port pin."
#endif

// Declare port pins for SPI and MCP2515
Dim
   SCK As SPI_SCK.SPI_SCK@,             ' clock pin
   SDI As SPI_SDI.SPI_SDI@,             ' data in pin
   SDO As SPI_SDO.SPI_SDO@,             ' data out pin
   CSN As MCP_CSN.MCP_CSN@,             ' chip select pin
   MCP2515_INT As MCP_INT.MCP_INT@      ' INT pin 

// has more than one SSP module?...   
#else
    #error "MCP2515 module does not support MSSP2"
#endif
    
// CAN operating frequency, valid modes are: 125kbp, 250kbp, 500kbp, 1mb             
// Obtained from the MCP2515 timing calculator (MBTime) with 20Mhz crystal           
// config1 = CNF1 mcp2515 register                                                       
// config2 = CNF2 mcp2515 register                                                       
// config3 = CNF3 mcp2515 register 

#if IsOption(CAN_BAUDRATE) And Not (CAN_BAUDRATE in (125, 250, 500, 1000))    
    #error CAN_BAUDRATE, "Invalid option, CAN_BAUDRATE must be 125, 250, 500, 1000."
#endif

#if Not IsOption(CAN_BAUDRATE)
  #option CAN_BAUDRATE = 250 ' Default CAN operating frequency to 250Kbps
  ' Comment out the warning if you do not want it!
  #warning "CAN_BAUDRATE option is set to default = 250Kbps"
#endif
                                                                               
#if CAN_BAUDRATE = 125
Public Const
    config1 = $03,
    config2 = $BA,
    config3 = $07
 #elseif CAN_BAUDRATE = 250
Public Const
    config1 = $01,
    config2 = $BA,
    config3 = $07
 #elseif  CAN_BAUDRATE = 500
Public Const
    config1 = $00,
    config2 = $B6,
    config3 = $04
 #elseif  CAN_BAUDRATE = 1000
Public Const
    config1 = $00,
    config2 = $A0,
    config3 = $02
#endif

//  SPI MSSP
Public Dim
    SSPControl1 As SSPCON1,             ' MSSP Control register 1
    SSPStatus   As SSPSTAT,             ' MSSP Status register (SPI MODE)
    SSPBuffer   As SSPBUF               ' Receive buffer/Transmit register

// SSPSTAT bitnames
Public Dim
    BF  As SSPStatus.booleans(0),       ' buffer full (receive and transmit)
    SMP As SSPStatus.7,                 ' read sample mode
    CKE As SSPStatus.6                  ' clock edge control

// SSPCON1 bitnames, master mode only...
Public Dim
    WCOL  As SSPControl1.booleans(7),   ' write collision Detect
    SSPOV As SSPControl1.booleans(6),   ' receive overflow
    SSPEN As SSPControl1.booleans(5),   ' synchronous receive enable
    CKP   As SSPControl1.4,             ' clock polarity

    // synchronous mode select bits, %00XX for master mode
    SSPM3 As SSPControl1.3,             ' always zero
    SSPM2 As SSPControl1.2,             ' slave Mode
    SSPM1 As SSPControl1.1,             ' clock Mode (MSB)
    SSPM0 As SSPControl1.0              ' clock Mode (LSB)

// interrupt flags
Public Dim
    SSPIF As PIR1.3,
    SSPIE As PIE1.3

// standard SPI bus modes
Public Const
    SPI_MODE_0      = 0,    ' ckp=0, cke=1... clock idle low, mosi changes on falling clk
    SPI_MODE_1      = 1,    ' ckp=0, cke=0... clock idle low, mosi changes on rising clk
    SPI_MODE_2      = 2,    ' ckp=1, cke=1... clock idle high, mosi changes on rising clk
    SPI_MODE_3      = 3     ' ckp=1, cke=0... clock idle high, mosi changes on falling clock
    
Public Const
    spiOscDiv4       = 0,   ' master mode FOSC/4
    spiOscDiv16      = 1,   ' master mode FOSC/16
    spiOscDiv64      = 2,   ' master mode FOSC/64
    spiOscTimer2     = 3,   ' master mode TMR2 provides clock

    // RX data sampling settings  (SSPStatus.6 - SMP)
    spiSampleEnd     = $80, ' input data sampled at end of data output time
    spiSampleMiddle  = $00  ' input data sampled at middle of data output time

// SPI Mode, Set SPI to master mode, spiOscDiv4 (DEFAULT, 10mhz) And sets I/O for SPI to MCP2515
Sub spi_set_as_master(pOscMode As Byte = spiOscDiv4)
    // disable mssp for the time being
    SSPEN = false   
    // set master mode
    SSPControl1 = SSPControl1 And $F0
    SSPControl1 = SSPControl1 Or pOscMode
End Sub

// set io pins for SPI and MCP2515
Sub set_IO_ports()
    Output(SDO)
    Output(SCK)
    Input(SDI)
    Output(CSN)
    Input(MCP2515_INT)
End Sub

// SPI sample, Sets when the SPI input data is sampled 
Macro spi_set_sample(m)
    If (m = 0) Then
        SMP = 0         ' spiSampleMiddle
    Else
        SMP = 1         ' spiSampleEnd
    EndIf
End Macro

// standard SPI bus modes, Set SPI idle state and data transmission clock edge
Sub spi_set_mode(m As Byte)
    Select (m)
        Case SPI_MODE_1
            CKP = 0
            CKE = 0
        Case SPI_MODE_2
            CKP = 1
            CKE = 1
        Case SPI_MODE_3
            CKP = 1
            CKE = 0
        Else            ' default to mode 0 (0,0)
            CKP = 0
            CKE = 1
    End Select
End Sub

// Enables SPI and clears any flags 
Inline Sub spi_enable_port()
    SSPIE = 0           ' disable intr (polled mode only)
    WREG = SSPBuffer    ' clear buffer
    SSPIF = 0           ' reset intr flag
    SSPEN = true        ' enable mssp
End Sub

// init MSSP to spi master, spi mode 0, transmission 10Mhz, set I/O 
Public Sub init_spi()
    spi_set_as_master(spiOscDiv4)    ' spi speed (if spiOscDiv4 then you need to uncomment nop in mcp_cs_delay sub)
    set_IO_ports()                   ' set io pins for SPI and MCP2515
    spi_set_mode(SPI_MODE_0)         ' set SPI idle state and data transmission clock edge
    spi_set_sample(spiSampleMiddle)  ' sample input data at middle of data out time
    spi_enable_port()
End Sub

{
**************************************************************************************
* Name    : spi_transfer                                                             *
* Purpose : transfer a byte (does a proper SPI transaction...write and read)         *
*         : Returns received spi byte                                                *
**************************************************************************************
}
Public Function spi_transfer(b As WREG) As WREG
    // reset buffer full and SSPIF
    BF = false
    SSPIF = 0

    // send the byte and wait for it to transmit
    SSPBuffer = b
    Repeat
    Until (SSPIF = 1)

    // get the byte that just came in... this clears BF
    result = SSPBuffer

    // make sure write collision is cleared
    WCOL = false
End Function

{
**************************************************************************************
* Name    : mcp_cs_delay, mcp_assert_cs, mcp_deassert_cs                             *
* Purpose : delay for asserting CS pin                                               *
*         : Set CS Low for comms to mcp2515                                          *
*         : Set CS High to stop comms to mcp2515                                     *
*                                                                                    *
* note: the timing specs below are worst case. they're actually less (~ 50ns?)       *
* If you're running up to 40MHz, then there's enough overhead in the spi_transfer()  *
* calls, and you can just comment the nop out.                                       *
**************************************************************************************
}
Public Inline Sub mcp_cs_delay()
   Asm          '
      nop       ' comment out if not needed
   End Asm      '
End Sub

Public Inline Sub mcp_assert_cs()
    CSN = 0
    mcp_cs_delay()  ' Tcss setup time = 50ns?
End Sub

Public Inline Sub mcp_deassert_cs()
    mcp_cs_delay()  ' Tcsh hold = 100ns?
    CSN = 1
    mcp_cs_delay()  ' Tcsd cs disable time = 100ns?
End Sub

{
**************************************************************************************
* Name    : mcp2515_Reset                                                            *
* Purpose : Software Reset mcp2515                                                   *
*         : reset mcp2515 via SPI and will put the mcp2515 into Configuration Mode   *
**************************************************************************************
}
Public Sub mcp2515_Reset()
    mcp_assert_cs()                         ' start comms to MCP2515
	spi_transfer(SPI_RESET)                 ' send reset to mcp2515
    mcp_deassert_cs()                       ' stop comms to MCP2515
	DelayMS(20)                            	' wait for the MCP2515 to restart
End Sub

{
**************************************************************************************
* Name    : mcp2515_CAN_Freq                                                         *
* Purpose : set CAN operation Freq, Can only be set in Configuration mode            *
*         : sets CNF1, CNF2, CNF3 registers                                          *
**************************************************************************************
}
Public Sub mcp2515_CAN_Freq()
    mcp_assert_cs()                         ' start comms to MCP2515
	spi_transfer(SPI_WRITE)                 ' send write command
	spi_transfer(CNF3)                      ' address
	spi_transfer(config3)                   ' CNF3 		
	spi_transfer(config2)                   ' CNF2	  
	spi_transfer(config1)                   ' CNF1
    mcp_deassert_cs()                       ' stop comms to MCP2515
End Sub

{
**************************************************************************************
* Name    : mcp2515_read_register                                                    *
* Purpose : Read mcp2515 Registers at Address                                        *
*         : Returns received spi byte from mcp2515                                   *
**************************************************************************************
}
Public Function mcp2515_read_register(address As Byte) As Byte	
    mcp_assert_cs()                         ' start comms to MCP2515
	spi_transfer(SPI_READ)                  ' send mcp2515 read instruction 
	spi_transfer(address)	                ' send address 
	result = spi_transfer($FF)              ' receive spi data from mcp2515 send dummy byte
    mcp_deassert_cs()	                    ' stop comms to MCP2515
End Function

{
**************************************************************************************
* Name    : mcp2515_write_register                                                   *
* Purpose : Write mcp2515 Registers                                                  *
*         : Send spi data to mcp2515 at Address, Data                                *
**************************************************************************************
}
Public Sub mcp2515_write_register(address As Byte, data As Byte)
    mcp_assert_cs()                       	' start comms to MCP2515
	spi_transfer(SPI_WRITE)                 ' send write instruction
	spi_transfer(address)                   ' send address
	spi_transfer(data)                      ' send data byte
    mcp_deassert_cs()	                    ' stop comms to MCP2515
End Sub

{
**************************************************************************************
* Name    : mcp2515_bit_modify                                                       *
* Purpose : Bit Modify provides a means for setting or clearing individual bits      *
*         : in registers                                                             *
* notes   : not all registers are available for bit modify see datasheet             *
* CANCTRL, TXRTSCTRL, BFPCTRL, EFLG, CANINTF, CANINTE, CNF1, CNF2, CNF3, TXB0CTRL    *
* TXB1CTRL, TXB2CTRL, RXB0CTRL, RXB1CTRL - locations that allow the user to          *
* manipulate individual bits using the Bit Modify command.                           *
**************************************************************************************
}
Public Sub mcp2515_bit_modify(address As Byte, mask As Byte, data As Byte)
    mcp_assert_cs()                       	' start comms to MCP2515		
	spi_transfer(SPI_BIT_MODIFY)            ' send bit modify instruction 
	spi_transfer(address)                   ' send address 
	spi_transfer(mask)                      ' send mask byte
	spi_transfer(data)                      ' send data byte
    mcp_deassert_cs()                       ' stop comms to MCP2515
End Sub

{
**************************************************************************************
* Name    : mcp2515_read_status                                                      *
* Purpose : Reads all the important bits interrupts/buffers TX/RX                    *
*         : same has if you used the standard read command                           *
* notes   : Returns recieved status from mcp2515                                     *
*         : see mcp215 datasheet TABLE 12-1: SPI INSTRUCTION SET                     *
**************************************************************************************
}
Public Function mcp2515_read_status(pStatus As Byte) As Byte
    mcp_assert_cs()                         ' start comms to MCP2515
	spi_transfer(pStatus)                   ' read status of register 
	result = spi_transfer($FF)              ' receive spi data from mcp2515 send dummy byte
    mcp_deassert_cs()                       ' stop comms to MCP2515
End Function

{
**************************************************************************************
* Name    : mcp2515_CAN_Mode                                                         *
* Purpose : to configure/set CAN Mode                                                *
*         :                                                                          *
* notes   : CAN modes, Config, Normal, Sleep, Listen, Loopback                       *
**************************************************************************************
}
Public Sub mcp2515_CAN_Mode(cfg As Byte)
	Dim mode, done As Byte                       ' temp var
        done = 0
	While (done = 0)                             ' keep sending mode untill set
		mcp2515_write_register(CANCTRL, cfg)
		DelayMS(1)				                 ' delay
		mode = mcp2515_read_register(CANSTAT)    ' read the config mode back
		mode = mode And $E0  	                 ' mask off the config bits
		If (mode = cfg) Then                     ' check to see if mode has been set
			done = 1			                 ' it has been set correctly	
        End If
	  DelayMS(1)				                 ' delay
    Wend
End Sub

{
**************************************************************************************
* Name    : RBX0F_IO_pin                                                             *
* Purpose : set or clear digital output pin on mcp2515, pin RX0BF                    *
*         :                                                                          *
* notes   : Example: RBX0F_IO_pin(1) = pin high / RBX0F_IO_pin(0) = pin low          *
*         : must set register eg: (BFPCTRL = %00000100)                              *
**************************************************************************************
}
Public Sub RBX0F_IO_pin(pSet As Bit)
    // activate the RXnBF Pins (RX0BF Pin active)
    // LED connected to pin to show comms to mcp2515
    If pSet = 1 Then
        ' register, mask bit, data bit
        mcp2515_bit_modify(BFPCTRL, (1 << B0BFS), (1 << B0BFS))    
    Else
        ' register, mask bit, data bit
        mcp2515_bit_modify(BFPCTRL, (1 << B0BFS), (0 << B0BFS)) 
    EndIf
End Sub

{
**************************************************************************************
* Name    : RBX1F_IO_pin                                                             *
* Purpose : set or clear digital output pin on mcp2515, pin RX1BF                    *
*         :                                                                          *
* notes   : Example: RBX1F_IO_pin(1) = pin high / RBX1F_IO_pin(0) = pin low          *
*         : must set register eg: (BFPCTRL = %00001000)                              *
**************************************************************************************
}
Public Sub RBX1F_IO_pin(pSet As Bit)
    // activate the RXnBF Pins (RX1BF Pin active)
    // LED connected to pin to show comms to mcp2515
    If pSet = 1 Then
        ' register, mask bit, data bit
        mcp2515_bit_modify(BFPCTRL, (1 << B1BFS), (1 << B1BFS))    
    Else
        ' register, mask bit, data bit
        mcp2515_bit_modify(BFPCTRL, (1 << B1BFS), (0 << B1BFS)) 
    EndIf
End Sub


// init SPI and set MCP2515
init_spi()

End Module

Heres the Definitions support module for MCP2515
MCP2515_def.rar
(2.14 KiB) Downloaded 763 times

User avatar
brad
Site Admin
Site Admin
Posts: 2578
Joined: Fri Mar 26, 2010 10:30 pm
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable

Re: Controller Area Network - CAN BUS Project

Post by brad » Mon Oct 31, 2011 9:44 pm

Very nicely done bitfogav! and might I say, some of the cleanest code I have ever seen (you should see my iphone code at the moment - such a mess!)

Post Reply
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable
[phpBB Debug] PHP Warning: in file [ROOT]/vendor/twig/twig/lib/Twig/Extension/Core.php on line 1266: count(): Parameter must be an array or an object that implements Countable

Who is online

Users browsing this forum: No registered users and 4 guests