www.pudn.com > canbus4linux.rar > DOCUMENTATION
D O C U M E N T A T I O N
C A N B U S 4 L I N U X V E R S I O N 0 . 3
Copyright 2001 by Juergen Eder
No liability for the contents of this document can be accepted. Use the concepts,
examples and other content at your own risk.
All copyrights are held by their respective owners, unless specifically noted otherwise.
Use of a term in this document should not be regarded as affecting the validity of
any trademark or service mark.
The file elektor_canpar.o is a driver for the can card from
"Elektor magazine june, 2000".
Homepage: http://www.elektor.de
The file can200par.o is a driver for the can card from CAN200 Project (it's also a card for the
parallelport)
Homepage: http://private.addcom.de/horo/can200/index.html
The file cantronik.o is a driver for the can card from cantronik.com
The canbus4linux driver is completely new written and use no part from
Elektor or CAN200 project!
****************************************************************************
Installation:
see file: INSTALL
****************************************************************************
Licence:
see file: COPYING
****************************************************************************
Features:
- interrupt driven
- should work with kernel 2.2.16 or newer
(tested with 2.6.6)
- support CAN200 card and elektor CAN card (both for the parallelport)
other cards can easily added with mini driver
- support CAN 2.0A and 2.0B (PeliCAN) of SJA1000 chip
- support /proc filesystem (/proc/canbus/...)
- parameters can be controlled by: IOCTL's and /proc filesystem
- read and write are implemented
=> example: echo "1234 0 12 34 55" > /dev/can0
send a can message with:
can id = 0x1234
rtr = 0
data bytes = 0x12 0x34 0x55
=> cat /dev/can0
shows the can messages
- support poll and fsync
- support fasync
- time stamp in all events
- a virtual CAN bus is simulated, if several applications uses the same CAN channel
=> example: 2 applications (x and y) open /dev/can0
-> application x send a message (and get the "transmission event)
-> application y get the receive message, because of the "virtual bus structure"
=> it's possible to turn off virtualization
--------------- |<------ virtual CAN bus
| | send data |
| App x |---->------>----->|
| | |
--------------- |
|
--------------- |
| | get data |
| App y |<-----<--------<--|
| | |
--------------- |
|
|
---------------
| Hardware |
---------------
|
|<------- real CAN bus
|
- the two drivers for the ELEKTOR CAN CARD and the CAN200 CAN CARD use
the parport driver
- the chipset driver (SJA1000.O) calculates the BTR registers
****************************************************************************
Description:
Actually the driver has three layers:
Layer 1: elektor_canpar.o and/or can200par.o
This layer implements the hardware access to the chip registers. This layer
is specific for every hardware.
Layer 2: SJA1000.O
It's the chipset layer and implements all features of the SJA1000
from Philips. This driver "translates" the order's from layer 3
to chip registers. For example layer 3 want 125000 baud. Layer 2 calculates
the BTR0 and BTR1 register and set this register with layer 1.
Layer 3: canbuscore.o
It's a core driver between the hardware driver and the application.
This layer implements all features: read/write, ioctl's, ...
---------------------------------------------
| APPLICATION |
---------------------------------------------
|
---------------------------------------------
| CANBUSCORE.O |
---------------------------------------------
| |
--------------- ------------------------------
| SJA1000.O | | | chipset driver or hardware driver
--------------- ------------------------------
| |
------------------ -------------------
| | | |
------------- --------------- --------- ---------
| ELEKTOR.O | | CAN200PAR.O | | | | | ....
------------- --------------- --------- ---------
****************************************************************************
Accessing CAN bus with scripts:
If a CAN driver is installed and started, it will create a directory:
/proc/canbus
and sub directories as many devices are available:
/proc/canbus/0
/proc/canbus/1
/proc/canbus/2
/proc/canbus/3
/proc/canbus/...
In "/proc/canbus/devices" you get the number of installed devices, for
example 1 sub directory if you have only LPT1 and installed only elektor_canpar.o
(or only can200par.o).
In the sub directories (./0, ./1, ...) you get information from every CAN channel. Some
information are write only and some are read only:
- ./baudrate (read/write: one line with decimal integer value)
- ./busload (read: busload in percentage => not implemented yet)
- ./filter (read/write: one line with 2 values hexadecimal acceptance filter)
- ./format (read/write: one line with 1 value integer: 0=default, 1=11 bit, 2=29 bit)
- ./lost (read: lost messages while receiving)
- ./mode (read/write: one line with 1 value integer: 0=CAN 2.0A 1=CAN 2.0B PeliCAN)
- ./receive (XXX: TODO)
- ./standby (read/write: one line with 1 value integer: 0=active 1=standby)
- ./transmit (write: one line with a CAN message, all values hexadecimal: [])
- ./virtualize (read/write: one line with 1 value integer: 0=virtualize off 1=virtualize on)
- ./information (read: information about the CAN channel)
****************************************************************************
Access with scripts:
To set all values, you can use the /proc filesystem and the echo command:
Examples:
Baudrate: echo 500000 > /proc/canbus/0/baudrate
Filter : echo "ffffffff ffffffff" > /proc/canbus/0/filter
Transmit: echo "1234 0 11 22 33 44 55 66 77 88" > /proc/canbus/0/transmit
To receive CAN messages, you can use the "cat" command:
cat /dev/can0
If some data will received, you get a line shown below:
received 1010852408:682453 00000111 0 0 [n data bytes] 0
| | | | | | |---- lost messages
| | | | | |-------------- n data bytes (max. 8)
| | | | |----------------------- dlc (data length code = number of received bytes)
| | | |-------------------------- rtr (remote transmission request bit)
| | |---------------------------------- CAN id
| |----------------------------------------------- 64 bit system time
|-------------------------------------------------------------- meaning of this event
Of course you can write CAN messages into a simple text file and 'copy' this
file to the CAN device:
content of simple.txt:
1234 0 11 22 33 44 55 66 77 88
0188 0 11 22
(Very important is the linefeed, don't forget a linefeed at the last line!)
Copying:
cp simple.txt /dev/can0
All messages in the text file will be sent over CAN bus.
If you use scripting, it's better to turn off virtualization:
echo 0 > /proc/canbus/0/virtualize
****************************************************************************
Accessing CAN bus using read/write and /proc - filesystem:
First open the CAN driver (for example /dev/can0). After that you
can read or write values into /proc - filesystem (see also above "Accessing CAN bus with scripts").
Example: Write one message
FILE *canbus;
canbus = fopen("/dev/can0","w");
if(canbus)
{
fprintf(canbus,"1234 0 11 22 33 44 55 66 77 88\n"); // the \n is important !!
fclose(canbus);
}
Example: Read one message
FILE *canbus;
canbus = fopen("/dev/can0","r");
if(canbus)
{
char buffer[100];
fgets(buffer,sizeof(buffer),canbus);
printf(buffer);
fclose(canbus);
}
Example: Set baudrate
FILE *canbus;
canbus = fopen("/proc/canbus/0/baudrate","w");
if(canbus)
{
fprintf(canbus,"500000");
fclose(canbus);
}
All other /proc/canbus parameters are described in "Accessing CAN bus with scripts".
****************************************************************************
Accessing CAN bus using ioctl: (recommended method)
In C or C++ programs, the header file "canbus4linux.h" can be used.
----------------------------------------------------------------------------
Open and close a CAN device with read/write access:
int file;
file = open("/dev/can0",O_RDWR);
if(file == -1)
{
printf("can't open canbus4linux device\n");
}
else
{
// Because of following 2 lines, a signal is generated on every event
// (receiving, transmitting, errors, warnings,...)
fcntl(file,F_SETOWN,getpid());
fcntl(file,F_SETFL, FASYNC | fcntl(file,F_GETFL));
}
Later close the CAN device:
if(file != -1)
{
close(file);
}
----------------------------------------------------------------------------
Determine CAN driver properties:
struct canbus_properties properties;
ioctl(file, CANBUS4LINUX_READ_PROPERTIES, &properties);
The properties are:
version Version number of canbus4linux
device_name[] A string with the channel name, this string can displayed for
user information
min Minimal supported baudrate
max Maximal supported baudrate
commands[] An array with supported commands of this CAN channel, all known commands
of canbus4linux are:
CANBUS_CMD_ENTER_STANDBY,
CANBUS_CMD_LEAVE_STANDBY,
CANBUS_CMD_ABORT_TRANSMISSION,
CANBUS_CMD_CLEAR_OVERRUN,
CANBUS_CMD_SELF_RECEPTION_REQUEST,
CANBUS_CMD_LISTEN_ON,
CANBUS_CMD_LISTEN_OFF,
CANBUS_CMD_VIRTUALIZE_ON,
CANBUS_CMD_VIRTUALIZE_OFF,
number_commands Number of valid entries in "commands[]"
baudrates[] (Optional) An array with supported baudrates of this CAN channel
number_baudrates Number of valid entries in "baudrates[]"
chipset_flags Bit field, which describes some features of the CAN channel:
CANBUS_CFS_CAN_2_0_A channel support CAN 2.0 A (Basic CAN)
CANBUS_CFS_CAN_2_0_B channel support CAN 2.0 B
CANBUS_CFS_EXT_FRAME channel support extended frame format (only used if
supports CAN 2.0 B too)
CANBUS_CFS_POLLING channel is not(!) interrupt driven, all
data must get with polling method
number_registers Number of supported registers
Note:
CANBUS_CFS_POLLING is not implemented yet
number_registers is not implemented yet
----------------------------------------------------------------------------
Init CAN channel:
To init the CAN channel, this function is used:
ioctl(file, CANBUS4LINUX_INIT, 0);
----------------------------------------------------------------------------
Read/Write acceptance filter:
Read acceptance filter
struct canbus_acceptance_filter filter;
ioctl(file, CANBUS4LINUX_READ_ACCEPTANCE_FILTER, &filter);
Write acceptance filter:
struct canbus_acceptance_filter filter;
filter.code = .....;
filter.mask = .....;
ioctl(file, CANBUS4LINUX_WRITE_ACCEPTANCE_FILTER, &filter);
----------------------------------------------------------------------------
Read/Write baudrate:
Read baudrate (baudrate is calculated by driver):
baudrate = ioctl(file, CANBUS4LINUX_GET_BAUDRATE, 0);
Write baudrate (baudrate is calculated by driver):
ioctl(file, CANBUS4LINUX_SET_BAUDRATE, );
Read baudrate (baudrate is a constant):
index = ioctl(file, CANBUS4LINUX_GET_BAUDRATE_BY_CONSTANT, 0);
Write baudrate (baudrate is a constant):
ioctl(file, CANBUS4LINUX_SET_BAUDRATE_BY_CONSTANT, );
----------------------------------------------------------------------------
Set CAN mode (2.0A or 2.0B)
Set to CAN 2.0 A:
ioctl(file, CANBUS4LINUX_SET_CAN_MODE, CANBUS_FORMAT_CAN_2_0_A);
Set to CAN 2.0 B:
ioctl(file, CANBUS4LINUX_SET_CAN_MODE, CANBUS_FORMAT_CAN_2_0_B);
----------------------------------------------------------------------------
Set default frame format:
Set frame format in dependency of CAN mode. If CAN 2.0A is selected the
frame format is always 11 bit (standard frame format). If CAN 2.0B
the frame format can be 11 bit (CANBUS_TRANS_FMT_STD) or 29 bit (CANBUS_TRANS_FMT_EXT).
Set to standard frames:
ioctl(file, CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT, CANBUS_TRANS_FMT_STD);
Set to extended frames:
ioctl(file, CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT, CANBUS_TRANS_FMT_EXT);
----------------------------------------------------------------------------
Hardware test:
Test if the hardware is installed. This is useful for external CAN devices, e.g for
the parallel port or for USB or other ports.
if (ioctl(file, CANBUS4LINUX_TEST_DEVICE, 0) > 0)
{
// CAN device is installed
}
else
{
// CAN device is not installed or an error ocured (return value < 0)
}
----------------------------------------------------------------------------
Read time:
With every event you get an absolute time stamp from the can driver. Also the actually time
can be read with this function.
struct canbus_time time;
ioctl(file, CANBUS4LINUX_READ_TIME, &time);
The time is a 64 bit value, with a resolution of 1 microsecond.
struct canbus_time
{
unsigned long low;
unsigned long high;
};
If relative timings are needed, it must be calculated in the application, for example:
....
time1 = read time with above function
...
...
time2 = event from driver
difference = time2 - time1
time1 = time2
...
...
time2 = event from driver
difference = time2 - time1
...
...
etc.
----------------------------------------------------------------------------
Transmit a CAN message:
To transmit a message, this call is used. In CAN 2.0B mode the CAN id format
can be specified in entry: "fmt" in the canbus_transmit_data structure.
If this entry is 0, the default (set by: CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT)
is used. In mode CAN 2.0A always standard frame format is used.
Example:
struct canbus_transmit_data data;
data.fmt = 0;
data.identifier = 0x1234
data.rtr = 0;
data.dlc = 8;
data.msg[0] = 0x11;
data.msg[1] = 0x22;
data.msg[2] = 0x33;
data.msg[3] = 0x44;
data.msg[4] = 0x55;
data.msg[5] = 0x66;
data.msg[6] = 0x77;
data.msg[7] = 0x88;
ioctl(file, CANBUS4LINUX_WRITE_TRANSMIT_DATA, &data);
canbus_transmit_data structure:
fmt Format of the transmitted CAN id
CANBUS_TRANS_FMT_DEFAULT use default format set by
ioctl(CANBUS4LINUX_SET_DEFAULT_FRAME_FORMAT)
CANBUS_TRANS_FMT_STD force standard frame format
CANBUS_TRANS_FMT_EXT force extended frame format (only useful
in CAN 2.0B mode)
identifier CAN identifier 11 or 29 bit
rtr 0=data frame 1=remote transmission frame
dlc data length code = number of valid entries in msg[]
msg[] data bytes, maximal 8 bytes msg[0]...msg[7]
----------------------------------------------------------------------------
Event processing:
The driver can send signals to the application. For example if following
lines are pass through after opening the CAN driver:
fcntl(file,F_SETOWN,getpid());
fcntl(file,F_SETFL, FASYNC | fcntl(file,F_GETFL));
To receive a signal in the application you need further code as shown here:
void SignalFromDriver(int signum)
{
struct canbus_event data;
while(1)
{
if (ioctl(file, CANBUS4LINUX_READ_EVENT_DATA, &data) <= 0)
{
break;
}
// interpret event:
switch(data.event)
{
case CANBUS_EVENT_RECEIVED:
// do something...
break;
case CANBUS_EVENT_TRANSMITTED:
// do something...
break;
case CANBUS_EVENT_BUS_ERROR:
// do something...
break;
case CANBUS_EVENT_WARNING:
// do something...
break;
case CANBUS_EVENT_LEAVING_STANDBY:
// do something...
break;
case CANBUS_EVENT_ARBITRATION_LOST:
// do something...
break;
case CANBUS_EVENT_OVERRUN:
// do something...
break;
case CANBUS_EVENT_PASSIVE:
// do something...
break;
case CANBUS_EVENT_ENTERING_STANDBY:
// do something...
break;
case CANBUS_EVENT_DEVICE_CHANGED:
// do something...
break;
}
}
return;
}
void Init()
{
// open CAN device and other initialization's
file = open("/dev/can0",O_RDWR);
if(file == -1)
{
printf("can't open canbus4linux device\n");
return;
}
else
{
// Because of the next 2 lines, a signal is generated on every event
// (receiving, transmitting, errors, warnings,...)
fcntl(file,F_SETOWN,getpid());
fcntl(file,F_SETFL, FASYNC | fcntl(file,F_GETFL));
}
// now CAN device is ready to create signals
// install signal handler
struct sigaction sa;
memset(&sa,0,sizeof(sa));
sa.sa_handler = Refresh;
sa.sa_flags = SA_RESTART;
sigaction(SIGIO,&sa,0);
}
All events are buffered in driver and at least one signal will be sent to the
application. In the application all events are get with CANBUS4LINUX_READ_EVENT_DATA.
****************************************************************************
Implementing a layer 1 driver:
Layer 1 driver (described in above model with SJA1000) need functions to:
- open and close the CAN channel
- 2 functions (read/write) for chip access with Reset-Bit=0
- 2 functions (read/write) for chip access with Reset-Bit=1
- a function to register a callback function from layer 2 for hardware interrupts
- a function to free the callback from layer 2
- if the driver have set CANBUS_CFS_POLLING, a callback function will not registered
(this feature is not implemented yet!)
Also the layer 2 (sja1000.o) need some information about the hardware and the layer 1
driver:
- bCanChipsetFlags With the following flags you specify the
features of the hardware:
CANBUS_CFS_CAN_2_0_A Chipset support CAN 2.0 A
CANBUS_CFS_CAN_2_0_B Chipset support CAN 2.0 B
CANBUS_CFS_EXT_FRAME Chipset support extended frame format
This feature is used only if CANBUS_CFS_CAN_2_0_B
is set
CANBUS_CFS_POLLING Chipset driver supports only polling
(not implemented yet)
For a 82C200 chip the bits:
CANBUS_CFS_2_0_B and CANBUS_CFS_EXT_FRAME
are never set.
- chipset_frequency Frequency of crystal (mostly 24MHz or 16 MHz, CAN200 project use 8MHz)
This information is needed to calculate the baudrate
- output_control_register The setting of this register in the SJA1000 chip. This information
is needed to initialize the sja1000 chip.
To register the driver at layer 2, a structure (sja_1000_access) must be filled out:
struct sja1000_access
{
sja1000_openCanDevice pOpenCanDevice;
sja1000_closeCanDevice pCloseCanDevice;
sja1000_writeToRegister pWriteToRegister;
sja1000_writeToRegisterRR pWriteToRegisterRR;
sja1000_readFromRegister pReadFromRegister;
sja1000_readFromRegisterRR pReadFromRegisterRR;
sja1000_registerIsr pRegisterIsr;
sja1000_unregisterIsr pUnregisterIsr;
int bCanChipsetFlags; // show Flags: CANBUS_CSF_...
int chipset_frequency;
unsigned char output_control_register;
};
The first parameter in every function is a pointer to a user structure of the layer 1 driver.
In this structure every driver can save settings and/or variables. Example:
--------------------- registering ->
| |-------------------- sja1000_register_device("name", , ...);
| Layer 1 driver | |
| | |
| |<---------------------------------
| ---------| call functions; example: openCanDevice();
| | var. |
| | |
---------------------
var. = user structure of every driver
While registering a layer 1 driver with "sja1000_register_device()", the pointer of this user structure
will be saved in the next layer 2 and will used in every function call.
int openCanDevice(void *pSpecificPar);
Parameter: pointer to user structure
Return: standard return values (0 = OK)
This function is called to open the can channel. In this function you can claim hardware
resources. Don't initialize the CAN hardware in this function!
int closeCanDevice(void *pSpecificPar);
Parameter: pointer to user structure
Return: standard return values (0 = OK)
This function is called to close the can channel. In this function you can free hardware
resources.
void writeToRegister(void *pSpecificPar, unsigned char adr, unsigned char value);
Parameter: pointer to user structure
sja1000 register addresse (0...127)
value to write
This function is called to write data into sja1000. While access, the Reset-Bit should
set to 0.
void writeToRegisterRR(void *pSpecificPar, unsigned char adr, unsigned char value);
Parameter: pointer to user structure
sja1000 register addresse (0...127)
value to write
This function is called to write data into sja1000. While access, the Reset-Bit should
set to 1.
unsigned char readFromRegister(void *pSpecificPar, unsigned char adr);
Parameter: pointer to user structure
sja1000 register addresse (0...127)
Return: value of sja1000 register
This function is called to read data from sja1000. While access, the Reset-Bit should
set to 0.
unsigned char readFromRegisterRR(void *pSpecificPar, unsigned char adr);
Parameter: pointer to user structure
sja1000 register addresse (0...127)
Return: value of sja1000 register
This function is called to read data from sja1000. While access, the Reset-Bit should
set to 1.
****************************************************************************