ESM7000异构CPU实时应用——支持高分辨率旋转编码器

 2022-8-10 10:04:32     作者:刘乾坤 黄志超    

ESM7000是英创基于i.MX7D处理器开发的低功耗高性能工控主板,支持双网口、6串口、双CAN总线接口、PCIe、ISA总线等丰富的通讯接口,支持18-bit并行RGB或LVDS显示接口。主CPU i.MX7D是NXP推出的异构多核处理器,配置了主频高达1GHz的ARM Cortex-A7双核和一颗运行速度240MHz、带硬件浮点运算的ARM Cortex-M4内核。Linux系统在Cortex-A7核心上运行,对于一些实时性要求极高的应用,Linux系统可能无法满足对中断事件的及时响应,而且频繁的中断响应也会大大的降低操作系统性能。对这类应用场合就可充分利用i.MX7D异构多核结构,由高性能的Cortex-A7(Linux系统)完成人机交互、数据处理、通讯管理等复杂运算,而对于实时的数据采集、高速的中断事件响应等实时任务交由Cotex-M4完成。


旋转编码器是工业领域最常见的传感器之一,通过对编码器输出的A/B脉冲信号个数及相位的识别,就可以得到精确的转速或位置信息。以欧姆龙的E6B2系列旋转编码器为例,当编码器分辨率200个脉冲/转,每分钟旋转3000转时,编码器输出脉冲频率为10KHz,如果将编码器分辨率提高到2000个脉冲/转,则编码器输出脉冲频率为100KHz。对于高分辨率旋转编码器的支持,通常需要SOC内部具有专门针对编码器硬件的硬件脉冲计数器,或通过独立的单片机来实现。


对于ESM7000工控主板,主CPU i.MX7D内部没有专门的硬件脉冲计数器,但我们可充分利用ESM7000的异构CPU结构,由i.MX7D内的Cortex-M4 来对编码器脉冲信号进行解析和计算,而Linux系统只需要直接从M4处获取计算结果即可。这样就将高速中断的响应和处理全部交给了M4,Linux系统几乎没有任何负载。我们在M4上运行了FreeRTOS操作系统,具有很高的实时性,根据实际测试可以满足同时两路100KHz频率的脉冲输入。在Linux侧设计了相应的驱动程序和提供相应的驱动程序API,为客户外接高分辨率旋转编码器提供了一种快速低成本的解决方案。


接口硬件说明


下面是欧姆龙旋转编码器E6B2-CWZ1X输出的脉冲信号,对于速度或位置监测,只需要接入A相和B相信号,如果选择接入`A /`B相,只需要在软件设置中将初始电平极性设置为1(高电平)即可。

image.png


上图的左边是A、B相在编码器顺时针方向旋转时的波形,其特点是A相脉冲超前B相脉冲90°相位。而图的右边是编码器逆时针旋转时的波形,此时B相超前A相90°相位。


ESM7000的GPIO仅支持3.3V TTL电平信号输入,旋转编码器的脉冲信号通常需要经过隔离及电平转换电路后,才能接入ESM7000的相应管脚。ESM7000支持两路旋转编码器对应的管脚如下:

编码器编码器信号ESM7000管脚简要说明
旋转编码器1ESM8000异构CPU实时应用——支持高分辨率旋转编码器.pngGPIO18支持最高100KHz脉冲输入,3.3V TTL电平
ESM8000异构CPU实时应用——支持高分辨率旋转编码器.pngGPIO19
旋转编码器2ESM8000异构CPU实时应用——支持高分辨率旋转编码器.pngGPIO20
ESM8000异构CPU实时应用——支持高分辨率旋转编码器.pngGPIO21


接口软件说明


在ESM7000的Linux系统中,可以通过RPMsg和Crotex-M4进行通讯来获取相关的信息,关于RPMsg的介绍可以参考《ESM7000异构CPU实时应用之二基于rpmsg的通讯机制》。为了方便使用,英创公司以字符设备的方式提供了相应的驱动文件,加载后会在/dev目录下生成em_rpmsg_rot0和em_rpmsg_rot1两个设备节点,分别对应两路旋转编码器的硬件接口。在驱动中会通过RPMsg和Crotex-M4进行通信以及数据的处理,但对于用户来说是不需要关心的,直接使用标准的字符设备操作函数即可。驱动会将用户程序对设备的操作通过RPMsg发送给Crotex-M4,然后由Crotex-M4实际对硬件执行对应的操作,如下图所示:

                                                                                             

image.png

驱动文件在系统启动完成后会自动加载,如下图:

image.png


可以看到在/dev目录下会生成相应的设备节点,按照字符设备的操作操作流程,首先需要调用open函数打开设备节点,成功后会就返回句柄:

int fd;  
  
fd = open("/dev/em_rpmsg_rot1", O_RDWR);  
if(fd < 0) {  
      printf("open device failed!\n");  
      return fd;  
}



通过返回的句柄,就可以调用write和read函数来操作设备了,我们使用write函数用于设置旋转编码器的采集,我们一共定义了五种操作,分别是设置正极性,设置负极性,开始,停止以及复位。具体定义以及通过write函数设置的代码如下:

#define ROT_POL_NEGATIVE     0        //负极性,初始电平为低  
#define ROT_POL_POSITIVE     1        //正极性,初始电平为高  
#define ROT_START            2        //启动旋转编码器采集  
#define ROT_RESET            3        //复位计数  
#define ROT_STOP             4        //停止旋转编码器采集  
  
int cmd;  
  
//设置负极性    
cmd = ROT_POL_NEGATIVE;    
ret = write(fd, &cmd, sizeof(cmd));    
if(ret < 0) {    
      printf("write cmd failed!\n");    
}    
        
//启动    
cmd = ROT_START;    
ret = write(fd, &cmd, sizeof(cmd));    
if(ret < 0) {    
      printf("write cmd failed!\n");    
}


当启动了旋转编码器之后,程序中可以通过read函数来读取当前的计数值,计数值为一个整型数据,正负代表方向。根据计数值,根据实际应用的不同就可以计算出位置,角度等数据。

int val;  
  
//读取计数值,计数值为一个整型数据,正负代表方向  
ret = read(fd, &val, sizeof(int));  
if(ret < 0) {  
      printf("read cmd failed!\n");  
}  
printf("val = %d\n", val);


本文中仅通过旋转编码器来获取位置信息,同样的方法也可用来实现对转速的监控,感兴趣的客户,可以和英创的工程师联系,索取完整的测试代码。