📄 drv_can.c
字号:
/**********************************************************************/
/* */
/* File name: drv_can.c */
/* */
/* Since: 2005-Jan-19 */
/* */
/* Version: PICos18 v2.00 */
/* Copyright (C) 2003, 2004, 2005 Pragmatec. */
/* CAN driver v1.00 (initial release) */
/* */
/* Author: Designed by Pragmatec S.A.R.L. www.pragmatec.net */
/* MONTAGNE Xavier [XM] xavier.montagne@pragmatec.net */
/* */
/* Purpose: PIC18 CAN peripheral management. */
/* It allows task tosend data at the send time through a */
/* dedicated FIFO, and to wait for a certain CAN frame. */
/* */
/* Distribution: This file is part of PICos18. */
/* PICos18 is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2, or (at your option) */
/* any later version. */
/* */
/* PICos18 is distributed in the hope that it will be */
/* useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with gpsim; see the file */
/* COPYING.txt. If not, write to the Free Software */
/* Foundation, 59 Temple Place - Suite 330, */
/* Boston, MA 02111-1307, USA. */
/* */
/* > A special exception to the GPL can be applied should */
/* you wish to distribute a combined work that includes */
/* PICos18, without being obliged to provide the source */
/* code for any proprietary components. */
/* */
/* History: */
/* 2005/01/19 [XM] Create this file. */
/* 2005/01/31 [XM] Added reception buffer overflow management. */
/* If an overflow occurs, new messages are discarded.*/
/* */
/**********************************************************************/
#include "define.h"
#include "drv_can.h"
/**********************************************************************
* Definition dedicated to the local functions.
**********************************************************************/
EventMaskType CAN_event;
CAN_message_tRef CAN_list_head; // Start of message queue
CAN_message_tRef CAN_current_message; // Current message
unsigned char CAN_list_count = 0; // Number of items currently in queue
CAN_message_tRef CAN_list_head_rcv; // Start of message queue
CAN_message_tRef CAN_current_message_rcv;// Current message
unsigned char CAN_list_count_rcv = 0; // Number of items currently in queue
/**********************************************************************
* Task of the CAN driver, waiting for any of these 4 events :
* CAN_TX_EVENT : A message has been sent then a hardware transmitter
* is free. The driver will tranfer a software buffer
* into a free TX[0,1,2] hardware buffer.
* CAN_RX_EVENT : A message is arrived in the RX[0,1] buffer.
* the driver transfer the content of the message into
* a software buffer waiting for this message ID or
* discard the message to free the hardware.
* CAN_ERR_EVENT : Something wrong appended and the driver must clean
* the hardware before being disconnected. To be
* completed...
* ALARM_EVENT : Sometimes a task waiting for a specific message is
* not fast enough to read all the content of the
* hardware buffers. The driver have to keep available
* this content the time needed by other tasks.
* Then the driver periodicaly checks if the other tasks
* have finished to read the hardware buffers or needs
* more time.
*
* @param void
* @return void
**********************************************************************/
TASK(CAN_Drv)
{
CAN_config();
while(1)
{
WaitEvent(CAN_NEW_MSG | CAN_RCV_MSG | CAN_ERR_MSG | ALARM_EVENT);
GetEvent(CAN_DRV_ID, &CAN_event);
if (CAN_event & CAN_NEW_MSG)
{
ClearEvent(CAN_NEW_MSG);
WriteCANBuffer();
}
if (CAN_event & CAN_RCV_MSG)
{
ClearEvent(CAN_RCV_MSG);
ReadCANBuffer();
}
if (CAN_event & CAN_ERR_MSG)
{
ClearEvent(CAN_ERR_MSG);
}
}
}
/**********************************************************************
* Hardware settings of the CAN port.
*
* @param void
* @return void
**********************************************************************/
void CAN_config(void)
{
CANCON = 0x80;
TRISBbits.TRISB2 = 0;
TRISBbits.TRISB3 = 1;
BRGCON1 = 0x41;
BRGCON2 = 0xEE;
BRGCON3 = 0x05;
CIOCON = 0x20;
PIE3 = 0xFF;/* All RX and TX enabled */
RXM0SIDL = 0;
RXM0SIDH = 0;
RXM0EIDL = 0x00;
RXM0EIDH = 0x00;
RXF0SIDL = 0x00;
RXF0SIDH = 0x00;
RXF0EIDL = 0x00;
RXF0EIDH = 0x00;
RXB0CON = 0x24; /* Only valid messages */
TXB0CON = 0x00;
#ifdef __LOOPBACK__
CANCON = 0x40;
#else
CANCON = 0x00;
#endif
/* Settings for the first frame to send */
PIE3bits.TXB0IE = 0;
/* Init the different FIFO */
CAN_current_message = NULL;
CAN_list_head = NULL;
CAN_list_head_rcv = NULL;
}
/**********************************************************************
* Called by the CAN driver task.
* Call the CopyFrmaeBuffer2Hard 3 times, one for each TX buffer.
* Indeed the 3 buffers could be free then we have to take our chance
* to send 3 waiting frames at the same time.
*
* @param void
* @return Status Always return E_OK
**********************************************************************/
StatusType WriteCANBuffer(void)
{
if ((PIR3bits.TXB0IF == 1) ||
((PIR3bits.TXB0IF == 0) &&
(PIR3bits.TXB1IF == 0) &&
(PIR3bits.TXB2IF == 0)))
{
CANCONbits.WIN2 = 1;
CANCONbits.WIN1 = 0;
CANCONbits.WIN0 = 0;
CopyFrameBuffer2Hard();
PIR3bits.TXB0IF = 0;
PIE3bits.TXB0IE = 1;
}
if (PIR3bits.TXB1IF == 1)
{
CANCONbits.WIN2 = 0;
CANCONbits.WIN1 = 1;
CANCONbits.WIN0 = 1;
if (CopyFrameBuffer2Hard() == E_OK)
{
PIR3bits.TXB1IF = 0;
PIE3bits.TXB1IE = 1;
}
}
if (PIR3bits.TXB2IF == 1)
{
CANCONbits.WIN2 = 0;
CANCONbits.WIN1 = 1;
CANCONbits.WIN0 = 0;
if (CopyFrameBuffer2Hard() == E_OK)
{
PIR3bits.TXB2IF = 0;
PIE3bits.TXB2IE = 1;
}
}
return(E_OK);
}
/**********************************************************************
* Parse the entier TX message list to find any message to transfer.
* Once a such message is found we post an event to the sending task
* to tell the transfer is started and we break.
* The event is used if the task want to send as fast as possible a
* set of message. Doing so the task will be able to send a new message
* every time a TASK_CAN_TX_EVENT event is received.
*
* @param type IN Number of the hardware buffer
* @return Status E_OK if tranfer initiated
* E_OS_STATE otherwise
**********************************************************************/
StatusType CopyFrameBuffer2Hard(void)
{
StatusType returned_type;
returned_type = E_OS_STATE;
CAN_current_message = CAN_deqMsg();
if (CAN_current_message == NULL)
return(returned_type);
RXB0SIDH = CAN_current_message->SIDH;
RXB0SIDL = 0x00;
RXB0DLC = CAN_current_message->length & 0x0F;
RXB0D0 = CAN_current_message->data[0];
RXB0D1 = CAN_current_message->data[1];
RXB0D2 = CAN_current_message->data[2];
RXB0D3 = CAN_current_message->data[3];
RXB0D4 = CAN_current_message->data[4];
RXB0D5 = CAN_current_message->data[5];
RXB0D6 = CAN_current_message->data[6];
RXB0D7 = CAN_current_message->data[7];
CAN_current_message->state = CAN_MSG_SENT;
SetEvent(CAN_current_message->CallerID, CAN_QUEUE_EMPTY);
/* Same than TXB0CONbits.TXREQ = 1 thanks to WIN */
RXB0CONbits.RXRTRRO = 1;
returned_type = E_OK;
return(returned_type);
}
/**********************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -