赞
踩
今天来调一下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 或者其他模块的连接。
模块特征:
操作模式
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_FD bool fdEnabled = FLEXCAN_IsFDEnabled(base); #endif //只有在冻结模式下才能被写入,在其他模式下该位被硬件锁定 FLEXCAN_EnterFreezeMode(base); #if FEATURE_CAN_HAS_FD if (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_FD if (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_SELECT FLEXCAN_SelectClock(base, data->pe_clock); #endif /* Enable the CAN clock */ FLEXCAN_Enable(base); FLEXCAN_EnterFreezeMode(base); //初始化 1.复位 2.中止传输 3.清空RAM 4.寄存器重置 //5.状态与错误寄存器init FLEXCAN_Init(base); #if FEATURE_CAN_HAS_FD FLEXCAN_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.接收私有掩码寄存器RXIMR result = 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_FD if (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_DET FLEXCAN_DisableMemErrorDetection(base); #endif state->transferType = data->transfer_type; #if FEATURE_CAN_HAS_DMA_ENABLE state->rxFifoDMAChannel = data->rxFifoDMAChannel; #endif state->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_FD cs.enable_brs = tx_info->enable_brs; cs.fd_enable = tx_info->fd_enable; cs.fd_padding = tx_info->fd_padding; #endif cs.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=0x01 val1 = (((base->CTRL2) & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT); //val2 = 9 val2 = RxFifoOcuppiedLastMsgBuff(val1); //为啥现在我也不知道。。。脑子不够用了,搞不动了 if (msgBuffIdx <= val2) { stat = STATUS_CAN_BUFF_OUT_OF_RANGE; } } if (stat == STATUS_SUCCESS) { #if FEATURE_CAN_HAS_FD if (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)); #else DEV_ASSERT((uint8_t)cs->dataLen <= 8U); #endif dlc_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); #else for (databyte = 0; databyte < (cs->dataLen & ~3U); databyte += 4U) { FlexcanSwapBytesInWord(msgData_32[databyte >> 2U], flexcan_mb_data_32[databyte >> 2U]); } #endif for ( ; 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_FD uint8_t payload_size = FLEXCAN_GetPayloadSize(base); #else uint8_t payload_size = 8U; #endif uint8_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 =0 ramBlockOffset = 128U * (msgBuffIdx / (uint32_t)maxMbNum); //在这块ram中索引=0+1*16/4=4 uint32_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(二)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。