[已解决]求助,GD32E103 CAN发送数据异常

[复制链接]
495|12
 楼主 | 2020-1-11 07:51 | 显示全部楼层 |阅读模式
本帖最后由 innovak 于 2020-1-12 17:14 编辑

接收数据如图,can-fd模式发送.程序中测试对同一个数据串用不同数据长度发送,当发送64字节大小的帧时,收到的数据前面4字节会变成01 01 00 00,有小概率会变成01 01 00 0a.
使用的库版本是V1.0.2.调试中确认最后写入TMDATA00寄存器的前4字节数据是正确的,但是发送出的数据有误.有没有遇到同样情况的朋友?





已解决:问题代码在v1.0.2版本的gd32e103_can.c中:
            for(j = 0; j < i+1; j++){
                CAN_TMDATA0(can_periph, mailbox_number) = *(uint32_t *)p_temp;
                p_temp = ((uint32_t)((uint32_t)p_temp + 4U));
            }
因为邮箱只支持32bit访问,这位gd程序员在计算循环数的时候直接用数据长度除以4,为了解决无法整除的长度,就在这个循环里加了个1,导致发送64字节数据时can邮箱的数据被覆盖了4个字节.需要判断下是否是发送64字节帧,如果是64字节就不要加1就行.
CAN64字节异常.png

使用特权

评论回复
| 2020-1-13 00:05 | 显示全部楼层
真的解决了吗?我表示怀疑,依着老弟的分析,不仅仅是在传输64个字节时出错吧!
凡事4的整数倍都应该出错,你在测测看,是不是这么回事!!!

使用特权

评论回复
| 2020-1-13 09:09 | 显示全部楼层
其实,按照楼主的分析,不仅仅是64字节时,所有4的整倍数都有问题,都会多推送一次。

使用特权

评论回复

评论

innovak 2020-1-13 23:10 回复TA
的确是这样,因为can外设发送是按设置的实际数据长度发送的,所以没有读到后面多写入的数据.64字节时缓冲器发生了覆盖,才暴露了这个问题. 
| 2020-1-13 09:17 | 显示全部楼层
只是其他,没有发生数据覆盖,在64字节时,多推送的一次,折返覆盖了第一个字。就出现了楼主所说的问题,
修改这段代码,首先需要判断数据长度是否大于0,如果大于0这段代码才被执行,计算 i 值时,应该将
数据长度先减1后,再除4,这样修改就完美了。

使用特权

评论回复
 楼主 | 2020-1-15 16:51 | 显示全部楼层
dxfshsh 发表于 2020-1-13 00:05
真的解决了吗?我表示怀疑,依着老弟的分析,不仅仅是在传输64个字节时出错吧!
凡事4的整数倍都应该出错, ...

其他字节没有问题,因为can实际发送的数据是按照DLENC寄存器设置的值读取的,正常的情况下不会读取后面的字节,也不会发生覆盖第一个字节所以没有关系.

使用特权

评论回复
| 2020-1-16 12:07 | 显示全部楼层
楼主在自己解决问题后,能把解决方法写出来供大家参考,先点赞一下。

使用特权

评论回复
| 2020-1-21 17:56 | 显示全部楼层
可以参考下下面2个函数的处理:
uint8_t can_message_transmit(uint32_t can_periph, can_trasnmit_message_struct* transmit_message)
{
    uint8_t mailbox_number = CAN_MAILBOX0;
    uint8_t i = 0U;
    uint8_t hit = 0U;
    uint32_t canfd_en = 0U;
    volatile uint32_t p_temp;
    uint32_t reg_temp = 0U;

    /* select one empty mailbox */
    if(CAN_TSTAT_TME0 == (CAN_TSTAT(can_periph)&CAN_TSTAT_TME0)){
        mailbox_number = CAN_MAILBOX0;
    }else if(CAN_TSTAT_TME1 == (CAN_TSTAT(can_periph)&CAN_TSTAT_TME1)){
        mailbox_number = CAN_MAILBOX1;
    }else if(CAN_TSTAT_TME2 == (CAN_TSTAT(can_periph)&CAN_TSTAT_TME2)){
        mailbox_number = CAN_MAILBOX2;
    }else{
        mailbox_number = CAN_NOMAILBOX;
    }
    /* return no mailbox empty */
    if(CAN_NOMAILBOX == mailbox_number){
        return CAN_NOMAILBOX;
    }

    CAN_TMI(can_periph, mailbox_number) &= CAN_TMI_TEN;
    if(CAN_FF_STANDARD == transmit_message->tx_ff){
        /* set transmit mailbox standard identifier */
        CAN_TMI(can_periph, mailbox_number) |= (uint32_t)(TMI_SFID(transmit_message->tx_sfid) | \
                                                transmit_message->tx_ft);
    }else{
        /* set transmit mailbox extended identifier */
        CAN_TMI(can_periph, mailbox_number) |= (uint32_t)(TMI_EFID(transmit_message->tx_efid) | \
                                                transmit_message->tx_ff | \
                                                transmit_message->tx_ft);
    }

    if(CAN_FDF_CLASSIC == transmit_message->fd_flag){
        /* set the data length */
        CAN_TMP(can_periph, mailbox_number) &= ~CAN_TMP_DLENC;
        CAN_TMP(can_periph, mailbox_number) |= transmit_message->tx_dlen;
        /* set the data */
        CAN_TMDATA0(can_periph, mailbox_number) = TMDATA0_DB3(transmit_message->tx_data[3]) | \
                                                  TMDATA0_DB2(transmit_message->tx_data[2]) | \
                                                  TMDATA0_DB1(transmit_message->tx_data[1]) | \
                                                  TMDATA0_DB0(transmit_message->tx_data[0]);
        CAN_TMDATA1(can_periph, mailbox_number) = TMDATA1_DB7(transmit_message->tx_data[7]) | \
                                                  TMDATA1_DB6(transmit_message->tx_data[6]) | \
                                                  TMDATA1_DB5(transmit_message->tx_data[5]) | \
                                                  TMDATA1_DB4(transmit_message->tx_data[4]);
    }else{
        canfd_en = CAN_FDCTL(can_periph) & CAN_FDCTL_FDEN;
        /* check FD funciton has been enabled */
        if(canfd_en){
            if(transmit_message->tx_dlen <= 8U){
                /* set the data length */
                reg_temp |= transmit_message->tx_dlen;
            }else{
                /* data length greater than 8 */
                for(i = 0U; i < 7U; i++){
                    if(transmit_message->tx_dlen == g_can_fdlength_table[i]){
                        hit = 1U;
                        break;
                    }
                }
                /* data length is valid */
                if(1U == hit){
                   reg_temp |= 9U + i;
                }else{
                    CAN_ERROR_HANDLE("dlen is invalid \r\n");
                }
            }
            reg_temp |= (((uint32_t)transmit_message->fd_brs << 5U) | ((uint32_t)transmit_message->fd_esi << 4U) | ((uint32_t)transmit_message->fd_flag << 7U));
            CAN_TMP(can_periph, mailbox_number) = reg_temp;
            
            /* set the data */
            i = transmit_message->tx_dlen / 4U;
            
            /* data length is 5-7 need send 2 word */
            if((1U==i) && (4U!=transmit_message->tx_dlen)){
                i++;
            }
            p_temp = (uint32_t)transmit_message->tx_data;
            if((0U==i)){
                CAN_TMDATA0(can_periph, mailbox_number) = *(uint32_t *)p_temp;
            }else{
                for(; i>0U; i--){
                    CAN_TMDATA0(can_periph, mailbox_number) = *(uint32_t *)p_temp;
                    p_temp = ((uint32_t)((uint32_t)p_temp + 4U));
                }
            }
            
        }else{
            CAN_ERROR_HANDLE("CAN FD function disabled \r\n");
        }
    }

    /* enable transmission */
    CAN_TMI(can_periph, mailbox_number) |= CAN_TMI_TEN;

    return mailbox_number;
}

void can_message_receive(uint32_t can_periph, uint8_t fifo_number, can_receive_message_struct* receive_message)
{
    uint32_t canfd_en = 0U;
    volatile uint32_t p_temp;
    uint32_t data_temp;
    uint8_t canfd_recv_cnt = 0U;
    uint8_t i;

    /* get the frame format */
    receive_message->rx_ff = (uint8_t)(CAN_RFIFOMI_FF & CAN_RFIFOMI(can_periph, fifo_number));
    if(CAN_FF_STANDARD == receive_message->rx_ff){
        /* get standard identifier */
        receive_message->rx_sfid = (uint32_t)(GET_RFIFOMI_SFID(CAN_RFIFOMI(can_periph, fifo_number)));
    }else{
        /* get extended identifier */
        receive_message->rx_efid = (uint32_t)(GET_RFIFOMI_EFID(CAN_RFIFOMI(can_periph, fifo_number)));
    }

    /* get frame type */
    receive_message->rx_ft = (uint8_t)(CAN_RFIFOMI_FT & CAN_RFIFOMI(can_periph, fifo_number));
    /* filtering index */
    receive_message->rx_fi = (uint8_t)(GET_RFIFOMP_FI(CAN_RFIFOMP(can_periph, fifo_number)));
    receive_message->fd_flag = (uint8_t)(CAN_RFIFOMP_FDF & CAN_RFIFOMP(can_periph, fifo_number));

    if(CAN_FDF_CLASSIC == receive_message->fd_flag){
        /* get recevie data length */
        receive_message->rx_dlen = (uint8_t)(GET_RFIFOMP_DLENC(CAN_RFIFOMP(can_periph, fifo_number)));
        /* receive data */
        receive_message->rx_data[0] = (uint8_t)(GET_RFIFOMDATA0_DB0(CAN_RFIFOMDATA0(can_periph, fifo_number)));
        receive_message->rx_data[1] = (uint8_t)(GET_RFIFOMDATA0_DB1(CAN_RFIFOMDATA0(can_periph, fifo_number)));
        receive_message->rx_data[2] = (uint8_t)(GET_RFIFOMDATA0_DB2(CAN_RFIFOMDATA0(can_periph, fifo_number)));
        receive_message->rx_data[3] = (uint8_t)(GET_RFIFOMDATA0_DB3(CAN_RFIFOMDATA0(can_periph, fifo_number)));
        receive_message->rx_data[4] = (uint8_t)(GET_RFIFOMDATA1_DB4(CAN_RFIFOMDATA1(can_periph, fifo_number)));
        receive_message->rx_data[5] = (uint8_t)(GET_RFIFOMDATA1_DB5(CAN_RFIFOMDATA1(can_periph, fifo_number)));
        receive_message->rx_data[6] = (uint8_t)(GET_RFIFOMDATA1_DB6(CAN_RFIFOMDATA1(can_periph, fifo_number)));
        receive_message->rx_data[7] = (uint8_t)(GET_RFIFOMDATA1_DB7(CAN_RFIFOMDATA1(can_periph, fifo_number)));
    }else{
        canfd_en = CAN_FDCTL(can_periph) & CAN_FDCTL_FDEN;
        /* check FD funciton has been enabled */
        if(canfd_en){
            /* get recevie data length */
            canfd_recv_cnt = (uint8_t)(GET_RFIFOMP_DLENC(CAN_RFIFOMP(can_periph, fifo_number)));

            if(canfd_recv_cnt <= 8U){
                /* set the data length */
                receive_message->rx_dlen = canfd_recv_cnt;
            }else{
                receive_message->rx_dlen = g_can_fdlength_table[canfd_recv_cnt - 9U];
            }

            receive_message->fd_brs = (uint8_t)((CAN_RFIFOMP(can_periph, fifo_number) & CAN_RFIFOMP_BRS) >> 5);
            receive_message->fd_esi = (uint8_t)((CAN_RFIFOMP(can_periph, fifo_number) & CAN_RFIFOMP_ESI) >> 4);

            /* get the data */
            i = receive_message->rx_dlen / 4U;
            
            /* data length is 5-7 need receive 2 word */
            if((1U==i) && (4U!=receive_message->rx_dlen)){
                i++;
            }
            p_temp = (uint32_t)(uint32_t)receive_message->rx_data;
            if(0U==i){
                data_temp = CAN_RFIFOMDATA0(can_periph, fifo_number);
                *(uint32_t *)p_temp = data_temp;   
            }else{
                /* get the data by reading from CAN_RFIFOMDATA0 register*/
                for(; i>0U; i--){
                    data_temp = CAN_RFIFOMDATA0(can_periph, fifo_number);
                    *(uint32_t *)p_temp = data_temp;
                    p_temp = ((uint32_t)((uint32_t)p_temp + 4U));
                }
            }
            
        }else{
            CAN_ERROR_HANDLE("CAN FD function disabled \r\n");
        }
    }

    /* release FIFO */
    if(CAN_FIFO0 == fifo_number){
        CAN_RFIFO0(can_periph) |= CAN_RFIFO0_RFD0;
    }else{
        CAN_RFIFO1(can_periph) |= CAN_RFIFO1_RFD1;
    }
}

使用特权

评论回复
| 2020-1-21 20:39 | 显示全部楼层
本帖最后由 dxfshsh 于 2020-1-21 20:51 编辑

      /* set the data */                 

        if(transmit_message->tx_dlen>0)
          {
               i = transmit_message->tx_dlen-1 / 4U;
               for( j=0; j<i+1; j++)
              {
                    CAN_TMDATA0(can_periph, mailbox_number) = *(uint32_t *)p_temp;
                    p_temp = ((uint32_t)((uint32_t)p_temp + 4U));

              }
          }
这是我写的对应代码,是不是更简洁,如有错误请及时指正!万分感谢!!!!

不用单独考虑所谓: /* data length is 5-7 need send 2 word */





使用特权

评论回复
| 2020-1-22 09:35 | 显示全部楼层
本帖最后由 高IAI阳 于 2020-1-22 09:37 编辑
dxfshsh 发表于 2020-1-21 20:39
/* set the data */                 

        i ...

这个写法如果tx_dlen=0就存在问题了(而且书写格式有问题),之前的写法是在GD老版本处理上修了BUG(也是从GD那里获取的),应该在下个版本会更新,不容易引起其它问题,当然也只是参考。

使用特权

评论回复
| 2020-1-27 18:49 | 显示全部楼层
其实这是一个非常简单的写法,见下,希望GD能采用
/* set the data */                 
      
               i =( transmit_message->tx_dlen+3) / 4U;
               for( j=0; j<i; j++)
              {
                    CAN_TMDATA0(can_periph, mailbox_number) = *(uint32_t *)p_temp;
                    p_temp = ((uint32_t)((uint32_t)p_temp + 4U));
              }
         

使用特权

评论回复
| 2020-2-17 15:13 | 显示全部楼层
chenbagan 发表于 2020-1-27 18:49
其实这是一个非常简单的写法,见下,希望GD能采用
/* set the data */                 
      

CAN是可以发送数据长度为0的数据的帧的,当发送数据长度是0的情况是需要单独考虑的

使用特权

评论回复
| 2020-2-17 19:24 | 显示全部楼层
高IAI阳 发表于 2020-2-17 15:13
CAN是可以发送数据长度为0的数据的帧的,当发送数据长度是0的情况是需要单独考虑的 ...

已经考虑过了,您在验证一下。

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表