英创公司推出了ESM7000异构CPU的实时应用,由高性能的Cortex-A7双核完成人机交互、数据处理、通讯管理等复杂运算,而对于高速的数据采集、中断事件响应等实时任务交由i.MX7D的Cotex-M4完成,具体的介绍可以参考文章《ESM7000异构CPU架构实时应用简介》。基于ESM7000的异构CPU平台,英创公司实现了多通道的高速数采方案,该方案最高支持100kSPS采样率的AD转换。
关于M4端的AD操作的实现可以参考文章《ESM7000异构CPU实时应用之一 8通道并行100K 16bit AD采集》,本文主要介绍Linux系统中需要做的操作以及程序的实现,文章分为三个部分,第一部分是介绍如何将编译好的M4程序烧写到主板中,并设置自动启动。第二部分是介绍如何加载英创公司提供的RPMsg驱动,RPMsg驱动主要实现了ESM7000中Crotex-A7核心与M4核心之间的通讯。第三部分是介绍Linux系统端User app的实现和性能的测试结果,其中User app正是通过英创公司定义的RPMsg通讯协议来实现的,关于RPMsg和通讯协议具体的介绍可以参考文章《ESM7000异构CPU实时应用之二 基于rpmsg的通讯机制》。
本文测试硬件平台基于ESM2001工控机,感兴趣的客户可参考这里:EMX2000系列工控机。
M4应用程序的烧写
首先将编译好的M4应用程序(这里以英创公司提供的例程emx2001.bin为例)拷贝到主板中的,例如/mnt/mmc中,然后就可以通过英创公司提供的工具flash_opt将程序烧写到系统中,并设置好随系统自动启动。flash_opt工具已经集成在了主板中,可以直接在命令执行。
M4的应用程序可以选择三个区域烧写,分别是TCM、OCRAM 或 DDR 中运行,在TCM中的运行速度最快,但是代码空间最小,OCRAM中运行速度会慢一些,代码空间相对更大,而DDR中代码运行速度最慢,但是代码空间最大。各个区域提供的程序代码空间具体数据如下表所示:
| Configure | 文件名 | CODE Size |
| TCM | emx2001_tcm.bin | 32K |
| OCRAM | emx2001_ocram.bin | 128K |
| DDR | emx2001_ddr.bin | 1MB |
在烧写前需要根据不同的烧写区域对程序重命名,如果需要烧写到TCM 中,则程序需要命名为 emx2001_tcm.bin,如果烧写到 OCRAM 中,则命名为 emx2001_ocram.bin,如果是烧写到 DDR,则为 emx2001_ddr.bin。重命名只是为了满足 flash_opt 对命令格式的要求,程序在编译时必须根据运行的位置选择对应的 ESM7000_M4_*.ld 文件。
比如我们需要将emx2001.bin放在TCM中,则将程序命名为emx2001_tcm.bin,然后输入命令#>flash_opt m4 /mnt/mmc/ emx2001_tcm.bin,如下图:

完成之后,每次主板重启就都会自动启动烧写进去的M4应用程序。关于程序放在不同区域的具体的说明和对比,可以参考《ESM7000 Cortex-M4技术开发参考手册》,这里不再赘述。
RPMsg驱动的加载
RPMsg的驱动也同样集成在了系统中,可以直接通过命令加载,只需要一条命令#>modprobe emx_rpmsg_tty,加载后驱动会生成响应的设备节点/dev/ttyEMx同时会打印出关于AD的信息,如下图:

从驱动打印的信息可以看到AD的详细参数信息。驱动加载完成后,就可以运行User app来进行采集了。
User app的实现和测试
通过《ESM7000异构CPU实时应用之二 基于rpmsg的通讯机制》的介绍,我们已经了解了英创公司设计的基于RPMsg的通讯协议,本文介绍的User app正是使用这一套通讯协议来实现的。
驱动emx_rpmsg_tty.ko会虚拟出串口设备,所以通信部分的代码都是使用的串口的标准操作函数来实现的。首先是向M4发送消息,设置好AD的采样率,然后启动AD,通过write函数就可以向M4发送数据,英创公司已经封装好了函数供客户参考:
int EM_Adc::setup_adc( int freq )
{
int ret;
struct emx_rpmsg_t *msg_t;
//打开虚拟串口ttyEMx,并建立好接收线程
ret = OpenPort();
if( ret<0 )
{
printf( "ttyEMx open fail\n");
return -1;
}
//发送复位指令
ret = Send_cmd(CMD_CODE_RESET, NULL, 0);
if( ret<0 )
{
printf( "send failed\n");
}
//发送设置指令,设置AD的采样率
ret = Send_cmd(CMD_CODE_SETUP, (void *)&freq, sizeof(freq));
if( ret<0 )
{
printf( "send failed\n");
}
//发送启动指令,开始采集
ret = Send_cmd(CMD_CODE_RUN, NULL, 0);
if( ret<0 )
{
printf( "send failed\n");
}
Dflags = 1;
return 0;
}
启动了AD之后,M4就会开始进行数据采集,因为多通过告诉采集的数据量十分庞大,所以采用了共享内存的方式来发送数据。例程定义了两块32KB大小的共享区域,当M4采集的数据量达到16K之后,就会将数据写入共享内存中,然后根据通讯协议发送消息通知User app去读取。我们还是通过一个线程来专门接收采集数据,具体代码如下:
int EM_Adc::PackagePro( char* Buf, int len )
{
int i1, num;
int buf_len;
char status_buf[100];
memcpy(&msg, (char *)Buf, sizeof(struct emx_rpmsg_t));
if(msg.cmd == CMD_CODE_DATA) {
Mlen = msg.len;
//判断数据存放在哪一块共享区域,然后将数据拷贝出来
if(msg.flags == 0) {
memcpy(MemBuf, (void *)base0, msg.len);
}
else {
memcpy(MemBuf, (void *)base1, msg.len);
}
//处理数据,这里是将每个通道的数据保存成文件
save_data(MemBuf, Mlen);
}
return 0;
}
例程中数据的处理主要是把每个通道的数据分离出来,分别保存在不同的文件中。为了保证写文件的速度,一开始是写在内存中,当文件大小超过1MB,就关闭AD,并且将文件拷贝到/mnt/mmc中储存,处理数据的代码如下:
int EM_Adc::save_data(int16_t *data, int len)
{
FILE *fp;
char filename[20];
int i1, i2, ret;
for(i1=0; i1<8; i1++) {
sprintf( filename, "/tmp/ch%d", i1);
fp = fopen(filename, "ab+");
if( fp==NULL )
{
printf("open %s fail!\n", filename);
ret = -1;
return ret;
}
//将每个通道的数据分离出来,分别保存在文件中
for(i2=0; i2<(len/16); i2++) {
memcpy(&CHxBuf[i2], ((int16_t *)data + i1 + i2*8), sizeof(int16_t));
}
fwrite( CHxBuf, (i2-1)*sizeof(int16_t), 1, fp );
//如果保存数据已经大于1M,则关闭AD,将文件移至/mnt/mmc目录保存,然后退出程序
if(i1 == 7) {
fseek(fp, 0, SEEK_END);
long length = ftell(fp);
if(length > 1024*1024) {
fclose(fp);
system("cp /tmp/ch* /mnt/mmc");
stop_adc();
return 0;
}
}
fclose(fp);
}
return 0;
}
在实际测试的时候,我们将两路正弦波信号分别接入通道1和通道2,当采集完成后使用波形绘制工具读取保存的文件,效果如下:

从图中可以看到采集波形的效果,在实际应用中,客户可以根据需求自行修改对于数据处理的方式。
M4端应用程序采用的方式是每采集16000字节发送一次数据,为了验证这套方案能够满足应用需求,我们对M4通过RPMsg发出消息,到Linux系统中User app读取到共享内存数据的时间做了详细的测试,响应时间如下表:
| 采样率 | 平均时间(us) | 最长时间(us) |
| 5ksps | 298 | 495 |
| 10ksps | 300 | 489 |
| 50ksps | 287 | 488 |
| 100ksps | 287 | 469 |
按照100ksps的采样率计算,M4端每10us会采集一次,每个通道单次采集数据大小为2Byte,8个通道就为16Byte。所以在100Ksps采样率的情况下,每10ms就会发送一次数据。按照这个时间间隔来看,ESM7000异构CPU平台完全可以满足需求。
对这套方案感兴趣的客户可以和英创公司的工程师联系,索取相关例程的代码。
成都英创信息技术有限公司 028-8618 0660