⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chip_sja1000p.c

📁 it s free for can driver prelican mode
💻 C
字号:
/* SJA1000 PeliCAN driver - Paul Miller <pamiller@uiuc.edu> */

#include "io.h"

#define __CHIP_SJA1000P_REG
#include "chip_SJA1000P.h"
#include "c6xdsk_aux.h"

struct SJA1000_REGS sja1000_regs;
extern far int SDRAM;


/* min/max macros */
#define min(A,B)			(((A) <= (B)) ? (A) : (B))
#define max(A,B)			(((A) >= (B)) ? (A) : (B))

/* status register */
#define sja1000_status()	(sja1000_read(SJA1000_SR))

/* interrupt register */
#define sja1000_int()		(sja1000_read(SJA1000_IR))

/* check transmit buffer status */
#define sja1000_tbs()		(sja1000_read(SJA1000_SR) & SJA1000_SR_TBS)

/* check receive buffer status */
#define sja1000_rbs()		(sja1000_read(SJA1000_SR) & SJA1000_SR_RBS)

/* check reset mode */
#define sja1000_rm()		(sja1000_read(SJA1000_MOD) & SJA1000_MOD_RM)

/* arbitration lost code */
#define sja1000_alc()		(SJA1000_ALC_CODE(sja1000_read(SJA1000_ALC)))

/* error capture code */
#define sja1000_ecc()		(sja1000_read(SJA1000_ECC))

/* receive message counter */
#define sja1000_rmc()		(sja1000_read(SJA1000_RMC))

/* receive message error counter */
#define sja1000_rxerr()		(sja1000_read(SJA1000_RXERR))

/* transmit message error counter */
#define sja1000_txerr()		(sja1000_read(SJA1000_TXERR))

/* transmit message */
#define sja1000_tx()		(sja1000_write(SJA1000_CMR, SJA1000_CMR_TR))

/* abort message transmission */
#define sja1000_abort()		(sja1000_write(SJA1000_CMR, SJA1000_CMR_AT))

/* release message */
#define sja1000_release()	(sja1000_write(SJA1000_CMR, SJA1000_CMR_RRB))

/* clear data overrun */
#define sja1000_cdo()		(sja1000_write(SJA1000_CMR, SJA1000_CMR_CDO))










/* sja1000 read cycle */
static inline int sja1000_read(int addr)
{
	int data;
	SJA1000_IRQ_DISABLE();
	outp(SJA1000_ADDR, addr);
	data = inp(SJA1000_DATA) & 0xFF;
	SJA1000_IRQ_ENABLE();
	return data;
}

/* sja1000 write cycle */
static inline void sja1000_write(int addr, int data)
{
	SJA1000_IRQ_DISABLE();
	outp(SJA1000_ADDR, addr);
	outp(SJA1000_DATA, data);
	SJA1000_IRQ_ENABLE();
}

/* initialize all shadow registers to the chip's current state */
static void sja1000_registers(void)
{
	int offset, data;

	if (!sja1000_rm())
		return;

	sja1000_regs.MOD = sja1000_read(SJA1000_MOD);
	sja1000_regs.IER = sja1000_read(SJA1000_IER);
	sja1000_regs.BTR0 = sja1000_read(SJA1000_BTR0);
	sja1000_regs.BTR1 = sja1000_read(SJA1000_BTR1);
	sja1000_regs.OCR = sja1000_read(SJA1000_OCR);
	sja1000_regs.CDR = sja1000_read(SJA1000_CDR);

	for (data = 0, offset = 0; offset < 4; offset++) {
		 data |= sja1000_read(SJA1000_ACR + offset) << (offset*8);
	}
	sja1000_regs.ACR = data;
	for (data = 0, offset = 0; offset < 4; offset++) {
		data |= sja1000_read(SJA1000_AMR + offset) << (offset*8);
	}
	sja1000_regs.AMR = data;
	sja1000_regs.EWLR = sja1000_read(SJA1000_EWLR);
}

/* put chip into operation mode */
void can_operate_mode(void)
{
	clrb(sja1000_regs.MOD, SJA1000_MOD_RM);
	sja1000_write(SJA1000_MOD,sja1000_regs.MOD);
}

/* put chip into reset (configuration) mode */
void can_reset_mode(void)
{
	do {
		setb(sja1000_regs.MOD, SJA1000_MOD_RM);
		sja1000_write(SJA1000_MOD,sja1000_regs.MOD);
		sja1000_regs.MOD = sja1000_read(SJA1000_MOD);
	} while (!sja1000_rm());
}

/*
try to choose the "best" bit timing register settings...

baud = baud rate (KHz)
opt_bt = optimal bit timing (time quantums)
opt_sp = optimal sampling point (percent*100)
sjw = synchro jump width (time quantums)

For verification, see: http://www.port.de/engl/canprod/sv_req_form.html
*/

#define TSEG1_MIN			0
#define TSEG1_MAX			16
#define TSEG2_MIN			0
#define TSEG2_MAX			8
#define BRP_MIN				0
#define BRP_MAX				64

/* costs for errors */
#define COST_BAUD_UNDER		100
#define COST_BAUD_OVER		100
#define COST_BT_UNDER		10
#define COST_BT_OVER		15
#define COST_SP_UNDER		10
#define COST_SP_OVER		12

int sja1000_btr(int baud, int opt_bt, int opt_sp, int sjw)
{
	int tseg, tseg1, tseg2, brp, bt;
	int best_tseg1, best_tseg2, best_brp;
	int baud_err, bt_err, sp_err;
	int cost, best_cost;
	int khz;
	int i;

	best_cost = INT_MAX;
	khz = SJA1000_CLK_KHZ / 2;

	for (tseg=(TSEG1_MIN+1+TSEG2_MIN+1); tseg<=(TSEG1_MAX+1+TSEG2_MAX+1); tseg++) {

		/* search one time quantum above and below sample point */
		for (i = -1; i <= 1; i++) {

			/* calculate bit timing for given segment length in TQ */
			tseg1 = opt_sp*(tseg+sjw)/100 - sjw + i;
			tseg2 = tseg - tseg1;
			bt = tseg1 + tseg2 + sjw;

			/* eliminate illegal combinations */
			if (tseg1 < TSEG1_MIN || tseg1 > TSEG1_MAX) continue;
			if (tseg2 < TSEG2_MIN || tseg2 > TSEG2_MAX) continue;
			if (tseg1 < tseg2) continue;
			if (sjw > tseg2) continue;

			/* calculate baud rate prescaler */
			brp = khz/baud/bt;
			if (brp < BRP_MIN+1 || brp > BRP_MAX+1) continue;

			/* calculate errors */
			baud_err = khz/brp/bt - baud;
			bt_err = bt - opt_bt;
			sp_err = 100*(tseg1+sjw)/bt - opt_sp;

			/* calculate cost of errors */
			cost = 0;
			cost += (baud_err < 0) ? -baud_err*COST_BAUD_UNDER : baud_err*COST_BAUD_OVER;
			cost += (bt_err < 0) ? -bt_err*COST_BT_UNDER : bt_err*COST_BT_OVER;
			cost += (sp_err < 0) ? -sp_err*COST_SP_UNDER : sp_err*COST_SP_OVER;

			if (cost <= best_cost) {
				best_cost = cost;
				best_brp = brp;
				best_tseg1 = tseg1;
				best_tseg2 = tseg2;
			}
		}
	}

	/* save configuration */
	sja1000_regs.BTR0 = 0;
	sja1000_regs.BTR1 = 0;
	sja1000_regs.BTR0 |= SJA1000_BTR0_BRP(best_brp-1);
	sja1000_regs.BTR0 |= SJA1000_BTR0_SJW(sjw-1);
	sja1000_regs.BTR1 |= SJA1000_BTR1_TSEG1(best_tseg1-1);
	sja1000_regs.BTR1 |= SJA1000_BTR1_TSEG2(best_tseg2-1);

	sja1000_write(SJA1000_BTR0,sja1000_regs.BTR0);
	sja1000_write(SJA1000_BTR1,sja1000_regs.BTR1);

	return best_cost;
}

static inline void sja1000_read_msg(CAN_Obj_t *obj)
{
	unsigned int addr, frame;
	int i;

	obj->timehstamp = CLK_gethtime();
	obj->timelstamp = CLK_getltime();
	frame = sja1000_read(SJA1000_FRAME);
	
	obj->flags = 0x0;
	obj->flags |= (frame & SJA1000_FRAME_EXT) ? CAN_FLAGS_EXT : 0;
	obj->flags |= (frame & SJA1000_FRAME_RTR) ? CAN_FLAGS_RTR : 0;
	obj->len = SJA1000_FRAME_DLC(frame);
	
	if (frame & SJA1000_FRAME_EXT) {
		obj->id =  sja1000_read(SJA1000_MSGID + 0) << 21;
		obj->id |= sja1000_read(SJA1000_MSGID + 1) << 13;
		obj->id |= sja1000_read(SJA1000_MSGID + 2) << 5;
		obj->id |= sja1000_read(SJA1000_MSGID + 3) >> 3;
		addr = SJA1000_EXTDATA;
	} else {
		obj->id =  sja1000_read(SJA1000_MSGID + 0) << 21;
		obj->id |= (sja1000_read(SJA1000_MSGID + 1) & 0xE0) << 13;
		addr = SJA1000_SFFDATA;
		
		obj->id >>= 18;
	}
	for (i = 0; i < obj->len; i++, addr++) {
		obj->data[i] = sja1000_read(addr);
	}
}

static inline void sja1000_write_msg(CAN_Obj_t *obj)
{
	unsigned int id, addr, frame;
	int i;

	id = obj->id;

	frame = 0x0;
	frame |= (obj->flags & CAN_FLAGS_EXT) ? SJA1000_FRAME_EXT : 0;
	frame |= (obj->flags & CAN_FLAGS_RTR) ? SJA1000_FRAME_RTR : 0;
	frame |= SJA1000_FRAME_DLC(obj->len);

	sja1000_write(SJA1000_FRAME,frame);
	if (frame & SJA1000_FRAME_EXT) {
		sja1000_write(SJA1000_MSGID + 0, id >> 21);
		sja1000_write(SJA1000_MSGID + 1, id >> 13);
		sja1000_write(SJA1000_MSGID + 2, id >> 5);
		sja1000_write(SJA1000_MSGID + 3, id << 3);
		addr = SJA1000_EXTDATA;
	} else {
		id <<= 18;

		sja1000_write(SJA1000_MSGID + 0, id >> 21);
		sja1000_write(SJA1000_MSGID + 1, (id >> 13) & 0xE0);
		addr = SJA1000_SFFDATA;
	}
	for (i = 0; i < obj->len; i++, addr++) {
		sja1000_write(addr,obj->data[i]);
	}
}

unsigned int msglost = 0;

/* can interrupt */
void sja1000_irq(void)
{
	CAN_Obj_t *obj;
	int vect;

	if (!(vect = sja1000_int()))
		return;

	/* receive interrupt */
	if (sja1000_rbs()) {
		if (QUE_empty(&QUE_CANrx_free)) {
			// delete oldest message (first in queue)
			obj = QUE_get(&QUE_CANrx_msg);
			msglost++;
		} else {
			obj = QUE_get(&QUE_CANrx_free);
		}
		sja1000_read_msg(obj);
		sja1000_release();
		QUE_put(&QUE_CANrx_msg, obj);
		SEM_post(&SEM_CANrx);
	}

	/* transmit interrupt */
	if (!QUE_empty(&QUE_CANtx_msg)) {
		SEM_post(&SEM_CANtx);
	}

	/* bus error interrupt */
	if (vect & SJA1000_IR_BEI) {
	}

	/* arbitration lost interrupt */
	if (vect & SJA1000_IR_ALI) {
	}

	/* error-passive interrupt */
	if (vect & SJA1000_IR_EPI) {
	}

	/* wake-up interrupt */
	if (vect & SJA1000_IR_WUI) {
	}

	/* data overrun interrupt */
	if (vect & SJA1000_IR_DOI) {
		sja1000_cdo();
	}

	/* error interrupt */
	if (vect & SJA1000_IR_EI) {
	}

	/* if chip went into reset mode (too many errors) */
	if (sja1000_rm()) {
		sja1000_registers();
	}
}

/* transmit task */
void sja1000_tx_task(void)
{
	CAN_Obj_t *obj;

	while (1) {
		SEM_reset(&SEM_CANtx, 0);
		SEM_pend(&SEM_CANtx, SYS_FOREVER);

		while (!QUE_empty(&QUE_CANtx_msg)) {

			// wait until transmit buffer is available
			if (!sja1000_tbs()) {
				TSK_yield();
				continue;
			}

			// transmit
			obj = QUE_get(&QUE_CANtx_msg);
			sja1000_write_msg(obj);
			sja1000_tx();
			QUE_put(&QUE_CANtx_free, obj);
		}
	}
}

/* user send function */
int can_send(int id, int flags, char *buf, int length)
{
	CAN_Obj_t *obj;
	int i;

	if (QUE_empty(&QUE_CANtx_free))
		return -1;

	obj = QUE_get(&QUE_CANtx_free);
	if (length > CAN_MSGLEN) length = CAN_MSGLEN;

	obj->id = id;
	obj->flags = flags;
	obj->len = length;
	for (i = 0; i < length; i++) obj->data[i] = buf[i];

	QUE_put(&QUE_CANtx_msg, obj);
	SEM_post(&SEM_CANtx);

	return 0;
}

/* set acceptance code and mask registers */
void sja1000_mask(int code, int mask)
{
	int offset;


	for (offset = 0; offset < 4; offset++) {
		sja1000_write(SJA1000_ACR + offset, code);
		code >>= 8;
	}
	sja1000_regs.ACR = code;

	for (offset = 0; offset < 4; offset++) {
		sja1000_write(SJA1000_AMR + offset, mask);
		mask >>= 8;
	}
	sja1000_regs.AMR = mask;
}






/* full can reset */
void sja1000_full_reset(void)
{
	CAN_Obj_t *obj;

	sja1000_regs.MOD = 0x0;
	sja1000_regs.IER = 0x0;
	sja1000_regs.OCR = 0x0;
	sja1000_regs.EWLR = 0x0;
	sja1000_regs.ACR = 0x0;
	sja1000_regs.AMR = 0x0;
	sja1000_regs.CDR = 0x0;
	can_reset_mode();

	setb(sja1000_regs.CDR, SJA1000_CDR_CLKOUT);	// disable clkout
	setb(sja1000_regs.CDR, SJA1000_CDR_CANMODE);// PeliCAN mode
	sja1000_write(SJA1000_CDR,sja1000_regs.CDR);

	setb(sja1000_regs.OCR, SJA1000_OCR_OCTP0);
	setb(sja1000_regs.OCR, SJA1000_OCR_OCTN0);
	clrb(sja1000_regs.OCR, SJA1000_OCR_OCPOL0);
	clrb(sja1000_regs.OCR, SJA1000_OCR_OCMODE0);
	setb(sja1000_regs.OCR, SJA1000_OCR_OCMODE1);
	sja1000_write(SJA1000_OCR,sja1000_regs.OCR);

	setb(sja1000_regs.IER, SJA1000_IER_RIE);	// receive interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_TIE);	// transmit interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_EIE);	// error interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_DOIE);	// data overrun interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_WUIE);	// wake-up interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_EPIE);	// error passive interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_ALIE);	// arbitration lost interrupt enable
	setb(sja1000_regs.IER, SJA1000_IER_BEIE);	// bus error interrupt enable
	sja1000_write(SJA1000_IER,sja1000_regs.IER);

	sja1000_regs.EWLR = 96;
	sja1000_write(SJA1000_EWLR,sja1000_regs.EWLR);

	sja1000_mask(0x0, 0xFFFFFFFF);
	sja1000_int();
	sja1000_registers();

	SJA1000_IRQ_DISABLE();
	while (!QUE_empty(&QUE_CANrx_msg)) {
		obj = QUE_get(&QUE_CANrx_msg);
		QUE_put(&QUE_CANrx_free, obj);
	}
	while (!QUE_empty(&QUE_CANtx_msg)) {
		obj = QUE_get(&QUE_CANtx_msg);
		QUE_put(&QUE_CANtx_free, obj);
	}
	SJA1000_IRQ_ENABLE();
}


/* can initialization */
void init_can(int baud, int opt_bt, int opt_sp, int sjw)
{
	CAN_Obj_t *obj;
	int i;

	SJA1000_IRQ_DISABLE();
	memset(&sja1000_regs, 0, sizeof(sja1000_regs));

	/* allocate receive queues */
	obj = (CAN_Obj_t *)MEM_alloc(SDRAM, CAN_QLENGTH*sizeof(*obj), 0);
	if (obj == MEM_ILLEGAL) {
		SYS_abort("Memory allocation failed!\n");
	}
	for (i = 0; i < CAN_QLENGTH; i++, obj++) {
		QUE_put(&QUE_CANrx_free,obj);
	}

	/* allocate transmit queues */
	obj = (CAN_Obj_t *)MEM_alloc(SDRAM, CAN_QLENGTH*sizeof(*obj), 0);
	if (obj == MEM_ILLEGAL) {
		SYS_abort("Memory allocation failed!\n");
	}
	for (i = 0; i < CAN_QLENGTH; i++, obj++) {
		QUE_put(&QUE_CANtx_free,obj);
	}
	SJA1000_IRQ_ENABLE();

	sja1000_full_reset();
	sja1000_btr(baud,opt_bt,opt_sp,sjw);
	can_operate_mode();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -