灵动微电子 MM32
直播中

zhu

8年用户 1640经验值
擅长:控制/MCU
私信 关注
[原创]

灵动微课堂 (第129讲) | 基于MM32 MCU的OS移植与应用——AMetal CAN通信配置

CAN 是Controller Area Network的缩写(以下称为CAN),是ISO国际标准化的串行通信协议。CAN 的高性能和可靠性被得到广泛的认可,并被应用于工业自动化、船舶、医疗设备、工业设备等方向,为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有力的技术支持。

MM32L073内置CAN模块,可以广泛应用于需要CAN通信的应用场景,具体以下特点:
  • 支持 CAN 协议的 2.0 A 和 2.0 B
  • 扩展的接收缓冲器 (64 字节、先进先出 FIFO)
  • 同时支持 11 位和 29 位识别码
  • 位速率可达 1Mbits/s
  • 支持PeliCAN 模式扩展功能
  • 支持硬件滤波器


AMetal已经完成了对MM32L073的适配,若用户选用AMetal平台,则无需自行适配,直接使用相应的CAN功能接口进行操作即可。


   初始化   

以CAN初始化函数为例,函数原型为:

am_can_handle_t am_mm32l073_can_inst_init(void);

该函数在user_config目录下的am_hwconf_mm32l073_can.c文件中定义为:

/** CAN 实例初始化,获得 CAN 标准服务句柄 */
am_can_handle_t am_mm32l073_can_inst_init(void)
{
  return am_mm32l073_can_init(&__g_can_dev, &__g_can_devinfo);
}

在am_mm32l073_inst_init.h中声明为:

am_can_handle_t am_mm32l073_can_inst_init(void);

因此使用CAN初始化函数时,需要包含头文件am_mm32l073_inst_init.h。初始化CAN,调用该函数时需要定义一个am_can_handle_t类型的变量,用于保存获取的CAN服务句柄,CAN初始化程序为:

am_can_handle_t can_handle;
can_handle = am_mm32l073_can_inst_init();


  接口函数  

AMetal 提供了CAN相关的接口函数,详见表1。

函数原型
功能简介
am_can_start (am_can_handle_t handle);
启动CAN通信
am_can_reset (am_can_handle_t handle);
复位CAN通信
am_can_sleep (am_can_handle_t handle);
CAN睡眠
am_can_wakeup (am_can_handle_t handle);
CAN唤醒
am_can_int_enable (am_can_handle_t handle,am_can_int_type_t mask);
CAN中断使能
am_can_int_disable (am_can_handle_t handle,
am_can_int_type_t mask);
CAN中断禁能
am_can_mode_set ( am_can_handle_t handle,
am_can_mode_type_t mode)
CAN工作模式设置
am_can_baudrate_set (am_can_handle_t handle,
struct am_can_bps_param *p_can_baudrate)
CAN波特率设置
am_can_baudrate_get (am_can_handle_t handle,
struct am_can_bps_param *p_can_baudrate)
CAN波特率获取
am_can_err_cnt_get ( am_can_handle_t handle,
struct am_can_err_cnt *p_can_err_cnt)
CAN获取错误计数
am_can_err_cnt_clr (am_can_handle_t handle);
CAN清除错误计数
am_can_msg_send ( am_can_handle_t handle,
am_can_message_t *p_txmsg)
CAN发送消息
am_can_msg_recv (am_can_handle_t handle,
am_can_message_t *p_rxmsg)
CAN接收消息
am_can_msg_stop_send(am_can_handle_t handle);
CAN停止发送
am_can_filter_tab_set (am_can_handle_t handle,
uint8_t *p_filterbuff,
size_t lenth)
CAN设置滤波
am_can_filter_tab_get (am_can_handle_t handle,
uint8_t *p_filterbuff,
size_t *p_lenth)
CAN获取滤波设置
am_can_status_get ( am_can_handle_t handle,
am_can_int_type_t *p_int_type,
am_can_bus_err_t *p_bus_err)
CAN状态获取
am_can_connect ( am_can_handle_t handle,
am_pfnvoid_t pfn_isr,
void *p_arg)
CAN中断连接
am_can_disconnect ( am_can_handle_t handle,
am_pfnvoid_t pfn_isr,
void *p_arg)
CAN删除中断连接
am_can_intcb_connect ( am_can_handle_t handle,
am_can_int_type_t inttype,
am_pfnvoid_t pfn_callback,
void *p_arg)
CAN注册中断回调函数
am_can_intcb_disconnect ( am_can_handle_t handle,
am_can_int_type_t inttype)
CAN解除中断回调的注册
表 1 CAN 接口函数

1. CAN 通信启动
CAN 通信完成初始化之后,调用启动 CAN 通信函数开始通信,函数原型为:am_can_err_t am_can_start (am_can_handle_t handle)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;


2. CAN 通信复位
复位 CAN 通信,函数原型为:am_can_err_t am_can_reset (am_can_handle_t handle)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;


3. CAN 通信睡眠
CAN 通信睡眠的函数原型为:
am_can_err_t am_can_sleep (am_can_handle_t handle)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;


4. CAN 通信唤醒
CAN 通信唤醒的函数原型为:
am_can_err_t am_can_wakeup (am_can_handle_t handle)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • 返回值为 AM_CAN_NOERROR, 唤醒成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则唤醒失败,参数错误;


5. CAN 中断使能
CAN 中断使能的函数原型为:
am_can_err_t am_can_int_enable (am_can_handle_t handle, am_can_int_type_t mask)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • mask 为中断类型;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;


AMetal 中定义了 CAN 的中断类型, 详见表2。

CAN 中断类型宏
功能说明
AM_CAN_INT_NONE
无类型中断
AM_CAN_INT_ERROR
错误中断
AM_CAN_INT_BUS_OFF
总线关闭中断
AM_CAN_INT_WAKE_UP
唤醒中断
AM_CAN_INT_TX
发送中断
AM_CAN_INT_RX
接收中断
AM_CAN_INT_DATAOVER
总线超载中断
AM_CAN_INT_WARN
警告中断
AM_CAN_INT_ERROR_PASSIVE
错误被动中断
AM_CAN_INT_ALL
所有中断
表 2 中断类型说明

6. CAN 中断禁能
CAN 中断禁能的函数原型为:am_can_err_t am_can_int_disable (am_can_handle_t handle, am_can_int_type_t mask)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • mask 为中断类型;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;


AMetal 中定义了 CAN 的中断类型, 详见表2。

7. CAN 设置模式
CAN 工作模式设置的函数原型为:
am_can_err_t am_can_mode_set (am_can_handle_t handle,
                              am_can_mode_type_t  mode)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • mode 为工作模式;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;


AMetal 中定义了 CAN 的工作模式,详见表3。

CAN 工作模式宏说明
模式说明
AM_CAN_MODE_NROMAL
正常工作模式
AM_CAN_MODE_LISTEN_ONLY
只听工作模式
表 3 CAN 工作模式说明
8. CAN 设置波特率
CAN 波特率设置的函数原型为:
am_can_err_t am_can_baudrate_set (am_can_handle_t handle,
                                  struct am_can_bps_param *p_can_baudrate)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • p_can_baudrate 为波特率结构体指针;
  • 返回值为 AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;



9. CAN 获取波特率
CAN 波特率获取的函数原型为:
am_can_err_t am_can_baudrate_get (am_can_handle_t struct handle,
                                  am_can_bps_param *p_can_baudrate)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_can_baudrate为波特率结构体指针;
  • 返回值为 AM_CAN_NOERROR,获取成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则获取失败,参数错误;


10. CAN 获取错误计数
CAN 获取错误计数的函数原型为:
am_can_err_t am_can_err_cnt_get ( am_can_handle_t handle,
                                  struct am_can_err_cnt *p_can_err_cnt)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_can_err_cnt为错误计数的结构体指针;
  • 返回值为 AM_CAN_NOERROR,获取成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER 则获取失败,参数错误;


11. CAN 清空错误计数
CAN 清空错误计数的函数原型为:
am_can_err_t am_can_err_cnt_clr (am_can_handle_t handle)

  • handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
  • 返回值为 AM_CAN_NOERROR, 清空成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则清空失败,参数错误;


12. CAN发送消息
CAN发送消息的函数原型为:
am_can_err_t am_can_msg_send(am_can_handle_t handle,
                             am_can_message_t *p_txmsg)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_txmsg为发送消息的结构体指针;
  • 返回值为AM_CAN_NOERROR,发送成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则发送失败,参数错误;


13. CAN接收消息
CAN接收消息的函数原型为:am_can_err_t am_can_msg_recv(am_can_handle_t handle,
                             am_can_message_t *p_rxmsg)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_rxmsg为发送消息的结构体指针;
  • 返回值为AM_CAN_NOERROR,接收成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则接收失败,参数错误;


14. CAN停止发送消息
CAN停止发送消息的函数原型为:
am_can_err_t am_can_msg_stop_send(am_can_handle_t handle)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • 返回值为AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;


15. CAN设置滤波
CAN设置滤波的函数原型为:am_can_err_t am_can_filter_tab_set (am_can_handle_t handle,
                                    uint8_t *p_filterbuff,
                                    size_t lenth)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_filterbuff为滤波表的首地址;
  • lenth为滤波表长度;
  • 返回值为AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;


16. CAN获取设置滤波
CAN获取设置滤波的函数原型为:
am_can_err_t am_can_filter_tab_get (am_can_handle_t handle,
                                    uint8_t *p_filterbuff,
                                    size_t *p_lenth)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_filterbuff为滤波表的首地址;
  • lenth为滤波表长度;
  • 返回值为AM_CAN_NOERROR,获取成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则获取失败,参数错误;


17. CAN状态获取
CAN获取状态的函数原型为:am_can_err_t am_can_status_get (am_can_handle_t handle,
                                am_can_int_type_t *p_int_type,
                                am_can_bus_err_t *p_bus_err)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • p_int_type为中断类型;
  • p_bus_err为总线错误类型;
  • 返回值为AM_CAN_NOERROR,获取成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则获取失败,参数错误;


18. CAN中断连接
CAN中断连接的函数原型为:
am_can_err_t am_can_connect (am_can_handle_t handle,
                             am_pfnvoid_t pfn_isr,
                             void *p_arg)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • pfn_isr为中断服务函数;
  • p_arg为中断服务参数;
  • 返回值为AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;


19. CAN删除中断连接
CAN删除中断连接的函数原型为:
am_can_err_t am_can_disconnect (am_can_handle_t handle,
                                am_pfnvoid_t pfn_isr,
                                void *p_arg)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • pfn_isr为中断服务函数;
  • p_arg为中断服务参数;
  • 返回值为AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;


20. CAN注册中断回调函数
CAN注册中断回调函数的原型为:
am_can_err_t am_can_intcb_connect (am_can_handle_t handle,
                                   am_can_int_type_t inttype,
                                   am_pfnvoid_t pfn_callback,
                                   void *p_arg)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • inttype为中断类型;
  • pfn_callback为中断回调函数;
  • p_arg为回调函数参数;
  • 返回值为AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;


21. CAN解除中断回调函数的注册
CAN解除中断回调函数注册的函数原型为:
am_can_err_t am_can_intcb_connect (am_can_handle_t handle,
                                   am_can_int_type_t inttype,
                                   am_pfnvoid_t pfn_callback,
                                   void *p_arg)

  • handle为CAN的服务句柄,即为初始化CAN获取的句柄;
  • inttype为中断类型;
  • 返回值为AM_CAN_NOERROR,设置成功;
  • 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;



  应用实例  

本例将演示一个CAN通信的示例,需要通过USB转CAN连接到PC端,借助USB转CAN的上位机来演示收发过程。为了便于观察,可以通过串口观察收到的数据,实现代码如下:
#include "ametal.h"
#include "am_can.h"
#include "am_delay.h"
#include "am_vdebug.h"
#include "amhw_mm32l073_can.h"
#include "am_mm32l073_can.h"
/* 滤波表 */
static uint8_t table[8] = {0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xc0};
/* 错误判断*/
static void __can_err_sta(am_can_bus_err_t err)
{
if (err & AM_CAN_BUS_ERR_BIT)
{ /* 位错误 */
  am_kprintf(("AM_CAN_BUS_ERR_BITn"));
}
if (err &AM_CAN_BUS_ERR_ACK)
{ /* 应答错误 */
  am_kprintf(("AM_CAN_BUS_ERR_ACKn"));
}
if (err &AM_CAN_BUS_ERR_CRC)
{ /* CRC 错误 */
  am_kprintf(("AM_CAN_BUS_ERR_CRCn"));
}
if (err &AM_CAN_BUS_ERR_FORM)
{ /* 格式错误 */
  am_kprintf(("AM_CAN_BUS_ERR_FORMn"));
}
if (err &AM_CAN_BUS_ERR_STUFF)
{ /* 填充错误 */
  am_kprintf(("AM_CAN_BUS_ERR_STUFFn"));
}
}

/* 例程入口 */
void demo_mm32l073_can_entry (am_can_handle_t can_handle,
am_can_bps_param_t *can_btr_baud)
{
am_can_err_t ret;
uint8_t i = 0;
am_can_message_t can_rcv_msg = {0};
am_can_bus_err_t can_bus_err_status;
am_can_int_type_t can_int_status;
/* 配置波特率 */
ret =am_can_baudrate_set (can_handle, can_btr_baud); //设置 CAN 波特率
if (ret == AM_CAN_NOERROR)
{
  am_kprintf("rnCAN: controller baudrate set ok. rn");
}
else
{
  am_kprintf("rnCAN: controller baudrate set error! %d rn", ret);
}
/* 配置滤波表 */
ret =am_can_filter_tab_set( can_handle,table,sizeof(table)/sizeof(uint8_t));
if (ret == AM_CAN_NOERROR)
{
  am_kprintf("rnCAN: controller filter tab set ok. rn");
}
else
{
  am_kprintf("rnCAN: controller filter tab set error! %d rn", ret);
}
/* 启动 can */
ret =am_can_start (can_handle);
if (ret == AM_CAN_NOERROR)
{
  am_kprintf("rnCAN: controller start rn");
}
else
{
  am_kprintf("rnCAN: controller start error! %d rn", ret);
}
AM_FOREVER {
             ret =am_can_msg_recv (can_handle, &can_rcv_msg); //接收数据
             if (can_rcv_msg.msglen || can_rcv_msg.flags || can_rcv_msg.id)
             { //校验ID
              am_kprintf("can recv id: 0x%xrn",can_rcv_msg.id);
              for (i = 0; i < can_rcv_msg.msglen; i++)
              {
               am_kprintf("data: 0x%x rn",can_rcv_msg.msgdata);
              }
              ret =am_can_msg_send (can_handle, &can_rcv_msg); //数据发送
              if (ret == AM_CAN_NOERROR)
              {
               am_kprintf(("rnCAN: controller rcv data ok. rn"));
              }
              else
              {
               am_kprintf("rnCAN: controller no rcv data! rn");
              }
             }
             ret =am_can_status_get (can_handle, //获取 CAN 通信状态
                                     &can_int_status,
                                     &can_bus_err_status);
             am_mdelay(10);
             if (can_bus_err_status != AM_CAN_BUS_ERR_NONE)
             {
              __can_err_sta(can_bus_err_status);
             }
            }
}

更多回帖

×
20
完善资料,
赚取积分