查看: 7645|回复: 15

[已解决] k61 CAN模块的使用(已解决)

[复制链接]

该用户从未签到

6

主题

27

帖子

0

注册会员

Rank: 2

积分
77
最后登录
1970-1-1
发表于 2014-1-8 14:12:21 | 显示全部楼层 |阅读模式
 1. 最近在做K61的CAN驱动,但是不能正常工作。我的做法是,在外挂节点测试发送的时候,在can的CAN_Init函数就会进入到严重硬件错误中。代码如下:
 
void LPLD_CAN_Init(CAN_InitTypeDef can_init_structure)
{
  uint8 i;
  CAN_MemMapPtr canx = can_init_structure.CAN_Canx;
  uint32 baud = can_init_structure.CAN_BaudRate;
  uint8  mask_mode = can_init_structure.CAN_RxMaskMode;
  PortPinsEnum_Type tx_pin = can_init_structure.CAN_TxPin;
  PortPinsEnum_Type rx_pin = can_init_structure.CAN_RxPin;
    
  OSC_CR |= OSC_CR_ERCLKEN_MASK | OSC_CR_EREFSTEN_MASK;
  
  if(canx == CAN0_BASE_PTR)
    SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0_MASK;
  else
    SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1_MASK;
  
  if(canx == CAN0_BASE_PTR)
  {
          if(tx_pin == PTF0)//CAN0_TX
    {
      PORTF_PCR0 = PORT_PCR_MUX(2); 
    }
    else if(tx_pin == PTB18)
    {
      PORTB_PCR18 = PORT_PCR_MUX(2); 
    }
    else
    {
      PORTA_PCR12 = PORT_PCR_MUX(2); 
    }
 
        if (rx_pin == PTF1)//CAN0_RX
        {
          PORTF_PCR1 = PORT_PCR_MUX(2); 
        }
    else if(rx_pin == PTB19)//CAN0_RX
    {
      PORTB_PCR19 = PORT_PCR_MUX(2); 
    }
    else
    {
      PORTA_PCR13 = PORT_PCR_MUX(2); 
    }
  }
  else
  {
          if(tx_pin == PTF25)//CAN1_TX
    {
          PORTF_PCR25 = PORT_PCR_MUX(2); 
          }
    else if(tx_pin == PTC17)
    {
      PORTC_PCR17 = PORT_PCR_MUX(2); 
    }
    else
    {
      PORTE_PCR24 = PORT_PCR_MUX(2);
    }
 
        if(rx_pin == PTF24)//CAN1_RX
    {
      PORTF_PCR24 = PORT_PCR_MUX(2); 
        }
    else if(rx_pin == PTC16)
    {
      PORTC_PCR16 = PORT_PCR_MUX(2); 
    }
    else
    {
      PORTE_PCR25 = PORT_PCR_MUX(2);
    }
  }          
  //禁止CAN外设
  //canx->MCR   |= CAN_MCR_MDIS_MASK;
  //只有在LPM_ACK = 1情况下才可以选择钟源
  canx->CTRL1 |= CAN_CTRL1_CLKSRC_MASK;  //选择peripheral clock作为CAN外设的时钟源
                                         //设置此位必须在CAN停止模式下
  //在时钟初始化完毕和CAN总线使能完毕后,
  //单片机自动进入冻结模式
  //只有在冻结模式下才能配置大多数CAN总线寄存器
  //使能冻结模式
  canx->MCR |= CAN_MCR_HALT_MASK; 
  canx->MCR |= CAN_MCR_FRZ_MASK;
  canx->MCR &= ~CAN_MCR_MDIS_MASK; 
  
  while(!(canx->MCR & CAN_MCR_LPMACK_MASK));       
 
  //进行软件复位
  canx->MCR ^= CAN_MCR_SOFTRST_MASK;
  while(canx->MCR & CAN_MCR_SOFTRST_MASK);
            
  //等待进入冻结模式 
  while(!(canx->MCR & CAN_MCR_FRZACK_MASK));
  
  if(mask_mode == CAN_MSGOBJ_GLOBAL_MASKING)
  {
    canx->MCR &= ~CAN_MCR_IRMQ_MASK;   //使能全局匹配寄存器禁止单独匹配 
  }
  else
  {
    canx->MCR |= CAN_MCR_IRMQ_MASK;   //使能Msg单独匹配 
  }
  
  canx->MCR |= CAN_MCR_SUPV_MASK ;   //设置成管理模式 
  canx->MCR |= CAN_MCR_SRXDIS_MASK ; //禁止自我接收
  canx->MCR &= ~CAN_MCR_WRNEN_MASK;  //不产生警告中断
  canx->MCR &= ~CAN_MCR_RFEN_MASK ;  //禁止接收FIFO
  canx->MCR &= ~CAN_MCR_AEN_MASK;    //禁止Abort
  canx->MCR &= ~CAN_MCR_LPRIOEN_MASK;//禁止本地优先
  
  //配置相关的寄存器
  canx->CTRL2 |= CAN_CTRL2_EACEN_MASK; //接收邮箱过滤IDE匹配,RTR不匹配
  canx->CTRL2 &= ~CAN_CTRL2_RRS_MASK;  //不自动产生远程请求帧产生
  canx->CTRL2 |= CAN_CTRL2_MRP_MASK;   //ID首先从邮箱中匹配
 
  //canx->CTRL1 |= CAN_CTRL1_LBUF_MASK;  //发送的时候从低Msg开始
  canx->CTRL1 &= ~CAN_CTRL1_LBUF_MASK;   //发送的时候从低优先级发送
                             
  //canx->CTRL1 |= CAN_CTRL1_LPB_MASK;  //loop 模式,用于测试
  canx->CTRL1 &= ~CAN_CTRL1_LPB_MASK;   //使用正常模式
  //设置CAN总线通信的波特率
  LPLD_CAN_SetBaudRate(canx,baud);
  //清空CAN自由计数器 
  canx->TIMER = 0x0000; 
  //将MB_MAX个邮箱缓冲区内容清0
  for(i = 0;i < MSG_MAX_NO; i++)
  {
    canx->MB.CS    = 0x00000000;
    canx->MB.ID    = 0x00000000;
    canx->MB.WORD0 = 0x00000000;
    canx->MB.WORD1 = 0x00000000;        
  }
  //清除64个邮箱的标志位
  //canx->IFLAG1 = 0xFFFFFFFF;
  //canx->IFLAG2 = 0xFFFFFFFF;
  //禁止邮箱中断
  //canx->IMASK1 = 0x00000000;
  //canx->IMASK2 = 0x00000000;
   /*
  如果MCR的IRMQ为1,表示每个邮箱都可以单独进行ID匹配
  注意:如果是low cost MCUs(低配置的MCU),没有单独匹配这项功能。
          1\ID匹配会选择free to receive状态的邮箱作为胜者,
          获胜的邮箱可以从接收缓冲区内将接收的帧 Move in 到MB中;
          2\如果出现ID号相同的邮箱,会首先从序号低的邮箱进行匹配,如果
          低序号邮箱是non free to receive状态,那么匹配过程将会查找
          下一个邮箱直到找到free to receive状态且ID相同的邮箱;
          3\如果ID号相同的邮箱都处于non free to receive状态,那么匹配过程
          将停止在最后一个有相同ID的邮箱位置,将帧Move in 到MB中并且将该邮
          箱的状态设置成OVERRUN。
          RXIMR存储在单片机的RAM中,只有在CAN冻结模式下可写。
          此时CANx_RXMGMASK、CANx_RX14MASK、CANx_RX15MASK不起作用
  */
 
  for(i = 0;i < MSG_MAX_NO; i++)
  {
    canx->RXIMR = 0x1FFFFFFF;//设置邮箱29位全部屏蔽
  }
 /*
  如果MCR的IRMQ为0,表示使用全局匹配寄存器进行匹配,
          此时CANx_RXMGMASK、CANx_RX14MASK、CANx_RX15MASK起作用;
          CANx_RXMGMASK管理除CANx_RX14MASK、CANx_RX15MASK以外的所有Msg;
          ID匹配过程会停止在找到的第一个ID相同的邮箱位置,不管该邮箱是否处于
          free to receive状态。
  */
 
  canx->RXMGMASK = 0x1FFFFFFF; //29位ID全部匹配            
  canx->RX14MASK = 0x1FFFFFFF;
  canx->RX15MASK = 0x1FFFFFFF; 
 
  canx->MCR &= ~CAN_MCR_FRZ_MASK; //退出冻结模式
  //等待直到退出冻结模式
  while( canx->MCR & CAN_MCR_FRZACK_MASK); 
  //只有在冻结模式下才能配置,配置完推出冻结模式
  canx->MCR &= ~(CAN_MCR_HALT_MASK); 
  //等到不在冻结模式,休眠模式或者停止模式
  while( canx->MCR & CAN_MCR_NOTRDY_MASK);
  //使能CAN外设
  canx->MCR &= ~CAN_MCR_MDIS_MASK;
}
以上是拉普兰德公司的驱动,因为我使用的是k61所以做了部分修改,就是在管脚设置那里。中间的
 
  //清除64个邮箱的标志位
  //canx->IFLAG1 = 0xFFFFFFFF;
  //canx->IFLAG2 = 0xFFFFFFFF;
  //禁止邮箱中断
  //canx->IMASK1 = 0x00000000;
  //canx->IMASK2 = 0x00000000;
这几句如果不去掉会进入严重错误中断。但我不明白为什么。
 
2.我有点不明白CAN0_IMASK1,CAN0_IMASK2的作用。CAN0模块一共只有16个message buffer,那么为何要用CAN0_IMASK1和CAN0_IMASK2两个寄存器呢。
3.我调用发送函数进行发送,发现之后CS的状态一直是0b1100,无法变为为0b1000。我觉得就是未执行发送。但是这时候自由运行定时器(CAN0_TIMER)一直在跑,应该模块是工作了。我的发送函数如下:
 
uint8 LPLD_CAN_TransmitMessage(CAN_MSGOBJ_InitTypeDef can_msg_init_structure, CAN_MessageFormat_TypeDef *can_tx_msg )
{
  uint8  request;
  uint8  msg_num_temp  = can_msg_init_structure.CAN_MsgNum;
  CAN_MemMapPtr canx_ptr   = can_msg_init_structure.CAN_Canx;
  uint32  message_id = can_tx_msg->CAN_MsgID;  
  uint8  *in_data_buffer = can_tx_msg->CAN_MsgDataBuffer;
  uint8   in_data_length = can_tx_msg->CAN_MsgDataLength;
  //如果发送Msg缓冲区中的CODE不等于CAN_MSGOBJ_TX_UNCONDITIONAL
  if( LPLD_CAN_GetMsgCode(canx_ptr,msg_num_temp) != CAN_MSGOBJ_TX_UNCONDITIONAL)
  {
    //向发送Msg缓冲区中的CODE中写INACTIVE命令
    canx_ptr->MB[msg_num_temp].CS |= CAN_MB_CS_CODE(CAN_MSGOBJ_TX_INACTIVE);
    //设置Msg的ID
    LPLD_CAN_SetMsgID(canx_ptr,msg_num_temp,message_id);
    //向Msg中写入要发送的数据
    LPLD_CAN_WriteData(canx_ptr,msg_num_temp,in_data_length,in_data_buffer);
    //设置Msg的长度
    LPLD_CAN_SetMsgLength(canx_ptr,msg_num_temp,in_data_length);
    //向发送Msg缓冲区中的CODE中写TX_UNCONDITIONAL命令,等待发送完成
    canx_ptr->MB[msg_num_temp].CS |= CAN_MB_CS_CODE(CAN_MSGOBJ_TX_UNCONDITIONAL);
    //如果开启发送中断,发送完毕后会触发中断
    request = 1;
  }
  else
  {
    request = 0;
  }
  return (request);
}
 
 
 
 
我知道答案 目前已有15人回答
回复

使用道具 举报

  • TA的每日心情
    难过
    2021-12-15 16:01
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    305

    主题

    4701

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    377
    最后登录
    2023-8-16
    发表于 2014-1-8 15:42:12 | 显示全部楼层

    RE:k61 CAN模块的使用

    单步仿真到哪儿会产生硬件错误中断?
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    6

    主题

    27

    帖子

    0

    注册会员

    Rank: 2

    积分
    77
    最后登录
    1970-1-1
     楼主| 发表于 2014-1-8 15:58:18 | 显示全部楼层

    RE:k61 CAN模块的使用

    单步的时候步会进入错误中断,但是全速的时候执行到
      //canx->IFLAG1 = 0xFFFFFFFF;
      //canx->IFLAG2 = 0xFFFFFFFF;
      //禁止邮箱中断
      //canx->IMASK1 = 0x00000000;
      //canx->IMASK2 = 0x00000000;
    这四句会有错误中断。现象是复位后,在这四句之后打断点将不会运行到那里。停止运行后发现,发现已经进入错误中断。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    6

    主题

    27

    帖子

    0

    注册会员

    Rank: 2

    积分
    77
    最后登录
    1970-1-1
     楼主| 发表于 2014-1-8 15:59:23 | 显示全部楼层

    RE:k61 CAN模块的使用

    上面字打错了,应该是:
    单步的时候不会进入错误中断。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    85

    主题

    790

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2279
    最后登录
    1970-1-1
    发表于 2014-1-8 16:22:18 | 显示全部楼层

    RE:k61 CAN模块的使用

    你好,由于你的问题比较多,下面我逐条回复一下.
    1. 你在初始化的时候就会进入硬件错误状态.请检查一下你使用的CAN的通信引脚的时钟是否打开.
    2. 给出两个寄存器,我个人觉得是为了后续产品扩展预留的.
    3. 这个需要仔细的看一下你的代码,我晚些时候回复你.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    85

    主题

    790

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2279
    最后登录
    1970-1-1
    发表于 2014-1-8 16:25:27 | 显示全部楼层

    RE:k61 CAN模块的使用

    你全速运行到哪条语句就会出错呢?你可以通过断点来看一下,跑到哪里就会出错了.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    6

    主题

    27

    帖子

    0

    注册会员

    Rank: 2

    积分
    77
    最后登录
    1970-1-1
     楼主| 发表于 2014-1-8 16:32:38 | 显示全部楼层

    RE:k61 CAN模块的使用

    回复楼上的问题:
    1.我使用的是PORTF,在can之前已经初始化了。问题是从现象上看是
    //canx->IFLAG1 = 0xFFFFFFFF;
    //canx->IFLAG2 = 0xFFFFFFFF;
    //禁止邮箱中断
    //canx->IMASK1 = 0x00000000;
    //canx->IMASK2 = 0x00000000;
    这四句导致死机的,我现在把这几句注释掉了,但是不明白为何会导致死机。
    2.第二个问题我已经明白了。
    3.现在主要是第三个问题需要解决了。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    难过
    2021-12-15 16:01
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    305

    主题

    4701

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    377
    最后登录
    2023-8-16
    发表于 2014-1-9 09:06:53 | 显示全部楼层

    RE:k61 CAN模块的使用

    CS的值没有改变,说明数据没有发送出去。建议看一下发送错误计数器的值,确认当前数据是否发送成功。
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    6

    主题

    27

    帖子

    0

    注册会员

    Rank: 2

    积分
    77
    最后登录
    1970-1-1
     楼主| 发表于 2014-1-9 09:32:14 | 显示全部楼层

    RE:k61 CAN模块的使用

    我现在回环测试,发现可以发送出去,但是无法进入接收中断。我怀疑是MASK屏蔽字导致的问题:
    void USR_INF_CAN_Init(void)
    {
            flexcan_init_param_t.CAN_BaudRate = CAN_BAUD_RATE_250KBPS;
            flexcan_init_param_t.CAN_Canx  = CAN0_BASE_PTR;
            flexcan_init_param_t.CAN_RxMaskMode = CAN_MSGOBJ_GLOBAL_MASKING;
            flexcan_init_param_t.CAN_RxPin = PTF1;
            flexcan_init_param_t.CAN_TxPin = PTF0;
            LPLD_CAN_Init(flexcan_init_param_t);
            LPLD_CAN_EnableIrq(flexcan_init_param_t);
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_Canx           = CAN0_BASE_PTR;
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgNum         = MSG_NUM_0;//Msg0
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgDataLength  = CAN_DATA_MAX_BYTES;//8个字节长度
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgDirection   = CAN_MSGOBJ_DIR_RX; //接收模式
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgIdLength    = CAN_MSGOBJ_ID_STD;
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgInterrupt   = TRUE;              //使能该Msg0中断
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgSRR         = 0;                 //禁止SRR
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_MsgRTR         = 0;                 //禁止RTR
            flexcan_msgobj_param_t[MSG_NUM_0].CAN_Isr            = can_msg0_isr;      //设置中断回掉函数
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_Canx           = CAN0_BASE_PTR;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgNum         = MSG_NUM_1;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgDataLength  = CAN_DATA_MAX_BYTES;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgDirection   = CAN_MSGOBJ_DIR_RX;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgIdLength    = CAN_MSGOBJ_ID_STD;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgInterrupt   = TRUE;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgSRR         = 0;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_MsgRTR         = 0;
            flexcan_msgobj_param_t[MSG_NUM_1].CAN_Isr            = can_msg1_isr;
            //双缓冲区模式接收数据
            LPLD_CAN_InitMessageObject(flexcan_msgobj_param_t[MSG_NUM_0], INF_ID);//ID设置成相同
            LPLD_CAN_InitMessageObject(flexcan_msgobj_param_t[MSG_NUM_1], INF_ID);//ID设置成相同
            /*在发送模式下
            利用MSG_NUM_4作为发送缓冲
            如果成功发送将触发中断,可以设置中断回掉函数,在中断回掉函数中再次发送另一帧数据
            在这里没有设置发送中断回到函数
            */
            can_tx_message.CAN_MsgID = INF_ID;
            memcpy(can_tx_message.CAN_MsgDataBuffer,send_buffer,sizeof(send_buffer));
            can_tx_message.CAN_MsgDataLength = sizeof(send_buffer);
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_Canx           = CAN0_BASE_PTR;
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgNum         = MSG_NUM_4;
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgDataLength  = CAN_DATA_MAX_BYTES;
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgDirection   = CAN_MSGOBJ_DIR_TX;//发送模式
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgIdLength    = CAN_MSGOBJ_ID_STD;//29位扩展帧
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgInterrupt   = TRUE;//使能该Msg1中断
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgSRR         = 0;
            flexcan_msgobj_param_t[MSG_NUM_4].CAN_MsgRTR         = 0;
            LPLD_CAN_InitMessageObject(flexcan_msgobj_param_t[MSG_NUM_4], 0x5AA);
    }
    发送函数如下:
    void USR_INF_CAN_Tx(void)
    {
            LPLD_CAN_TransmitMessage(flexcan_msgobj_param_t[MSG_NUM_4],&can_tx_message);
    }
    请帮我看看MASK是否有问题
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    难过
    2021-12-15 16:01
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    305

    主题

    4701

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    377
    最后登录
    2023-8-16
    发表于 2014-1-9 10:00:16 | 显示全部楼层

    RE:k61 CAN模块的使用

    MASK用全掩码接收就可以了。注意一下,掩码寄存器对应位为0是过滤该位,为1是过滤该位。
    0 The corresponding bit in the filter is "don’t care."
    1 The corresponding bit in the filter is checked.
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-9-6 21:55 , Processed in 0.103578 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表