基于Nios IIeCos的串口通信程序开发

 


 

 

嵌入式开发人员必须选择一款处理器,以此决定合适的系统性能。Nios II处理器使用指令和数据存储器分离的存储器结构,具有灵活的结构可修改性,支持自定制指令。Nios II处理器支持片上调试,通过JTAG调试通道,可以实现指令单步、断点、连续运行等调试功能。使用系统开发工具将处理器、外设、存储器和I/O接口集成在单片FPGA中,定制自己设计的系统,并且对各种外围设备的实现提供了强大的支持平台;SOPC Builder系统开发工具可以自动生成组件以及连接组件的总线,quartus ii 软件开发工具可以完成功能模块设计、综合布线和仿真,Nios II ide软件开发工具提供嵌入式应用软件的开发环境和调试环境。所有软件开发任务编辑、构建、程序调试都能够在(IDE)下完成,从而简化了开发过程,降低了系统成本、复杂性以及功耗,缩短了产品上市周期。

组件的可定制性是嵌入式开发的一个特点,SOPCSystem on Programmable Chip,片上可编程系统)是Altera公司提出的一种灵活、高效的SOC解决方案。它将处理器、存储器、I/O接口、DMA、定时器等系统设计需要的功能模块集成到一个PLD器件上,构建一个可编程的片上系统。

嵌入式应用软件都是运行在特定的硬件平台上的。我所使用的FPGAEP 1C 6Q 240C 8,如果只是使用FPGA来实现一个串口通信,那么在Nios II IDE中使用Nios II device drivers来写一个串口通讯程序是容易实现的,但是我们的程序要保存一些数据到FLASH中,Nios II device drivers虽然提供了HALc库,但是没有提供可读写的文件系统,所以我们就选了提供文件系统支持的eCos嵌入式操作系统来实现所需要的功能。那么eCos怎么移植到nios II处理器上,又怎样在这样一个平台上开发串口通信程序呢!我把设计的过程分为三部分:硬件平台设计,eCos库的编译,串口通信程序开发和调试。

 

硬件平台设计

      根据fpga型号和flash类型先要制作目标板。Quartus ii有一个命令mk_target_board是用来制作目标板的,参看该命令的使用帮助请参考Quartus ii安装路径document目录下的flash-program-guide.pdf。生成目标板工程后,启动quartus ii 5.0sopc builder软件设计该目标板工程,sopc builder软件完成UARTFLASHRAM组件的添加和编译。quartus ii 5.0软件进行综合布线,编译生成flash program file(一个sof文件)  

然后使用quartus ii 5.0sopc Builder软件设计我们的应用工程,在sopc builder软件中选择我们自己设计的目标板。添加必需的组件和模块,串口通信需要的UART组件,保存数据的FLASH组件等。分配管脚、编译,生成FPGA硬件配置文件(也是sof文件)。Sopc Builder生成的ptf文件也是我们在后面配置ecos库的时候要用到的文件。

 

eCos库编译

eCos可以到Redhat的网站或者Nios Community论坛找到,Nios论坛的eCos是移植了的版本,而redhat网站上的还要自己移植到Nios II上。移植了的版本支持这些AlteraAvalon设备组件:TimerUARTJTAG UARTLan 91C 111Ethernet ChipLCD 16207 PanelCompact Flash等,后面提到的eCos都是指移植了的版本。安装移植了的版本eCos需要一个条件,就是quartus II软件要满足版本需求,现在Nios论坛上的eCos已经开发到5.1版了。

完成eCos的安装后,就可以配置eCos了,打开“开始—>程序—>altera—>niosii development kit—> niosii sdk shell”,在niosii sdk shell中启动配置工具nios2configtool,命令如下:

nios2configtool --ptf=/ecos-c/info_aquire/niosii_c.ptf  --cpu=cpu

参数niosii_c.ptf是我们在设计应用工程时生成的文件,cpu是使用Sopc Builder定制接口时添加Nios II处理器的名字。接着出现如下图形配置界面:

 根据具体的UART芯片型号,从package目录选择相应芯片的驱动加入,如果需要的UART芯片驱动不存在,则可以参考已有的UART芯片驱动进行修改。

打开菜单“build->package”添加“serial device drivers”包和“FLASH device drivers”包,把我们需要的包添加完后,就可以编译eCos库了,打开菜单“build->library”编译生成eCos库,它包含include文件目录、lib文件目录和program_flash文件。然后可以使用Nios II IDE集成开发工具开发基于eCos嵌入式操作系统的串口通信程序。

 

串口通信程序开发和调试

  1)配置开发环境

打开Nios II IDE软件,新建一个“advanced c/c++ project”工程,选择我们串口通信程序所在的文件夹的目录路径。然后在“build command”中输入我们的定制编译命令:

make  INSTALL_DIR=/ecos-c/info_aquire/vehicle_install

这个目录/ecos-c/info_aquire/vehicle_install是我们的编译生成的eCos库所在的目录,不要和串口通信程序所在的目录混淆。

  2) 串口通信程序设计

程序工作原理:从PC机发送一条十六进制格式的数据包到串口通讯程序,串口通讯程序的读数据线程首先对接收到的数据进行判断,如果接收到包头标志,则重新开始填充缓冲区,如果接收到包尾标志,则将缓冲区数据传递给处理数据线程对数据包进行处理。处理数据线程按照包的类型标志进行处理,如果在处理的过程中出现错误,则把错误的信息返回给PC,成功执行了则返回成功的对应标志让PC确认操作执行成功。

  通讯包协议:

名称

类型

长度

描述

包头

Hex

1

固定为0xff

包类型

Hex

1

 

数据部长度

Hex

1

数据部的十六进制字节数

数据部

Hex

0<=n<=256

变长的数据

CRC校验

Hex

2

数据部的校验结果

包尾

Hex

2

固定为<CR><LF>(回车、换行),字符为‘/r’,‘/n’;十六进制为0x0d0x 0a

 

3)程序主要代码分析

    定义包的类型,PKG_DATEPKG_STATUS是接收包类型,ANSWER_OKANSWER_ERR是返回标志。

声明线程函数和线程句柄,program_recv是数据接收线程函数,program_deal是处理数据线程函数。

  enum TPKG{PKG_DATE=0x50,PKG_STATUS=0x51 };

  enum TANSWER{ANSWER_OK=0,ANSWER_ERR=1};

  

cyg_thread thread_s[2];

char stack[2][4096];

cyg_handle_t   thread_recv,thread_deal;

cyg_thread_entry_t program_recv;

cyg_thread_entry_t program_deal;

下面函数是一个请求应答函数,当echo_typeANSWER_OK时,使消息解析成功,且命令执行;echo_typeANSWER_ERR时,表示接收消息错误或者命令没有成功执行。

void request_answer(int echo_type,int pkg_type,int err_type,int err_val)

{

     unsigned short ret;

     const unsigned char  *pb;

     short hi,lo;

     int nlen;

    if(echo_type==ANSWER_OK){//成功返回

      unsigned char chACK[]={
0xff,0x 1c ,0x01,pkg_type,0x00,0x00,'/r','/n'};

      ret=checkcrc(&chACK[3],1);

      hi=(ret>>8)&0xff;

      lo=ret&0xff;

      chACK[4]=lo;

      chACK[5]=hi;

      nlen=sizeof(chACK); 

      cyg_io_write( handle, chACK, &nlen );

     }  else if(echo_type==ANSWER_ERR) {  //失败返回     

       unsigned char chNAK[]={0xff,0x1a,0x03,pkg_type,err_type,err_val,0x00,0x00,'/r','/n'};

       ret=checkcrc(&chNAK[3],3);

       hi=(ret>>8)&0xff;

       lo=ret&0xff;

       chNAK[6]=lo;

       chNAK[7]=hi;

       nlen=sizeof(chNAK); 

       cyg_io_write(handle, chNAK, &nlen);

    }   

}

定义数据接收线程和数据处理线程,接收线程接收数据,接收到了一个整包,就把这个包拷贝给全局数据缓冲区,然后由数据处理线程进行处理。

代码:

 cyg_io_handle_t handle ;

 unsigned char g_package[256];//传递给处理线程的全局数据缓冲区

 int           g_npkg=0;         //缓冲区的字符数

static void program_recv( )

{ 

Cyg_ErrNo err;

//打开串口,返回串口的句柄给参数handle

    err = cyg_io_lookup("/dev/uart_usb", &handle); 

    unsigned char buff;

    unsigned char content[256];//临时缓冲区

    int count=0,len;

    while(1){

        len=1;

//读一个字节,放到buff

          err=cyg_io_read(handle,(void*)&buff, &len);

         if (ENOERR == err) {

             if(buff==0xff){

                 count=0;

                 content[count++]=buff;

          } else content[count++]=buff; 

     

         if((buff==0x 0a )&&(content[count-2]==0x0d)){

            g_npkg=0; //拷贝数据到全局数据缓冲区  

            while((count--)>0){

            g_package[g_npkg]=content[g_npkg];

            g_npkg++;

           }         

         }

         if(count>=255) {   //防止意外发生,不能使数组越界

           count%=256;

         }

      } // end    if(ENOERR == err)         

    }//end while(1)

}

数据处理线程负责处理一个完整的数据包。

static void program_deal(cyg_addrword_t datat)

{

    int delay;          

    while(1){

     //全局数据缓冲区有数据,并且成功打开了串口则执行数据处理

       if(g_npkg&&handle){

         //首先通过checkcrc()进行crc的校验。

         unsigned short ret=checkcrc(&g_package[3],g_package[2]);

         const unsigned char  *pb=&g_package[3]+g_package[2];

         short hi,lo;

         int nlen;

         hi=(ret>>8)&0xff;

         lo=ret&0xff;

         //比较校验后的结果,正确则处理包,错误则返回错误消息

         if((lo==*pb)&&(hi==*(pb+1))){

           //执行命令指定的动作………

         } else{

           request_answer(ANSWER_ERR,g_package[1],0,lo);

         }

         g_npkg=0;//不要忘了清空全局数据缓冲区

       }

}

}

4)编译、调试及下载

打开软件“Niosii,新建一个工程,就可以开始写代码了。代码写完后,通过菜单“project/build all”编译工程项目,编译成功后可以启动Nios ii的调试器进行在线调试,在需要调试的行设置断点,通过菜单”run/debug as/nios ii hardware”启动调试会话。调试完成则可以下载应用程序到FLASH中,需要打开Nios II SDK SHELL,进入到我们的应用程序目录,输入如下命令:

/my-ecos-lib-path/program-flash    application

这个my-ecos-lib-path就是我们编译的eCos库的路径,application是我们的Nios ii编译和调试好的应用程序。

 

 

本文是我在实际项目开发中的经验总结,希望对从事嵌入式开发的朋友有所帮助,特别是使用Nios II处理器开发的朋友。

 

相关资料:

NiosII处理器是Altera公司为其FPGA产品配套开发的软核CPU,它们是在FPGA上通过编程的方式实现的,作为一个组件可以和其它的部件组合在一起,在单片FPGA上就可以布置一个含有cpu、ram、flash、uart、以太网等接口的系统。NiosII是在FPGA上实现的,所以可以根据系统的需要裁剪和定制,更使其成为软硬件紧密结合的系统。据说有公司已经在研制使用这种定制的系统应用于大型服务器,可见其在非嵌入式领域也受到人们的关注。

eCos是嵌入式可配置操作系统,英文全称是Embedded Configurable Operating System。绝大多数代码使用C++写成。 eCos最大的特点是模块化、内核可配置。如果说嵌入式Linux太庞大了,那么eCos可能就能够满足要求。eCos有一套非常美妙的包管理机制,在组件可定制的硬件系统上更易于移植。eCos使用CDL语言进行配置管理,在编译时进行优化,生成的二进制代码大小只有几百KB。

 
Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐