You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1208 lines
35 KiB
1208 lines
35 KiB
/* vxbFtcan.c - CAN driver */
|
|
|
|
/*
|
|
*
|
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
|
|
* This program 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.
|
|
*
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <stdio.h>
|
|
#include <taskLib.h>
|
|
#include <msgQLib.h>
|
|
#include <intLib.h>
|
|
#include <cacheLib.h>
|
|
#include <drv/timer/timerDev.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <sys/times.h>
|
|
#include <vxBusLib.h>
|
|
#include <hwif/vxbus/vxBus.h>
|
|
#include <hwif/util/hwMemLib.h>
|
|
#include <drv/pci/pciConfigLib.h>
|
|
#include <vxBusLib.h>
|
|
#include <hwif/vxbus/vxBus.h>
|
|
#include <hwif/vxbus/hwConf.h>
|
|
#include <hwif/vxbus/vxbPciLib.h>
|
|
#include <hwif/util/vxbParamSys.h>
|
|
#include <../src/hwif/h/vxbus/vxbAccess.h>
|
|
#include "vxbFtcan.h"
|
|
|
|
#undef FTCAN_DEBUG
|
|
#ifdef FTCAN_DEBUG
|
|
#define FTCAN_LOGMSG(fmt,p1,p2,p3,p4,p5,p6) logMsg(fmt,p1,p2,p3,p4,p5,p6)
|
|
#else
|
|
#define FTCAN_LOGMSG(fmt,p1,p2,p3,p4,p5,p6)
|
|
#endif
|
|
|
|
/* VxBus methods */
|
|
|
|
LOCAL void ftCanInstInit (VXB_DEVICE_ID);
|
|
LOCAL void ftCanInstInit2 (VXB_DEVICE_ID);
|
|
LOCAL void ftCanInstConnect (VXB_DEVICE_ID);
|
|
LOCAL void ftCanInt (FTCAN_DRV_CTRL *pDrvCtrl);
|
|
LOCAL void ftCanRecvTask(FTCAN_DRV_CTRL * pDrvCtrl);
|
|
|
|
LOCAL int ftcan_set_bittiming(VXB_DEVICE_ID pDev,struct can_bittiming *bt);
|
|
LOCAL int can_calc_bittiming( struct can_bittiming *bt,const struct can_bittiming_const *btc);
|
|
|
|
/* END functions */
|
|
|
|
LOCAL struct drvBusFuncs ftCanFuncs =
|
|
{
|
|
ftCanInstInit, /* devInstanceInit */
|
|
ftCanInstInit2, /* devInstanceInit2 */
|
|
ftCanInstConnect /* devConnect */
|
|
};
|
|
|
|
LOCAL device_method_t ftCan_methods[] =
|
|
{
|
|
{ 0, 0}
|
|
};
|
|
|
|
LOCAL struct vxbDevRegInfo ftCanDevPlbRegistration =
|
|
{
|
|
|
|
NULL, /* pNext */
|
|
VXB_DEVID_DEVICE, /* devID */
|
|
VXB_BUSID_PLB, /* busID = PLB */
|
|
VXB_VER_4_0_0, /* vxbVersion */
|
|
"ftCan", /* drvName */
|
|
&ftCanFuncs, /* pDrvBusFuncs */
|
|
NULL, /* pMethods */
|
|
NULL, /* devProbe */
|
|
NULL /* pParamDefaults */
|
|
};
|
|
|
|
LOCAL VXB_DEVICE_ID glftCanDev[CAN_MAX_CTL];
|
|
|
|
#ifdef __DCC__
|
|
LOCAL const struct can_bittiming_const ftcan_bittiming_const = {
|
|
"vxbftCan",
|
|
1,
|
|
16,
|
|
1,
|
|
8,
|
|
4,
|
|
1,
|
|
512,
|
|
2
|
|
};
|
|
#else
|
|
LOCAL const struct can_bittiming_const ftcan_bittiming_const = {
|
|
.name = "vxbftCan",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 512,
|
|
.brp_inc = 2,
|
|
};
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
*vxbFtCanRegister - register with the VxBus subsystem
|
|
*
|
|
* This routine registers the Template driver with VxBus as a
|
|
* child of the PCI bus type.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
void vxbFtCanRegister(void)
|
|
{
|
|
vxbDevRegister((struct vxbDevRegInfo *)&ftCanDevPlbRegistration);
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanInstInit - VxBus instInit handler
|
|
*
|
|
* This function implements the VxBus instInit handler for an template
|
|
* device instance. The only thing done here is to select a unit
|
|
* number for the device.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftCanInstInit
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
FTCAN_DRV_CTRL * pDrvCtrl;
|
|
HCF_DEVICE * pHcf;
|
|
|
|
/* get the HCF device from the instance ID */
|
|
|
|
pHcf = hcfDeviceGet (pDev);
|
|
|
|
/* if pHcf is NULL, no device is present in hwconf.c */
|
|
|
|
if (pHcf == NULL)
|
|
return;
|
|
|
|
/* allocate memory for the data */
|
|
|
|
pDrvCtrl = (FTCAN_DRV_CTRL *)hwMemAlloc (sizeof(FTCAN_DRV_CTRL));
|
|
|
|
if (pDrvCtrl == NULL)
|
|
return;
|
|
|
|
bzero((char *)pDrvCtrl, sizeof(FTCAN_DRV_CTRL));
|
|
|
|
pDrvCtrl->ftCanDev = pDev;
|
|
if (devResourceGet (pHcf, "regBase", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->ftCanRegbase) != OK)
|
|
{
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree((char *)pDrvCtrl);
|
|
#endif
|
|
return;
|
|
}
|
|
if (devResourceGet (pHcf, "irq", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->irq) != OK)
|
|
{
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree((char *)pDrvCtrl);
|
|
#endif
|
|
return;
|
|
}
|
|
if (devResourceGet (pHcf, "bitrate", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->ftcan_bittiming.bitrate) != OK)
|
|
{
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree((char *)pDrvCtrl);
|
|
#endif
|
|
return;
|
|
}
|
|
pDev->pDrvCtrl = pDrvCtrl;
|
|
vxbRegMap(pDev, 0, &pDrvCtrl->ftCanHandle);
|
|
glftCanDev[pDev->unitNumber]= pDev;
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanInstInit2 - VxBus instInit2 handler
|
|
*
|
|
* This function implements the VxBus instInit2 handler for an template
|
|
* device instance. Once we reach this stage of initialization, it's
|
|
* safe for us to allocate memory, so we can create our pDrvCtrl
|
|
* structure and do some initial hardware setup. The important
|
|
* steps we do here are to create a child miiBus instance, connect
|
|
* our ISR to our assigned interrupt vector, read the station
|
|
* address from the EEPROM, and set up our vxbDma tags and memory
|
|
* regions. We need to allocate a 64K region for the RX DMA window
|
|
* here.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftCanInstInit2
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
FTCAN_DRV_CTRL *pDrvCtrl;
|
|
UINT is_config_mode=0;
|
|
struct can_bittiming bt;
|
|
int ret;
|
|
|
|
pDrvCtrl = (FTCAN_DRV_CTRL *)pDev->pDrvCtrl;;
|
|
if ((pDrvCtrl->ftcanQueue = msgQCreate(FTCAN_QUEUE_SIZE, VXB_FTCAN_MSG_SIZE,
|
|
MSG_Q_FIFO)) == NULL)
|
|
{
|
|
FTCAN_LOGMSG("<ftCanInstInit2> Unable to create FT CAN message queue\n",
|
|
0,0,0,0,0,0);
|
|
return;
|
|
}
|
|
|
|
if ((pDrvCtrl->canTxSem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY)) == NULL)
|
|
{
|
|
FTCAN_LOGMSG("<ftCanInstInit2> Unable to create FT CAN Tx Sem\n",
|
|
0,0,0,0,0,0);
|
|
return;
|
|
}
|
|
|
|
is_config_mode = CSR_READ_4(pDev,FTCAN_CTRL_OFFSET);
|
|
if (is_config_mode&FTCAN_CTRL_XFER_MASK) {
|
|
FTCAN_LOGMSG("FT can is not in configration mode\n",1,2,3,4,5,6);
|
|
return;
|
|
}
|
|
CSR_WRITE_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6));/*bit 6 is internal reset**/
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_AIME_MASK);
|
|
CSR_WRITE_4(pDev, FTCAN_ACC_ID0_MASK_OFFSET, FTCAN_ACC_IDN_MASK);
|
|
CSR_WRITE_4(pDev, FTCAN_ACC_ID1_MASK_OFFSET, FTCAN_ACC_IDN_MASK);
|
|
CSR_WRITE_4(pDev, FTCAN_ACC_ID2_MASK_OFFSET, FTCAN_ACC_IDN_MASK);
|
|
CSR_WRITE_4(pDev, FTCAN_ACC_ID3_MASK_OFFSET, FTCAN_ACC_IDN_MASK);
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6));
|
|
|
|
bt.bitrate = pDrvCtrl->ftcan_bittiming.bitrate;
|
|
bt.sjw = 0;
|
|
bt.sample_point = 0;
|
|
ret = can_calc_bittiming(&bt,&ftcan_bittiming_const);
|
|
if(ret<0){
|
|
FTCAN_LOGMSG("can_calc_bittiming error\n",1,2,3,4,5,6);
|
|
return ;
|
|
}
|
|
if (ftcan_set_bittiming(pDev,&bt)) {
|
|
FTCAN_LOGMSG("ftcan_set_bittiming error\n",1,2,3,4,5,6);
|
|
return ;
|
|
}
|
|
pDrvCtrl->ftcan_bittiming.brp=bt.brp;
|
|
pDrvCtrl->ftcan_bittiming.sjw=bt.sjw;
|
|
pDrvCtrl->ftcan_bittiming.tq =bt.tq;
|
|
pDrvCtrl->ftcan_bittiming.phase_seg1= bt.phase_seg1;
|
|
pDrvCtrl->ftcan_bittiming.phase_seg2= bt.phase_seg2;
|
|
pDrvCtrl->ftcan_bittiming.sample_point=bt.sample_point;
|
|
|
|
pDrvCtrl->txCfMax = FTCAN_TX_FIFO_MAX/FTCAN_FIFOFRAME_SIZE;
|
|
pDrvCtrl->txCfCnt = 0;
|
|
}
|
|
|
|
LOCAL unsigned int div64_32(unsigned long long *n, unsigned int base)
|
|
{
|
|
unsigned long long rem = *n;
|
|
unsigned long long b = base;
|
|
unsigned long long res, d = 1;
|
|
unsigned int high = rem >> 32;
|
|
|
|
/* Reduce the thing a bit first */
|
|
res = 0;
|
|
if (high >= base) {
|
|
high /= base;
|
|
res = (unsigned long long) high << 32;
|
|
rem -= (unsigned long long) (high*base) << 32;
|
|
}
|
|
|
|
while ((unsigned long long)b > 0 && b < rem) {
|
|
b = b+b;
|
|
d = d+d;
|
|
}
|
|
|
|
do {
|
|
if (rem >= b) {
|
|
rem -= b;
|
|
res += d;
|
|
}
|
|
b >>= 1;
|
|
d >>= 1;
|
|
} while (d);
|
|
|
|
*n = res;
|
|
return rem;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* can_update_sample_point - Bit-timing calculation
|
|
*
|
|
* Calculates proper bit-timing parameters for a specified bit-rate
|
|
* and sample-point, which can then be used to set the bit-timing
|
|
* registers of the CAN controller.
|
|
*
|
|
* RETURNS: sample point
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int can_update_sample_point( const struct can_bittiming_const *btc,
|
|
unsigned int sample_point_nominal, unsigned int tseg,
|
|
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
|
unsigned int *sample_point_error_ptr)
|
|
{
|
|
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
|
unsigned int sample_point, best_sample_point = 0;
|
|
unsigned int tseg1, tseg2;
|
|
int i;
|
|
|
|
for (i = 0; i <= 1; i++) {
|
|
tseg2 = tseg + CAN_CALC_SYNC_SEG - (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i;
|
|
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
|
tseg1 = tseg - tseg2;
|
|
if (tseg1 > btc->tseg1_max) {
|
|
tseg1 = btc->tseg1_max;
|
|
tseg2 = tseg - tseg1;
|
|
}
|
|
|
|
sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG);
|
|
sample_point_error = abs(sample_point_nominal - sample_point);
|
|
|
|
if ((sample_point <= sample_point_nominal) && (sample_point_error < best_sample_point_error)) {
|
|
best_sample_point = sample_point;
|
|
best_sample_point_error = sample_point_error;
|
|
*tseg1_ptr = tseg1;
|
|
*tseg2_ptr = tseg2;
|
|
}
|
|
}
|
|
|
|
if (sample_point_error_ptr)
|
|
*sample_point_error_ptr = best_sample_point_error;
|
|
|
|
return best_sample_point;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* can_calc_bittiming - Bit-timing calculation
|
|
*
|
|
* Calculates proper bit-timing parameters for a specified bit-rate
|
|
* and sample-point, which can then be used to set the bit-timing
|
|
* registers of the CAN controller.
|
|
*
|
|
* RETURNS: 0 on success and failure value on error
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int can_calc_bittiming( struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc)
|
|
{
|
|
unsigned int bitrate; /* current bitrate */
|
|
unsigned int bitrate_error; /* difference between current and nominal value */
|
|
unsigned int best_bitrate_error = UINT_MAX;
|
|
unsigned int sample_point_error; /* difference between current and nominal value */
|
|
unsigned int best_sample_point_error = UINT_MAX;
|
|
unsigned int sample_point_nominal; /* nominal sample point */
|
|
unsigned int best_tseg = 0; /* current best value for tseg */
|
|
unsigned int best_brp = 0; /* current best value for brp */
|
|
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
|
unsigned long long v64;
|
|
|
|
/* Use CiA recommended sample points */
|
|
if (bt->sample_point) {
|
|
sample_point_nominal = bt->sample_point;
|
|
} else {
|
|
if (bt->bitrate > 800000)
|
|
sample_point_nominal = 750;
|
|
else if (bt->bitrate > 500000)
|
|
sample_point_nominal = 800;
|
|
else
|
|
sample_point_nominal = 875;
|
|
}
|
|
|
|
/* tseg even = round down, odd = round up */
|
|
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
|
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
|
tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
|
|
|
|
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
|
brp = CAN_CLK_FREQ / (tsegall * bt->bitrate) + tseg % 2;
|
|
|
|
/* choose brp step which is possible in system */
|
|
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
|
|
|
if ((brp < btc->brp_min) || (brp > btc->brp_max))
|
|
continue;
|
|
|
|
bitrate = CAN_CLK_FREQ / (brp * tsegall);
|
|
|
|
bitrate_error = abs(bt->bitrate - bitrate);
|
|
/* tseg brp biterror */
|
|
if (bitrate_error > best_bitrate_error)
|
|
continue;
|
|
|
|
/* reset sample point error if we have a better bitrate */
|
|
if (bitrate_error < best_bitrate_error)
|
|
best_sample_point_error = UINT_MAX;
|
|
|
|
can_update_sample_point(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error);
|
|
if (sample_point_error > best_sample_point_error)
|
|
continue;
|
|
|
|
best_sample_point_error = sample_point_error;
|
|
best_bitrate_error = bitrate_error;
|
|
best_tseg = tseg / 2;
|
|
best_brp = brp;
|
|
|
|
if (bitrate_error == 0 && sample_point_error == 0)
|
|
break;
|
|
}
|
|
|
|
if (best_bitrate_error) {
|
|
/* Error in one-tenth of a percent */
|
|
v64 = (unsigned long long)best_bitrate_error * 1000;
|
|
div64_32(&v64, bt->bitrate);
|
|
bitrate_error = (unsigned int)v64;
|
|
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
|
FTCAN_LOGMSG("bitrate error %d.%d%% too high\n",
|
|
bitrate_error / 10, bitrate_error % 10,3,4,5,6);
|
|
return -EDOM;
|
|
}
|
|
FTCAN_LOGMSG( "bitrate error %d.%d%%\n",
|
|
bitrate_error / 10, bitrate_error % 10,3,4,5,6);
|
|
}
|
|
|
|
/* real sample point */
|
|
bt->sample_point = can_update_sample_point(btc, sample_point_nominal, best_tseg,
|
|
&tseg1, &tseg2, NULL);
|
|
|
|
v64 = (unsigned long long)best_brp * 1000 * 1000 * 1000;
|
|
div64_32(&v64, CAN_CLK_FREQ);
|
|
bt->tq = (unsigned long long)v64;
|
|
bt->prop_seg = tseg1 / 2;
|
|
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
|
bt->phase_seg2 = tseg2;
|
|
|
|
/* check for sjw user settings */
|
|
if (!bt->sjw || !btc->sjw_max) {
|
|
bt->sjw = 1;
|
|
} else {
|
|
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
|
if (bt->sjw > btc->sjw_max)
|
|
bt->sjw = btc->sjw_max;
|
|
/* bt->sjw must not be higher than tseg2 */
|
|
if (tseg2 < bt->sjw)
|
|
bt->sjw = tseg2;
|
|
}
|
|
|
|
bt->brp = best_brp;
|
|
|
|
/* real bitrate */
|
|
bt->bitrate = CAN_CLK_FREQ / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftcan_set_bittiming - CAN set bit timing routine
|
|
*
|
|
* This is the driver set bittiming routine.
|
|
*
|
|
* RETURNS: 0 on success and failure value on error
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL int ftcan_set_bittiming(VXB_DEVICE_ID pDev,struct can_bittiming *bt)
|
|
{
|
|
|
|
UINT btr;
|
|
UINT is_config_mode;
|
|
|
|
/* Setting Baud Rate prescalar value in BRPR Register */
|
|
btr = (bt->brp - 1) << 16;
|
|
|
|
/* Setting Time Segment 1 in BTR Register */
|
|
btr |= (bt->prop_seg - 1) << 2;
|
|
|
|
btr |= (bt->phase_seg1 - 1) << 5;
|
|
|
|
/* Setting Time Segment 2 in BTR Register */
|
|
btr |= (bt->phase_seg2 - 1) << 8;
|
|
|
|
/* Setting Synchronous jump width in BTR Register */
|
|
btr |= (bt->sjw - 1);
|
|
|
|
FTCAN_LOGMSG("%s:Update Can btr:0x%x \n", __func__, btr,3,4,5,6);
|
|
|
|
/* Check whether FT2000/4 CAN is in configuration mode.
|
|
* It cannot set bit timing if FT2000/4 CAN is not in configuration mode.
|
|
*/
|
|
is_config_mode = (CSR_READ_4(pDev, FTCAN_CTRL_OFFSET) &
|
|
FTCAN_CTRL_XFER_MASK);
|
|
if (is_config_mode) {
|
|
/*Disable Transfer*/
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
|
|
}
|
|
CSR_WRITE_4(pDev, FTCAN_DAT_RATE_CTRL_OFFSET, btr);
|
|
CSR_WRITE_4(pDev, FTCAN_ARB_RATE_CTRL_OFFSET, btr);
|
|
|
|
/*Enable Transfer*/
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
|
|
FTCAN_LOGMSG( "DAT=0x%08x, ARB=0x%08x\n",
|
|
CSR_READ_4(pDev, FTCAN_DAT_RATE_CTRL_OFFSET),
|
|
CSR_READ_4(pDev, FTCAN_ARB_RATE_CTRL_OFFSET),3,4,5,6);
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftcan_err_interrupt - error frame Isr
|
|
*
|
|
* This is the CAN error interrupt and it will
|
|
* check the the type of error
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL void ftcan_err_interrupt(VXB_DEVICE_ID pDev, UINT isr)
|
|
{
|
|
UINT txerr = 0, rxerr = 0;
|
|
|
|
rxerr = CSR_READ_4(pDev, FTCAN_ERR_CNT_OFFSET) & FTCAN_ERR_CNT_RFN_MASK;
|
|
txerr = ((CSR_READ_4(pDev, FTCAN_ERR_CNT_OFFSET) &
|
|
FTCAN_ERR_CNT_TFN_MASK) >> FTCAN_ERR_CNT_TFN_SHIFT);
|
|
|
|
FTCAN_LOGMSG("%s: rx error count %d, tx error count %d\n",
|
|
__func__, rxerr,txerr,4,5,6);
|
|
FTCAN_LOGMSG("%s: error status register:0x%x\n",
|
|
__func__, (CSR_READ_4(pDev,FTCAN_INTR_OFFSET) & FTCAN_INTR_STATUS_MASK),3,4,5,6);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftcan_tx_interrupt - Tx Done Isr
|
|
*
|
|
* This is the CAN Tx Done interrupt
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL void ftcan_tx_interrupt(VXB_DEVICE_ID pDev, UINT isr)
|
|
{
|
|
FTCAN_DRV_CTRL * pFtCanCtrl;
|
|
pFtCanCtrl = pDev->pDrvCtrl;
|
|
|
|
CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_TEIC_MASK | FTCAN_INTR_REIC_MASK);
|
|
|
|
pFtCanCtrl->txCfCnt--;
|
|
|
|
if(pFtCanCtrl->txCfCnt != 0){
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK);
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
}
|
|
else{
|
|
if (semGive (pFtCanCtrl->canTxSem) == ERROR)
|
|
{
|
|
FTCAN_LOGMSG ("semGive error\n", 0, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftcan_rx_interrupt - Rx Done Isr
|
|
*
|
|
* This is the CAN Rx Done interrupt
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL void ftcan_rx_interrupt(FTCAN_DRV_CTRL* pDrvCtrl, UINT isr)
|
|
{
|
|
UINT id_ftcan,data[2] = {0, 0};
|
|
UINT dlc = 0;
|
|
FTCAN_FRAME ftCanFrame;
|
|
VXB_DEVICE_ID pDev;
|
|
|
|
pDev= pDrvCtrl->ftCanDev;
|
|
|
|
while((CSR_READ_4(pDev, FTCAN_FIFO_CNT_OFFSET)&0x3f) > 0)
|
|
{
|
|
/* Read a frame from FT2000/4 CAN */
|
|
id_ftcan = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET);
|
|
id_ftcan = be32_to_cpup(id_ftcan);
|
|
|
|
/* Change FT2000/4 CAN ID format to socketCAN ID format */
|
|
if (id_ftcan & FTCAN_IDR_IDE_MASK) {
|
|
/* The received frame is an Extended format frame */
|
|
dlc = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET);
|
|
dlc = be32_to_cpup(dlc);
|
|
dlc = ((dlc & FTCAN_IDR_EDLC_MASK ) >> FTCAN_IDR_EDLC_SHIFT);
|
|
|
|
ftCanFrame.can_id = (id_ftcan & FTCAN_IDR_ID1_MASK) >> 3;
|
|
ftCanFrame.can_id |= (id_ftcan & FTCAN_IDR_ID2_MASK) >> FTCAN_IDR_ID2_SHIFT;
|
|
ftCanFrame.can_id |= CAN_EFF_FLAG;
|
|
if (id_ftcan & FTCAN_IDR_RTR_MASK)
|
|
ftCanFrame.can_id |= CAN_RTR_FLAG;
|
|
} else {
|
|
dlc = ((id_ftcan & FTCAN_IDR_DLC_MASK ) >> FTCAN_IDR_SDLC_SHIFT);
|
|
|
|
/* The received frame is a standard format frame */
|
|
ftCanFrame.can_id = (id_ftcan & FTCAN_IDR_ID1_MASK) >> FTCAN_IDR_ID1_SHIFT;
|
|
if (id_ftcan & FTCAN_IDR_SRR_MASK)
|
|
ftCanFrame.can_id |= CAN_RTR_FLAG;
|
|
}
|
|
|
|
/* Change FT2000/4 CAN data length format to socketCAN data format */
|
|
ftCanFrame.can_dlc = get_can_dlc(dlc);
|
|
|
|
if (!(ftCanFrame.can_id & CAN_RTR_FLAG)) {
|
|
/* Change FT2000/4 CAN data format to socketCAN data format */
|
|
if (ftCanFrame.can_dlc > 0){
|
|
data[0] = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET);
|
|
*(UINT *)(ftCanFrame.data) = (data[0]);
|
|
}
|
|
|
|
if (ftCanFrame.can_dlc > 4){
|
|
data[1] = CSR_READ_4(pDev, FTCAN_RX_FIFO_OFFSET);
|
|
*(UINT *)(ftCanFrame.data + 4) = (data[1]);
|
|
}
|
|
}
|
|
FTCAN_LOGMSG("recevied canid %x can_dlc %d data 0x%2x 0x%2x 0x%2x 0x%2x ",
|
|
ftCanFrame.can_id & CAN_EFF_MASK,ftCanFrame.can_dlc,
|
|
ftCanFrame.data[0],ftCanFrame.data[1],ftCanFrame.data[2],
|
|
ftCanFrame.data[3]);
|
|
FTCAN_LOGMSG("0x%2x 0x%2x 0x%2x 0x%2x\r\n",ftCanFrame.data[4],
|
|
ftCanFrame.data[5],ftCanFrame.data[6],ftCanFrame.data[7],5,6);
|
|
msgQSend(pDrvCtrl->ftcanQueue,(char * )&ftCanFrame,sizeof(ftCanFrame),NO_WAIT,MSG_PRI_NORMAL);
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanInt - VxBus interrupt handler
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL void ftCanInt (FTCAN_DRV_CTRL* pDrvCtrl)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
UINT isr;
|
|
pDev = pDrvCtrl->ftCanDev;
|
|
/* Get the interrupt status from FT2000/4 CAN */
|
|
isr = (CSR_READ_4(pDev, FTCAN_INTR_OFFSET) & FTCAN_INTR_STATUS_MASK);
|
|
if (!isr)
|
|
return;
|
|
/*Check for Tx interrupt and Processing it */
|
|
if ((isr & FTCAN_INTR_TEIS_MASK)){
|
|
isr &= (~FTCAN_INTR_REIS_MASK);
|
|
ftcan_tx_interrupt(pDev, isr);
|
|
}
|
|
/* Check for the type of error interrupt and Processing it */
|
|
if (isr & (FTCAN_INTR_EIS_MASK | FTCAN_INTR_RFIS_MASK |
|
|
FTCAN_INTR_BOIS_MASK | FTCAN_INTR_PEIS_MASK | FTCAN_INTR_PWIS_MASK)) {
|
|
CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, (FTCAN_INTR_EIC_MASK |
|
|
FTCAN_INTR_RFIC_MASK | FTCAN_INTR_BOIC_MASK |
|
|
FTCAN_INTR_PEIC_MASK | FTCAN_INTR_PWIC_MASK));
|
|
ftcan_err_interrupt(pDev, isr);
|
|
}
|
|
/* Check for the type of receive interrupt and Processing it */
|
|
if (isr & (FTCAN_INTR_REIS_MASK)) {
|
|
CSR_CLRBIT_4(pDev, FTCAN_INTR_OFFSET,FTCAN_INTR_REIE_MASK);
|
|
ftcan_rx_interrupt(pDrvCtrl,isr);
|
|
CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_REIC_MASK);
|
|
CSR_SETBIT_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_REIE_MASK);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanInstConnect - VxBus instConnect handler
|
|
*
|
|
* This function implements the VxBus instConnect handler for an template
|
|
* device instance.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void ftCanInstConnect
|
|
(
|
|
VXB_DEVICE_ID pDev
|
|
)
|
|
{
|
|
int st;
|
|
FTCAN_DRV_CTRL * pFtCanCtrl;
|
|
char task_name[32];
|
|
TASK_ID tid;
|
|
|
|
pFtCanCtrl = pDev->pDrvCtrl;
|
|
|
|
bzero(task_name, sizeof(task_name));
|
|
sprintf(task_name, "tCanRx%d", pDev->unitNumber);
|
|
tid = taskSpawn(task_name, 100, 0, 0x20000,
|
|
(FUNCPTR) ftCanRecvTask,(_Vx_usr_arg_t) pFtCanCtrl,
|
|
2,3,4,5,6,7,8,9,10);
|
|
if(TASK_ID_ERROR == tid)
|
|
{
|
|
FTCAN_LOGMSG("failed to spawn can recv task!\n",1,2,3,4,5,6);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Attach our ISR. For PCI, the index value is always
|
|
* 0, since the PCI bus controller dynamically sets
|
|
* up interrupts for us.
|
|
*/
|
|
st = vxbIntConnect (pDev, 0, ftCanInt, pFtCanCtrl);
|
|
st |= vxbIntEnable (pDev, 0, ftCanInt, pFtCanCtrl);
|
|
|
|
if(st != OK)
|
|
{
|
|
FTCAN_LOGMSG("interrupt cn/en failed!\n",1,2,3,4,5,6);
|
|
return;
|
|
}
|
|
|
|
/* Enable interrupts */
|
|
CSR_WRITE_4(pDev, FTCAN_INTR_OFFSET, FTCAN_INTR_EN);
|
|
|
|
/*Enable Transfer*/
|
|
CSR_WRITE_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
FTCAN_LOGMSG("status:#x%08x\n",CSR_READ_4(pDev,FTCAN_XFER_STS_OFFSET),2,3,4,5,6);
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftcan_send_txfifo - Write the Frame to CAN TX FIFO
|
|
*
|
|
* Write the Frame to CAN TX FIFO
|
|
*
|
|
* RETURNS: Sent frame number
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL unsigned int ftcan_send_txfifo(VXB_DEVICE_ID pDev, struct can_frame *df)
|
|
{
|
|
struct can_frame *cf = df;
|
|
UINT id, dlc, frame_head[2] = {0, 0}, data[8] = {0, 0};
|
|
|
|
/* Watch carefully on the bit sequence */
|
|
if (cf->can_id & CAN_EFF_FLAG) {
|
|
/* Extended CAN ID format */
|
|
id = ((cf->can_id & CAN_EFF_MASK) << FTCAN_IDR_ID2_SHIFT) &
|
|
FTCAN_IDR_ID2_MASK;
|
|
id |= (((cf->can_id & CAN_EFF_MASK) >>
|
|
(CAN_EFF_ID_BITS-CAN_SFF_ID_BITS)) <<
|
|
FTCAN_IDR_ID1_SHIFT) & FTCAN_IDR_ID1_MASK;
|
|
|
|
id |= FTCAN_IDR_IDE_MASK | FTCAN_IDR_SRR_MASK;
|
|
if (cf->can_id & CAN_RTR_FLAG)
|
|
/* Extended frames remote TX request */
|
|
id |= FTCAN_IDR_RTR_MASK;
|
|
dlc = cf->can_dlc << FTCAN_IDR_EDLC_SHIFT;
|
|
frame_head[0] = cpu_to_be32p(id);
|
|
frame_head[1] = cpu_to_be32p(dlc);
|
|
/* Write the Frame to FT2000/4 CAN TX FIFO */
|
|
CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, frame_head[0]);
|
|
CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, frame_head[1]);
|
|
} else {
|
|
/* Standard CAN ID format */
|
|
id = ((cf->can_id & CAN_SFF_MASK) << FTCAN_IDR_ID1_SHIFT) &
|
|
FTCAN_IDR_ID1_MASK;
|
|
if (cf->can_id & CAN_RTR_FLAG)
|
|
/* Standard frames remote TX request */
|
|
id |= FTCAN_IDR_SRR_MASK;
|
|
dlc = ((cf->can_dlc << FTCAN_IDR_SDLC_SHIFT) | FTCAN_IDR_PAD_MASK);
|
|
id |= dlc;
|
|
frame_head[0] = cpu_to_be32p(id);
|
|
/* Write the Frame to CAN TX FIFO */
|
|
CSR_WRITE_4(pDev,FTCAN_TX_FIFO_OFFSET, frame_head[0]);
|
|
}
|
|
if (!(cf->can_id & CAN_RTR_FLAG)) {
|
|
if (cf->can_dlc > 0){
|
|
data[0] = (*(UINT*)(cf->data + 0));
|
|
CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, data[0]);
|
|
}
|
|
if (cf->can_dlc > 4){
|
|
data[1] = (*(UINT*)(cf->data + 4));
|
|
CSR_WRITE_4(pDev, FTCAN_TX_FIFO_OFFSET, data[1]);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftcan_write - Sending the CAN data
|
|
*
|
|
* RETURNS: Sent frame number
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL UINT ftcan_write(VXB_DEVICE_ID pDev, char *buf, size_t len)
|
|
{
|
|
FTCAN_DRV_CTRL * pFtCanCtrl;
|
|
struct can_frame *ftCanFrame;
|
|
UINT frameNum,frameLeft,sendNumOnce,i;
|
|
pFtCanCtrl = pDev->pDrvCtrl;
|
|
|
|
if(buf == NULL)
|
|
{
|
|
FTCAN_LOGMSG("Send Buff is NULL.\r\n", 1,2,3,4,5,6);
|
|
return 0;
|
|
}
|
|
if(len%sizeof(struct can_frame))
|
|
{
|
|
FTCAN_LOGMSG("Lenth is invalid\n",1,2,3,4,5,6);
|
|
return 0;
|
|
}
|
|
|
|
frameNum = len/sizeof(struct can_frame);
|
|
for(frameLeft = frameNum; frameLeft > 0; )
|
|
{
|
|
if(frameLeft/pFtCanCtrl->txCfMax >= 1)
|
|
{
|
|
sendNumOnce = pFtCanCtrl->txCfMax;
|
|
frameLeft -= pFtCanCtrl->txCfMax;
|
|
}
|
|
else
|
|
{
|
|
sendNumOnce = frameLeft;
|
|
frameLeft = 0;
|
|
}
|
|
/*shut down tranmission*/
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK);
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
|
|
for(i=0;i<sendNumOnce;i++){
|
|
ftCanFrame = (struct can_frame *)buf;
|
|
ftcan_send_txfifo(pDev, ftCanFrame);
|
|
buf = buf + sizeof(struct can_frame);
|
|
}
|
|
pFtCanCtrl->txCfCnt = sendNumOnce;
|
|
/* triggers tranmission */
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK);
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK);
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_TXREQ_MASK|FTCAN_CTRL_XFER_MASK);
|
|
|
|
if (semTake (pFtCanCtrl->canTxSem, WAIT_FOREVER) == ERROR)
|
|
{
|
|
FTCAN_LOGMSG ("SemTake Error\n",1 ,2, 3, 4, 5, 6);
|
|
}
|
|
}
|
|
|
|
return frameNum;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanSend - send can msg. API function.
|
|
*
|
|
* This function is used to send data
|
|
*
|
|
* RETURNS: OK/ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
STATUS ftCanSend
|
|
(
|
|
unsigned char ctlNo,
|
|
char * sendbuff,
|
|
int lenth
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
UINT sentLenth;
|
|
|
|
if(ctlNo >= CAN_MAX_CTL)
|
|
{
|
|
printf("ctlNo %d is invalid.\r\n", ctlNo);
|
|
return ERROR;
|
|
}
|
|
|
|
pDev= glftCanDev[ctlNo];
|
|
if(pDev == NULL)
|
|
{
|
|
printf("pDev is NULL!\r\n");
|
|
return ERROR;
|
|
}
|
|
|
|
sentLenth = ftcan_write(pDev,sendbuff,lenth);
|
|
if (sentLenth > 0)
|
|
{
|
|
return OK;
|
|
}
|
|
else
|
|
{
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanRecvCallback - receive callback
|
|
*
|
|
* Registers the receive processing function for the specified CAN controller
|
|
* ftCanRecvRtn:The pointer function of the receiving process
|
|
*
|
|
* RETURNS: OK/ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
STATUS ftCanRecvCallback
|
|
(
|
|
unsigned char ctlNo,
|
|
void (*ftCanRecvRtn)(FTCAN_FRAME* pFtCanFrame)
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
FTCAN_DRV_CTRL * pDrvCtrl;
|
|
|
|
if(ctlNo >= CAN_MAX_CTL)
|
|
{
|
|
FTCAN_LOGMSG("ctlNo %d is invalid.\r\n", ctlNo,2,3,4,5,6);
|
|
return ERROR;
|
|
}
|
|
pDev= glftCanDev[ctlNo];
|
|
|
|
if(pDev == NULL)
|
|
{
|
|
FTCAN_LOGMSG("pDev is NULL!\r\n",1,2,3,4,5,6);
|
|
return ERROR;
|
|
}
|
|
|
|
pDrvCtrl = (FTCAN_DRV_CTRL * )pDev->pDrvCtrl;
|
|
|
|
if(pDrvCtrl == NULL)
|
|
{
|
|
FTCAN_LOGMSG("pDrvCtrl is NULL for %d!\r\n", pDev->unitNumber,2,3,4,5,6);
|
|
return ERROR;
|
|
}
|
|
|
|
pDrvCtrl->ftCanRecvRtn = ftCanRecvRtn;
|
|
return OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanSetBitrate - set bitrate
|
|
*
|
|
* This function Set Bitrate for can
|
|
*
|
|
* RETURNS: OK/ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
STATUS ftCanSetBitrate
|
|
(
|
|
unsigned char ctlNo,
|
|
UINT bitrate
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
struct can_bittiming bt;
|
|
int ret;
|
|
FTCAN_DRV_CTRL * pDrvCtrl;
|
|
pDev= glftCanDev[ctlNo];
|
|
pDrvCtrl= pDev->pDrvCtrl;
|
|
bt.bitrate = bitrate;
|
|
bt.sjw = 0;
|
|
bt.sample_point = 0;
|
|
ret = can_calc_bittiming(&bt,&ftcan_bittiming_const);
|
|
if(ret<0){
|
|
return -ret;
|
|
}
|
|
if (ftcan_set_bittiming(pDev,&bt)) {
|
|
return -EFAULT;
|
|
}
|
|
pDrvCtrl->ftcan_bittiming.bitrate = bitrate;
|
|
pDrvCtrl->ftcan_bittiming.brp=bt.brp;
|
|
pDrvCtrl->ftcan_bittiming.sjw=bt.sjw;
|
|
pDrvCtrl->ftcan_bittiming.tq =bt.tq;
|
|
pDrvCtrl->ftcan_bittiming.phase_seg1= bt.phase_seg1;
|
|
pDrvCtrl->ftcan_bittiming.phase_seg2= bt.phase_seg2;
|
|
pDrvCtrl->ftcan_bittiming.sample_point=bt.sample_point;
|
|
return OK;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanSetIDFilter - set id filter
|
|
*
|
|
* This function Set set id filter for can
|
|
*
|
|
* RETURNS: OK/ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
STATUS ftCanSetIDFilter
|
|
(
|
|
unsigned char ctlNo,
|
|
UINT filterNo,
|
|
UINT id,
|
|
UINT mask,
|
|
UINT type
|
|
)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
UINT32 idRegOffset[4] = {FTCAN_ACC_ID0_OFFSET, FTCAN_ACC_ID1_OFFSET, FTCAN_ACC_ID2_OFFSET, FTCAN_ACC_ID3_OFFSET};
|
|
UINT32 maskRegOffset[4] = {FTCAN_ACC_ID0_MASK_OFFSET, FTCAN_ACC_ID1_MASK_OFFSET, FTCAN_ACC_ID2_MASK_OFFSET, FTCAN_ACC_ID3_MASK_OFFSET} ;
|
|
|
|
pDev= glftCanDev[ctlNo];
|
|
|
|
CSR_WRITE_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6));/*bit 6 is internal reset**/
|
|
|
|
if(type == STANDARD_FRAME)
|
|
{
|
|
id = id << FTCAN_ACC_IDN_SHIFT;
|
|
mask = mask << FTCAN_ACC_IDN_SHIFT;
|
|
}
|
|
CSR_WRITE_4(pDev, idRegOffset[filterNo], id);
|
|
CSR_WRITE_4(pDev, maskRegOffset[filterNo], mask);
|
|
|
|
CSR_CLRBIT_4(pDev, FTCAN_CTRL_OFFSET, (0x1<<6));
|
|
|
|
CSR_SETBIT_4(pDev, FTCAN_CTRL_OFFSET, FTCAN_CTRL_XFER_MASK | FTCAN_CTRL_AIME_MASK);
|
|
return OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ftCanRecvTask - Receiving work
|
|
*
|
|
* This function receives data
|
|
* printf : canid,can_dlc,data.
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
LOCAL void ftCanRecvTask
|
|
(
|
|
FTCAN_DRV_CTRL * pDrvCtrl
|
|
)
|
|
{
|
|
FTCAN_FRAME ftCanFrame;
|
|
UINT maxNBytes = sizeof(ftCanFrame);
|
|
ULONG cnt = 1;
|
|
for(;;)
|
|
{
|
|
bzero((char *)&ftCanFrame, sizeof(ftCanFrame));
|
|
msgQReceive(pDrvCtrl->ftcanQueue,(char *)&ftCanFrame,maxNBytes,WAIT_FOREVER);
|
|
|
|
if(pDrvCtrl->ftCanRecvRtn != NULL)
|
|
{
|
|
pDrvCtrl->ftCanRecvRtn(&ftCanFrame);
|
|
}
|
|
else
|
|
{
|
|
printf("%s count:%d \r\n"
|
|
" recevied canid:%x can_dlc:%d. data:%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
|
|
__FUNCTION__,cnt, ftCanFrame.can_id & CAN_EFF_MASK,ftCanFrame.can_dlc,
|
|
ftCanFrame.data[0],ftCanFrame.data[1],
|
|
ftCanFrame.data[2],ftCanFrame.data[3],
|
|
ftCanFrame.data[4],ftCanFrame.data[5],
|
|
ftCanFrame.data[6],ftCanFrame.data[7]);
|
|
|
|
cnt++;
|
|
}
|
|
}
|
|
return ;
|
|
}
|
|
|
|
#define FTCAN_DEBUG
|
|
#ifdef FTCAN_DEBUG
|
|
/*****************************************************************************
|
|
*
|
|
* testCanRecvCallback - Test Receive Callback
|
|
*
|
|
* This function is used to test the Receive Callback
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
void testCanRecvCallback(struct can_frame* ftCanFrame)
|
|
{
|
|
ULONG cnt = 1;
|
|
if(NULL == ftCanFrame)
|
|
{
|
|
printf("%s,%d NULL can frame, no recv\r\n", __FUNCTION__, __LINE__);
|
|
return;
|
|
}
|
|
printf("%s count:%d \r\n"
|
|
" recevied canid:%x can_dlc:%d. data:%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
|
|
__FUNCTION__, cnt, ftCanFrame->can_id & CAN_EFF_MASK,ftCanFrame->can_dlc,
|
|
ftCanFrame->data[0],ftCanFrame->data[1],
|
|
ftCanFrame->data[2],ftCanFrame->data[3],
|
|
ftCanFrame->data[4],ftCanFrame->data[5],
|
|
ftCanFrame->data[6],ftCanFrame->data[7]);
|
|
|
|
cnt++;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* testCanRecv - Test Receive Callback
|
|
*
|
|
* This function is used to test the Receive Callback
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
void testCanRecv(void)
|
|
{
|
|
ftCanRecvCallback(0, testCanRecvCallback);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* testCanSend - TEST CAN0
|
|
*
|
|
* This function is used to test the transmitted data
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
void testCanSend(int channel, int cnt)
|
|
{
|
|
struct can_frame canFrame[10];
|
|
int i = 0;
|
|
|
|
if(0 == cnt) cnt=1;
|
|
|
|
for(i=0;i<10;i++)
|
|
{
|
|
canFrame[i].can_id = (i) | CAN_EFF_FLAG;
|
|
canFrame[i].can_dlc = 8;
|
|
canFrame[i].data[0]=0;
|
|
canFrame[i].data[1]=1;
|
|
canFrame[i].data[2]=2;
|
|
canFrame[i].data[3]=3;
|
|
canFrame[i].data[4]=4;
|
|
canFrame[i].data[5]=5;
|
|
canFrame[i].data[6]=6;
|
|
canFrame[i].data[7]=7;
|
|
}
|
|
for(i=0;i<cnt;i++)
|
|
ftCanSend(channel,(char * )&canFrame,10 * sizeof(struct can_frame));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* dumpFtCanReg
|
|
*
|
|
* This function is used to print the value of the can register
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
void dumpFtCanReg(unsigned char ctlNo)
|
|
{
|
|
VXB_DEVICE_ID pDev;
|
|
int i =0;
|
|
FTCAN_DRV_CTRL * pDrvCtrl;
|
|
pDev= glftCanDev[ctlNo];
|
|
pDrvCtrl= pDev->pDrvCtrl;
|
|
for ( i=0; i<0x40;)
|
|
{
|
|
printf("addr 0x%x value 0x%x\r\n",i,CSR_READ_4(pDev,i));
|
|
i=i+4;
|
|
}
|
|
}
|
|
#endif /* FTCAN_DEBUG */
|
|
|
|
|