______________________________________________________________________ > < > CAN bus driver v1.05 < > for < > PICos18 release 2.05 < > < > PICos18 - Real-time kernel for PIC18 family < > < > < > www.picos18.com www.pragmatec.net < >______________________________________________________________________< This file contains all necessary informations to use properly the PIC18 CAN driver for PICos18 v2.xx. This driver let you design a multi-task application using the same CAN port without being concerned by the CAN shared access. Then every task of your application can send messages without being necessarily synchronised to the others. ______________________________________________________________________ > < > I - Zip file content < >______________________________________________________________________< The drv_can zip file contains : - drv_can.c - drv_can.h : header file - drv_can.txt : this file To use the PICos18 CAN driver, first unzip the file. Place the C and H file in your project directory. This driver is supposed to be use with PICos18 and has been tested with MPLAB 7.00 and C18 v2.40. Do not use this driver at a frequency lower than 8 Mhz (use the PIC18 PLL to increase the internal frequency). ______________________________________________________________________ > < > II - Hardware settings < >______________________________________________________________________< The driver is able to run in loopback mode. It means you can run your application with this driver without necessarily being connected to a real network. To activate the loopback mode, add the following compiler option in the MPLAB C18 panel of the Build Options window : __LOOPBACK__ The basic job of the driver is to filter the incoming message by software. If a task is waiting for a certain CAN ID, the CAN driver is in charge of waking the waiting task as soon as the expected message arrives. To disable this feature and so to force the driver to wake up ALL the task of your application each time a new message arrives, add the following option in the MPLAB C18 panel of the Build Options window : __NOFILTER__ In a current usage, you don't have to activate these both options. For instance the LOOPBACK mode could be use to test the hardware before starting the application and the NOFILTER option may be use to design a kind of software bus analyser. Moreover you HAVE to specify if you want to use this driver in 11 bits or in 29 bits mode (length of the CAN ID field). To activate the standart mode (11 bits) add the following option in the MPLAB C18 panel of the Build Options window : __SDT11BITS__ To activate the extended mode (29 bits) add the following option in the MPLAB C18 panel of the Build Options window : __EXT29BITS__ If you forget to select any one of the modes, the compiler will exit with an error message : "you should define 11 or 29 bits for CANID !" Baudrate Settings: ------------------ This CAN driver has a predefined CAN baud rate. You just have to define your oscillator frequency in MHz in the drv_can.c file : #define OSCILATOR_FREQ 40 Note : We have only define baud rate settings for 16, 20, 32 and 40 MHz Finaly you have to define the appropriate baud rate as follow : #define DEFAULT_SPEED 0 //for 10 kbps #define DEFAULT_SPEED 1 //for 20 kbps #define DEFAULT_SPEED 2 //for 50 kbps #define DEFAULT_SPEED 3 //for 125kbps #define DEFAULT_SPEED 4 //for 250kbps #define DEFAULT_SPEED 5 //for 500kbps #define DEFAULT_SPEED 6 //for 800kbps #define DEFAULT_SPEED 7 //for 1000kbps ______________________________________________________________________ > < > III - TASCDESC settings (1) < >______________________________________________________________________< Update also the tascdesc.c file to take into account the new CAN driver in your application : /********************************************************************** * ----------------------- TASK & STACK DEFINITION -------------------- **********************************************************************/ DeclareTask(Example); DeclareTask(CAN_Drv); ... volatile unsigned char stack0[DEFAULT_STACK_SIZE]; volatile unsigned char stack_can[DEFAULT_STACK_SIZE]; ... ______________________________________________________________________ > < > IV - TASCDESC settings (2) < >______________________________________________________________________< Finally add the task and alarm descriptor to the tascdesc.c file : ... /********************************************************************** * ----------------------------- CAN task ----------------------------- **********************************************************************/ rom_desc_tsk rom_desc_CAN_DRV = { DRV_CAN_PRIO, /* prioinit from 0 to 15 */ stack_can, /* stack address (16 bits) */ CAN_Drv, /* start address (16 bits) */ READY, /* state at init phase */ CAN_DRV_ID, /* id_tsk from 0 to 15 */ sizeof(stack_can) /* ctx address (16 bits) */ }; ... To use the CAN we propose an EXAMPLE task that send some messages periodicaly. Because the task is a periodic one, we create an alarm : AlarmObject Alarm_list[] = { /******************************************************************* * ----------------------- Example task ---------------------------- *******************************************************************/ { OFF, /* State */ 0, /* AlarmValue */ 0, /* Cycle */ &Counter_kernel, /* ptrCounter */ Example, /* TaskID2Activate */ ALARM_EVENT, /* EventToPost */ 0 /* CallBack */ } }; ______________________________________________________________________ > < > V - TASK Settings < >______________________________________________________________________< Open define.h and add these definitions with suitable values : #define ALARM_EVENT 0x80 #define CAN_NEW_MSG 0x02 #define CAN_RCV_MSG 0x04 #define CAN_ERR_MSG 0x08 #define CAN_QUEUE_FULL 0x01 #define CAN_QUEUE_EMPTY 0x02 ... #define CAN_DRV_ID 6 #define DRV_CAN_PRIO 8 #define EXAMPLE_ID 4 #define EXAMPLE_PRIO 5 The CAN task is considered to be a driver, that means you have to give one of the highest priority to the CAN driver to let it run each time the CAN buffer is updated. Adapt the values to your application is necessary (event values...). ______________________________________________________________________ > < > VI - ISR connection < >______________________________________________________________________< Open the file int.c and declare the external CAN ISR function : extern void AddOneTick(void); extern void CAN_INT(void); // <= here void InterruptVector(void); And complete the InterruptVector function : void InterruptVectorL(void) { EnterISR(); if (INTCONbits.TMR0IF == 1) AddOneTick(); if ((PIR3 & PIE3) != 0) CAN_INT(); LeaveISR(); } ______________________________________________________________________ > < > VII - CAN driver usage (1) < >______________________________________________________________________< In the task, you have first to specify a SIDL and SIDH values as a CAN ID. In this CAN driver release only the SIDH field is managed by the driver, then the CAN ID is 8 bits long only. Check the next release to be able to manage 21 bits CAN ID field. In the Example task, include the driver header: #include "drv_can.h" And declare a CAN message (type CAN_message_t): CAN_ message_t CAN_msg; See hereafter a basic example to send a "Test: xx" message with a counter value to a CAN network: #include "define.h" #include "drv_can.h" /* Replace by the correct value of your alarm ID */ #define CAN_TASK_ALARM 0 /********************************************************************** * Variables shared with the rest of application. **********************************************************************/ CAN_message_t SND1_message; unsigned char data1, data2; /********************************************************************** * ------------------------- Internal test TASK ----------------------- * * The task sends a CAN message every 3 secondes. * **********************************************************************/ TASK(CAN_sender) { SetRelAlarm(CAN_TASK_ALARM, 3000, 3000); SND1_message.CANID = 0x7AA; // SND1_message.CANID = 0x1A55AA55; // In 29 bits mode only SND1_message.length = 8; SND1_message.data[0] = 'T'; SND1_message.data[1] = 'e'; SND1_message.data[2] = 's'; SND1_message.data[3] = 't'; SND1_message.data[4] = ':'; SND1_message.data[5] = ' '; SND1_message.data[6] = '0'; SND1_message.data[7] = '0'; data1 = 0x30; data2 = 0x30; while (1) { WaitEvent(ALARM_EVENT); ClearEvent(ALARM_EVENT); data2++; if (data2 == 0x3A) { data2 = 0x30; data1++; if (data1 == 0x3A) data1 = 0x30; } SND1_message.data[6] = data1; SND1_message.data[7] = data2; CAN_enqMsg(&SND1_message); SetEvent(CAN_DRV_ID, CAN_NEW_MSG); /* Optionnal : we don't need to wait for end of transmission */ WaitEvent(CAN_QUEUE_EMPTY); ClearEvent(CAN_QUEUE_EMPTY); } } ______________________________________________________________________ > < > VIII - CAN driver usage (2) < >______________________________________________________________________< In your application you can have one or more task waiting for a certain can message (specifyed by a certai CAN ID). In the Example task, include the driver header: #include "drv_can.h" And declare a CAN message (type CAN_message_t): CAN_ message_t CAN_msg; See hereafter a basic example to wait for a message with a specific CAN ID value : #include "define.h" #include "drv_can.h" /* Replace by the correct value of your alarm ID */ #define CAN_TASK_ALARM 0 /********************************************************************** * Variables shared with the rest of application. **********************************************************************/ CAN_message_t RCV_message; unsigned char data1, data2, length; /********************************************************************** * ------------------------- Internal test TASK ----------------------- * * The task wait for the CAN message with 64 as SIDH CAN ID. * **********************************************************************/ TASK(CAN_reciever) { unsigned char i; RCV_message.CANID = 0x7AA; //RCV_message.CANID = 0x1A55AA55; // In 29 bits mode only CAN_RCV_Register(&RCV_message); while(1) { WaitEvent(CAN_QUEUE_FULL); ClearEvent(CAN_QUEUE_FULL); length = RCV_message.length; data1 = RCV_message.data[length-2]; data2 = RCV_message.data[length-1]; CAN_freeMsg(RCV_message); SetEvent(CAN_DRV_ID, CAN_RCV_MSG); } } ______________________________________________________________________ > < > IX - Conclusion < >______________________________________________________________________< With a such example here is what you should see on the CAN network : ID 64 : ID 64 : ID 64 : ID 64 : The code has been tested on the PIC18F458, PIC18F258 and PIC18F4680 without any trouble. This CAN driver is provided from the PICos18 web site with other drivers dedicated to oher peripherals. Some zip files are also provided to be used with a driver. Error are taken into account by the CAN driver but not yet report in a structured log file. Do not hesitate to check periodicaly the www.picos18.com web site in order to download the last versions of PIC18 drivers for PICos18. /* End of File : drv_can.txt */