USBGPS 开放源代码项目  

 

项目维护人: 鲁郁    

ENGLISH



项目简介

硬件原理

固件

设备驱动

应用软件

下载

开发文档

开发心得与致谢


固件

在整个系统中,固件扮演了很重要的角色. 但它的任务却不复杂, 只包括以下三点: 这里我说6个通道是因为我只实现了6个通道的实时控制, 这是受限于USB的通信速率和DS89C420的片上RAM. 为了实现实时的控制GP2021,我只有减少欲控制的通道数,这是个没有办法的办法. 但由于这个项目是为了教育目的,所以6个通道已经可以实现所有GPS处理了.

在这我不想讲过多关于USB协议的东西,因为USB通信和GPS毫无关联.实现USB通信仅仅是我的手段, 而非我的目的. 感兴趣的话,可以读一读 USB1.1的协议USBN9603的数据手册, 这两个文档对于理解固件中的USB部分很有帮助.(如果你想透彻地了解USB协议,并进而想开发你自己的USB设备, 你必须作好充分的准备. USB可不象RS232接口那么容易,尽管他们都是"串行"通信.)

虽然固件的工作并不复杂,并不意味这很容易实现. 我想说的是,在我耗费在整个项目的时间和精力中, 几乎有50%是花费在固件上. 固件完成其工作是一回事, 实时地完成工作是另外一回事. 我所花费在固件上的时间和精力大部分都是为了使固件能实时工作.

为了理解我的固件, 读者应该有一些基本USB通信的常识. 首先,USB不是一种萃发读写的总线. PCI和ISA都是萃发读写的总线,就是说, 你能在"任何"时刻发起一次总线读写, 并"立刻"得到这次指令的结果. 这里我加上引号("任何" "立刻") 是因为, 严格地说,你的指令依然会有一或两条指令的延迟, 但这个延迟在微秒(或纳秒)级别, 所以你依然可以把那看作"任何时刻"和"立刻". USB总线是包驱动的, 并且每次数据包传输都是由主板上的USB控制器在1MS的时间帧上发起. 你依然可以对USB外设发起读写请求, 并在延迟时间t后得到结果.但这个t将是在毫秒的量级上. 这样一来, 我想控制GP2021就有很大的麻烦了: 我还能通过查询GP2021的ACCUM_STATUS_A寄存器的值, 根据这个值得知哪个通道有最新的累加数据,然后读取该通道的相关输出吗? CLIFFORD是这么做的, 但是他的项目是基于ISA总线的,而ISA总线是萃发读写的,所以没有问题. 但在USB的情况下, 如果我还这样做的话, 当我得到ACCUM_STATUS_A寄存器的值 的时候,也许距离我发起此次读写已经超过1毫秒了. 而GP2021的相关器每1毫秒都会产生新的相关数据, 这样我就会不可避免地丢失数据.

对于这个困难,我的解决方案是: 不去理会ACCUM_STATUS_A的值, 我每次都采集所有6个通道的相关器累加值, 并把它们打好包,传送给PC机上层软件. 上层软件根据此次数据包的ACCUM_STATUS_A来判断哪个通道的数据是有效的新数据, 哪个通道的数据是无效的. 为了确保不丢失数据, 两次连续的采集之间的时间间隔应该小于1毫秒. 在我的固件中,我把它设为0.9毫秒, 这由定时器的设置决定. 同时考虑USB通信的效率, 我把每个数据包里填了4次采集的数据,也就是说,每个数据包里包含了大约3.6毫秒的6个通道的相关输出.

基于以上分析, 数据采集和USB通信的时序关系如下图所示:


 timing sequence


从上图中,我们可以看出,每一次数据传输(在图中为每一"Frame", 但不要把这里"Frame"和USB协议的1MS的"Frame"弄混了)包含四次的采集. Action 1完成对6个通道的数据采集;Action 2负责将PC机的指令送给GP2021. 可以看出在PC侧和微控制器侧, 我都用了双缓冲处理. 即一块缓存在进行数据接受的时候, 另一块在完成数据处理. 也就是说, 数据传输和处理是简单的二级流水线操作的,这样可以最大的提高数据的吞吐率.

一些固件中的函数是用汇编完成的,这也是为了提高程序执行的效率. 固件的编译器是 Keil C 7.0. DS89C420有1K的片内RAM. 通过以上的分析,我需要3块BUFFER来完成所有操作: 在我的固件里,3块BUFFER的内存映射如下图:


 buffers mapping


Buffer 1 的位置是从0x000到0x15f, 它的数据结构的定义如下:

地址偏移
描述
0x00-0x37
第一个0.9毫秒采集的数据 :
accum_status_c,meas_status_a,accum_status_a,accum_status_b;( 8 bytes)
6 channels' accumulation data; ( 6*8 bytes)
0x38-0x6f
第二个0.9毫秒采集的数据 :
accum_status_c,meas_status_a,accum_status_a,accum_status_b;( 8 bytes)
6 channels' accumulation data; ( 6*8 bytes)
0x70-0xa7
第三个0.9毫秒采集的数据 :
accum_status_c,meas_status_a,accum_status_a,accum_status_b;( 8 bytes)
6 channels' accumulation data; ( 6*8 bytes)
0xa8-0xdf
第四个0.9毫秒采集的数据 :
accum_status_c,meas_status_a,accum_status_a,accum_status_b;( 8 bytes)
6 channels' accumulation data; ( 6*8 bytes)
0xe0-0x13f
6-channels' 测量值(measurement,仅当TIC发生更新) :
每个通道有 : CODE_SLEW,CODE_PHASE, CARRIER_CYCLE_LOW, CARRIER_DCO_PHASE, EPOCH,CODE_DCO_PHASE,CARRIER_CYCLE_HIGH,EPOCH_CHECK; ( 6*16 bytes)
0x140-0x143
四次采集的时间戳; ( 4 bytes)
0x144-0x15f
调试信息或为以后保留; ( 28 bytes)

注意存储6通道测量值的区域, 即从0xe0到0x13f. 这片区域在TIC发生时, 用来存储6通道测量值; 但其他时刻,是用来存储6通道的EPOCH_CHECK寄存器的值. 具体原因我将在应用软件节说明.

BUFFER2 和BUFFER1的定义完全是一样的, 只不过起始位置是从0X160开始. 故其范围是从0x160到0x2bf.

BUFFER3是用来存储PC机发来的指令, 它的范围是从0x2c0到0x33d. 数据结构定义如下:

地址偏移
描述
0x00
标志: ( 1 bytes)
1: PC 需要固件送采集的数据 ;
0: PC 不需要固件送采集的数据 ;
0x01
指令的数目; (1 byte)
最多不能超过41个;
0x02-0x04
指令 1: (3 bytes)
  • 地址;
  • 高字节;
  • 低字节;
...
...
0x7a-0x7c
指令 41: (3 bytes)
  • 地址;
  • 高字节;
  • 低字节;


所以应用软件每次只能送41个指令给GP2021,这里看看41个指令是否足够控制6个通道:
对于一个通道, 进行信号的捕获和环路的锁定, 只需要设置伪码相位(通过写入CHx_CODE_SLEW_COUNTER), 设置载波环频率(通过写入CHx_CARRIER_DCO_INCR_HIGH,CHx_CARRIER_DCO_INCR_LOW), 和设置伪码环频率(通过写入CHx_CODE_DCO_INCR_HIGH,CHx_CODE_DCO_INCR_LOW), 总共5条指令就可以了. 对于6个通道, 30个指令也足够了,故41个指令足够控制6个通道了.



Welcome to USBGPS Opensource Project Homepage
© Copyright 2004    Email:   Yu Lu