/**
******************************************************************************
* @file tae32f53xx_ll_can.c
* @author MCD Application Team
* @brief CAN LL Module Driver.
*
******************************************************************************
* @attention
*
*
© Copyright (c) 2020 Tai-Action.
* All rights reserved.
*
* This software is licensed by Tai-Action under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "tae32f53xx_ll.h"
#define DBG_TAG "CAN LL"
#define DBG_LVL DBG_ERROR
#include "dbg/tae32f53xx_dbg.h"
/** @addtogroup TAE32F53xx_LL_Driver
* @{
*/
/** @defgroup CAN_LL CAN LL
* @brief CAN LL Module Driver
* @{
*/
#ifdef LL_CAN_MODULE_ENABLED
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup CAN_LL_Private_Functions
* @{
*/
LL_StatusETypeDef LL_CAN_AcceptFilCfg(CAN_TypeDef *Instance, CAN_AcceptFilCfgTypeDef *fil_cfg);
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup CAN_LL_Exported_Functions CAN LL Exported Functions
* @brief CAN LL Exported Functions
* @{
*/
/** @defgroup CAN_LL_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and de-initialization functions
* @{
*/
/**
* @brief CAN LL Init
* @param Instance Specifies CAN peripheral
* @param user_cfg user config pointer
* @return Status of the Initialization
*/
LL_StatusETypeDef LL_CAN_Init(CAN_TypeDef *Instance, CAN_UserCfgTypeDef *user_cfg)
{
assert_param(Instance);
assert_param(user_cfg);
/* Init the low level hardware eg. Clock, NVIC */
LL_CAN_MspInit(Instance);
/* Set reset status to config some register which can config in reset status only */
__LL_CAN_Reset_Set(Instance);
//Baudrate config
assert_param(user_cfg->baudrate);
__LL_CAN_SS_Prescaler_Set(Instance, (LL_SYSCTRL_AHBClkGet() / 10 / user_cfg->baudrate - 1));
//Bit timing config
__LL_CAN_SS_BitTimingSeg1_Set(Instance, user_cfg->bit_timing_seg1);
__LL_CAN_SS_BitTimingSeg2_Set(Instance, user_cfg->bit_timing_seg2);
__LL_CAN_SS_SyncJumpWidth_Set(Instance, user_cfg->bit_timing_sjw);
//Acceptance filter config
for (uint8_t i = 0; i < user_cfg->accept_fil_cfg_num; i++) {
LL_CAN_AcceptFilCfg(Instance, (CAN_AcceptFilCfgTypeDef *)&user_cfg->accept_fil_cfg_ptr[i]);
}
/*Clear reset status to config other register */
__LL_CAN_Reset_Clr(Instance);
//RX buffer almost full and error warning limit set
__LL_CAN_RxBufAlmostFullLimit_Set(Instance, user_cfg->rx_almost_full_limit);
__LL_CAN_ErrWarnLimit_Set(Instance, user_cfg->err_limit);
return LL_OK;
}
/**
* @brief CAN LL DeInit
* @param Instance Specifies CAN peripheral
* @return Status of the DeInitialization
*/
LL_StatusETypeDef LL_CAN_DeInit(CAN_TypeDef *Instance)
{
/* DeInit the low level hardware eg. Clock, NVIC */
LL_CAN_MspDeInit(Instance);
return LL_OK;
}
/**
* @brief Initializes the CAN MSP.
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_MspInit(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitializes the CAN MSP
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_MspDeInit(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_MspDeInit could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup CAN_LL_Exported_Functions_Group2 Send data functions
* @brief Send data functions
* @{
*/
/**
* @brief CAN LL send standard primary transmit buffer
* @param Instance Specifies CAN peripheral
* @param buf_fmt buffer format pointer
* @param buf buffer pointer
* @return success send length in byte
*/
uint32_t LL_CAN_SendStandard_PTB(CAN_TypeDef *Instance, CAN_TxBufFormatTypeDef *buf_fmt, uint32_t *buf)
{
uint32_t i, j;
assert_param(Instance);
assert_param(buf_fmt);
assert_param(buf);
//TX buffer select PTB
__LL_CAN_TxBufSel_PTB(Instance);
//Write buffer format data to TX buffer
Instance->TXBUF[0] = *((uint32_t *)buf_fmt);
Instance->TXBUF[1] = *(((uint32_t *)buf_fmt) + 1);
//Write data to TX buffer
for (i = 0, j = 0; i < buf_fmt->data_len_code; i += 4, j++) {
Instance->TXBUF[2 + j] = *buf++;
}
//TX primary enable
__LL_CAN_TxPriEn_Set(Instance);
//Wait TX complete
while (__LL_CAN_TxPriEn_Get(Instance));
return buf_fmt->data_len_code;
}
/**
* @brief CAN LL send standard secondary transmit buffer
* @param Instance Specifies CAN peripheral
* @param buf_fmt buffer format pointer
* @param buf buffer pointer
* @return success send length in byte
*/
uint32_t LL_CAN_SendStandard_STB(CAN_TypeDef *Instance, CAN_TxBufFormatTypeDef *buf_fmt, uint32_t *buf)
{
uint32_t i, j;
assert_param(Instance);
assert_param(buf_fmt);
assert_param(buf);
//TX buffer select STB
__LL_CAN_TxBufSel_STB(Instance);
//Write buffer format data to TX buffer
Instance->TXBUF[0] = *((uint32_t *)buf_fmt);
Instance->TXBUF[1] = *(((uint32_t *)buf_fmt) + 1);
//Write data to TX buffer
for (i = 0, j = 0; i < buf_fmt->data_len_code; i += 4, j++) {
Instance->TXBUF[2 + j] = *buf++;
}
//TX buffer Secondary next
__LL_CAN_TxSecNext_Set(Instance);
//TX secondary send one start
__LL_CAN_TxSecOne_Set(Instance);
//Wait TX complete
while (__LL_CAN_TxSecOne_Get(Instance));
return buf_fmt->data_len_code;
}
/**
* @brief CAN LL send a multi-package standard secondary transmit buffer
* @param Instance Specifies CAN peripheral
* @param buf_fmt buffer format pointer
* @param buf buffer pointer
* @param send_cnt send packets count
* @return success send length in byte
*/
uint32_t LL_CAN_SendStandard_STB_Multi(CAN_TypeDef *Instance, CAN_TxBufFormatTypeDef *buf_fmt,
uint32_t *buf, uint32_t send_cnt)
{
uint32_t i, j, cnt;
assert_param(Instance);
assert_param(buf_fmt);
assert_param(buf);
//TX buffer select STB
__LL_CAN_TxBufSel_STB(Instance);
for (cnt = 0; cnt < send_cnt; cnt++) {
//Write buffer format data to TX buffer
Instance->TXBUF[0] = *((uint32_t *)buf_fmt);
Instance->TXBUF[1] = *(((uint32_t *)buf_fmt) + 1);
//Write data to TX buffer
for (i = 0, j = 0; i < buf_fmt->data_len_code; i += 4, j++) {
Instance->TXBUF[2 + j] = *buf++;
}
//TX buffer Secondary next
__LL_CAN_TxSecNext_Set(Instance);
//TX buffer Secondary full and send
if (__LL_CAN_IsTxSecBufFull(Instance)) {
//TX secondary send all start
__LL_CAN_TxSecAll_Set(Instance);
//Wait TX complete
while (__LL_CAN_TxSecAll_Get(Instance));
}
}
//TX secondary send all start
__LL_CAN_TxSecAll_Set(Instance);
//Wait TX complete
while (__LL_CAN_TxSecAll_Get(Instance));
return buf_fmt->data_len_code * send_cnt;
}
/**
* @}
*/
/** @defgroup CAN_LL_Exported_Functions_Interrupt CAN Interrupt handler and call back
* @brief CAN Interrupt handler and call back
* @{
*/
/**
* @brief CAN IRQ Handler
* @param Instance Specifies CAN peripheral
* @note All interrupt pending will be reset immediately after a read access
* @return None
*/
void LL_CAN_IRQHandler(CAN_TypeDef *Instance)
{
uint8_t txrx_int_sta = __LL_CAN_IntSta_Get(Instance);
uint8_t err_int_sta = __LL_CAN_ErrIntSta_Get(Instance);
if (txrx_int_sta & CAN_RX_INT_STA_Msk) {
LL_CAN_RxCallback(Instance);
}
if (txrx_int_sta & CAN_RX_BUF_OVER_INT_STA_Msk) {
LL_CAN_RxOverCallback(Instance);
}
if (txrx_int_sta & CAN_RX_BUF_FULL_INT_STA_Msk) {
LL_CAN_RxFullCallback(Instance);
}
if (txrx_int_sta & CAN_RX_BUF_ALMOST_FULL_INT_STA_Msk) {
LL_CAN_RxAlmostFullCallback(Instance);
}
if (txrx_int_sta & CAN_TX_PRI_INT_STA_Msk) {
LL_CAN_TxPriCallback(Instance);
}
if (txrx_int_sta & CAN_TX_SEC_INT_STA_Msk) {
LL_CAN_TxSecCallback(Instance);
}
if (txrx_int_sta & CAN_ERR_INT_STA_Msk) {
LL_CAN_ErrCallback(Instance);
}
if (txrx_int_sta & CAN_ABORT_INT_STA_Msk) {
LL_CAN_AbortCallback(Instance);
}
if (err_int_sta & CAN_ERR_PASS_INT_STA_Msk) {
LL_CAN_ErrPassiveCallback(Instance);
}
if (err_int_sta & CAN_ARB_LOST_INT_STA_Msk) {
LL_CAN_ArbLostCallback(Instance);
}
if (err_int_sta & CAN_BUS_ERR_INT_STA_Msk) {
LL_CAN_BusErrCallback(Instance);
}
}
/**
* @brief CAN RX interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_RxCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_RxCallback could be implemented in the user file
*/
}
/**
* @brief CAN RX over interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_RxOverCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_RxOverCallback could be implemented in the user file
*/
}
/**
* @brief CAN RX full interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_RxFullCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_RxFullCallback could be implemented in the user file
*/
}
/**
* @brief CAN RX almost full interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_RxAlmostFullCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_RxAlmostFullCallback could be implemented in the user file
*/
}
/**
* @brief CAN TX primary interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_TxPriCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_TxPriCallback could be implemented in the user file
*/
}
/**
* @brief CAN TX secondary interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_TxSecCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_TxSecCallback could be implemented in the user file
*/
}
/**
* @brief CAN error interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_ErrCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_ErrCallback could be implemented in the user file
*/
}
/**
* @brief CAN abort interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_AbortCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_AbortCallback could be implemented in the user file
*/
}
/**
* @brief CAN error passive interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_ErrPassiveCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_ErrPassiveCallback could be implemented in the user file
*/
}
/**
* @brief CAN arbitration lost interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_ArbLostCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_ArbLostCallback could be implemented in the user file
*/
}
/**
* @brief CAN bus error interrupt callback
* @param Instance Specifies CAN peripheral
* @return None
*/
__WEAK void LL_CAN_BusErrCallback(CAN_TypeDef *Instance)
{
/* Prevent unused argument(s) compilation warning */
LL_UNUSED(Instance);
/* NOTE: This function should not be modified, when the callback is needed,
the LL_CAN_BusErrCallback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup CAN_LL_Private_Functions CAN LL Private Functions
* @brief CAN LL Private Functions
* @{
*/
/**
* @brief CAN LL acceptance filter config
* @param Instance Specifies CAN peripheral
* @param fil_cfg filter config pointer
* @return Config result
*/
LL_StatusETypeDef LL_CAN_AcceptFilCfg(CAN_TypeDef *Instance, CAN_AcceptFilCfgTypeDef *fil_cfg)
{
assert_param(Instance);
assert_param(fil_cfg);
//Check in reset status or not
if (!__LL_CAN_ResetSta_Get(Instance)) {
LOG_E("Acceptance filter register can config in reset status only!\n");
return LL_ERROR;
}
//CAN acceptance filter Code and Mask config
__LL_CAN_AcceptFilAddr_Set(Instance, fil_cfg->slot);
__LL_CAN_AcceptFilContentSel_Code(Instance);
__LL_CAN_AcceptFilCodeOrMaskVal_Set(Instance, fil_cfg->code_val);
__LL_CAN_AcceptFilContentSel_Mask(Instance);
__LL_CAN_AcceptFilCodeOrMaskVal_Set(Instance, fil_cfg->mask_val);
//CAN acceptance filter enable
__LL_CAN_AcceptFil_En(Instance, ((uint8_t)fil_cfg->slot));
return LL_OK;
}
/**
* @}
*/
#endif /* LL_CAN_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
/************************* (C) COPYRIGHT Tai-Action *****END OF FILE***********/