3580|5

6841

帖子

11

TA的资源

版主

楼主
 

【国民技术N32G457评测】9 RT_Thread Studio 驱动CAN 填坑之苦难历程! [复制链接]

  本帖最后由 lugl4313820 于 2022-1-28 01:48 编辑

今天成功的挂载了CAN1设备,抄了官的can_sample进行测试:

/*
 * 程序清单:这是一个 CAN 设备使用例程
 * 例程导出了 can_sample 命令到控制终端
 * 命令调用格式:can_sample can1
 * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
 * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
*/

#include <rtthread.h>
#include "rtdevice.h"

#define CAN_DEV_NAME       "can1"      /* CAN 设备名称 */

static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
static rt_device_t can_dev;            /* CAN 设备句柄 */

/* 接收数据回调函数 */
static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
{
    /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

static void can_rx_thread(void *parameter)
{
    int i;
    rt_err_t res;
    struct rt_can_msg rxmsg = {0};

    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(can_dev, can_rx_call);

#ifdef RT_CAN_USING_HDR
    struct rt_can_filter_item items[5] =
    {
        RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */
        RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */
        RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */
        RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr 为 - 1 */
        {0x555, 0, 0, 0, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */
    };
    struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 */
    /* 设置硬件过滤表 */
    res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
    RT_ASSERT(res == RT_EOK);
#endif

    while (1)
    {
        /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */
        rxmsg.hdr = -1;
        /* 阻塞等待接收信号量 */
        rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        /* 从 CAN 读取一帧数据 */
        rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
        /* 打印数据 ID 及内容 */
        rt_kprintf("ID:%x", rxmsg.id);
        for (i = 0; i < 8; i++)
        {
            rt_kprintf("%2x", rxmsg.data);
        }

        rt_kprintf("\n");
    }
}

int can_sample(int argc, char *argv[])
{
    struct rt_can_msg msg = {0};
    rt_err_t res;
    rt_size_t  size;
    rt_thread_t thread;
    char can_name[RT_NAME_MAX];

    if (argc == 2)
    {
        rt_strncpy(can_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
    }
    /* 查找 CAN 设备 */
    can_dev = rt_device_find(can_name);
    if (!can_dev)
    {
        rt_kprintf("find %s failed!\n", can_name);
        return RT_ERROR;
    }
    rt_kprintf("find %s !\n", can_name);
    /* 初始化 CAN 接收信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);

    /* 以中断接收及发送方式打开 CAN 设备 */
    res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
    rt_kprintf("opne %s !\n", can_name);
    RT_ASSERT(res == RT_EOK);
    /* 创建数据接收线程 */
    thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        rt_kprintf("create can_rx thread failed!\n");
    }

    msg.id = 0x78;              /* ID 为 0x78 */
    msg.ide = RT_CAN_STDID;     /* 标准格式 */
    msg.rtr = RT_CAN_DTR;       /* 数据帧 */
    msg.len = 8;                /* 数据长度为 8 */
    /* 待发送的 8 字节数据 */
    msg.data[0] = 0x00;
    msg.data[1] = 0x11;
    msg.data[2] = 0x22;
    msg.data[3] = 0x33;
    msg.data[4] = 0x44;
    msg.data[5] = 0x55;
    msg.data[6] = 0x66;
    msg.data[7] = 0x77;
    /* 发送一帧 CAN 数据 */
    size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
    if (size == 0)
    {
        rt_kprintf("can dev write data failed!\n");
    }

    return res;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(can_sample, can device sample);

下载到开发板后,成功的找到设备,但是报:

find can1 !
can init error2
To initialize device:can1 failed. The error code is -1
(res == RT_EOK) assertion failed at function:can_sample, line number:98

找到报错的地方:

  我于是考虑是不是can是不是坏了,为了排除can是否正常,我下载了官方提供的demo:

用can1 CAN_LoopBack_Mode 模块测试是好的。改为CAN_Normal_Mode模式,接上can收发模块,用CAN工具测试也是好的:


/* CAN1 transmit message */
    TransmitMailbox = CANTxMessage(CAN1,
                                   &CAN1_TxMessage,
                                   0x0400,
                                   0x00,
                                   CAN_ID_STD,
                                   CAN_RTRQ_DATA,
                                   CAN_TXDLC_8,
                                   0x01,
                                   0x02,
                                   0x03,
                                   0x04,
                                   0x05,
                                   0x06,
                                   0x07,
                                   0x08);

电脑上收到的数据:

 从上面的测试得出,RT_Thread Studio 生成的 can INIT有问题:

调试模式追踪进去:


static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg)
{
    struct n32g45x_can *drv_can;
    rt_uint32_t baud_index;

    RT_ASSERT(can);
    RT_ASSERT(cfg);
    drv_can = (struct n32g45x_can *)can->parent.user_data;
    RT_ASSERT(drv_can);

    /* Configure CAN1 and CAN2 */
    if (drv_can->CANx == CAN1)
    {
        RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_CAN1, ENABLE);
        n32_msp_can_init(CAN1);
    }

这是初始化 can的数据:

 

出错的地方就是在这里:

 

 

  我用MDK初始化到这里的这样的:

 然后两个对比一下!

 查看数据手册:

 

都半夜了,想想,还是找找办法,网上找到这篇文章,帮了大忙:

RT-Thread-[ N32G457 ] rtthread上使用can设备驱动收发数据RT-Thread问答社区 - RT-Thread

把他的示例抄下来:

can_sample.c

/*
* Change Logs:
* Date           Author       Notes
* 2022-01-15     chenbin
*/
#include "stdint.h"
#include "stdio.h"
#include "string.h"
#include "rtthread.h"
#include "rtdevice.h"

#define DBG_TAG "can1"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#define CAN1_DEVICE_NAME            "can1"

static                 rt_device_t            can1_dev;     /* CAN 设备句柄 */
static struct rt_semaphore        can1_rx_sem;     /* 用于接收消息的信号量 */

/* 接收数据回调函数 */
static rt_err_t can1_rx_call(rt_device_t dev, rt_size_t size)
{
    /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&can1_rx_sem);

    return RT_EOK;
}


void can1_send_0x123(void)
{
    struct rt_can_msg msg = {0};
    msg.id =  0x123;              /* ID 为 0x123 */
    msg.ide = RT_CAN_STDID;     /* 标准格式 */
    msg.rtr = RT_CAN_DTR;       /* 数据帧 */
    msg.len = 8;                /* 数据长度为 8 */
    /* 待发送的 8 字节数据 */
    msg.data[0] = 0x00;
    msg.data[1] = 0x11;
    msg.data[2] = 0x22;
    msg.data[3] = 0x33;
    msg.data[4] = 0x44;
    msg.data[5] = 0x55;
    msg.data[6] = 0x66;
    msg.data[7] = 0x77;
    /* 发送一帧 CAN 数据 */
    int size = rt_device_write(can1_dev, 0, &msg, sizeof(msg));
    if (size < 0)
    {
        rt_kprintf("can1 dev write data failed rc:%d\n",size);
    }
}

void can1_send_0x456_RTR(void)
{
    struct rt_can_msg msg = {0};
    msg.id =  0x456;              /* ID 为 0x456 */
    msg.ide = RT_CAN_STDID;     /* 标准格式 */
    msg.rtr = RT_CAN_RTR;       /* 远程帧 */

    int size = rt_device_write(can1_dev, 0, &msg, sizeof(msg));
    if (size < 0)
    {
        rt_kprintf("can1 dev write data failed rc:%d\n",size);
    }
}

static void can1_thread(void *param)
{
    int rc = 0;
    can1_dev = rt_device_find(CAN1_DEVICE_NAME);
    if (!can1_dev)
    {
            rt_kprintf("find %s failed!\n", CAN1_DEVICE_NAME);
            return ;
    }else
    {
        rt_kprintf("find %s ok!\n", CAN1_DEVICE_NAME);
    }
    rt_sem_init(&can1_rx_sem, "can1_rx_sem", 0, RT_IPC_FLAG_FIFO);

    /* 以中断接收及发送方式打开 CAN 设备 */
    rc = rt_device_open(can1_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
    RT_ASSERT(rc == RT_EOK);

    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(can1_dev, can1_rx_call);

    rt_device_control(can1_dev, RT_CAN_CMD_SET_BAUD, (void *)CAN500kBaud);

    rt_device_control(can1_dev, RT_CAN_CMD_SET_MODE, (void *)RT_CAN_MODE_NORMAL);

#ifdef RT_CAN_USING_HDR
    struct rt_can_filter_item items[5] =
    {
        RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */
        RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 1, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */
        RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 1, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */
        RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr 为 - 1 */
        {0x555, 0, 0, 1, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */
    };
    struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 */
    /* 设置硬件过滤表 */
    res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
    RT_ASSERT(res == RT_EOK);
#endif
    struct rt_can_msg rxmsg = {0};
    while(1)
    {
            /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */
            rxmsg.hdr = -1;
            /* 阻塞等待接收信号量 */
            rt_sem_take(&can1_rx_sem, RT_WAITING_FOREVER);
            /* 从 CAN 读取一帧数据 */
            rt_device_read(can1_dev, 0, &rxmsg, sizeof(rxmsg));

            rt_kprintf("CAN1 RX\n");
            /* 打印数据 ID 及内容 */
            if(rxmsg.rtr == RT_CAN_RTR)  //远程帧
            {
                if(rxmsg.ide == RT_CAN_EXTID)//扩展帧
                {
                    rt_kprintf("ID:0x%08X RTR len:%d \n", rxmsg.id, rxmsg.len);
                }else
                {
                    rt_kprintf("ID:0x%04X RTR len:%d \n", rxmsg.id, rxmsg.len);
                }
                if(rxmsg.id == 0x123)
                {
                    can1_send_0x123();
                }
            }else  //数据帧
            {
                if(rxmsg.ide == RT_CAN_EXTID)//扩展帧
                {
                    rt_kprintf("ID:0x%08X len:%d ", rxmsg.id, rxmsg.len);
                    for (int i = 0; i < rxmsg.len; i++)
                    {
                            rt_kprintf(" %02X", rxmsg.data[i]);
                    }
                    rt_kprintf("\n");
                }else
                {
                    rt_kprintf("ID:0x%04X len:%d ", rxmsg.id, rxmsg.len);
                    for (int i = 0; i < rxmsg.len; i++)
                    {
                            rt_kprintf(" %02X", rxmsg.data[i]);
                    }
                    rt_kprintf("\n");
                }
            }
    }
}

int can1_test_init(void)
{
    static int can1_init = 0;
    rt_thread_t tid;
    if(can1_init > 0)
    {
        return 0;
    }
    can1_init = 1;

    tid = rt_thread_create("can1",can1_thread, NULL,2048,20, 10);
    if (tid != RT_NULL)
            rt_thread_startup(tid);
    return 0;
}


void can1_test(uint8_t argc, char **argv)
{
    rt_kprintf("can1 test\n");
    can1_send_0x123();
}
MSH_CMD_EXPORT(can1_test, can1 test);

void can1_test1(uint8_t argc, char **argv)
{
    rt_kprintf("can1 test1\n");
    can1_send_0x456_RTR();
}
MSH_CMD_EXPORT(can1_test1, can1 test1);


void can1_debug(uint8_t argc, char **argv)
{
    if(argc > 1)
    {
        int val = atoi(argv[1]);
        rt_kprintf("can1 debug set %d\n",val);
    }
}
MSH_CMD_EXPORT(can1_debug, can1 debug);

main.c:

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2015-07-29     Arda.Fu      first implementation
 */
#include <stdint.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_can.h"



/* defined the LED1 pin: PB5 */
#define LED1_PIN    91
    int can1_test_init(void);

int main(void)
{
    uint32_t Speed = 200;
    /* set LED1 pin mode to output */
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
   // rt_hw_can_init();
    can1_test_init();
    while (1)
    {
        rt_pin_write(LED1_PIN, PIN_LOW);
        rt_thread_mdelay(Speed);
        rt_pin_write(LED1_PIN, PIN_HIGH);
        rt_thread_mdelay(Speed);
    }
}

然后还不对,看到他的文章修改CAN1的脚,因为我用MDK用的是PD0跟PD1,我查一下资料,才知道CAN1的TX RX默认是PA11 PA12,悲伤呀,可能是由于脚不对,初始化不成功。立马把线跳到PA11、PA12.

烧录下果然没有报错了:

msh >can1_te
can1_test
can1_test1
msh >can1_test
can1 test
msh >
 \ | /
- RT -     Thread Operating System
 / | \     4.0.5 build Jan 28 2022 01:22:53
 2006 - 2021 Copyright by rt-thread team
msh >find can1 ok!
嘿嘿,功夫不负有心人呀,只怪自己太初心了。。。。

 经过一天一夜的填坑,终于把CAN驱动好了。。。。

希望大家以后不要走我的老路,悲伤呀!!!

最新回复

使用上还是不方便,尤其是上层协议,要搞清楚还是有些饶   详情 回复 发表于 2022-3-14 22:42
点赞(1) 关注
 
 

回复
举报

6609

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

CAN1的TX RX默认是PA11 PA12,这下记住了

谢谢楼主的填坑经验

 
 
 

回复

9720

帖子

24

TA的资源

版主

板凳
 

为楼主的毅力点赞

这个引脚定义是官方资料没有提吗?

点评

官方资料手册默认的是:PA11,PA12,但是我看官方提供的DEMO是初始化的PD0与PD1,所以就没有想这么多。  详情 回复 发表于 2022-1-28 09:54
个人签名虾扯蛋,蛋扯虾,虾扯蛋扯虾
 
 
 

回复

6841

帖子

11

TA的资源

版主

4
 
littleshrimp 发表于 2022-1-28 09:36 为楼主的毅力点赞 这个引脚定义是官方资料没有提吗?

官方资料手册默认的是:PA11,PA12,但是我看官方提供的DEMO是初始化的PD0与PD1,所以就没有想这么多。

 
 
 

回复

6841

帖子

11

TA的资源

版主

5
 

CAN看来使用的地方比较少呀,不知道以后会不会跟串口一样使用普遍。是成本还是其他的,欢迎大家讨论。

点评

使用上还是不方便,尤其是上层协议,要搞清楚还是有些饶  详情 回复 发表于 2022-3-14 22:42
 
 
 

回复

7462

帖子

2

TA的资源

五彩晶圆(高级)

6
 
lugl4313820 发表于 2022-3-14 22:15 CAN看来使用的地方比较少呀,不知道以后会不会跟串口一样使用普遍。是成本还是其他的,欢迎大家讨论。

使用上还是不方便,尤其是上层协议,要搞清楚还是有些饶

个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表