EC600U_esp32_iap_uart/EC600U_can/mcp2515.c
2024-02-05 17:39:56 +08:00

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; // ·¢ËÍ»º³åÇøÂú,·¢ËÍʧ°Ü
}