📄 drv_can.c
字号:
/**********************************************************************/
/* */
/* File name: drv_can.c */
/* */
/* Since: 2005-Jan-19 */
/* */
/* Version: PICos18 v2.05 */
/* Copyright (C) 2003, 2004, 2005 Pragmatec. */
/* CAN driver v1.05 */
/* */
/* Author: Designed by Pragmatec S.A.R.L. www.pragmatec.net */
/* MONTAGNE Xavier [XM] xavier.montagne@pragmatec.net */
/* ROZIER Bertrand [RZR] bertrand.rozier@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.*/
/* 2006/03/03 [RZR] Add Pre-defined BaudRate selection */
/* Correct TX buffer allocation bug */
/* 2006/04/17 [RZR] Fixed bug ln 335 in CopyFrameBuffer2Hard (29 bits)*/
/* */
/**********************************************************************/
#include "define.h"
#include "drv_can.h"
///////////////////////////////////////////////////////////////////////////////
//
// OSCILLATOR SPEED
//
#define DEFAULT_CANSPEED 5
#define OSCILATOR_FREQ 40
/*******************************************************************************
CAN Baud rate setup table.
Thanks Janez :-)
*******************************************************************************/
rom struct{
unsigned char BRP; //(1...64) Baud Rate Prescaler
unsigned char SJW; //(1...4) SJW time
unsigned char PROP; //(1...8) PROP time
unsigned char PhSeg1; //(1...8) Phase Segment 1 time
unsigned char PhSeg2; //(1...8) Phase Segment 2 time
// BRP,SJW,PROP,PH1,PH1
}
CO_BitRateData[8] =
#if OSCILATOR_FREQ == 16
// BRP,SJW,PROP,PH1,PH1
{50, 1, 4, 8, 3, //CAN=10kbps
25, 1, 4, 8, 3, //CAN=20kbps
10, 1, 4, 8, 3, //CAN=50kbps
4, 1, 4, 8, 3, //CAN=125kbps
2, 1, 4, 8, 3, //CAN=250kbps
1, 1, 4, 8, 3, //CAN=500kbps
1, 1, 2, 4, 3, //CAN=800kbps
1, 1, 2, 3, 2}; //CAN=1000kbps
#elif OSCILATOR_FREQ == 20
// BRP,SJW,PROP,PH1,PH1
{50, 1, 6, 8, 5, //CAN=10kbps
25, 1, 6, 8, 5, //CAN=20kbps
10, 1, 6, 8, 5, //CAN=50kbps
5, 1, 4, 8, 3, //CAN=125kbps
2, 1, 6, 8, 5, //CAN=250kbps
1, 1, 6, 8, 5, //CAN=500kbps
1, 1, 3, 5, 3, //CAN=800kbps //combination does not work
1, 1, 2, 4, 3}; //CAN=1000kbps
#elif OSCILATOR_FREQ == 32
// BRP,SJW,PROP,PH1,PH1
{64, 1, 8, 8, 8, //CAN=10kbps
50, 1, 4, 8, 3, //CAN=20kbps
20, 1, 4, 8, 3, //CAN=50kbps
8, 1, 4, 8, 3, //CAN=125kbps
4, 1, 4, 8, 3, //CAN=250kbps
2, 1, 4, 8, 3, //CAN=500kbps
2, 1, 2, 4, 3, //CAN=800kbps
2, 1, 2, 3, 2}; //CAN=1000kbps
#elif OSCILATOR_FREQ == 40
// BRP, SJW, PROP, PH1, PH1
{64, 4, 8, 8, 8, //CAN=10kbps //combination does not work
50, 1, 6, 8, 5, //CAN=20kbps
25, 1, 4, 8, 3, //CAN=50kbps
8, 2, 6, 8, 8, //CAN=125kbps // DD
4, 2, 7, 8, 4, //CAN=250kbps // DD
2, 2, 7, 8, 4, //CAN=500kbps // DD
0, 0, 0, 0, 0, //CAN=800kbps
0, 0, 0, 0, 0}; //CAN=1000kbps
#else
#error define_OSCILATOR_FREQ OSCILATOR_FREQ not supported
#endif
/**********************************************************************
* 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
unsigned char BaudRate;
/**********************************************************************
* Task of the CAN driver, waiting for any of these 4 events :
* CAN_NEW_MSG : 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_RCV_MSG : 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_MSG : Something wrong appended and the driver must clean
* the hardware before being disconnected. To be
* completed...
*
* @param void
* @return void
**********************************************************************/
TASK(CAN_Drv)
{
// Determine CAN bus Speed
CAN_FindSpeed(&BaudRate);
CAN_config();
while(1)
{
WaitEvent(CAN_NEW_MSG | CAN_RCV_MSG | CAN_ERR_MSG);
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;
CAN_SetSpeed(BaudRate);
CIOCON = 0x20;
PIE3 = 0xE3;/* All RX and Err without TX enabled */
IPR3 = 0x00;
RXM0SIDL = 0;
RXM0SIDH = 0;
RXM0EIDL = 0x00;
RXM0EIDH = 0x00;
RXF0SIDL = 0x00;
RXF0SIDH = 0x00;
RXF0EIDL = 0x00;
RXF0EIDH = 0x00;
RXB0CON = 0x64; /* 0x24 for STD ID, 0x64 for EXT ID */
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.
* Function is incomplete now, finish later.
* For now, just return OK and continue...
*
* @param void
* @return Status Always return E_OK
**********************************************************************/
StatusType CAN_FindSpeed(unsigned char * speed)
{
*speed = DEFAULT_CANSPEED; // Set to default
return E_OK;
}
/**********************************************************************
* Sets the various baud rate registers based upon the CO_BitRateData table..
*
* @param void
* @return Status Always return E_OK
**********************************************************************/
StatusType CAN_SetSpeed(char speed)
{
if ((speed > 7) || (speed < 0))
return E_OS_STATE ;
// Prescaler in lower 6 bits; bits 5:0. BRP as coded, begins at 1, so
// you must subtract 1 to convert
BRGCON1 = CO_BitRateData[speed].BRP -1;
// Set the syncronizaiton jump width
BRGCON1 += (CO_BitRateData[speed].SJW -1)<< 6;
// Propigation in lower 3 bits, 2:0
BRGCON2 = CO_BitRateData[speed].PROP - 1;
// Located bits 5:3
BRGCON2 += (CO_BitRateData[speed].PhSeg1 -1) << 3;
BRGCON2bits.SEG2PHTS = 1;
// Set phase 2 segment time
BRGCON3 = CO_BitRateData[speed].PhSeg2 -1;
return E_OK;
}
/**********************************************************************
* 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)
{
pTXBUF_t txBuf;
while (CAN_list_count)
{
// Find an empty buffer
txBuf = TXBUF_START;
while (((txBuf->TXCON & TXCON_EMPTY) != 0) &&
(txBuf >=TXBUF_END)){
txBuf--;
}
// If we reached the end before finding an empty, return immed.
if (txBuf < TXBUF_END)
return E_OS_STATE;
CopyFrameBuffer2Hard(txBuf);
}
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -