📄 chip_sja1000p.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 + -