3622|4

603

帖子

1

TA的资源

纯净的硅(中级)

楼主
 

[BB方案]第四辑全月刊——php服务器+pruss初尝甜头+与pruss交换数据+php管道通信 [复制链接]

本帖最后由 sjtitr 于 2014-6-6 00:18 编辑

答应管理员本周内发新帖,就是要说到做到。
                                ——楼主


不做上辑回顾了。不只是因为上辑太遥远,实在想不起来做了什么;更是因为,这一辑是全新的开始,与前文无关,甚至,展开了一个全新的思路,不需要前文的技术铺垫了。
要不然也是计划本周整理一下的。忽悠一下,一个月过去了,上次也就是第三辑,已经过去一个月还多了。这一个月真的很忙很忙,工作上不能怠慢,家里琐事一堆。BBB的事尽管没有在桌面上,但是一直在心里,不断的挤出时间,沉淀一些知识。

纵然不回顾,也记得前面花了一个月的时间,研究BBB的内核驱动,为了利用驱动来实现红外遥控器功能。按照计划,第二个月,也就是刚刚过去的一个月,需要研究PHP相关的内容,以实现PHP和驱动的互动。如果你有耐心读完本文,你会知道,计划变了——本月没有花那么多时间研究PHP,最后的方案也不再使用内核驱动。究竟过去这一个月楼主都研究了些什么,且听我一一道来……鉴于现在还是挺忙的,大家的时间也宝贵,之后咱们就挑干的长话短说啦。

【一、PHP服务器的搭建】
@chenzhufly 老师还是很给力的,好多文章都不是白给的,仔细阅读,能节省不少青春岁月。

在beaglebone black上安装lighttp


仅仅是花了一会儿的时间,服务器就建立完毕,接下来是php的学习,不得不花点时间,学学网页开发吧。可以简单的编一些代码用于测试什么的。我还是喜欢到PHP 教程去学习,

只需两天,在服务器上建立自己的测试程序(php网页)就得心应手了。

如何用PHP页面控制小灯?我们来实现一个页面吧……

  1. <html>
  2. <head>
  3. <title>Test Page</title>
  4. </head>
  5. <body>
  6. <?php
  7.         $led = $_REQUEST['led'];
  8.         print("Hello World!");
  9.         echo nl2br("\n");
  10.         print("Led : ");
  11.         echo $led;
  12.         echo nl2br("\n");
  13.         print("sjtitr");
  14.         echo nl2br("\n");
  15.         if($led == 1)
  16.         {
  17.           $file = fopen("/sys/class/gpio/gpio44/value","w");
  18.           if($file)
  19.           {
  20.             fputs($file, "1");
  21.             fclose($file);
  22.           }
  23. ?>
  24. <a href="test.php?led=0">LED=0</a>
  25. <?php
  26.         }
  27.         else
  28.         {
  29.           $file = fopen("/sys/class/gpio/gpio44/value","w");
  30.           if($file)
  31.           {
  32.             fputs($file, "0");
  33.             fclose($file);
  34.           }
  35. ?>
  36. <a href="test.php?led=1">LED=1</a>
  37. <?php
  38.         }

  39. ?><br>
  40. </body>
  41. </html>
复制代码




使用页面以前呢,先通过命令行打开端口的设定。
  1. echo 44 > /sys/class/gpio/export
  2. echo out > /sys/class/gpio/gpio44/direction
  3. echo 1 > /sys/class/gpio/gpio44/value
复制代码



可是PHP如何与内核驱动结合起来呢?另外内核驱动控制小灯,明显频率不稳定,毕竟也参与系统调度中来了,那么如何获取精准的时序控制呢?那楼主第二周就来研究这个问题吧。

【二、pruss初次探秘】
不得不说,之前根本没有关注过BBB的这部分硬件内容。要不是我追求时序上的完美,几乎AM335x的这一利刃都要被我无视了。幸亏楼主孜孜不倦的搜索,终于被我给发现了——这是一个AM335x等芯片上自带的,独立于ARM CPU运行的子系统。其时钟频率为200MHz,可以直接控制特定的IO口,可以达到非常高的实时性要求。一般两种情况需要用到它:一是linux系统的实时性不满足要求的时候;二是芯片的功能模块不够用的时候(比如你想要10UART,但芯片上只有6个,那你可以用它再创造4个)。采自本论坛原文:AM335x的PRUSSv2简介与使用

同样的道理,参照该文,建立pruss的开发环境。最后可以操纵pruss对端口进行控制。

于是把之前做过的控制小灯的实验,搬到pru中来进行,还是那个引脚,还是那样连接……

楼主比较懒,所以还是先用命令行把端口设置妥当:

  1. echo 44 > /sys/class/gpio/export
  2. echo out > /sys/class/gpio/gpio44/direction
  3. echo 1 > /sys/class/gpio/gpio44/value
复制代码

之后pru只需要控制输出值的0、1就可以了。

  1. //prucode.p
  2. .origin 0
  3. .entrypoint START

  4. //Refer to this mapping in the file - prussdrvincludepruss_intc_mapping.h
  5. #define PRU0_ARM_INTERRUPT      19
  6. #define CONST_PRUCFG            C4

  7. //Refer to AM335X Technical Reference Manual & BBB SRM
  8. #define GPIO1 0x4804c000
  9. #define GPIO_CLEARDATAOUT 0x190
  10. #define GPIO_SETDATAOUT 0x194

  11. START:
  12.     // Enable OCP master port
  13.     LBCO      r0, CONST_PRUCFG, 4, 4
  14.     CLR       r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
  15.     SBCO      r0, CONST_PRUCFG, 4, 4

  16.     MOV r1, 3 // loop 3 times
  17. LOOP0:
  18.     MOV r2, 1<<12
  19.     MOV r3, GPIO1 | GPIO_SETDATAOUT
  20.     SBBO r2, r3, 0, 4

  21.     MOV r0, 20000000
  22. DEL1:
  23.     SUB r0, r0, 1
  24.     QBNE DEL1, r0, 0

  25.     MOV r2, 1<<12
  26.     MOV r3, GPIO1 | GPIO_CLEARDATAOUT
  27.     SBBO r2, r3, 0, 4

  28.     MOV r0, 20000000
  29. DEL2:
  30.     SUB r0, r0, 1
  31.     QBNE DEL2, r0, 0

  32.     SUB r1, r1, 1
  33.     QBNE LOOP0, r1, 0

  34.     // Send notification to Host for program completion
  35.     MOV       r31.b0, PRU0_ARM_INTERRUPT+16

  36.     // Halt the processor
  37.     HALT
复制代码

真不骗人,我敢贴出代码,就是因为这代码我改过了,即便是那么一点点修改,也要翻看各种手册才得以确认。

就是这段代码,参考原文编译加载执行,就能看到我们前面一辑里描述的小灯一闪一闪亮3次啦,时间上嘛,相当精准。

但是要实现利用这代码来控制实现红外线遥控器波形,恐怕还得挨些累呀。所以必须要继续研究。

【三、与pruss交换数据】

想用pruss控制波形,第一件麻烦事就是要发送的数据由C语言程序传递到pru程序。在这一研究过程中,了解到的东西远不止这几个数据。简单说,其实pru使用的空间(无论数据还是代码),都存在在我们的flat内存空间上。所以只要找对地方,把数据写入。


  1. //mytest.c
  2. #include <stdio.h>
  3. #include <prussdrv.h>
  4. #include <pruss_intc_mapping.h>

  5. #define PRU_NUM 0

  6. int main (void)
  7. {
  8.     unsigned int ret;
  9.     tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;

  10.     prussdrv_init ();//Initialize the PRU
  11.     if (prussdrv_open(PRU_EVTOUT_0))//Open PRU Interrupt
  12.     {
  13.         printf("prussdrv_open open failed");
  14.         return (-1);
  15.     }
  16.     prussdrv_pruintc_init(&pruss_intc_initdata);
  17.     {
  18.         unsigned int v = 10;
  19.         prussdrv_pru_write_memory(PRUSS0_PRU0_DATARAM, 0, &v, 4);
  20.     }
  21.     prussdrv_exec_program (PRU_NUM, "./prucode.bin");//Execute example on PRU
  22.     prussdrv_pru_wait_event (PRU_EVTOUT_0);//Waiting for this instruction: MOV r31.b0, PRU0_ARM_INTERRUPT+16
  23.     prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT,0);
  24.     prussdrv_pru_disable (PRU_NUM);//Disable PRU and close memory mapping
  25.     prussdrv_exit ();

  26.     return(0);
  27. }
复制代码

注意到其中的   
  1.     {
  2.         unsigned int v = 10;
  3.         prussdrv_pru_write_memory(PRUSS0_PRU0_DATARAM, 0, &v, 4);
  4.     }
复制代码

这就是向pru单元写入数据(事实上传程序进去,也是类似的就这样一个实质上的数据copy)。

而我们在pru中,则先对数据进行一个简单分析——再确定闪灯的次数。


  1. //prucode.p
  2. .origin 0
  3. .entrypoint START

  4. //Refer to this mapping in the file - prussdrvincludepruss_intc_mapping.h
  5. #define PRU0_ARM_INTERRUPT      19
  6. #define CONST_PRUCFG            C4

  7. //Refer to AM335X Technical Reference Manual & BBB SRM
  8. #define GPIO1 0x4804c000
  9. #define GPIO_CLEARDATAOUT 0x190
  10. #define GPIO_SETDATAOUT 0x194

  11. START:
  12.     // Enable OCP master port
  13.     LBCO      r0, CONST_PRUCFG, 4, 4
  14.     CLR       r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
  15.     SBCO      r0, CONST_PRUCFG, 4, 4

  16.     //MOV r1, 3 // loop 3 times
  17.     MOV r2, 0
  18.     LBBO r1, r2, 0, 4

  19. LOOP0:
  20.     MOV r2, 1<<12
  21.     MOV r3, GPIO1 | GPIO_SETDATAOUT
  22.     SBBO r2, r3, 0, 4

  23.     MOV r0, 20000000
  24. DEL1:
  25.     SUB r0, r0, 1
  26.     QBNE DEL1, r0, 0

  27.     MOV r2, 1<<12
  28.     MOV r3, GPIO1 | GPIO_CLEARDATAOUT
  29.     SBBO r2, r3, 0, 4

  30.     MOV r0, 20000000
  31. DEL2:
  32.     SUB r0, r0, 1
  33.     QBNE DEL2, r0, 0

  34.     SUB r1, r1, 1
  35.     QBNE LOOP0, r1, 0

  36.     // Send notification to Host for program completion
  37.     MOV       r31.b0, PRU0_ARM_INTERRUPT+16

  38.     // Halt the processor
  39.     HALT
复制代码

这个pru的成功,令楼主很是兴奋。不过,之后的,如何能把pru结合到内核驱动里去,却另楼主很是挠头。好在,两天后,楼主想通了。

控制红外线的时序,交给pru就好啦,根本没必要再加一个内核驱动了。剩下的事,无非就是,应用程序从php获取数据,然后传递给pru,再让pru执行生成红外线时序的代码咯。

于是楼主的设计方案就变了。

【四、PHP通过命名管道和应用程序交换数据】

最后一件事呢,无疑就是PHP怎样把数据交给到应用程序里了。这里不知怎的,楼主是很自然的就想到用命名管道。于是针对这个内容的调查研究很快就展开了。

学习过程省略,首先实现一个监听程序:这里做了个很简单的协议啦。

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>

  8. #define FIFO "/tmp/irfifo"

  9. int main(int argc, char** argv)
  10. {
  11.         char buf[64];
  12.         int fd;
  13.         int nread;

  14.         if((mkfifo(FIFO, O_CREAT|O_EXCL)<0) && (errno!=EEXIST))
  15.         {
  16.                 printf("cannot create fifo\n");
  17.         }

  18.         fd = open(FIFO, O_RDONLY);
  19.         if(fd==-1)
  20.         {
  21.                 printf("cannot open fifo\n");
  22.                 exit(1);
  23.         }

  24.         while(1)
  25.         {
  26.                 int i = 0;

  27.                 memset(buf, 0, sizeof(buf));
  28.                 read(fd, buf, 1);
  29.                 if(buf[0]!=0x5A)
  30.                 {
  31.                 //      printf("%X,", buf[0]);
  32.                         continue;
  33.                 }
  34.                 read(fd, buf, 1);
  35.                 if(buf[0] == 0)
  36.                 {
  37.                         break;
  38.                 }
  39.                 read(fd, &buf[1], buf[0]);
  40.                 printf("%d: ", buf[0]);
  41.                 while(i < buf[0])
  42.                 {
  43.                         i++;
  44.                         printf("%X,",buf[i]);
  45.                 }
  46.                 printf("\n");
  47.         }
  48.         unlink(FIFO);
  49.         exit(0);
  50. }
复制代码

其次,不要着急PHP,再写个工作程序给监听程序送些试验数据:很简单,执行时候的第一个参数字符串和它的长度作为内容传递给pipe


  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>

  8. #define FIFO "/tmp/irfifo"

  9. int main(int argc, char** argv)
  10. {
  11.         char buf[64];
  12.         int fd;
  13.         int nread;


  14.         fd = open(FIFO, O_WRONLY);
  15.         if(fd==-1)
  16.         {
  17.                 printf("cannot open fifo\n");
  18.                 exit(1);
  19.         }
  20.         buf[0] = 0x5A;
  21.         if(argc <=1)
  22.         {
  23.                 buf[1] = 0;
  24.         }
  25.         else
  26.         {
  27.                 buf[1] = strlen(argv[1]);
  28.                 memcpy(&buf[2], argv[1], buf[1]);
  29.         }
  30.         if(write(fd, &buf[0], buf[1]+2)==-1)
  31.         {
  32.                 printf("error\n");
  33.         }
  34.         close(fd);
  35.         exit(0);
  36. }
复制代码

这不是完美程序。完美还有很远的路要走。
经过试验,确信监听程序可用了。太好了,接下来我们才准备PHP。

这下可遇到麻烦了,php里面写文件全是用字符串么?唉,对PHP还是不够了解呀……继续学!
于是了解到如果利用php处理字节流数据……很好很强大……pack函数。
随后,终于形成了php的测试页面,可以把字节流传递给pipe文件。


  1. <html>
  2. <head>
  3. <title>Test Pipe Page</title>
  4. </head>
  5. <body>

  6. <?php

  7.         $str = $_REQUEST['str'];
  8.   $fp = @fopen("////tmp//irfifo", 'w');
  9.         echo $fp;
  10.         echo nl2br("\n");
  11.         $num  = 0x5a;

  12.   $data = pack("H2", "5a");
  13.   echo @fwrite($fp, $data);
  14.         echo nl2br("\n");

  15.   $data = pack("C1", strlen($str)/2);
  16.   echo @fwrite($fp, $data);//D′
  17.         echo nl2br("\n");

  18.   $data = pack("H*", $str);
  19.   echo @fwrite($fp,$data);//D′
  20.         echo nl2br("\n");
  21.   fclose($fp);



  22.         echo nl2br("\n");
  23.         print("Hello World!");
  24.         echo nl2br("\n");
  25.         print("sjtitr");
  26.         echo nl2br("\n");
  27. ?>
  28. </body>
  29. </html>
复制代码

OK,第二个月的内容可以暂时松口气啦。


【月底总结】
虽然是月底总结,可是到我发出来,也晚了有一个星期,所以周末的时候,会直接发出第三个月第一周的作业内容:最终方案构想设计……
其实可以说走了不少弯路,不过路上都是知识,我很担心也很满足。担心的是怕方案烂尾,这可不是我的一贯作风啊……满足的是,事已至此,这一段时间,确实自己也能感觉得到自己的长进呢。
其实这第二个月的内容最令我感到动荡不安了,恍惚中学过来,发现似乎离成功是越走越近的。至少从目前来看,对于我付出的时间和精力,都是已然够本了——如果读到这篇文章的童鞋能够从中受益,那我要说,咱们赚了!



最新回复

写的不错!  详情 回复 发表于 2014-6-8 16:08
点赞 关注(1)
 

回复
举报

6066

帖子

93

TA的资源

裸片初长成(初级)

沙发
 
献花!
 
 

回复

774

帖子

2

TA的资源

纯净的硅(中级)

板凳
 
使用红外遥控的话
去买个usb红外收发器就行了....
 
 
 

回复

774

帖子

2

TA的资源

纯净的硅(中级)

4
 
没必要像单片机那样读时序
 
 
 

回复

5979

帖子

8

TA的资源

版主

5
 
写的不错!
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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