5127|1

5260

帖子

239

TA的资源

管理员

楼主
 

AM335x的PRUSSv2简介与使用 [复制链接]

转帖:http://blog.csdn.net/wyt2013/article/details/17429399
PRUSSv2= Programmable Real-time Unit Sub-System = PRU-ICSS = PRU Industrial Communication Sub-System = 上一代PRUSSv2进化版
这是一个AM335x等芯片上自带的,独立于ARM CPU运行的子系统。其时钟频率为200MHz,可以直接控制特定的IO口,可以达到非常高的实时性要求。一般两种情况需要用到它:一是linux系统的实时性不满足要求的时候;二是芯片的功能模块不够用的时候(比如你想要10UART,但芯片上只有6个,那你可以用它再创造4个)。
几个可能的应用场合:
高速ADC
摄像机接口
显示屏接口
音频处理
电机反馈控制
从某种意义上说,有了它,我们就有了一个片上CPLDFPGA,只不过PRU编程不是用VDHL语言,而是用专门的汇编语言。它的汇编语句都是在一个时钟周期内执行完的,没有流水线之类可能扰乱程序时序的因素,这使得程序的可预测性大大提高。
AM335x芯片上带有两个PRU。(不知道能不能同时工作?)
配置BBB,安装PRU assembler和示例程序
root@beaglebone:~/tmp# git clone git://github.com/beagleboard/am335x_pru_package.git
Cloning into 'am335x_pru_package'...
...
root@beaglebone:~/tmp# cd am335x_pru_package/pru_sw/app_loader/interface
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/app_loader/interface# make CROSS_COMPILE="" #无需交叉编译
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/app_loader/interface# cd ../../utils/pasm_source
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/utils/pasm_source# ./linuxbuild
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/utils/pasm_source# cd ../../example_apps
root@beaglebone:~/tmp# git clone git://github.com/beagleboard/am335x_pru_package.git
Cloning into 'am335x_pru_package'...
...
root@beaglebone:~/tmp# cd am335x_pru_package/pru_sw/app_loader/interface
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/app_loader/interface# make CROSS_COMPILE="" #无需交叉编译
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/app_loader/interface# cd ../../utils/pasm_source
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/utils/pasm_source# ./linuxbuild
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/utils/pasm_source# cd ../../example_apps
编辑一下example_apps目录中的Makefile,把 PASM?=../utils/pasm_2 改成 PASM?=../utils/pasm_2.arm,然后继续
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/example_apps# make CROSS_COMPILE=""
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/example_apps# make CROSS_COMPILE=""
编译完成以后PRU assembler和示例程序就安装好了。但BBB默认是没有使能pruss的(BB white好像不用进行下面这一步),所以还需要修改一下系统dtb文件
cd /boot
cp am335x-boneblack.dtb am335x-boneblack.dtb_orig
dtc -I dtb -O dts am335x-boneblack.dtb > am335x-boneblack.dts
cd /boot
cp am335x-boneblack.dtb am335x-boneblack.dtb_orig
dtc -I dtb -O dts am335x-boneblack.dtb > am335x-boneblack.dts
(插一句,我之前没有仔细看过dtc命令,原来还可以反编译dtb文件啊。。。)
找到
pruss@4a30000 {
...
status = "disabled";
...
};
pruss@4a30000 {
...
status = "disabled";
...
};
"disabled"改成"okay",保存。
dtc -I dts -O dtb am335x-boneblack.dts > am335x-boneblack.dtb_pru
cp am335x-boneblack.dtb_pru am335x-boneblack.dtb
dtc -I dts -O dtb am335x-boneblack.dts > am335x-boneblack.dtb_pru
cp am335x-boneblack.dtb_pru am335x-boneblack.dtb
然后重启。至此,BBB也已经配置好了。
重启后我们用自带的example_apps测试一下
root@beaglebone:~#cd tmp/am335x_pru_package/pru_sw/example_apps/bin
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/example_apps/bin# modprobe uio_pruss #每次重启都要运行这句话
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/example_apps/bin# ./PRU_memAccessPRUDataRam
INFO: Starting PRU_memAccessPRUDataRam example.
AM33XX
INFO: Initializing example.
INFO: Executing example.
File ./PRU_memAccessPRUDataRam.bin open passed
INFO: Waiting for HALT command.
INFO: PRU completed transfer.
INFO: Example executed succesfully.
root@beaglebone:~#cd tmp/am335x_pru_package/pru_sw/example_apps/bin
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/example_apps/bin# modprobe uio_pruss #每次重启都要运行这句话
root@beaglebone:~/tmp/am335x_pru_package/pru_sw/example_apps/bin# ./PRU_memAccessPRUDataRam
INFO: Starting PRU_memAccessPRUDataRam example.
AM33XX
        INFO: Initializing example.
        INFO: Executing example.
File ./PRU_memAccessPRUDataRam.bin open passed
        INFO: Waiting for HALT command.
        INFO: PRU completed transfer.
INFO: Example executed succesfully.
测试成功。
本文最开始的git文件建议在电脑上也clone一份,里面有几个关于PRUpdf文档可能需要经常查看。
现在,已经安装好了am335x_pru_package,本文将用它来编写、编译一个最简单的PRU程序——闪烁BBB上的led灯。
大体来说每个PRU程序都包括两部分:
ARM核的Linux系统中运行的C语言程序
PRU中运行的汇编程序(编译成.bin文件)
其中c语言程序有两个作用:将汇编程序传到PRU中;与PRU程序互相传递数据和互动。
汇编程序源文件包括.p.hp两种后缀的文件,最后编译成.bin文件被传到PRU执行。.hp文件类似于c语言的.h头文件,可以在.p文件中被include,它不是必须的,本例为了简单起见也不用.hp文件。
OK,我们开始做吧!
Step by step步骤
首先新建两个文件,内容分别如下:
//mytest.c  
#include   
#include   
#include   
#define PRU_NUM 0  
int main (void)
{
unsigned int ret;
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
prussdrv_init ();//Initialize the PRU  
if (prussdrv_open(PRU_EVTOUT_0))//Open PRU Interrupt  
{
printf("prussdrv_open open failed\n");
return (-1);
}
prussdrv_pruintc_init(&pruss_intc_initdata);
prussdrv_exec_program (PRU_NUM, "./prucode.bin");//Execute example on PRU  
prussdrv_pru_wait_event (PRU_EVTOUT_0);//Waiting for this instruction: MOV r31.b0, PRU0_ARM_INTERRUPT+16  
prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT);
prussdrv_pru_disable (PRU_NUM);//Disable PRU and close memory mapping  
prussdrv_exit ();
return(0);
}
//mytest.c
#include
#include
#include
#define PRU_NUM 0
int main (void)
{
    unsigned int ret;
    tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
   
    prussdrv_init ();//Initialize the PRU
    if (prussdrv_open(PRU_EVTOUT_0))//Open PRU Interrupt
    {
        printf("prussdrv_open open failed\n");
        return (-1);
    }
    prussdrv_pruintc_init(&pruss_intc_initdata);
    prussdrv_exec_program (PRU_NUM, "./prucode.bin");//Execute example on PRU
    prussdrv_pru_wait_event (PRU_EVTOUT_0);//Waiting for this instruction: MOV r31.b0, PRU0_ARM_INTERRUPT+16
    prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT);
    prussdrv_pru_disable (PRU_NUM);//Disable PRU and close memory mapping
    prussdrv_exit ();
    return(0);
}
//prucode.p  
.origin 0
.entrypoint START
//Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h  
#define PRU0_ARM_INTERRUPT 19  
#define CONST_PRUCFG C4  
//Refer to AM335X Technical Reference Manual & BBB SRM  
#define GPIO1 0x4804c000  
#define GPIO_CLEARDATAOUT 0x190  
#define GPIO_SETDATAOUT 0x194  
START:
// Enable OCP master port  
LBCO r0, CONST_PRUCFG, 4, 4
CLR r0, r0, 4 // Clear SYSCFG[STANDBY_INIT] to enable OCP master port  
SBCO r0, CONST_PRUCFG, 4, 4
MOV r1, 3 // loop 3 times  
LOOP0:
MOV r2, 1<<22
MOV r3, GPIO1 | GPIO_SETDATAOUT
SBBO r2, r3, 0, 4
MOV r0, 100000000
DEL1:
SUB r0, r0, 1
QBNE DEL1, r0, 0
MOV r2, 1<<22
MOV r3, GPIO1 | GPIO_CLEARDATAOUT
SBBO r2, r3, 0, 4
MOV r0, 100000000
DEL2:
SUB r0, r0, 1
QBNE DEL2, r0, 0
SUB r1, r1, 1
QBNE LOOP0, r1, 0
// Send notification to Host for program completion  
MOV r31.b0, PRU0_ARM_INTERRUPT+16
// Halt the processor  
HALT
//prucode.p
.origin 0
.entrypoint START
//Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h
#define PRU0_ARM_INTERRUPT      19
#define CONST_PRUCFG            C4
//Refer to AM335X Technical Reference Manual & BBB SRM
#define GPIO1 0x4804c000
#define GPIO_CLEARDATAOUT 0x190
#define GPIO_SETDATAOUT 0x194
START:
    // Enable OCP master port
    LBCO      r0, CONST_PRUCFG, 4, 4
    CLR       r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
    SBCO      r0, CONST_PRUCFG, 4, 4
    MOV r1, 3 // loop 3 times
LOOP0:
    MOV r2, 1<<22
    MOV r3, GPIO1 | GPIO_SETDATAOUT
    SBBO r2, r3, 0, 4
    MOV r0, 100000000
DEL1:
    SUB r0, r0, 1
    QBNE DEL1, r0, 0
    MOV r2, 1<<22
    MOV r3, GPIO1 | GPIO_CLEARDATAOUT
    SBBO r2, r3, 0, 4
    MOV r0, 100000000
DEL2:
    SUB r0, r0, 1
    QBNE DEL2, r0, 0
    SUB r1, r1, 1
    QBNE LOOP0, r1, 0
    // Send notification to Host for program completion
    MOV       r31.b0, PRU0_ARM_INTERRUPT+16
    // Halt the processor
    HALT
然后编译它们。编译之前先从am335x_pru_package中复制一些必要文件到标准目录中,省得我们添加引用目录。
pru_sw/app_loader/lib目录中的 libprussdrv.a 拷贝到 /usr/lib 中;
pru_sw/app_loader/include 目录中的两个文件都拷贝到 /usr/include 中;
pru_sw/utils 目录中的 pasm 拷贝到 /usr/bin 中。
下面开始编译,执行下面两条命令。
gcc mytest.c -lpthread -lprussdrv -o mytest
pasm -b prucode.p
gcc mytest.c -lpthread -lprussdrv -o mytest
pasm -b prucode.p
(其中 -lpthread -lprussdrv 参数是指要使用 libpthread.so libprussdrv.a这两个库文件。)
编译完以后就生成了要在linux中运行的mytest程序和要传到PRU中的prucode.bin文件。
注意,在运行程序前,还需要做一件事。用lsmod命令查看一下uio_pruss模块有没有加载。如果没有的话,手动加载一下。这个应该加载一次就可以了。
modprobe uio_pruss
modprobe uio_pruss
一切就绪!下面输入 ./mytest 来执行一下程序吧!
顺利的话你会看到第二个led灯亮灭了三次,每次亮和灭的时间是1秒钟。
几点分析
在执行过程中,终端处于忙碌状态,如果在这期间你按下Crtl+C终止了程序,会发现led还在按照原来的规律继续闪烁,可见灯的亮灭,或者说PRU的程序运行并不受linux程序的影响。
PRU简介中提到AM33xxPRUSSv2的主频是200MHz,每条汇编指令执行时间是一个时钟周期。通过这个程序也可以得到验证:
MOV r0, 100000000
:
SUB r0, r0, 1
QBNE DEL1, r0, 0
    MOV r0, 100000000
DEL1:
    SUB r0, r0, 1
    QBNE DEL1, r0, 0
在这个循环等待的部分,不断对寄存器r0执行自减1和判断是否为零这两条指令,执行了100M次,所以延时为1秒。
汇编程序START:紧接着的第一部分
// Enable OCP master port  
LBCO r0, CONST_PRUCFG, 4, 4
CLR r0, r0, 4 // Clear SYSCFG[STANDBY_INIT] to enable OCP master port  
SBCO r0, CONST_PRUCFG, 4, 4
    // Enable OCP master port
    LBCO      r0, CONST_PRUCFG, 4, 4
    CLR       r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
    SBCO      r0, CONST_PRUCFG, 4, 4
它把SYSCFG寄存器的STANDBY_INIT位置零,否则的话将无法访问任何外部memory,包括ARM的内存和IO口等。所以记得在每个程序一开始都加上这三条指令。
file:///C:/Users/ADMINI~1/AppData/Local/Temp/ksohtml/wps_clip_image-11722.png
Second choices
最后,如果你不想用官方工具,这里有second choicehttp://www.element14.com/community/community/knode/single-board_computers/next-gen_beaglebone/blog/2013/06/16/bbb--getting-ace-working
如果你想用java脚本与PRU里的程序互动,可以参考这里:https://npmjs.org/package/pru
上面这两个东西我都没仔细看过,仅列出来供参考。
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身

最新回复

"二是芯片的功能模块不够用的时候(比如你想要10个UART,但芯片上只有6个,那你可以用它再创造4个)"---是不是也可以说是可以有4个以太网?   详情 回复 发表于 2014-5-31 11:34
点赞 关注
 

回复
举报

20

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
"二是芯片的功能模块不够用的时候(比如你想要10个UART,但芯片上只有6个,那你可以用它再创造4个)"---是不是也可以说是可以有4个以太网?
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表