今天来调一下nxp S32K146的CAN通讯,硬件部分使用的是NXP TJA1043 CAN通讯芯片先翻译一下数据手册。
一、TJA1043 有这么几个特点:
①几种保护和诊断功能,包括母线短路检测和电池连接检测
②CANFD快速阶段以高达5Mbit/s的数据速率进行可靠的通信。
③用于节点诊断和故障控制的仅监听模式
④传输数据(TXD)主要超时功能与诊断(如何实现?)
⑤TJA1043支持五种操作模式。控制引脚STB_N和EN用于选择操作模式。 在模式之间切换允许通过引脚ERR_N访问许多诊断标志。
其他都略过了,详细看一下7.1 Operating modes

正常模式Normal mode
在正常模式下,收发器可以通过总线CANH和CANL传输和接收数据。差分接收器将总线上的模拟数据转换为数字数据,然后输出到引脚RXD。引脚INH是运行的,因此由引脚INH控制的电压调节器也将是运行的。
只听模式 Listen-only mode
在只听模式下,收发器的发射器被禁用,有效地提供了收发器的只听”功能。接收器仍将将引脚CANH和CANL上的模拟总线信号转换为数字数据,可通过引脚RXD输出,引脚INH保持运行的。
待机模式Standby mode
待机模式是TJA1043的一级节电模式,提供减少电流消耗。在备用模式下,收发器无法传输或接收数据,并激活低功率接收机以监控总线活动。引脚INH仍然是运行的,所以由这个引脚控制的电压调节器也将是运行的。Pins RXD和ERR_N将反映任何活动的唤醒请求。
进入睡眠模式Go-to-Sleep mode
进入睡眠模式是进入睡眠模式的控制路径。在进入睡眠模式下,收发器表现为待机模式,并附加了一个向收发器发出进入睡眠的命令。在进入睡眠模式之前,收发器将保持最短保持时间。如果pin STB_N或pin EN的状态发生改变,或者在结束(分钟)之前设置了唤醒标志,收发器将不会进入休眠模式。
睡眠模式 Sleep mode
睡眠模式是TJA1043的二级节电模式。睡眠模式通过进入睡眠模式进入,当VCC或VIO的欠压检测时间在相关电压水平恢复时进入。在睡眠模式下,收发器按照待机模式的描述行为,除了引脚INH设置为浮动。由此引脚控制的电压调节器将关闭,进入引脚VBAT的电流将减少到最小。pin STB_N、EN和Wake标志可以用来从睡眠模式中唤醒。
:INH拉出控制供电芯片的使能脚,也就是通过该引脚控制电源芯片是否使能。

再翻译一下 7.2内部标志
TJA1043使用7个内部标志为其故障安全回退模式控制和系统诊断支持。控制器可以通过引脚ERR_N轮询其中五个标志。在任何时候,引脚ERR_N上可用的标志取决于活动操作模式和许多其他条件。

UVNOM标志
UVNOM是VCC和VIO欠压检测标志。当引脚VCC上的电压低于VCC欠压检测电压Vuvd(VCC),且持续时间超过欠压检测时间tdet(uv),或者当引脚VIO上的电压低于Vuvd(VIO)且持续时间超过tdet(uv)时,设置该标志。设置UVNOM标志后,收发器进入Sleep模式,节省电能,保证总线不受干扰。在睡眠模式下,连接到引脚INH的稳压器是禁用的,避免任何额外的功耗,可能产生的短路条件。任何唤醒请求,设置Pwon标志或STB_N上的LOW-to-HIGH转换将清除UVNOM和定时器,允许稳压器重新激活(至少直到UVNOM再次被设置)。如果VCC和VIO恢复时间超过欠压恢复时间trec(uv), UVNOM也将被清除。然后,收发器将切换到由引脚STB_N和EN上的逻辑电平指示的工作模式。
UVBAT 标志
UVBAT是VBAT欠压检测标志。当引脚VBAT上的电压低于vvd (VBAT)时设置该标志。当设置UVBAT时,收发器将尝试进入待机模式以节省电力,并将从总线断开(零负载)。当引脚VBAT电压恢复时,UVBAT被清除。然后,收发器将切换到由引脚STB_N和EN上的逻辑电平指示的工作模式。
Pwon 标志
Pwon是VBAT开机标志。当引脚VBAT上的电压在之前下降到vvd (VBAT)以下后恢复时,设置该标志(通常是因为电池断开)。设置Pwon标志可以清除UVNOM标志和定时器。唤醒和唤醒源标志的设置,以确保在所有供应条件下的一致系统上电。在Listen-only模式下,Pwon标志可以通过引脚ERR_N进行轮询。当收发器进入Normal模式时,该标志被清除。
wake 标志
当收发器检测到本地或远程唤醒请求时设置唤醒标志。当引脚WAKE上的逻辑电平发生变化时,检测到本地唤醒请求,并且新电平至少在唤醒后保持稳定。可在待机模式、转睡眠模式或睡眠模式下设置唤醒标志。设置唤醒标志可以清除UVNOM标志和定时器。一旦设置,唤醒标志状态立即在引脚ERR_N和RXD上可用(提供VIO和VBAT)。该标志也在上电时设置,当设置UVNOM标志或收发器进入正常模式时清除。
Remote wake-up (via the CAN bus)
当总线上检测到专用的唤醒模式(在ISO 11898- 2:16中指定)时,TJA1043从待机或睡眠模式中唤醒。这种过滤有助于避免虚假的唤醒事件。一个虚假的唤醒序列可以被触发,例如,一个主导箝位总线或主导相位由噪声或尖峰总线上。唤醒模式包括:
•至少唤醒(busdom)的主导阶段紧随其后
•随后是至少苏醒(busrec)的隐性阶段
•至少唤醒(busdom)的主导阶段
在上述阶段之间的显性或隐性位,分别比twake(busdom) twake(busrec)短被忽略。在tto(wake)总线内必须接收到完全的显性-隐性-显性模式,才能被识别为有效的唤醒模式(见图5)。否则,内部唤醒逻辑将被重置。然后需要重新传输完整的唤醒模式来触发唤醒事件。引脚RXD保持高,直到唤醒事件被触发。当收到一个有效的唤醒模式时,如果以下任何一个事件发生,RXD上的唤醒事件不会被标记:
•TJA1043切换到普通模式
•在to(wake)总线中没有接收到完整的唤醒模式
•检测到VCC或VIO欠压
剩下的标志也不翻译了也不大能用上。。。。

二、S32K146 FLEXCAN SDK解读:
FlexCAN 模块是一个通信控制器,该模块实现了 CAN 协议即CAN2.0B 协议规范。 FlexCAN 模块的字模块,包括了用来存储消息缓冲的相关联的内存区域,Rx 全局掩码寄存器、Rx 私有掩码寄存器、Rx 先进先出队列以及 Rx 队列标识过滤器。消息缓冲区存储在一个专用于 FlexCAN 模块的 RAM 区,请求存取 RAM 接收和传输消息帧,验证接收到的消息以及进行错误处理。控制器主机接口子模块用来选择接收和传输的消息缓冲区,使用仲裁与 ID 匹配算法,以建立同 CPU 或者其他模块的连接。
模块特征

  1. 0 到 8
    字节长度报文缓冲区,每个报文缓冲区都可以配置成发送缓冲区或者接受缓冲区,支持标准和扩展帧格式,每个消息缓冲区都有自己的接受掩码控制寄存器
  2. 全功能的接受队列,该队列可以存储最多 6 个帧,并且自动进行内部指针处理,传输中止能力;可编程的 CAN 协议接口的时钟源,可以是总线时钟也可以是外部晶振;没有使用的结构空间可以当成普通的 RAM 空间使用;等其他特征。

操作模式

  1. 正常模式(用户与管理员) 在正常模式下,CAN 模块收发数据帧、处理错误,CAN协议的所有功能全部开启。对于一些控制比较严格的寄存器,在用户模式和管理员模式下访问时又区别的。
  2. 冻结模式
    如果 MCR 寄存器的 FRZ 位被置位,那么将开启 CAN 模块的冻结模式。当 MCR 的 HALT 位置位时或者在 MCU 级请求调试模式(Debug Mode)并且 MCR 寄存器的FRZ_ACK 位被置位时,CAN
    模块将进入到冻结模式。
  3. 监听模式
    当控制 1 寄存器的 LOM 位置位时,模块将进入到监听模式。在该模式下,CAN 模块禁止数据收发,所有的错误计数器都被冻结,且该模块工作在 CAN 被动错误模式。只有被其他 CAN节点应答了的报文才可以被监听的节点接受。如果 FlexCAN 检测到一个还没有被应答的报文,则标记为一个 BIT0 错误(不会改变 REC),将如同它试图应答报文一些样。
  4. 监听模式
    如果控制 1 寄存器的 LPB 位被置位,模块将进入到回环模式。在该模式下,FlexCAN 工作在内部闭环模式用于自测。从发送器发送出的比特流输出回内部的接收器输入。输入引脚将会被忽略,并且输出引脚将处于逻辑 1 状态。发送报文时,FlexCAN 模块和正常模式一样,而接收器则认为接受它自己的报文与接受远程节点的报文相同。FlexCAN 为保证能正确接受到自己发送的报文,将忽略应答间隙内的应答字段。报文接受发送时,如果中断使能则 FlexCAN 将向CPU 产生中断。
  5. 模块禁止模式
    当 MCR 寄存器的 MDIS 位被 CPU 置位并且 LPM_ACK 位被FlexCAN 模块置位时,模块将会进入该低功耗模式。如果模块被禁止,那么模块将会请求停止 CAN 协议引擎的时钟并且请求禁止控制器主机接口子模块。通过忽略 MCR 寄存器 MDIS 位可以退出该模式。有关该模块的更多信息参考“模块禁止模式”节。
  6. 睡眠模式
    当 MCR 寄存器的 DOZE 位被置位、在 MCU 级请求睡眠模式并且由 FlexCAN 置位 MCR 寄存器的 LPM_ACK 位时模块将进入到该低功耗模式。当模块处于睡眠模式时,FlexCAN 将会请求禁止CAN 协议引擎的时钟并且请求禁止 CAN 控制器主机接口子系统。当 MCR 寄存器的 DOZE 位被忽略(negated)、当 MCU 离开睡眠模式时或者当检测到 CAN 总线上有活动并且自醒机制开启时模块将退出睡眠模式。
  7. 停止模式
    在 MCU 级请求模式并且由 FlexCAN 模块置位 MCR 寄存器的 LPM_ACK 位时,模块将会进入到该低功耗模式。在停止模式中,模块将会将自己置于不活动状态,然后通知 CPU 可以关闭所有的时钟。当请求离开停止模式或者当检测到 CAN 总线上有或者并且开启了自醒即使时,FlexCAN将会退出该模式。

SDK函数分析(一)

//这个函数将为经典帧设置所有的时间段值,
//或者为FD帧的仲裁阶段设置扩展的时间段。
//这些时间段值由用户传入,并基于所需的波特率。
void FLEXCAN_DRV_SetBitrate(uint8_t instance, const flexcan_time_segment_t *bitrate)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);DEV_ASSERT(bitrate != NULL);CAN_Type * base = g_flexcanBase[instance];
#if FEATURE_CAN_HAS_FDbool fdEnabled = FLEXCAN_IsFDEnabled(base);
#endif
//只有在冻结模式下才能被写入,在其他模式下该位被硬件锁定FLEXCAN_EnterFreezeMode(base);#if FEATURE_CAN_HAS_FDif (fdEnabled){/* Set extended time segments*/FLEXCAN_SetExtendedTimeSegments(base, bitrate);}else
#endif{/* Set time segments*/FLEXCAN_SetTimeSegments(base, bitrate);}FLEXCAN_ExitFreezeMode(base);
}
//
static inline void FLEXCAN_SetTimeSegments(CAN_Type * base, const flexcan_time_segment_t *timeSeg)
{DEV_ASSERT(timeSeg != NULL);
//0bit 传播时间段 16-18bit 相位段2位时间长度 19-21 相位段1位时间长度
//31-24 bit 预分频器分频系数(base->CTRL1) = ((base->CTRL1) & ~((CAN_CTRL1_PROPSEG_MASK | CAN_CTRL1_PSEG2_MASK |CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PRESDIV_MASK) |CAN_CTRL1_RJW_MASK));(base->CTRL1) = ((base->CTRL1) | (CAN_CTRL1_PROPSEG(timeSeg->propSeg) |CAN_CTRL1_PSEG2(timeSeg->phaseSeg2) |CAN_CTRL1_PSEG1(timeSeg->phaseSeg1) |CAN_CTRL1_PRESDIV(timeSeg->preDivider) |CAN_CTRL1_RJW(timeSeg->rJumpwidth)));
}
//FLEXCAN进入冻结模式
void FLEXCAN_EnterFreezeMode(CAN_Type * base)
{bool enabled = false;//使能进入冻结模式base->MCR = (base->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(1U);//暂停FlexCAN模块base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U);
//判断是否关FLEXCAN模块if (((base->MCR & CAN_MCR_MDIS_MASK) >> CAN_MCR_MDIS_SHIFT) == 0U){enabled = true;}else{base->MCR &= ~CAN_MCR_MDIS_MASK;}//冻结模式确认位while (((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) == 0U) {}if (false == enabled){base->MCR |= CAN_MCR_MDIS_MASK;//是否进入低功耗while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 0U) {}}
}
//这个函数将返回经典帧或FD帧仲裁阶段的当前比特率设置。
void  FLEXCAN_DRV_GetBitrate(uint8_t instance, flexcan_time_segment_t *bitrate)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);DEV_ASSERT(bitrate != NULL);const CAN_Type * base = g_flexcanBase[instance];
#if FEATURE_CAN_HAS_FDif (true == FLEXCAN_IsFDEnabled(base)){/* Get the Extended time segments*/FLEXCAN_GetExtendedTimeSegments(base, bitrate);}else
#endif{/* Get the time segments*/FLEXCAN_GetTimeSegments(base, bitrate);}
}
//这个函数将返回经典帧或FD帧仲裁阶段的当前比特率设置
static inline void FLEXCAN_GetTimeSegments(const CAN_Type * base, flexcan_time_segment_t *timeSeg)
{DEV_ASSERT(timeSeg != NULL);
//得到刚才寄存器里面配置的值timeSeg->preDivider = ((base->CTRL1) & CAN_CTRL1_PRESDIV_MASK) >> CAN_CTRL1_PRESDIV_SHIFT;timeSeg->propSeg = ((base->CTRL1) & CAN_CTRL1_PROPSEG_MASK) >> CAN_CTRL1_PROPSEG_SHIFT;timeSeg->phaseSeg1 = ((base->CTRL1) & CAN_CTRL1_PSEG1_MASK) >> CAN_CTRL1_PSEG1_SHIFT;timeSeg->phaseSeg2 = ((base->CTRL1) & CAN_CTRL1_PSEG2_MASK) >> CAN_CTRL1_PSEG2_SHIFT;timeSeg->rJumpwidth = ((base->CTRL1) & CAN_CTRL1_RJW_MASK) >> CAN_CTRL1_RJW_SHIFT;
}
//关于FLEXCAN的SDK分成两层 上层:flexcan_driver.c 底层flexcan_access.c

SDK函数分析(二)


//Set RX masking type
//flexcan_rx_mask_type_t  分为全局/个人屏蔽
void  FLEXCAN_DRV_SetRxMaskType(uint8_t instance, flexcan_rx_mask_type_t type)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);CAN_Type * base = g_flexcanBase[instance];FLEXCAN_EnterFreezeMode(base);//上边分析了FLEXCAN_SetRxMaskType(base, type);FLEXCAN_ExitFreezeMode(base);//上边分析了
}
//判断是全局还是个人屏蔽
static inline void FLEXCAN_SetRxMaskType(CAN_Type * base, flexcan_rx_mask_type_t type)
{//关闭个别接收掩码和队列功能。if (type == FLEXCAN_RX_MASK_GLOBAL){base->MCR = (base->MCR & ~CAN_MCR_IRMQ_MASK) | CAN_MCR_IRMQ(0U);}else//开启个别接收掩码和队列功能。{base->MCR = (base->MCR & ~CAN_MCR_IRMQ_MASK) | CAN_MCR_IRMQ(1U);}
}//设置Rx FIFO全局掩码为11位标准掩码或29位扩展掩码
void FLEXCAN_DRV_SetRxFifoGlobalMask(uint8_t instance,flexcan_msgbuff_id_type_t id_type,uint32_t mask)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);//FLEXCAN_GetRxFifoIdFormat中两位用来定义接受队列过滤器表元素的格式// 格式A:每一个ID过滤表元素有一个全ID(标准的以及扩展的);//格式B:每一个ID过滤表元素都有两个全标准IDs或者两个14比特(标准的及扩展的)的IDs;//格式C:每一个过滤表元素有四个8比特标准IDs;//格式D:拒绝所有的帧flexcan_rx_fifo_id_element_format_t formatType;CAN_Type * base = g_flexcanBase[instance];uint32_t calcMask = 0U;FLEXCAN_EnterFreezeMode(base);//判断是否开启接收队列。该位用来控制是否开启接收队列if (true == FLEXCAN_IsRxFifoEnabled(base)){   //返回过滤器元素的格式formatType = FLEXCAN_GetRxFifoIdFormat(base);calcMask = FLEXCAN_GetRxFifoMask(id_type, formatType, mask);
//FLEXCAN_SetRxFifoGlobalMask设置接收队列 FIFO 全局掩码寄存器(CANx_RXFGMASK)该寄存器位于 RAM 区。
//如果接收 FIFO 队列被使能,RXFGMASK 被用来屏蔽接收队列 FIFO 过滤器表元素,
//这些表元素由于 CTRL2[RFEN]字段的设定并没有相应的 RXIMR。该寄存器只能在冻结模式下被写入,在其他模式下该字段被硬件锁定。switch (formatType){//FLEXCAN_SetRxFifoGlobalMask
//设置接收队列FIFO全局掩码位。这些比特位以完美对齐的方式用来屏蔽ID过滤器表元素case FLEXCAN_RX_FIFO_ID_FORMAT_A :FLEXCAN_SetRxFifoGlobalMask(base, calcMask);break;case FLEXCAN_RX_FIFO_ID_FORMAT_B :FLEXCAN_SetRxFifoGlobalMask(base, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1)));break;case FLEXCAN_RX_FIFO_ID_FORMAT_C :FLEXCAN_SetRxFifoGlobalMask(base, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1) |(calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2) |(calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3)));break;default :FLEXCAN_SetRxFifoGlobalMask(base, 0xFFFFFFFFU);break;}}FLEXCAN_ExitFreezeMode(base);
}
//设置邮箱全局掩码
void FLEXCAN_DRV_SetRxMbGlobalMask(uint8_t instance,flexcan_msgbuff_id_type_t id_type,uint32_t mask)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);CAN_Type * base = g_flexcanBase[instance];FLEXCAN_EnterFreezeMode(base);if (id_type == FLEXCAN_MSG_ID_STD){//设置接受邮箱全局掩码寄存器(CANx_RXMGMASK)FLEXCAN_SetRxMsgBuffGlobalStdMask(base, mask);}else if (id_type == FLEXCAN_MSG_ID_EXT){FLEXCAN_SetRxMsgBuffGlobalExtMask(base, mask);}else {}FLEXCAN_ExitFreezeMode(base);
}
//缓冲区14过滤字段提供掩码
void FLEXCAN_DRV_SetRxMb14Mask(uint8_t instance,flexcan_msgbuff_id_type_t id_type,uint32_t mask)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);CAN_Type * base = g_flexcanBase[instance];FLEXCAN_EnterFreezeMode(base);if (id_type == FLEXCAN_MSG_ID_STD){//提供该寄存器是为了对传统的支持。当 MCR[IRMQ]位被置位时,RX14MASK 无效。
//RX14MASK 用来给报文缓冲区 14 的过滤字段提供掩码。FLEXCAN_SetRxMsgBuff14StdMask(base, mask);}else if (id_type == FLEXCAN_MSG_ID_EXT){FLEXCAN_SetRxMsgBuff14ExtMask(base, mask);}else {}FLEXCAN_ExitFreezeMode(base);
}
//RX15MASK 用来给报文缓冲区 15 的过滤字段提供掩码。
void FLEXCAN_DRV_SetRxMb15Mask(uint8_t instance,flexcan_msgbuff_id_type_t id_type,uint32_t mask)
{//略同上
}
//设置个别掩码
status_t FLEXCAN_DRV_SetRxIndividualMask(uint8_t instance,flexcan_msgbuff_id_type_t id_type,uint8_t mb_idx,uint32_t mask)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);CAN_Type * base = g_flexcanBase[instance];FLEXCAN_EnterFreezeMode(base);
//MAXMB最大报文缓冲区个数if ((mb_idx > FLEXCAN_GetMaxMsgBuffNum(base)) || (mb_idx >= CAN_RXIMR_COUNT)){FLEXCAN_ExitFreezeMode(base);return STATUS_CAN_BUFF_OUT_OF_RANGE;}
//开启接收队列if (false == FLEXCAN_IsRxFifoEnabled(base)){//标准帧if (id_type == FLEXCAN_MSG_ID_STD){//设置接收私有掩码寄存器FLEXCAN_SetRxIndividualStdMask(base, mb_idx, mask);}else if (id_type == FLEXCAN_MSG_ID_EXT){//设置接收私有掩码寄存器FLEXCAN_SetRxIndividualExtMask(base, mb_idx, mask);}else{}}else{//单个掩码配置的最大过滤器是(7 + RFFN * 2)if (mb_idx <= FLEXCAN_GetNoOfIndividualMBsRxFIFO(base)){//返回过滤器元素的格式flexcan_rx_fifo_id_element_format_t formatType = FLEXCAN_GetRxFifoIdFormat(base);
//以FIFO模式的格式ID类型计算全局掩码uint32_t calcMask = FLEXCAN_GetRxFifoMask(id_type, formatType, mask);switch (formatType){case FLEXCAN_RX_FIFO_ID_FORMAT_A :FLEXCAN_SetRxIndividualMask(base, mb_idx, calcMask);//设置接收私有掩码寄存器,以FIFO模式的格式ID类型计算全局掩码break;case FLEXCAN_RX_FIFO_ID_FORMAT_B :FLEXCAN_SetRxIndividualMask(base, mb_idx, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATB_EXT_SHIFT1)));break;case FLEXCAN_RX_FIFO_ID_FORMAT_C :FLEXCAN_SetRxIndividualMask(base, mb_idx, (calcMask | (calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT1) |(calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT2) |(calcMask >> FLEXCAN_RX_FIFO_ID_FILTER_FORMATC_SHIFT3)));break;default :FLEXCAN_SetRxIndividualMask(base, mb_idx, 0xFFFFFFFFU);break;}}else{if (id_type == FLEXCAN_MSG_ID_STD){FLEXCAN_SetRxIndividualStdMask(base, mb_idx, mask);}else if (id_type == FLEXCAN_MSG_ID_EXT){FLEXCAN_SetRxIndividualExtMask(base, mb_idx, mask);}else{}}}FLEXCAN_ExitFreezeMode(base);return STATUS_SUCCESS;
}

SDK函数分析(三)

//flexcan初始化
status_t FLEXCAN_DRV_Init(uint8_t instance,flexcan_state_t *state,const flexcan_user_config_t *data)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);DEV_ASSERT(state != NULL);DEV_ASSERT(g_flexcanStatePtr[instance] == NULL);status_t result;CAN_Type * base = g_flexcanBase[instance];flexcan_time_segment_t bitrate;status_t osifStat;uint32_t i, j;if(FLEXCAN_IsEnabled(base)){FLEXCAN_EnterFreezeMode(base);FLEXCAN_Disable(base);}
//CAN引擎时钟源。CTRL1 13BIT 该位用来为CAN协议引擎(PE)选择时钟源,
//可以是设备外设时钟(有PLL驱动)也可以是外部晶体振荡器时钟。
#if FEATURE_CAN_HAS_PE_CLKSRC_SELECTFLEXCAN_SelectClock(base, data->pe_clock);
#endif/* Enable the CAN clock */FLEXCAN_Enable(base);FLEXCAN_EnterFreezeMode(base);//初始化 1.复位 2.中止传输 3.清空RAM 4.寄存器重置//5.状态与错误寄存器initFLEXCAN_Init(base);
#if FEATURE_CAN_HAS_FDFLEXCAN_SetFDEnabled(base, data->fd_enable);if (FLEXCAN_IsFDEnabled(base) != data->fd_enable){return STATUS_ERROR;}//flexcan_user_config_t配置FD是否使能FLEXCAN_SetStuffBitCount(base, data->fd_enable);
#endif
//不是回环模式if (data->flexcanMode != FLEXCAN_LOOPBACK_MODE){//MCR->SRXDIS使能自接受FLEXCAN_SetSelfReception(base, false);}if (data->is_rx_fifo_needed){//使能循环队列 1.mcr->rfen 2.CTRL->RFEN接收队列FIFO过滤器的数目//3.设置接受队列全局掩码寄存器(RXFGMASK)//4.接收私有掩码寄存器RXIMRresult = FLEXCAN_EnableRxFifo(base, (uint32_t)data->num_id_filters);if (result != STATUS_SUCCESS){return result;}}
#if FEATURE_CAN_HAS_DMA_ENABLE/* Enable DMA support for RxFIFO transfer, if requested. */if (data->transfer_type == FLEXCAN_RXFIFO_USING_DMA){if (FLEXCAN_IsRxFifoEnabled(base)){FLEXCAN_SetRxFifoDMA(base, true);}else{return STATUS_ERROR;}}if (data->transfer_type == FLEXCAN_RXFIFO_USING_INTERRUPTS){FLEXCAN_SetRxFifoDMA(base, false);}
#endif#if FEATURE_CAN_HAS_FD
//这个寄存器包含CAN FD操作的控制位。
// 它还定义了分配在RAM(内存块)的不同分区中的消息缓冲区的数据大小,如下表所示。FLEXCAN_SetPayloadSize(base, data->payload);
#endif
//设置缓冲区数量result = FLEXCAN_SetMaxMsgBuffNum(base, data->max_num_mb);if (result != STATUS_SUCCESS){return result;}#if FEATURE_CAN_HAS_FDif (FLEXCAN_IsFDEnabled(base)){bitrate = data->bitrate;FLEXCAN_SetExtendedTimeSegments(base, &bitrate);bitrate = data->bitrate_cbt;FLEXCAN_SetFDTimeSegments(base, &bitrate);}else
#endif{bitrate = data->bitrate;FLEXCAN_SetTimeSegments(base, &bitrate);}FLEXCAN_SetOperationMode(base, data->flexcanMode);if (data->flexcanMode != FLEXCAN_FREEZE_MODE){FLEXCAN_ExitFreezeMode(base);}FLEXCAN_EnableIRQs(instance);for (i = 0; i < FEATURE_CAN_MAX_MB_NUM; i++){osifStat = OSIF_SemaCreate(&state->mbs[i].mbSema, 0U);if (osifStat != STATUS_SUCCESS){for (j = 0; j < i; j++){(void)OSIF_SemaDestroy(&state->mbs[j].mbSema);}return STATUS_ERROR;}state->mbs[i].isBlocking = false;state->mbs[i].mb_message = NULL;state->mbs[i].state = FLEXCAN_MB_IDLE;}
#if FEATURE_CAN_HAS_MEM_ERR_DETFLEXCAN_DisableMemErrorDetection(base);
#endifstate->transferType = data->transfer_type;
#if FEATURE_CAN_HAS_DMA_ENABLEstate->rxFifoDMAChannel = data->rxFifoDMAChannel;
#endifstate->callback = NULL;state->callbackParam = NULL;state->error_callback = NULL;state->errorCallbackParam = NULL;g_flexcanStatePtr[instance] = state;return (STATUS_SUCCESS);
}

SDK函数分析(四)

//发送mb cofig
status_t FLEXCAN_DRV_ConfigTxMb(uint8_t instance,uint8_t mb_idx,const flexcan_data_info_t *tx_info,uint32_t msg_id)
{DEV_ASSERT(instance < CAN_INSTANCE_COUNT);DEV_ASSERT(tx_info != NULL);flexcan_msgbuff_code_status_t cs;CAN_Type * base = g_flexcanBase[instance];//这个没啥说的就是赋值cs.dataLen = tx_info->data_length;cs.msgIdType = tx_info->msg_id_type;
#if FEATURE_CAN_HAS_FDcs.enable_brs = tx_info->enable_brs;cs.fd_enable = tx_info->fd_enable;cs.fd_padding = tx_info->fd_padding;
#endifcs.code = (uint32_t)FLEXCAN_TX_INACTIVE;//下边解释return FLEXCAN_SetTxMsgBuff(base, mb_idx, &cs, msg_id, NULL);
}
//设置flexcan 发送msg buff
status_t FLEXCAN_SetTxMsgBuff(CAN_Type * base,uint32_t msgBuffIdx,const flexcan_msgbuff_code_status_t *cs,uint32_t msgId,const uint8_t *msgData)
{DEV_ASSERT(cs != NULL);uint32_t val1, val2 = 1;uint32_t flexcan_mb_config = 0;uint32_t databyte;uint8_t dlc_value;status_t stat = STATUS_SUCCESS;
//这个函数多墨迹几句在四的结尾处volatile uint32_t *flexcan_mb = FLEXCAN_GetMsgBuffRegion(base, msgBuffIdx);
//拿到刚才给的地址 指针指向volatile uint32_t *flexcan_mb_id   = &flexcan_mb[1];volatile uint8_t  *flexcan_mb_data = (volatile uint8_t *)(&flexcan_mb[2]);volatile uint32_t *flexcan_mb_data_32 = &flexcan_mb[2];const uint32_t *msgData_32 = (const uint32_t *)msgData;
//最大缓冲区的个数if (msgBuffIdx > (((base->MCR) & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT) ){stat = STATUS_CAN_BUFF_OUT_OF_RANGE;}if (((base->MCR & CAN_MCR_RFEN_MASK) >> CAN_MCR_RFEN_SHIFT) != 0U){//这几句解释起来真烦//这个CTRL2寄存器的27-24(RFEN)//这4位用来定义了下表中所示的接收队列过滤器的数目//过滤器使用的越多,满足条件的邮箱越少//eg:RFEN=01 消息邮箱 MB8-63 val1=0x01val1 = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);//val2 = 9val2 = RxFifoOcuppiedLastMsgBuff(val1);//为啥现在我也不知道。。。脑子不够用了,搞不动了if (msgBuffIdx <= val2) {stat =  STATUS_CAN_BUFF_OUT_OF_RANGE;}}if (stat == STATUS_SUCCESS){#if FEATURE_CAN_HAS_FDif (FLEXCAN_IsFDEnabled(base) && cs->enable_brs){base->FDCTRL = (base->FDCTRL & ~CAN_FDCTRL_FDRATE_MASK) | CAN_FDCTRL_FDRATE(1U);}DEV_ASSERT((uint8_t)cs->dataLen <= FLEXCAN_GetPayloadSize(base));
#elseDEV_ASSERT((uint8_t)cs->dataLen <= 8U);
#endifdlc_value = FLEXCAN_ComputeDLCValue((uint8_t)cs->dataLen);if (msgData != NULL){uint8_t payload_size = FLEXCAN_ComputePayloadSize(dlc_value);#if (defined(CPU_S32K116) || defined(CPU_S32K118))(void) msgData_32;databyte = FLEXCAN_DataTransferTxMsgBuff( flexcan_mb_data_32, cs, msgData);
#elsefor (databyte = 0; databyte < (cs->dataLen & ~3U); databyte += 4U){FlexcanSwapBytesInWord(msgData_32[databyte >> 2U], flexcan_mb_data_32[databyte >> 2U]);}
#endiffor ( ; databyte < cs->dataLen; databyte++){flexcan_mb_data[FlexcanSwapBytesInWordIndex(databyte)] =  msgData[databyte];}/* Add padding, if needed */for (databyte = cs->dataLen; databyte < payload_size; databyte++){flexcan_mb_data[FlexcanSwapBytesInWordIndex(databyte)] = cs->fd_padding;}}/* Clean up the arbitration field area */*flexcan_mb = 0;*flexcan_mb_id = 0;/* Set the ID according the format structure */if (cs->msgIdType == FLEXCAN_MSG_ID_EXT){/* ID [28-0] */*flexcan_mb_id &= ~(CAN_ID_STD_MASK | CAN_ID_EXT_MASK);*flexcan_mb_id |= (msgId & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK));/* Set IDE */flexcan_mb_config |= CAN_CS_IDE_MASK;/* Clear SRR bit */flexcan_mb_config &= ~CAN_CS_SRR_MASK;}if(cs->msgIdType == FLEXCAN_MSG_ID_STD){/* ID[28-18] */*flexcan_mb_id &= ~CAN_ID_STD_MASK;*flexcan_mb_id |= (msgId << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;/* make sure IDE and SRR are not set */flexcan_mb_config &= ~(CAN_CS_IDE_MASK | CAN_CS_SRR_MASK);}/* Set the length of data in bytes */flexcan_mb_config &= ~CAN_CS_DLC_MASK;flexcan_mb_config |= ((uint32_t)dlc_value << CAN_CS_DLC_SHIFT) & CAN_CS_DLC_MASK;/* Set MB CODE */if (cs->code != (uint32_t)FLEXCAN_TX_NOT_USED){if (cs->code == (uint32_t)FLEXCAN_TX_REMOTE){/* Set RTR bit */flexcan_mb_config |= CAN_CS_RTR_MASK;}/* Reset the code */flexcan_mb_config &= ~CAN_CS_CODE_MASK;/* Set the code */if (cs->fd_enable){flexcan_mb_config |= ((cs->code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK) | CAN_MB_EDL_MASK;}else{flexcan_mb_config |= (cs->code << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;}if (cs->enable_brs){flexcan_mb_config |= CAN_MB_BRS_MASK;}*flexcan_mb |= flexcan_mb_config;}}return stat;
}
//根据msgBuffIdx返回地址
volatile uint32_t* FLEXCAN_GetMsgBuffRegion(CAN_Type * base,uint32_t msgBuffIdx)
{#if FEATURE_CAN_HAS_FDuint8_t payload_size = FLEXCAN_GetPayloadSize(base);
#elseuint8_t payload_size = 8U;
#endifuint8_t arbitration_field_size = 8U;
//#define CAN_RAMn_COUNT                           128u
//typedef struct
//{// __IO uint32_t RAMn[CAN_RAMn_COUNT]; array offset: 0x80,
//} CAN_Type, *CAN_MemMapPtr;
//根据上边这几句所以uint32_t ramBlockSize = 512U;uint32_t ramBlockSize = 512U;uint32_t ramBlockOffset;//一个MB的大小uint8_t mb_size = (uint8_t)(payload_size + arbitration_field_size);//按这个算最大的mb个数uint8_t maxMbNum = (uint8_t)(ramBlockSize / mb_size);//偏移 eg msgBuffIdx =1 ramBlockOffset =0ramBlockOffset = 128U * (msgBuffIdx / (uint32_t)maxMbNum);//在这块ram中索引=0+1*16/4=4uint32_t mb_index = ramBlockOffset + ((msgBuffIdx % (uint32_t)maxMbNum) * ((uint32_t)mb_size >> 2U));return &(base->RAMn[mb_index]);
}
//最大512个字节 根据mb_size算一共有几个偏移多少返回地址

初始化需要的SDK函数

static void Can0Init(void)
{//TJA1043 EN STB 全部使能高电平进入正常收发状态hal_mcu_can_modeset();FLEXCAN_DRV_Init(INST_CANCOM0, &canCom0_State, &canCom0_InitConfig0);FLEXCAN_DRV_ConfigRxMb(INST_CANCOM0, RX_MAILBOX_0, &data_std_info, 0x87);FLEXCAN_DRV_ConfigTxMb(INST_CANCOM0, 1, &data_std_info, 0x228);FLEXCAN_DRV_InstallEventCallback(INST_CANCOM0, canRxCallback, NULL);FLEXCAN_DRV_Receive(INST_CANCOM0, RX_MAILBOX_0, &recvMsg0);
}
//CALLBACK 发什么回什么
void canRxCallback(uint8_t instance, flexcan_event_type_t eventType,uint32_t buffIdx, flexcan_state_t *flexcanState) {if(eventType == FLEXCAN_EVENT_RX_COMPLETE){FLEXCAN_DRV_Receive(INST_CANCOM0, RX_MAILBOX_0, &recvMsg0);FLEXCAN_DRV_Send(INST_CANCOM0, TX_MAILBOX_0 , &data_std_info , recvMsg0.msgId, recvMsg0.data);}
}


接下来搞一下掩码FIFO
NXP S32K146 CAN通讯 TJA1043(二)

NXP S32K146 CAN通讯 TJA1043(一)相关推荐

  1. NXP S32K146 FLEXI2C底层驱动+IAM-20680(二)

    NXP S32K146 FLEXI2C底层驱动+IAM-20680(一) 在上一篇文章的基础上,写IAM-20680的接口层,与上一篇差不多,os任务中分为初始化与正常运行,下面根据IAM-30680 ...

  2. NXP S32K146 打印LOG函数分析

    最近从STM32换成NXP的S32K1平台做项目,从读手册调外设驱动开始,关于外设驱动是怎么调的,我用的软件是S32 Design Studio for ARM Version 2.2 在官网下载的, ...

  3. 【WLAN】【软件】NXP芯片方案用户态和内核态通讯方式小结

    一.前言 之前已经撰文阐述过mtk芯片方案的用户态和内核态通讯方式,实际上这些方式并非mtk芯片方案所特用,其他芯片方案也是可以使用的. 本文将以NXP方案常用的方式作一总结,以对之前mtk方案常用的 ...

  4. tms570 can 接收大量数据_CAN通讯系列--CAN总线基础3

    上篇文章讲述了CAN总线的特点,以及CAN协议帧的基础知识,包括数据帧和遥控帧.本文将在此基础上通过相关的协议标准,寄存器和整车控制器CAN通信报文来进一步深化CAN协议帧的理解,同时可了解到一个简单 ...

  5. 多核处理器_基于NXP i.MX8MM多核应用处理器设计的智能加油机

    随着近几年信息技术的不断发展,智能化的概念逐渐渗透到各行各业以及我们的生活里,智能化.自助设备随处可见.在人来人往.车来车往的城市建设中,节省时间.免去排队百脸茫然.一脸懵圈的痛苦过程成为智能设备发展 ...

  6. NXP(I.MX6uLL) UART串口通信原理————这个未复习

    参考:Linux NXP (I.MX6uLL) UART串口通信原理 作者:一只青木呀 发布时间: 2020-09-20 16:48:33 网址:https://blog.csdn.net/weixi ...

  7. 2个相同的 stm32 can通讯不成功_一文读懂,基于 STM32 和 CAN 总线的温度监控系统的设计方法...

    1 系统总体方案概述 系统总体框图如图 1 所示,本系统采用主站+从站的结构,CAN 主站主要实现温度数据的存储以及 CAN 总线协议和串口协议之间的桥接,CAN 从站主要实现温度的采集.CAN 从站 ...

  8. 嵌入式Linux开发8——UART串口通讯

    1. 背景知识 1.1 UART通讯格式   串口全称叫做串行接口,通常也叫做 COM 接口,串行接口指的是数据一个一个的顺序传输,通信线路简单.使用两条线即可实现双向通信,一条用于发送,一条用于接收 ...

  9. 2022 极术通讯-安谋科技纷争尘埃落定,本土半导体产业基石更稳

    导读:极术通讯引入行业媒体和技术社区.咨询机构优质内容,定期分享产业技术趋势与市场应用热点 芯方向 • 基于TencentOS Tiny AIoT开发板.腾讯连连小程序的智能轮椅远程感知与控制 本文是 ...

  10. TJA1043 CanTrcv

    NXP TJA1043 CAN收发器整理 一. 硬件引脚图 二. 模式状态机 2.1 五种工作模式 (1)NORMAL MODE:EN = H .STB_N = H:(硬件初始化时STB_N :L-& ...

最新文章

  1. Ruby on Rails: 使用devise+cancan+rolify建立完整的权限管理系
  2. 多线程编程2 - NSOperation
  3. 数据结构课程设计(VS2012-c语言):算术表达式实现(加减乘除)
  4. ANSYS——“There is at least 1 small equation solver pivot term”问题的解决办法
  5. Acess 数据库 查询数据表结构等问题小记
  6. 麻雀虽小五脏俱全的Vue拉勾项目,看看应该有帮助
  7. 【Elasticsearch】java 操作 Elasticsearch 7.8 索引 文档 等操作
  8. tomcat运行模式(bio,aio,apr)
  9. mybaties中的selectKey和useGeneratedKeys=true
  10. Linux测网速工具,Linux中上下行网速测试工具 speedtest-cli
  11. 小米5USB 计算机连接,小米手机连接电脑不显示usb选项
  12. vue父与子组件,子与子组件间的方法调用和通信
  13. 计算机组装方案i5,3000元预算方案i5 8400/GTX1050Ti装配配置清单推荐
  14. 互联网大厂面试必问的JVM底层原理,美团阿里Java程序员晒工资被围观
  15. 软件测试基础理论-测试用例
  16. tensorflow笔记:tf.argmax()和tf.equal()的使用
  17. 数加加众包:奔驰“哭诉维权”美女硕士,你“不要脸”的样子真的很美
  18. Scrum框架详解总结
  19. 【有趣的Python小程序】Python多个简单上手的库制作WalkLattice 走格子游戏 (思路篇)上
  20. 乱码形成原因及其消除方法大全

热门文章

  1. Python构造树结构应用到城市层级编码
  2. linux移动到回收站快捷键,linux中使用rm命令将文件移到回收站的方法
  3. 数据结构 与游戏背包的设计
  4. python数据分析培训南京_基于Python的南京二手房数据可视化分析
  5. Photoshop技巧
  6. linux局域网互传文件(使用scp)
  7. 电脑没有声音(未安装任何音频输出设备)解决方案
  8. ajax传参无法传中文,IE浏览器 ajax传参数值为中文时出现乱码的解决方案
  9. cmd怎么查看当前静态路由_怎么使用cmd设置添加电脑上静态路由
  10. 【笔记】2022.06.20 python数据分析三大神器numpy、pandas、matplotlib