【国民技术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驱动好了。。。。
希望大家以后不要走我的老路,悲伤呀!!!
|