howto:dev:libcan
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | howto:dev:libcan [2007/12/20 16:21] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | FIXME Elaborate... | ||
+ | ====== Using libcan ====== | ||
+ | |||
+ | ===== What is libcan ? ===== | ||
+ | |||
+ | [[libcan]] is library to use the ECAN feature of the PIC18F2682/ | ||
+ | CAN (for [[http:// | ||
+ | |||
+ | **Announcement forum post: http:// | ||
+ | |||
+ | [[libcan]] has nothing specific to MIOS so you could also use it outside MIOS. | ||
+ | |||
+ | ===== Requirements ===== | ||
+ | |||
+ | [[libcan]] uses the [[autotools-skeleton|AutoTools application skeleton]]. So if you want to recompile it, you need all the related stuff. | ||
+ | |||
+ | The examples in this page also uses the [[autotools-skeleton|AutoTools application skeleton]]. | ||
+ | |||
+ | ===== CAN Wirings ===== | ||
+ | |||
+ | Here we describe some CAN wirings. | ||
+ | |||
+ | ==== Single wire CAN ==== | ||
+ | |||
+ | ==== Dual wire CAN with MCP2551 transceiver ==== | ||
+ | |||
+ | ===== Getting started with libcan ===== | ||
+ | |||
+ | ==== Message flows overview ==== | ||
+ | |||
+ | === Initialize CAN === | ||
+ | |||
+ | You first have to initialize the CAN module of the PIC. This is done via the // | ||
+ | <code c>void can_init();</ | ||
+ | |||
+ | === Sending a message === | ||
+ | |||
+ | Sending a data message is done via the // | ||
+ | <code c> | ||
+ | |||
+ | [[libcan]] then processes the message in the following way : | ||
+ | - Select a message transmit buffer | ||
+ | - Convert the application-local message ID to the corresponding bus-global message ID | ||
+ | - Fill the message buffer with the global ID and data | ||
+ | - Order the PIC to send the message | ||
+ | |||
+ | === Receiving messages === | ||
+ | |||
+ | Dispatching of data messages is done via the // | ||
+ | <code c>void can_dispatch(void);</ | ||
+ | |||
+ | Selected messages are then forwarded to the application via the // | ||
+ | <code c>extern void can_receive_data_handler(unsigned char local_id, unsigned char length, data_ptr data_field);</ | ||
+ | |||
+ | Thus to receive messages, one has to call the // | ||
+ | |||
+ | [[libcan]] processes incoming data messages in the following way : | ||
+ | - Fetch receive buffers until none is full | ||
+ | - Select a full receive buffer | ||
+ | - Convert the bus-global message ID to the corresponding application-local message ID | ||
+ | - If this id has been recognized, call // | ||
+ | - Empty the receive buffer | ||
+ | |||
+ | === Message IDs === | ||
+ | |||
+ | **Local IDs** are specific to the application. They are the IDs the application uses to reference the types of message it can send and receive. | ||
+ | |||
+ | **Global IDs** are bus-wide. They are the IDs that are communicated through the bus. | ||
+ | |||
+ | Local IDs are //unsigned char//s whereas global IDs are of type // | ||
+ | <code c> | ||
+ | #define CAN_STD_ID(id) \ | ||
+ | (can_id_t) ... // preprocessing of id to make it a standard ID | ||
+ | #define CAN_EXT_ID(id) \ | ||
+ | (can_id_t) ... // preprocessing of id to make it an extended ID | ||
+ | </ | ||
+ | |||
+ | |||
+ | >> In fact, the // | ||
+ | |||
+ | [[libcan]] uses local IDs to enable easy maintainability of the application. Thus one can change the local IDs or the global IDs independently. That is neat if you have many different applications that needs to communicate over a CAN bus. Also local/ | ||
+ | |||
+ | Conversion between local and global IDs are done via the // | ||
+ | <code c> | ||
+ | extern can_id_t can_local_to_global_id(unsigned char local_id); | ||
+ | extern unsigned char can_global_to_local_id(can_id_t internal_id); | ||
+ | </ | ||
+ | |||
+ | The library provides three helper functions // | ||
+ | <code c> | ||
+ | can_id_t can_helper_table_ltog(unsigned char local_id, | ||
+ | const can_id_mapping_element_t const mapping_table[]); | ||
+ | unsigned char can_helper_table_gtol(can_id_t internal_id, | ||
+ | const can_id_mapping_element_t const mapping_table[]); | ||
+ | </ | ||
+ | |||
+ | But let's jump into some examples, and you'll better understand the big picture... | ||
+ | |||
+ | |||
+ | |||
+ | ==== Sending message example ==== | ||
+ | |||
+ | In this example, we send a message for each change of the first encoder of the first shift register. | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | /* Encoder definition table */ | ||
+ | |||
+ | MIOS_ENC_TABLE { | ||
+ | MIOS_ENC_ENTRY(1, | ||
+ | MIOS_ENC_EOT | ||
+ | }; | ||
+ | |||
+ | /* Message ID definitions */ | ||
+ | |||
+ | #define ENCODER_CHANGE 1 | ||
+ | |||
+ | const can_id_mapping_element_t outgoingMessageIDs[] = { | ||
+ | {ENCODER_CHANGE, | ||
+ | }; | ||
+ | |||
+ | /* Application code */ | ||
+ | |||
+ | void Init(void) __wparam | ||
+ | { | ||
+ | MIOS_SRIO_UpdateFrqSet(1); | ||
+ | MIOS_SRIO_NumberSet(1); | ||
+ | MIOS_SRIO_DebounceSet(0); | ||
+ | MIOS_ENC_SpeedSet(0, | ||
+ | |||
+ | can_init(); | ||
+ | } | ||
+ | |||
+ | typedef __data struct { | ||
+ | unsigned char id; | ||
+ | char incrementer; | ||
+ | } encoder_change_message_t; | ||
+ | |||
+ | encoder_change_message_t encoderChangeMessage; | ||
+ | |||
+ | void ENC_NotifyChange(unsigned char encoder, char incrementer) __wparam | ||
+ | { | ||
+ | can_transmit_buffer_control_t * bc; | ||
+ | |||
+ | encoderChangeMessage.id = encoder; | ||
+ | encoderChangeMessage.incrementer = incrementer; | ||
+ | |||
+ | bc = can_transmit_data(ENCODER_CHANGE, | ||
+ | sizeof(encoder_change_message_t), | ||
+ | (data_ptr) & | ||
+ | } | ||
+ | |||
+ | can_id_t can_local_to_global_id(unsigned char local_id) | ||
+ | { | ||
+ | return can_helper_table_ltog(local_id, | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The important bits of this example could be summarized as follows : | ||
+ | - We create an // | ||
+ | - We init the CAN module in our //Init()// user handler | ||
+ | - We define a structure for the message data and instanciate it for the current message pending transmission | ||
+ | - In the // | ||
+ | * The message local ID : ENCODER_CHANGE | ||
+ | * The message priority (among other messages to send) : 0 | ||
+ | * The size of the data to send : sizeof(encoder_change_message_t) | ||
+ | * The data itself : (data_ptr) & | ||
+ | - We convert local to global IDs in the // | ||
+ | |||
+ | ==== Receiving messages example ==== | ||
+ | |||
+ | In the following example, we receive messages that tells us to toggle DOUT pins. | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | /* Message ID definitions */ | ||
+ | |||
+ | #define DOUT_TOGGLE 1 | ||
+ | |||
+ | const can_id_mapping_element_t incomingMessageIDs[] = { | ||
+ | {DOUT_TOGGLE, | ||
+ | }; | ||
+ | |||
+ | /* Application code */ | ||
+ | |||
+ | void Init(void) __wparam | ||
+ | { | ||
+ | MIOS_SRIO_UpdateFrqSet(1); | ||
+ | MIOS_SRIO_NumberSet(1); | ||
+ | MIOS_SRIO_DebounceSet(0); | ||
+ | MIOS_ENC_SpeedSet(0, | ||
+ | |||
+ | can_init(); | ||
+ | } | ||
+ | |||
+ | typedef __data struct { | ||
+ | unsigned char id; | ||
+ | unsigned char value; | ||
+ | } dout_toggle_message_t; | ||
+ | |||
+ | void doutToggle(dout_toggle_message_t * doutToggleMessage) | ||
+ | { | ||
+ | MIOS_DOUT_PinSet(doutToggleMessage-> | ||
+ | } | ||
+ | |||
+ | void Tick(void) __wparam | ||
+ | { | ||
+ | can_dispatch(); | ||
+ | } | ||
+ | |||
+ | void can_receive_data_handler( | ||
+ | unsigned char local_id, | ||
+ | unsigned char length, | ||
+ | data_ptr data_field) | ||
+ | { | ||
+ | switch (local_id) { | ||
+ | case DOUT_TOGGLE: | ||
+ | doutToggle((dout_toggle_message_t *) data_field); | ||
+ | break; | ||
+ | default: | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | unsigned char can_global_to_local_id(can_id_t global_id) | ||
+ | { | ||
+ | return can_helper_table_gtol(global_id, | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The important bits of this example could be summarized as follows : | ||
+ | - We create an // | ||
+ | - We init the CAN module in our //Init()// user handler | ||
+ | - We define a structure for the message data | ||
+ | - In the //Tick()// user handler, we call // | ||
+ | - In the // | ||
+ | - We convert global to local IDs in the // | ||
+ | |||
+ | >> Please note the **// | ||
+ | |||
+ | You should process the message data before the return of // | ||
+ | <code c>void can_helper_copy_data(data_ptr from, data_ptr to, unsigned char length);</ | ||
+ | |||
+ | ===== Detailed review of libcan ===== | ||
+ | |||
+ | ==== Local and global message IDs ==== | ||
+ | |||
+ | ==== ID conversion helpers ==== | ||
+ | |||
+ | === Message ID tables === | ||
+ | |||
+ | === Message ID binary decision tree === | ||
+ | |||
+ | ==== can_transmit_buffer_control type ==== |
howto/dev/libcan.txt · Last modified: 2007/12/20 16:21 by 127.0.0.1