设备树配置:
1)别名的定义
aliases {
ethernet0 = ðernet0;
serial0 = &uart4;
serial1 = &usart2;
serial2 = &uart7;
};
圈红色的部分非常关键,定义USART2使用serial1的别名,否则系统启动时候会提示“找不到别名,errno=-19”的错误。
2)Pinctrl引脚定义
这里我们重定义USART2的引脚为PF4和PF5 。
usart2_pins_b: usart2-0 {
pins1 {
pinmux = ; /* USART2_TX */
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = ; /* USART2_RX */
bias-disable;
};
};
usart2_idle_pins_b: usart2-idle-0 {
pins1 {
pinmux = ; /* USART2_TX */
};
pins2 {
pinmux = ; /* USART2_RX */
bias-disable;
};
};
usart2_sleep_pins_b: usart2-sleep-0 {
pins {
pinmux = , /* USART2_TX */
; /*USART2_RX */ };
};
3)使能USRAT2外设
仿照其它外设的使能方式,使用USART2外设,并分配资源到linux系统。
&usart2 {
pinctrl-names = "default","sleep", "idle";
pinctrl-0 = <&usart2_pins_b>;
pinctrl-1 =<&usart2_sleep_pins_b>;
pinctrl-2 = <&usart2_idle_pins_b>;
status = "okay";
};
2.9. 实时数据库在通讯协议转化中,尤其是复杂的系统下面,使用实时数据库的情况非常普遍。但是比较复杂和性能好的实时内存数据库多是收费的,对于简单测试应用还得开源的。最近在网上看了redis这个数据库,感觉比较简单,重要的是还是免费开源的,所以准备用这个数据库试试。
源码下载地址:
http://download.redis.io/releases/
选择redis-stable版本就可以了。
我们需要对它进行交叉编译,这个网上非常多,这里不罗嗦了。将编译好的执行文件安装到我们DK1板的系统中。
这里要提到重点是这个实时数据库的操作接口函数,redis提供了很多中语言的操作接口支持,我选择是C语言支持接口,叫做hiredis。
源码下载地址:
https://github.com/redis/hiredis
同样我们需要对这个接口库进行交叉编译,生成相应的库文件,当然也可以直接使用源码放到自己的工程中。我这里编译成库文件了。
2.9.1. Hiredis介绍hiredis是一个轻量级的访问redis数据库的c客户端。
它是轻量级的不仅仅是因为它仅仅提供对协议的最小支持,而且它使用了一个高级别的极度类似于printf的api使它的级别远高于其最小代码库和缺乏绑定的redis命令。简而言之,就是更灵活。
除了支持发送命令和接受命令,它还有一个与io层分离的回复解析器。它是一个简单灵活的流解析器,可以用于更高级别的语言绑定以实现有效的回复解析。
hiredis仅仅支持二进制安全的redsi协议,因此你可以使用它在redis的版本的大于1.2.0.
hiredis提供多套api,包括同步的api,异步api,回复解析的api.
下面介绍一下API接口的基本使用,更深层次的使用还需要进一步的研究。
1)数据库连接
/**连接数据库*/
redisContext *redisConnect(const char *ip,int port);
其中:ip为数据库的ip地址,本机使用也可以是127.0.0.1
port:为redis数据监听的端口号,redis默认监听的端口号为6379
2)资源释放
/*释放资源*/
void freeReplyObject(void *reply);
void redisFree(redisContext *c);
3)发送命令
/**发送命令请求*/
void *redisCommand(redisContext*c, const char *format, ...);
void *redisCommandArgv(redisContext *c, intargc, const char **argv, const size_t *argvlen);
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, intargc, const char **argv, const size_t *argvlen);
用的比较多的是redisCommand这个函数,还有其它几个函数,如果将来应用的话在深入研究。
n 参数说明
· 这个函数是一个带有不定参数的。可以按着format格式给出对应的参数,这就和printf函数类似。
· c 是一个reidsConnect函数返回的一个对象。
n 返回值
· 返回值是一个void类型的指针,实际为指向一个redisReply类型的指针。
· redisReply的定义
/* This is the reply object returned by redisCommand() */typedef struct redisReply { /*命令执行结果的返回类型*/ int type; /* REDIS_REPLY_* */ /*存储执行结果返回为整数*/ long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ /*字符串值的长度*/ size_t len; /* Length of string */ /*存储命令执行结果返回是字符串*/ char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ /*返回结果是数组的大小*/ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ /*存储执行结果返回是数组*/ struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */} redisReply;返回结果的类型reply->type,reply 为redisReply* 类型。
· REDIS_REPLY_STRING == 1:返回值是字符串,字符串储存在redis->str当中,字符串长度为redis->len。
· REDIS_REPLY_ARRAY== 2:返回值是数组,数组大小存在redis->elements里面,数组值存储在redis->element里面。数组里面存储的是指向redisReply的指针,数组里面的返回值可以通过redis->element->str来访问,数组的结果里全是type==REDIS_REPLY_STRING的redisReply对象指针。
· REDIS_REPLY_INTEGER == 3:返回值为整数 long long。
· REDIS_REPLY_NIL==4:返回值为空表示执行结果为空。
· REDIS_REPLY_STATUS ==5:返回命令执行的状态,比如set foo bar 返回的状态为OK,存储在str当中reply->str == "OK"。
· REDIS_REPLY_ERROR ==6 :命令执行错误,错误信息存放在 reply->str当中。
返回结果示例:
· set key value : 返回 string reply->str == "OK"。
A. hset key hkeyvalue:返回 integer reply->integer == 1。
B. hdel key hkey:返回 integer reply->integer==1。
C. sadd set member:返回 integerreply->integer ==1。
D. sismember setkeymember:返回 integer reply->integer ==1。
E. smembers setkey:返回 arrayreply->element->str为返回结果值。
hiredis提供的是一套redis数据库的客户端接口,他的使用需要具有一定的顺序。通常是先用 redisConnect 连接数据库,然后用 redisCommand 执行命令,执行完后用 freeReplyObject 来释放redisReply对象,最后用redisFree 来释放整个连接。
2.9.2. 实时数据库监视软件我发现了一个比较好的监视查询软件,treeNMS。它通过浏览器来观察redis数据的运行状态和数据库中的内容,挺方便,具体的使用方法希望大家网络搜索一下。
3. 应用程序基本结构Linux上的应用程序采用多线程技术,对于每个操作对象均采用独立的线程完成数据的收发和数据库写入操作。
应用程序中包含CAN总线收发线程,RS485总线收发线程,核间通讯收发线程等几个线程。
4. 结果验证
通过数据库中的内容刷新显示,我们可以观察到CAN-KEY、SERIAL-KEY和AD的8个通道数据的变化,说明我们的系统运作正常。
5. 总结通过这段时间对于STM32MP157A-DK1的研究和使用,尤其是异构多核的研究我发现了他的几个特点。
优点是:
A. 异构多核结构使MP1的应用灵活,适用范围广泛;
B. A7的主频650MHz~800MHz,CM4的主频209MHz,适合工控领域应用;
C. ST提供的CubeMAX和CubeIDE工具很强大,尤其对CM4内核应用开发,无处不看到STM32系列处理器熟悉的身影,比较容易接受,上手还算快;
D. 内部集成的资源外设大多数都可以在A7和CM4间共享,让工程实践中多了更多的选择;
E. CM4内核具备400KB的SRAM空间,这点设计太好了,可以将实时部分全功能软件都搬过来;
F. 大多数的引脚都是5V兼容,让硬件设计简化了好多;
G. 功耗比较低。
缺点是:
A. 官方还没有RT-linux系统的支持;
B. MP1就集成了一个以太网接口,对于工业应用来说太少了,最少二个;
总体感觉这款芯片对于工控应用比较适合,希望ST可以发展出来更多的同类产品,丰富自己的产品线,让我们可以有更多的选择。