bs_bcu_app/drv/drv_stm32f4xx/drv_can.c

425 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "drv_clk.h"
#include "drv_can.h"
#include "drv_gpio.h"
#include "drv_misc.h"
#include "kit_debug.h"
#define CAN_INIT_TIMEOUT (0xFFF0u)
#define CAN_SJW_1tq (0u)
#define CAN_BS2_1tq (0u)
#define CAN_BS2_2tq (1u)
#define CAN_BS1_4tq (3u)
#define CAN_BS1_6tq (5u)
#define CAN_BS1_13tq (12u)
#define CAN_BS1_16tq (15u)
#define CAN_RTR_DATA (0u)
#define GPIO_REMAP1_CAN1 ((uint32_t)0x00004000)
#define GPIO_REMAP2_CAN1 ((uint32_t)0x00006000)
#define GPIO_REMAP_CAN2 ((uint32_t)0x00400000)
typedef struct
{
uint8_t irq[kCanInterrupt_End];
CAN_TypeDef* reg;
}Stm32CanProp;
static KitResult drv_can_set_clock_gpio(CanDev dev, uint16_t rx_io, uint16_t tx_io);
static KitIrqCall can_irq_call[kCanDev_End][kCanInterrupt_End];
static const Stm32CanProp stm32_can[kCanDev_End] =
{
#if defined(STM32F10X_CL) || defined(STM32F40_41xxx) || defined(STM32F429_439xx)
{{CAN1_RX0_IRQn, CAN1_TX_IRQn}, CAN1},
{{CAN2_RX0_IRQn, CAN2_TX_IRQn}, CAN2},
#else
{{USB_LP_CAN1_RX0_IRQn, USB_HP_CAN1_TX_IRQn}, CAN1},
#endif
};
const uint8_t can_mailbox_tab[8] = {0xFF, 0, 1, 0, 2, 0, 1, 0};
uint8_t drv_can_get_mailbox(CanDev dev)
{
uint8_t mailbox = 0xFF;
KIT_ASSERT_PARAM(dev < kCanDev_End);
if(dev < kCanDev_End)
mailbox = can_mailbox_tab[(stm32_can[dev].reg->TSR >> 26) & 0x07];
return mailbox;
}
KitResult drv_can_send(CanDev dev, CanMsg *msg)
{
uint8_t id_move = 3, mailbox;
KitResult res = kKitResult_ParamErr;
CAN_TypeDef *can_reg;
KIT_ASSERT_PARAM(msg != NULL);
KIT_ASSERT_PARAM(dev < kCanDev_End);
if((dev < kCanDev_End) && (msg != NULL))
{
can_reg = stm32_can[dev].reg;
mailbox = can_mailbox_tab[(can_reg->TSR >> 26) & 0x07];
if (mailbox != 0xFF)
{
if (msg->ide == kCanIde_Std)
{
id_move = 21;
}
//write identifier
can_reg->sTxMailBox[mailbox].TIR = (msg->id.value << id_move) | (msg->ide << 2) | (msg->rtr << 1);
//write length
can_reg->sTxMailBox[mailbox].TDTR = msg->len & 0x0F;
//write data
can_reg->sTxMailBox[mailbox].TDLR = msg->data.value[0];
can_reg->sTxMailBox[mailbox].TDHR = msg->data.value[1];
//request send
can_reg->sTxMailBox[mailbox].TIR |= 0x00000001;
res = kKitResult_Ok;
}
else
{
res = kKitResult_OverFlow;
}
}
return res;
}
KitResult drv_can_receive(CanDev dev, CanMsg* msg)
{
KitResult res = kKitResult_ParamErr;
CAN_FIFOMailBox_TypeDef fifo;
KIT_ASSERT_PARAM(msg != NULL);
KIT_ASSERT_PARAM(dev < kCanDev_End);
if((dev < kCanDev_End) && (msg != NULL))
{
fifo = stm32_can[dev].reg->sFIFOMailBox[0];
/* Get the Id */
msg->rtr = (CanRtr)(0x00000001 & fifo.RIR >> 1);
msg->ide = (CanIde)(0x00000001 & fifo.RIR >> 2);
if (msg->ide == kCanIde_Std)
msg->id.value = (uint32_t)0x000007FF & (fifo.RIR >> 21);
else
msg->id.value = (uint32_t)0x1FFFFFFF & (fifo.RIR >> 3);
msg->len = (uint8_t)0x0F & fifo.RDTR;
msg->data.value[0] = fifo.RDLR;
msg->data.value[1] = fifo.RDHR;
/* Release the FIFO */
stm32_can[dev].reg->RF0R |= CAN_RF0R_RFOM0;
res = kKitResult_Ok;
}
return res;
}
/**********************************************************************************
* Func CAN1_REMAP0 CAN1_REMAP1 CAN1_REMAP2 CAN2_REMAP0 CAN2_REMAP1
* CAN_RX PA11 PB8 PD0 PB12 PB5
* CAN_TX PA12 PB9 PD1 PB13 PB6
**********************************************************************************/
static KitResult drv_can_set_clock_gpio(CanDev dev, uint16_t rx_idx, uint16_t tx_idx)
{
KitResult res = kKitResult_Ok;
uint32_t rx_io = drv_gpio_get_actual_io(rx_idx);
uint32_t tx_io = drv_gpio_get_actual_io(tx_idx);
switch (dev)
{
case kCanDev_1:
RCC->APB1ENR |= RCC_APB1Periph_CAN1;
if((rx_io == GPIO_PORT_PIN(kGpioPort_A, 11)) && (tx_io == GPIO_PORT_PIN(kGpioPort_A, 12)))
{
drv_gpio_set_af(kGpioPort_A, 11, 9);
drv_gpio_set_af(kGpioPort_A, 12, 9);
}
else if((rx_io == GPIO_PORT_PIN(kGpioPort_B, 8)) && (tx_io == GPIO_PORT_PIN(kGpioPort_B, 9)))
{
drv_gpio_set_af(kGpioPort_B, 8, 9);
drv_gpio_set_af(kGpioPort_B, 9, 9);
}
else if((rx_io == GPIO_PORT_PIN(kGpioPort_D, 0)) && (tx_io == GPIO_PORT_PIN(kGpioPort_D, 1)))
{
drv_gpio_set_af(kGpioPort_D, 0, 9);
drv_gpio_set_af(kGpioPort_D, 1, 9);
}
else
res = kKitResult_ParamErr;
break;
#if defined(STM32F10X_CL) || defined(STM32F40_41xxx) || defined(STM32F429_439xx)
//使用CAN2接收需要使能CAN1时钟
case kCanDev_2:
RCC->APB1ENR |= RCC_APB1Periph_CAN1;
RCC->APB1ENR |= RCC_APB1Periph_CAN2;
if((rx_io == GPIO_PORT_PIN(kGpioPort_B, 12)) && (tx_io == GPIO_PORT_PIN(kGpioPort_B, 13)))
{
drv_gpio_set_af(kGpioPort_B, 12, 9);
drv_gpio_set_af(kGpioPort_B, 13, 9);
}
else if((rx_io == GPIO_PORT_PIN(kGpioPort_B, 5)) && (tx_io == GPIO_PORT_PIN(kGpioPort_B, 6)))
{
drv_gpio_set_af(kGpioPort_B, 5, 9);
drv_gpio_set_af(kGpioPort_B, 6, 9);
}
else
res = kKitResult_ParamErr;
break;
#endif
default:
res = kKitResult_ParamErr;
break;
}
return res;
}
//默认全部关联到FIFO0
void can_set_list_filter(uint8_t channel, CanIde ide, CanRtr rtr, uint32_t rcv_id1, uint32_t rcv_id2)
{
uint8_t id_move = 3;
uint32_t bit;
KIT_ASSERT_PARAM(channel < 28);
KIT_ASSERT_PARAM(ide < kCanIde_End);
KIT_ASSERT_PARAM(rtr < kCanRtr_End);
bit = KIT_CREAT_BIT(channel);
CAN1->FMR |= CAN_FMR_FINIT; //进入CAN配置模式
CAN1->FM1R |= bit; //列表模式
CAN1->FS1R |= bit; //32位数据长度
id_move = 3;
if(ide == kCanIde_Std)
{
id_move = 21;
}
CAN1->sFilterRegister[channel].FR1 = (rcv_id1 << id_move) | (ide << 2) | (rtr << 1);
CAN1->sFilterRegister[channel].FR2 = (rcv_id2 << id_move) | (ide << 2) | (rtr << 1);
CAN1->FA1R |= bit;
CAN1->FMR &= ~CAN_FMR_FINIT;
}
//屏蔽位模式 0不关心 1必须匹配
void can_set_mask_filter(uint8_t channel, CanIde ide, CanRtr rtr, uint32_t rcv_id, uint32_t mask_id)
{
uint8_t id_move;
uint32_t bit;
KIT_ASSERT_PARAM(channel < 28);
KIT_ASSERT_PARAM(ide < kCanIde_End);
KIT_ASSERT_PARAM(rtr < kCanRtr_End);
bit = KIT_CREAT_BIT(channel);
CAN1->FMR |= CAN_FMR_FINIT; //进入CAN配置模式
CAN1->FM1R &= ~bit; //屏蔽模式
CAN1->FS1R |= bit; //32位数据长度
id_move = 3;
if(ide == kCanIde_Std)
{
id_move = 21;
}
CAN1->sFilterRegister[channel].FR1 = (rcv_id << id_move) | (ide << 2) | CAN_RTR_DATA;
CAN1->sFilterRegister[channel].FR2 = (mask_id << id_move) | (ide << 2) | CAN_RTR_DATA;
CAN1->FA1R |= bit;
CAN1->FMR &= ~CAN_FMR_FINIT;
}
/*----------------------------------------STM32F10x MCR(master control register)寄存器---------------------------------------------------
| Bit | 16 | 15 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
-----------------------------------------------------------------------------------------------------------------------------------------
| Item | DBF | RESET | TTCM | ABOM | AWUM | NART | RFLM | TXFP | SLEEP | INRQ |
-----------------------------------------------------------------------------------------------------------------------------------------
| DEF | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
-----------------------------------------------------------------------------------------------------------------------------------------
| Value |1 调试时冻结 |0 不复位 |0 禁用时间触发模式|1 硬件控制Buf off|1 硬件唤醒|0 自动重发|1 满停止接收|1 按顺序发送| | |
*软件通过置位SLEEP来请求进入睡眠模式置位后CAN在当前活动完成后将立即进入睡眠模式当AWUM置位后也可以被硬件唤醒清零
*CAN波特率=APB总线频率/BRP分频器/(1+tBS1+tBS2) 5kbps = 42000/900/(1+6+1)
*波特率必须是5kbps倍数,小于500以36M的APB1Periph时钟频率计算5kbps时在(SJW_1tq, BS1_6tq, BS2_1tq)预分频为900, 其他波特率分频计算 900 / (baud_rate/5)
*使用CAN2必须使能CAN1时钟
*CAN初始化同步到总线使用时间根据情况而定设备较多有报文需要等待的时间较长
*本驱动只使用FIFO0滤波器都关联到FIFO0
*CAN1过滤器起始地址为0共有14个CAN2为14共有14个
*0表示不过滤1表示对应位要过滤
*配置过滤器时必须处于初始化模式
----------------------------------------------------------------------------------------------------------------------------------------*/
KitResult drv_can_init(CanDev dev, uint32_t baud_rate, uint16_t rx_io, uint16_t tx_io)
{
uint32_t tmp;
KitResult res;
CAN_TypeDef *can_reg;
KIT_ASSERT_PARAM(dev < kCanDev_End);
KIT_ASSERT_PARAM(((baud_rate % 5) == 0) && (baud_rate <= 500));
res = drv_can_set_clock_gpio(dev, rx_io, tx_io);
if(res == kKitResult_Ok)
{
can_reg = stm32_can[dev].reg;
// leave sleep mode
can_reg->MCR &= (~(uint32_t)CAN_MCR_SLEEP);
// request init mode
can_reg->MCR |= CAN_MCR_INRQ ;
// wait init acknowledge
res |= kit_wait_flag(&can_reg->MSR, CAN_MSR_INAK, CAN_INIT_TIMEOUT);
//cfg main register 自动退出离线 | 多个报文同时等待发送由请求顺序决定 | 自动重发
tmp = (CAN_MCR_ABOM | CAN_MCR_TXFP | CAN_MCR_RFLM);
can_reg->MCR |= tmp;
//Baud rate prescaler BRP = CLOCK_PCLK1_FREQ / (SJW + BS1 + BS2) / baud_rate - 1
switch(baud_rate)
{
case 125:
case 250:
can_reg->BTR = ((uint32_t)CAN_SJW_1tq << 24) | ((uint32_t)CAN_BS1_6tq << 16) | ((uint32_t)CAN_BS2_1tq << 20) | (CLOCK_PCLK1_FREQ / 8000 / baud_rate - 1);
break;
case 500:
case 1000:
can_reg->BTR = ((uint32_t)CAN_SJW_1tq << 24) | ((uint32_t)CAN_BS1_4tq << 16) | ((uint32_t)CAN_BS2_1tq << 20) | (CLOCK_PCLK1_FREQ / 6000 / baud_rate - 1);
break;
default:
can_reg->BTR = ((uint32_t)CAN_SJW_1tq << 24) | ((uint32_t)CAN_BS1_6tq << 16) | ((uint32_t)CAN_BS2_1tq << 20) | (CLOCK_PCLK1_FREQ / 8000 / 250 - 1);
break;
}
//leave init mode
can_reg->MCR &= ~(uint32_t)CAN_MCR_INRQ;
// Wait the normal acknowledge,当总线有报文时等待时间会较长
res |= kit_wait_flag(&can_reg->MSR, CAN_MSR_INAK, CAN_INIT_TIMEOUT);
//默认接收任何ID的扩展帧和标准帧
dev *= 14; //通道2起始过滤器为14
CAN1->FMR |= CAN_FMR_FINIT; //进入CAN配置模式
CAN1->FM1R = 0; //所有过滤器组工作在屏蔽位模式
CAN1->FA1R |= KIT_CREAT_BIT(dev);
CAN1->sFilterRegister[dev].FR1 = 0; //所有位不关心
CAN1->sFilterRegister[dev].FR2 = 0;
CAN1->FMR &= ~CAN_FMR_FINIT;
}
KIT_ASSERT_RES(dev, res);
return res;
}
const uint8_t can_interrupt_bit[kCanInterrupt_End] = {0x02, 0x01};
KitResult drv_can_set_interrupt(CanDev dev, CanInterrupt it_type, uint16_t priority, KitIrqCall call)
{
KitResult res;
KIT_ASSERT_PARAM((dev < kCanDev_End) && (it_type < kCanInterrupt_End) && (call != NULL));
if((dev < kCanDev_End) && (it_type < kCanInterrupt_End) && (call != NULL))
{
can_irq_call[dev][it_type] = call;
drv_misc_set_nvic(stm32_can[dev].irq[it_type], priority);
stm32_can[dev].reg->IER |= can_interrupt_bit[it_type];
res = kKitResult_Ok;
}
else
{
res = kKitResult_ParamErr;
}
return res;
}
KitResult drv_can_ctrl_interrupt(CanDev dev, CanInterrupt it_type, bool is_enable)
{
KitResult res;
KIT_ASSERT_PARAM((dev < kCanDev_End) && (it_type < kCanInterrupt_End));
if((dev < kCanDev_End) && (it_type < kCanInterrupt_End))
{
if (is_enable == true)
stm32_can[dev].reg->IER |= can_interrupt_bit[it_type];
else
stm32_can[dev].reg->IER &= ~can_interrupt_bit[it_type];
res = kKitResult_Ok;
}
else
{
res = kKitResult_ParamErr;
}
return res;
}
void drv_can_rx_irq_handler(CanDev dev)
{
CanMsg msg;
if(can_irq_call[dev][kCanInterrupt_Rx] != NULL)
{
while((stm32_can[dev].reg->RF0R & 0x03) != 0)
{
drv_can_receive(dev, &msg);
can_irq_call[dev][kCanInterrupt_Rx](kKitResult_Ok, &msg);
}
}
else
{
//清除中断标志,防止一直进中断
stm32_can[dev].reg->RF0R |= CAN_RF0R_RFOM0;
}
}
void drv_can_tx_irq_handler(CanDev dev)
{
stm32_can[dev].reg->TSR |= 0x00010101;
if(can_irq_call[dev][kCanInterrupt_Tx] != NULL)
{
can_irq_call[dev][kCanInterrupt_Tx](kKitResult_Ok, NULL);
}
}
void CAN1_RX0_IRQHandler(void)
{
drv_can_rx_irq_handler(kCanDev_1);
}
void CAN1_TX_IRQHandler (void)
{
drv_can_tx_irq_handler(kCanDev_1);
}
#if defined(STM32F10X_CL) || defined(STM32F40_41xxx) || defined(STM32F429_439xx)
void CAN2_RX0_IRQHandler(void)
{
drv_can_rx_irq_handler(kCanDev_2);
}
void CAN2_TX_IRQHandler (void)
{
drv_can_tx_irq_handler(kCanDev_2);
}
#endif