475 lines
12 KiB
C
475 lines
12 KiB
C
|
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include "mcp2515.h"
|
||
|
#include "ql_api_spi.h"
|
||
|
#include "ql_api_osi.h"
|
||
|
// #include "hw.h"
|
||
|
#include "ql_log.h"
|
||
|
|
||
|
#define LOGD(msg, ...) QL_LOG(QL_LOG_LEVEL_DEBUG, "mcp2515", msg, ##__VA_ARGS__)
|
||
|
#define LOGI(msg, ...) QL_LOG(QL_LOG_LEVEL_INFO, "mcp2515", msg, ##__VA_ARGS__)
|
||
|
#define LOGW(msg, ...) QL_LOG(QL_LOG_LEVEL_WARN, "mcp2515", msg, ##__VA_ARGS__)
|
||
|
#define LOGE(msg, ...) QL_LOG(QL_LOG_LEVEL_ERROR, "mcp2515", msg, ##__VA_ARGS__)
|
||
|
|
||
|
extern struct can_status *can_status[2];
|
||
|
|
||
|
#define mcp_cs(fd) // ql_spi_cs_low(fd)
|
||
|
#define mcp_ncs(fd) // ql_spi_cs_high(fd)
|
||
|
|
||
|
static uint8_t spi_txbuf[32] __attribute__((aligned(32)));
|
||
|
static uint8_t spi_rxbuf[32] __attribute__((aligned(32)));
|
||
|
unsigned char spi_put(unsigned char);
|
||
|
|
||
|
void mcp_wr_can_eid(int fd, unsigned char add, unsigned long can_id)
|
||
|
{
|
||
|
unsigned char txbuf[4];
|
||
|
uint16_t canid;
|
||
|
canid = (uint16_t)can_id;
|
||
|
txbuf[EID0] = canid & 0xff;
|
||
|
txbuf[EID8] = (canid >> 8) & 0xff;
|
||
|
canid = (uint16_t)(can_id >> 16);
|
||
|
|
||
|
txbuf[SIDL] = canid & 0x03;
|
||
|
canid = canid << 3;
|
||
|
txbuf[SIDL] |= (canid & 0xe0);
|
||
|
txbuf[SIDL] |= 0x8;
|
||
|
txbuf[SIDH] = canid >> 8;
|
||
|
mcp_wrs(fd, add, txbuf, 4);
|
||
|
}
|
||
|
|
||
|
unsigned long mcp_rd_can_eid(int fd, unsigned char add)
|
||
|
{
|
||
|
unsigned char rcbuf[4];
|
||
|
uint32_t can_id;
|
||
|
uint16_t canid;
|
||
|
mcp_rds(fd, add, rcbuf, 4);
|
||
|
can_id = rcbuf[EID0] + (rcbuf[EID8] << 8);
|
||
|
canid = rcbuf[SIDL] + (rcbuf[SIDH] << 8);
|
||
|
canid = canid >> 3;
|
||
|
canid |= (rcbuf[SIDL] & 0x03);
|
||
|
can_id |= (canid << 16);
|
||
|
return can_id;
|
||
|
}
|
||
|
|
||
|
void mcp_wr_can_id(int fd, unsigned char add, unsigned int CanId)
|
||
|
{
|
||
|
unsigned char txbuf[4];
|
||
|
uint16_t sid;
|
||
|
uint32_t eid;
|
||
|
if (CanId & CAN_EFF_FLAG) // eid
|
||
|
{
|
||
|
sid = (CanId >> 18) & 0x7ff;
|
||
|
eid = CanId & 0x3ffff;
|
||
|
txbuf[SIDH] = (uint8_t)(sid >> 3);
|
||
|
txbuf[SIDL] = (sid << 5) & 0xe0;
|
||
|
txbuf[SIDL] |= (1 << 3);
|
||
|
txbuf[SIDL] |= (eid >> 16);
|
||
|
txbuf[EID8] = (eid >> 8) & 0xff;
|
||
|
txbuf[EID0] = eid & 0xff;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sid = CanId & 0x7ff;
|
||
|
txbuf[SIDH] = (uint8_t)(sid >> 3);
|
||
|
txbuf[SIDL] = (sid << 5) & 0xe0;
|
||
|
txbuf[EID8] = 0;
|
||
|
txbuf[EID0] = 0;
|
||
|
}
|
||
|
mcp_wrs(fd, add, txbuf, 4);
|
||
|
}
|
||
|
unsigned int mcp_rd_can_id(int fd, unsigned char add)
|
||
|
{
|
||
|
unsigned int CanId;
|
||
|
unsigned char rcbuf[4];
|
||
|
mcp_rds(fd, add, rcbuf, 4);
|
||
|
CanId = (rcbuf[SIDL] + (rcbuf[SIDH] << 8));
|
||
|
CanId >>= 5;
|
||
|
CanId &= 0x7ff;
|
||
|
if (rcbuf[SIDL] & (1 << 3))
|
||
|
{
|
||
|
unsigned int eid;
|
||
|
eid = rcbuf[EID0] | (rcbuf[EID8] << 8);
|
||
|
eid |= (rcbuf[SIDL] & 0x03) << 16;
|
||
|
CanId <<= 18;
|
||
|
CanId |= eid;
|
||
|
CanId |= CAN_EFF_FLAG;
|
||
|
}
|
||
|
return CanId;
|
||
|
}
|
||
|
void mcp_reset(int fd)
|
||
|
{
|
||
|
mcp_cs(fd);
|
||
|
spi_txbuf[0] = RESET;
|
||
|
spi_write(fd, spi_txbuf, 1);
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
// 单字节写
|
||
|
void mcp_wr(int fd, unsigned char add, unsigned char DAT)
|
||
|
{
|
||
|
spi_txbuf[0] = WRITE;
|
||
|
spi_txbuf[1] = add;
|
||
|
spi_txbuf[2] = DAT;
|
||
|
mcp_cs(fd);
|
||
|
spi_write(fd, spi_txbuf, 3);
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
// 多字节写
|
||
|
void mcp_wrs(int fd, unsigned char add, unsigned char *wr_dat, unsigned char length)
|
||
|
{
|
||
|
spi_txbuf[0] = WRITE;
|
||
|
spi_txbuf[1] = add;
|
||
|
mcp_cs(fd);
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
spi_txbuf[i + 2] = wr_dat[i];
|
||
|
}
|
||
|
spi_write(fd, spi_txbuf, length + 2);
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
// 单字节读
|
||
|
unsigned char mcp_rd(int fd, unsigned char add)
|
||
|
{
|
||
|
spi_txbuf[0] = READ;
|
||
|
spi_txbuf[1] = add;
|
||
|
spi_txbuf[2] = 0;
|
||
|
mcp_cs(fd);
|
||
|
spi_write_read(fd, spi_txbuf, spi_rxbuf, 3);
|
||
|
mcp_ncs(fd);
|
||
|
return (spi_rxbuf[2]);
|
||
|
}
|
||
|
// 多字节读
|
||
|
void mcp_rds(int fd, unsigned char add, unsigned char *DAT, unsigned char length)
|
||
|
{
|
||
|
spi_txbuf[0] = READ;
|
||
|
spi_txbuf[1] = add;
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
spi_txbuf[2 + i] = 0;
|
||
|
}
|
||
|
mcp_cs(fd);
|
||
|
spi_write_read(fd, spi_txbuf, spi_rxbuf, length + 2);
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
*DAT++ = spi_rxbuf[2 + i];
|
||
|
}
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
// 发送请求
|
||
|
void rts(int fd, unsigned char ch)
|
||
|
{
|
||
|
ch &= 0x7;
|
||
|
ch |= 0x80;
|
||
|
spi_txbuf[0] = ch;
|
||
|
mcp_cs(fd);
|
||
|
spi_write(fd, spi_txbuf, 1);
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
// 状态读
|
||
|
unsigned char get_mcp_status(int fd)
|
||
|
{
|
||
|
spi_txbuf[0] = STATUS;
|
||
|
spi_txbuf[1] = 0;
|
||
|
mcp_cs(fd);
|
||
|
spi_write_read(fd, spi_txbuf, spi_rxbuf, 2);
|
||
|
mcp_ncs(fd);
|
||
|
return (spi_rxbuf[1]);
|
||
|
}
|
||
|
void mcp_wr_bit(int fd, unsigned char add, unsigned char DAT, unsigned char mask)
|
||
|
{
|
||
|
spi_txbuf[0] = 0x05;
|
||
|
spi_txbuf[1] = add;
|
||
|
spi_txbuf[2] = mask;
|
||
|
spi_txbuf[3] = DAT;
|
||
|
mcp_cs(fd);
|
||
|
spi_write(fd, spi_txbuf, 4);
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
void mcp_rd_rxbuf(int fd, unsigned char buf, unsigned char *DAT, unsigned char length)
|
||
|
{
|
||
|
buf <<= 1;
|
||
|
buf &= 0x06;
|
||
|
buf |= 0x90;
|
||
|
spi_txbuf[0] = buf;
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
spi_txbuf[i + 1] = 0;
|
||
|
}
|
||
|
mcp_cs(fd);
|
||
|
spi_write_read(fd, spi_txbuf, spi_rxbuf, length + 1);
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
*DAT++ = spi_rxbuf[1 + i];
|
||
|
}
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
|
||
|
void mcp_ld_txbuf(int fd, unsigned char buf, unsigned char *DAT, unsigned char length)
|
||
|
{
|
||
|
mcp_cs(fd);
|
||
|
buf &= 0x07;
|
||
|
buf |= 0x40;
|
||
|
spi_txbuf[0] = buf;
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
spi_txbuf[i + 1] = 0;
|
||
|
}
|
||
|
spi_write_read(fd, spi_txbuf, spi_rxbuf, length + 1);
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
*DAT++ = spi_rxbuf[i + 1];
|
||
|
}
|
||
|
|
||
|
mcp_ncs(fd);
|
||
|
}
|
||
|
unsigned char get_mcp_rxstatus(int fd)
|
||
|
{
|
||
|
spi_txbuf[0] = 0xb0;
|
||
|
spi_txbuf[1] = 0;
|
||
|
mcp_cs(fd);
|
||
|
spi_write_read(fd, spi_txbuf, spi_rxbuf, 2);
|
||
|
mcp_ncs(fd);
|
||
|
return spi_rxbuf[1];
|
||
|
}
|
||
|
|
||
|
int mcp_can_init(int ch, can_config_t *cfg)
|
||
|
{
|
||
|
// uint8_t value;
|
||
|
int can_clock = 24000000;
|
||
|
uint8_t brp;
|
||
|
int bit_time;
|
||
|
mcp_reset(ch);
|
||
|
ql_rtos_task_sleep_ms(20);
|
||
|
mcp_wr(ch, CANCTRL, MODE_CONFIG);
|
||
|
if (mcp_rd(ch, CANCTRL) != MODE_CONFIG)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
bit_time = can_clock / 2 / cfg->baud_rate;
|
||
|
if (bit_time % 12 == 0) // ±ê×¼²¨ÌØÂÊ 125,250,500,10000
|
||
|
{
|
||
|
mcp_wr(ch, CNF2, BTLMODE_CNF3 + SEG3 * 8 + SEG5);
|
||
|
mcp_wr(ch, CNF3, SEG3);
|
||
|
brp = bit_time / 12 - 1;
|
||
|
if (brp > 7)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
mcp_wr(ch, CNF1, SJW1 + brp);
|
||
|
}
|
||
|
else if (bit_time % 15 == 0) // 100,200,400,800
|
||
|
{
|
||
|
mcp_wr(ch, CNF2, BTLMODE_CNF3 + SEG4 * 8 + SEG6);
|
||
|
mcp_wr(ch, CNF3, SEG4);
|
||
|
brp = bit_time / 15 - 1;
|
||
|
if (brp > 7)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
mcp_wr(ch, CNF1, SJW1 + brp);
|
||
|
}
|
||
|
else if (bit_time % 16 == 0) // 750,325
|
||
|
{
|
||
|
mcp_wr(ch, CNF2, BTLMODE_CNF3 + SEG5 * 8 + SEG6);
|
||
|
mcp_wr(ch, CNF3, SEG4);
|
||
|
brp = bit_time / 16 - 1;
|
||
|
if (brp > 7)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
mcp_wr(ch, CNF1, SJW1 + brp);
|
||
|
}
|
||
|
else // ²»Ö§³ÖµÄ²¨ÌØÂÊ
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
mcp_wr(ch, RXB0CTRL, cfg->rx_ctrl[0]); // Â˲¨Æ÷0
|
||
|
mcp_wr_can_id(ch, RXM0SIDH, cfg->rx_mask[0]);
|
||
|
mcp_wr_can_id(ch, RXF0SIDH, cfg->rx_filter[0]);
|
||
|
|
||
|
mcp_wr(ch, RXB1CTRL, cfg->rx_ctrl[1]); // Â˲¨Æ÷1
|
||
|
mcp_wr_can_id(ch, RXF1SIDH, cfg->rx_filter[1]);
|
||
|
mcp_wr_can_id(ch, RXM1SIDH, cfg->rx_mask[1]);
|
||
|
mcp_wr_can_id(ch, RXF2SIDH, cfg->rx_filter[2]);
|
||
|
mcp_wr_can_id(ch, RXF3SIDH, cfg->rx_filter[3]);
|
||
|
mcp_wr_can_id(ch, RXF4SIDH, cfg->rx_filter[4]);
|
||
|
mcp_wr_can_id(ch, RXF5SIDH, cfg->rx_filter[5]);
|
||
|
|
||
|
mcp_wr(ch, CANINTE, 0x03);
|
||
|
mcp_wr(ch, CANINTF, 0x00);
|
||
|
|
||
|
mcp_wr_bit(ch, TXRTSCTRL, 0x0, 0xff);
|
||
|
mcp_wr_bit(ch, BFPCTRL, 0x3c, 0xff);
|
||
|
mcp_wr(ch, CANCTRL, (cfg->can_mode & 0xf0));
|
||
|
LED0_ON(ch);
|
||
|
LED1_ON(ch);
|
||
|
LOGD("[%s] can%d init ok", __FUNCTION__, ch);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int can_read_rxbuf(int ch, CanRxMsg *RxMsg)
|
||
|
{
|
||
|
unsigned char status;
|
||
|
uint32_t can_id;
|
||
|
status = get_mcp_rxstatus(ch);
|
||
|
if (status & 0x40)
|
||
|
{
|
||
|
RxMsg->Id = mcp_rd_can_id(ch, 0x61);
|
||
|
if (RxMsg->Id & (1 << 31))
|
||
|
{
|
||
|
RxMsg->Id &= 0x1fffffff;
|
||
|
RxMsg->IDE = CAN_Id_Extended;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RxMsg->Id &= 0x7ff;
|
||
|
RxMsg->IDE = CAN_Id_Standard;
|
||
|
}
|
||
|
RxMsg->DLC = mcp_rd(ch, 0x65);
|
||
|
if (RxMsg->DLC & 0x40)
|
||
|
{
|
||
|
RxMsg->DLC = 0;
|
||
|
RxMsg->RTR = 1;
|
||
|
goto ret1; // Ë͵½rtr
|
||
|
}
|
||
|
RxMsg->RTR = 0;
|
||
|
if (RxMsg->DLC > 8)
|
||
|
{
|
||
|
RxMsg->DLC = 8;
|
||
|
}
|
||
|
mcp_rd_rxbuf(ch, 0x1, RxMsg->Data, RxMsg->DLC);
|
||
|
ret1:
|
||
|
mcp_wr_bit(ch, CANINTF, 0x00, 0x01);
|
||
|
return 1;
|
||
|
}
|
||
|
if (status & 0x80)
|
||
|
{
|
||
|
RxMsg->Id = mcp_rd_can_id(ch, 0x71);
|
||
|
if (can_id & (1 << 31))
|
||
|
{
|
||
|
RxMsg->Id &= 0x1fffffff;
|
||
|
RxMsg->IDE = CAN_Id_Extended;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RxMsg->Id &= 0x7ff;
|
||
|
RxMsg->IDE = CAN_Id_Standard;
|
||
|
}
|
||
|
RxMsg->DLC = mcp_rd(ch, 0x75);
|
||
|
if (RxMsg->DLC & 0x40)
|
||
|
{
|
||
|
RxMsg->DLC = 0;
|
||
|
RxMsg->RTR = 1;
|
||
|
goto ret2; // ÊÕµ½rtr
|
||
|
}
|
||
|
RxMsg->RTR = 0;
|
||
|
if (RxMsg->DLC > 8)
|
||
|
{
|
||
|
RxMsg->DLC = 8;
|
||
|
}
|
||
|
mcp_rd_rxbuf(ch, 0x3, RxMsg->Data, RxMsg->DLC);
|
||
|
ret2:
|
||
|
mcp_wr_bit(ch, CANINTF, 0x00, 0x02);
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int can_tx_pack(int ch, CanTxMsg *TxPack)
|
||
|
{
|
||
|
// #ifdef _CAN_DEBUG_
|
||
|
// char msg[256];
|
||
|
// int i;
|
||
|
// int n = sprintf(msg, "CAN%d Tx: Id=0x%x,IDE=%x,DLC=%d,Data=[", ch, TxPack->Id, TxPack->IDE, TxPack->DLC);
|
||
|
// for (i = 0; i < TxPack->DLC; i++)
|
||
|
// {
|
||
|
// n += sprintf(&msg[n], "%02x ", TxPack->Data[i]);
|
||
|
// }
|
||
|
// msg[n - 1] = ']';
|
||
|
// eat_trace(msg);
|
||
|
// #endif
|
||
|
can_status[0]->tx_cnt++;
|
||
|
if (!(mcp_rd(ch, 0x30) & 0x08))
|
||
|
{ // ·¢ËÍ»º³åÇø0¿Õ£¿
|
||
|
LED1_ON(ch);
|
||
|
if (TxPack->IDE == CAN_Id_Extended)
|
||
|
{
|
||
|
TxPack->Id |= (1 << 31);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TxPack->Id &= 0x7ff;
|
||
|
}
|
||
|
mcp_wr_can_id(ch, 0x31, TxPack->Id);
|
||
|
if (TxPack->RTR)
|
||
|
{
|
||
|
mcp_wr(ch, 0x35, 0x40); // ·¢ËÍRTR
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mcp_wr(ch, 0x35, TxPack->DLC);
|
||
|
mcp_ld_txbuf(ch, 0x1, (uint8_t *)&TxPack->Data[0], TxPack->DLC);
|
||
|
}
|
||
|
rts(ch, 1);
|
||
|
LED1_OFF(ch);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
if (!(mcp_rd(ch, 0x40) & 0x08))
|
||
|
{ // ·¢ËÍ»º³åÇø1¿Õ£¿
|
||
|
LED1_ON(ch);
|
||
|
if (TxPack->IDE == CAN_Id_Extended)
|
||
|
{
|
||
|
TxPack->Id |= (1 << 31);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TxPack->Id &= 0x7ff;
|
||
|
}
|
||
|
mcp_wr_can_id(ch, 0x41, TxPack->Id);
|
||
|
if (TxPack->RTR)
|
||
|
{
|
||
|
mcp_wr(ch, 0x45, 0x40); // ·¢ËÍRTR
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mcp_wr(ch, 0x45, TxPack->DLC);
|
||
|
mcp_ld_txbuf(ch, 0x3, (uint8_t *)&TxPack->Data[0], TxPack->DLC);
|
||
|
}
|
||
|
rts(ch, 2);
|
||
|
LED1_OFF(ch);
|
||
|
return 0;
|
||
|
}
|
||
|
if (!(mcp_rd(ch, 0x50) & 0x08))
|
||
|
{ // ·¢ËÍ»º³åÇø2¿Õ£¿
|
||
|
LED1_ON(ch);
|
||
|
if (TxPack->IDE == CAN_Id_Extended)
|
||
|
{
|
||
|
TxPack->Id |= (1 << 31);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TxPack->Id &= 0x7ff;
|
||
|
}
|
||
|
mcp_wr_can_id(ch, 0x51, TxPack->Id);
|
||
|
if (TxPack->RTR)
|
||
|
{
|
||
|
mcp_wr(ch, 0x55, 0x40); // ·¢ËÍRTR
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mcp_wr(ch, 0x55, TxPack->DLC);
|
||
|
mcp_ld_txbuf(ch, 0x5, (uint8_t *)&TxPack->Data[0], TxPack->DLC);
|
||
|
}
|
||
|
rts(ch, 4);
|
||
|
LED1_OFF(ch);
|
||
|
return 0;
|
||
|
}
|
||
|
if (mcp_rd(ch, EFLG) & (1 << 5))
|
||
|
{
|
||
|
mcp_wr(ch, TEC, 0);
|
||
|
}
|
||
|
return 1; // ·¢ËÍ»º³åÇøÂú,·¢ËÍʧ°Ü
|
||
|
}
|