GD32 CAN — CAN 自回环

GD32 GD32F30x_Firmware_Library V3.0.3 CAN CAN 自回环 示例教学

CAN — CAN 自回环

固件库: GD32F30x_Firmware_Library V3.0.3
芯片: GD32
源文件: GD32F30x_Firmware_Library_V3.0.3/Examples/CAN/communication_Loopback/main.c


功能简介

本示例演示 CAN 自回环测试。TX 发出的数据直接回到 RX,不需要外部 CAN 收发器,非常适合验证 CAN 配置是否正确。

硬件准备

  • CAN 收发器模块(如 TJA1050、MCP2551)
  • 自回环测试模式下可不接外部设备

完整代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "gd32f30x.h"
#include <stdio.h>
#include "gd32f307c_eval.h"
#define DEV_CAN0_USED

void nvic_config(void);
void led_config(void);
ErrStatus can_loopback(void);
ErrStatus can_loopback_interrupt(void);
void can_loopback_init(void);

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    /* enable CAN clock */
    rcu_periph_clock_enable(RCU_CAN0);
#ifdef GD32F30X_CL
    rcu_periph_clock_enable(RCU_CAN1);
#endif /* GD32F30X_CL */
    
    /* configure NVIC */
    nvic_config();
    
    /* configure leds */
    led_config();
    /* set all the leds off */
    gd_eval_led_off(LED2);
    gd_eval_led_off(LED3);
    gd_eval_led_off(LED4);
    gd_eval_led_off(LED5);
    /* loopback of polling */
    test_flag = can_loopback();
 
    if(SUCCESS == test_flag){
        /* loopback test is success */
        gd_eval_led_on(LED2);
        gd_eval_led_on(LED3);
    }else{
        /* loopback test is failed */
        gd_eval_led_off(LED2);
        gd_eval_led_off(LED3);
    }
    /* loopback of interrupt */
    test_flag_interrupt = can_loopback_interrupt();

    if(SUCCESS == test_flag_interrupt){
        /* interrupt loopback test is success */
        gd_eval_led_on(LED4);
        gd_eval_led_on(LED5);
    }else{
        /* interrupt loopback test is failed */
        gd_eval_led_off(LED4);
        gd_eval_led_off(LED5);
    }
    while (1);
}

void can_loopback_init(void)
{
    can_parameter_struct        can_parameter;
    can_filter_parameter_struct can_filter;
    
    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
    
    /* initialize CAN register */
    can_deinit(CANX);
    
    /* initialize CAN */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = ENABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.auto_retrans = ENABLE;
    can_parameter.rec_fifo_overwrite = DISABLE;
    can_parameter.trans_fifo_order = DISABLE;
    can_parameter.working_mode = CAN_LOOPBACK_MODE;
    /* configure baudrate to 125kbps */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
    can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
    can_parameter.prescaler = 48;
    can_init(CANX, &can_parameter);

    /* initialize filter */
#ifdef  DEV_CAN0_USED
    /* CAN0 filter number */
    can_filter.filter_number = 0;
#else
    /* CAN1 filter number */
    can_filter.filter_number = 14;
#endif
    /* initialize filter */    
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    can_filter.filter_list_high = (uint16_t)(DEV_CAN_POLLING_ID << 5);
    can_filter.filter_list_low = 0x0000;
    /* ID and standard frame matched */
    can_filter.filter_mask_high = (uint16_t)(0x7FF << 5);
    can_filter.filter_mask_low = (uint16_t)(1U << 2);
    
    can_filter.filter_fifo_number = CAN_FIFO1;
    can_filter.filter_enable=ENABLE;
    can_filter_init(&can_filter);
    
    /* initialize filter */
#ifdef  DEV_CAN0_USED
    /* CAN0 filter number */
    can_filter.filter_number = 1;
#else
    /* CAN1 filter number */
    can_filter.filter_number = 15;
#endif
    /* initialize filter */
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    /* ID and extend frame matched */
    can_filter.filter_list_high = (uint16_t)(DEV_CAN_INTERRUPT_ID >> 13);
    can_filter.filter_list_low = (uint16_t)(((uint16_t)DEV_CAN_INTERRUPT_ID << 3) | (1U << 2));
    can_filter.filter_mask_high = (uint16_t)(0x1FFFFFFF >> 13);
    can_filter.filter_mask_low = (uint16_t)(((uint16_t)0x1FFFFFFF << 3) | (1U << 2));
    can_filter.filter_fifo_number = CAN_FIFO1;
    can_filter.filter_enable=ENABLE;
    can_filter_init(&can_filter);
}

void nvic_config(void)
{
    /* configure CAN0 NVIC */
    nvic_irq_enable(CAN0_RX1_IRQn,0,0);
#ifdef GD32F30X_CL
    /* configure CAN1 NVIC */
    nvic_irq_enable(CAN1_RX1_IRQn,0,0);
#endif /* GD32F30X_CL */
}

void led_config(void)
{
    gd_eval_led_init(LED2);
    gd_eval_led_init(LED3);
    gd_eval_led_init(LED4);
    gd_eval_led_init(LED5);
}

代码讲解

中断优先级配置:NVIC 设置中断的抢占优先级和子优先级。数字越小优先级越高。

实验现象

  • CAN 自回环:发送的报文直接回到接收端
  • 校验通过 LED 亮起
世界是你们
使用 Hugo 构建
主题 StackJimmy 设计