3552 views|5 replies

6818

Posts

11

Resources
The OP
 

[National Technology N32G457 Review] 9 RT_Thread Studio drives CAN and the difficult journey of filling the pit! [Copy link]

 This post was last edited by lugl4313820 on 2022-1-28 01:48

Today, I successfully mounted the CAN1 device and copied the official can_sample for testing:

/*
 * 程序清单:这是一个 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);

After downloading to the development board, the device is successfully found, but it reports:

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

Find the place where the error is reported:

I then wondered if the CAN was broken. To rule out whether the CAN was normal, I downloaded the official demo:

The test is good with can1 CAN_LoopBack_Mode module. Change to CAN_Normal_Mode mode, connect the can transceiver module, and test with CAN tool.


/* 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);

Data received on the computer:

From the above test, it can be concluded that there is a problem with can INIT generated by RT_Thread Studio:

Debug mode trace in:


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的数据:

This is where things go wrong:

I used MDK to initialize it like this:

Then compare the two!

View data sheet:

It was already midnight, so I thought I might as well find a solution. I found this article online, which helped me a lot:

RT-Thread-[N32G457] Using CAN device driver to send and receive data on RTThread RT-Thread Q&A Community - RT-Thread

Copy down his example:

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);
    }
}

Then it was still not right. I saw his article about modifying the pins of CAN1. Because I used PD0 and PD1 with MDK, I checked the information and found that the default TX and RX of CAN1 are PA11 and PA12. Sadly, it may be because of the wrong pins, and the initialization failed. I immediately jumped the line to PA11 and PA12.

There was no error after burning:

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!
Hehe, hard work pays off. I can only blame myself for being too naive. 。

After a day and a night of hard work, I finally got the CAN driver working. . . .

I hope everyone won’t follow my old path in the future, it’s so sad!!!

This post is from Domestic Chip Exchange

Latest reply

It is still inconvenient to use, especially the upper layer protocol, which is still a bit tricky to understand.   Details Published on 2022-3-14 22:42
 
 

6555

Posts

0

Resources
2
 

The default TX and RX of CAN1 are PA11 and PA12. Remember this.

Thank you for the experience of filling the hole

This post is from Domestic Chip Exchange
 
 
 

9702

Posts

24

Resources
3
 

Thumbs up for the author's perseverance

Is this pin definition not mentioned in the official documentation?

This post is from Domestic Chip Exchange

Comments

The default setting in the official manual is: PA11, PA12, but I saw that the official DEMO initialized PD0 and PD1, so I didn’t think too much about it.  Details Published on 2022-1-28 09:54
Personal signature虾扯蛋,蛋扯虾,虾扯蛋扯虾
 
 
 

6818

Posts

11

Resources
4
 
littleshrimp posted on 2022-1-28 09:36 I like the author's perseverance. Is this pin definition not mentioned in the official document?

The default setting in the official manual is: PA11, PA12, but I saw that the official DEMO initialized PD0 and PD1, so I didn’t think too much about it.

This post is from Domestic Chip Exchange
 
 
 

6818

Posts

11

Resources
5
 

CAN seems to be used in few places. I wonder if it will be as common as the serial port in the future. Is it cost or other factors? Welcome to discuss.

This post is from Domestic Chip Exchange

Comments

It is still inconvenient to use, especially the upper layer protocol, which is still a bit tricky to understand.  Details Published on 2022-3-14 22:42
 
 
 

7422

Posts

2

Resources
6
 
lugl4313820 posted on 2022-3-14 22:15 CAN seems to be used in relatively few places. I wonder if it will be as widely used as the serial port in the future. Is it cost or other factors? Welcome to discuss.

It is still inconvenient to use, especially the upper layer protocol, which is still a bit tricky to understand.

This post is from Domestic Chip Exchange
Personal signature

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

 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Featured Posts
Homemade STEVAL-IPM05F 3Sh board: FOC motor control 400V/8A non-sensing/sensing Hall/sensing encoder and other reference programs...

This post was last edited by music_586 on 2019-4-4 19:06 This content was originally created by EEWORLD forum user musi ...

C language uses binary tree to parse polynomials and evaluate

It mainly realizes the analysis of polynomial data calculation. If there is a need to make a simple calculator based on ...

Zhouyi Compass Simulation Experiment 2——Environment and Routine Analysis

Zhouyi Compass Simulation Experiment 2——Environment and Routine Analysis In simulation experiment 1 (https://bbs.eewor ...

【Development and application based on NUCLEO-F746ZG motor】13. Parameter configuration - USART3 configuration

The function of this serial port on the development board is to communicate with ST-LINK, and then connect ST_LINK2 to t ...

[EEWorld invites you to play disassembly] PISEN fast charging power bank 10500mAh 22.5W

Quote: Thank you EEWorld for inviting you to the disassembly (fourth issue): popular power bank disassembly event. As w ...

Please tell me why this machine often burns the starting resistor at the customer's place

Please tell me why the resistor burned out and how to fix it? 627875627874627873

[Flower carving hands-on] Interesting and fun music visualization series of small projects (26) - LED hypercube

This post was last edited by eagler8 on 2022-10-5 08:59 I had the urge to do a series of topics on sound visualization. ...

Is it possible to perform socket communication without IP and port number?

When using socket communication, whether it is internal communication within the local machine or communication betwee ...

Development Background and Advantages of SiC Power Devices

SiC power components have higher withstand voltage, lower on-resistance, can operate at higher speeds, and can operate a ...

【Digi-Key Follow me Issue 2】Task Collection

I got the board quite late, and after completing the task, I got busy with a lot of other things so I didn't have time t ...

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list