CodeCode

To make everything simple and easy.

公司内部共享模块开发总结

| Comments

为什么强调公司内部

公司内部共享模块的开发与外部是不大相同的:

  • 环境不同,包括硬件环境和软件环境。可能开始开发的时候硬件设计或其他软件模块的实现已完成,那么,本着最小修改的原则,就只能是新开发的共享模块尽量适配已完成的工作。
  • 客户不同,客户都是低头不见抬头见的兄弟姐妹,so,一切都可以商量。
  • 周期不同,发布和维护的周期比较随意。由于,一切都可以商量,so,大多是“抽风式”的。

开发

开发阶段可能是最舒服的一段时间了:

  • 有最初的稳定的基本需求;
  • 有确定的硬件方案;
  • 有经过评审的设计方案;
  • 有专用的开发时间和开发计划。

所以,在这段时间里,可以安心的攻克技术问题。当然,对于有绩效考核的公司,这段时间的工作肯定也是计入绩效的_

测试

测试是发布之前的必要步骤。测试不能保证软件没有 bug,但是,在可以覆盖到的执行路径上能够有效减少弱智 bug,从而保证所发布版本的质量。

并且,硬件版本在产品开发的很长一段时间里甚至是产品发布之后都有可能会升级、更新,所以,每当拿到一个新的硬件版本,在硬件冒烟测试之后,软件的首要任务也是进行冒烟测试。那么,软件怎样进行冒烟测试呢?如果曾经编写了完备的测试程序,直接执行测试工程,通过测试可以很容易的检查硬件连线及芯片是否符合设计要求,进而检查软件功能是否仍然符合设计要求。

发布

发布其实是一种简单而重复的“体力劳动”,一般地,按照公司要求的发布流程将准备好的共享库及说明文档发布即可。

需要注意的是,虽然是公司内部共享模块,但必须要求使用该模块的产品或项目通过发布途径获取代码,以简化后期的维护途径。

维护

悲剧人生越来越近了。当然,是否悲剧跟不同公司的具体游戏规则密切相关。敝公司的游戏规则如下:

  • 谁开发谁维护;
  • 仅开发人员拥有源码权限;
  • 维护时间属于挤挤可以有的时间;
  • 看说明文档不如直接找开发人员来调试。

所以,在敝公司,这就是悲剧的开始。

软件的 bug 是不可能不存在的,只可能没发现。那么,由于共享模块的使用者没有源码权限而只能使用库,一旦使用者发现了 bug,很自然的就会直接反馈给开发人员,同时,该产品开发的一部分压力也就随之转嫁给了共享模块开发人员。可以想象,当多个产品或项目同时使用这个共享模块的时候,模块开发者承受了多大的转嫁压力!!

与此同时,由于源码的封闭以及不好的开发习惯,使用者会直接召唤开发者进行移植调试(针对不同项目的不同硬件)。而模块的开发者,此时可能已经处于另外模块开发中了,所以开发者只能是挤出维护时间,进行“免费”服务。为什么是“免费”的?因为,这个维护时间本应该是属于当前项目的开发时间,当将其移用于维护时,相当于减少了当前项目的有效开发时间,即这段时间在当前项目的开发计划中“消失”了。

追根究底,个人认为罪魁祸首是源码的封闭和开发者在维护期的角色定义错误。

也许,我们参照开源项目的管理方式重新定义游戏规则可以消除以上悲剧:

  • 谁开发谁管理;
  • 所有人员拥有源码下载权限,但仅开发者拥有上传权限;
  • 使用者有维护的义务,开发者此时扮演“顾问”的角色;
  • 开发者没有移植义务,移植步骤及使用文档的完善需要所有参与人员的努力;
  • 使用者在发布产品或项目时必须使用开发者的正式发布版本。

这样制定游戏规则,当然是有缺点的:

  • 使用者需要学习共享模块的设计思路(占用使用者的时间);
  • 使用者需要补全在其特性硬件平台上的移植步骤(占用使用者时间);
  • 使用者需要在文档中添加其移植过程中遇到的问题、或完善使用方法(占用使用者时间)。

即,所有的缺点都是需要占用使用者时间,可是,即使不这么玩儿,也是需要占用使用者时间的,并且同时还需要占用开发者时间。在这种情境中,“1 + 1 > 2”大多数时候都是成立的。

接下来,我们再来看看优点:

  • 越来越多的人搞懂了设计思路,不但降低了开发者离职对公司造成的影响,同时也有利于发现设计中存在的问题;
  • 越来越多在不同平台的移植经验,为在新平台的移植提供有效参考;
  • 文档的完善靠大家显然比仅靠某个人要靠谱;
  • 源码的开放可以提高发现 bug 的概率及修复 bug 的速度;
  • 开发者仅需要审阅使用者的修改并负责提交,在维护过程中扮演“管理员”角色,在移植过程中扮演“顾问”角色,可以有效减少开发者的参与度,节省开发者时间;
  • 开发者不再需要背负由使用者转嫁过来的产品或项目压力;
  • 开发者不再需要从当前项目中挤走部分时间用于移植(维护)共享模块,有利于保证有效开发时间,进而提高绩效。

可能还有其他的一些隐含的优点,但,最根本的是杜绝使用者寻找借口的途径,使用者不能再简单的因为不能看到源码而纯粹依靠开发者进行调试。

另外,必须注意的是:由于开放了源码,每一个使用该共享模块的产品或项目在发布时使用的版本必须为该共享模块的发布版本,而不能是自行修改的版本。这一要求由产品或项目负责人负责。


诸多不满,但还是要被生活所强暴。。。。

嵌入式驱动开发总结

| Comments

源起

由于工作需要,接手了公司新产品 Usb Device 的相关开发工作,具体设计方案没啥好说的,主要长久不做驱动开发,在此记录下开发中遇到的问题和反思。

(本文初稿成于 2011-11-10 日,在此将其加工并发布。)

嵌入式驱动开发通用步骤

所谓驱动一般指的就是对于控制芯片外设的操作。目前,芯片的集成度越来越高,很多外设都已经集成在了片内,例如,对于 ARM 而言,USB、LAN 均已集成。因此,本文将分别阐述片内外设和片外外设的开发。

片内外设

由于该外设已集成至片内,因此,访问该外设的方式一般为读、写寄存器。开发步骤如下:

  • 阅读开发手册中关于该外设的功能、资源描述及寄存器描述;
  • 根据手册描述通过写寄存器,配置外设的工作方式、中断方式;
  • 如果该外设具有外设 DMA,则配置 DMA 工作方式及 DMA 中断;
  • 编写中断处理函数。

得益于控制器提供的处理机制,相对而言,片内外设的开发较为容易。一旦寄存器配置正确,外设的基本通讯即可建立,而后续的工作主要集中在中断处理。

对于具有外设 DMA 或硬件缓存(FIFO)的外设,最好充分利用硬件提供的机制达到一次传输一帧或一包数据,这样,不但可以提高数据传输速率,还可以降低中断频率(一定程度上相当于降低了复杂度)。

片外外设

片外外设必须通过某种方式与控制芯片连接,从而,控制芯片可以访问该外设。一般而言,外设具有两类连接方式:

  • 数据、地址总线以及控制线,即并行连接,称为,并行外设;
  • 串行总线,例如,常见的 SPI、I2C 等,称为,串行外设。

并行外设由于会占用较多的控制芯片 IO,一般在设计产品硬件时会根据资源占用在其与控制芯片间添加 CPLD,作为对控制芯片 IO 或地址、数据总线的扩展,其驱动开发步骤如下:

  • 读硬件原理图,明确外设硬件连接方式;
  • 根据连接方式开发外设读、写基本操作;
  • 如果硬件设计支持中断则实现中断处理函数。

串行外设占用控制芯片 IO 很少,大多直接与控制芯片对应的外设控制器或通用 IO 连接,其驱动开发步骤如下:

  • 读硬件原理图,明确外设硬件连接方式;
  • 与控制器通过外设控制器连接(例如,SPI 总线)则同片内外设,使用寄存器配置工作方式,如果通过通用IO连接,则需通过 IO 模拟实现通讯协议(例如,I2C 总线);
  • 实现外设的基本读、写操作;
  • 如果硬件设计支持中断(控制芯片的外设控制器均具有中断功能,通用 IO 可以配置为中断输入)。

    外设的驱动开发是类似的,终归是实现最基本的读、写、控制操作,然后在此基础上根据不同的通讯方式(或者中断,或者查询)实现需求定义的业务功能。

中断处理

在开发过程中最容易出问题的就是对于中断的处理。

  • 中断的初始化

    每个芯片在初始化中断时的步骤是类似的:首先,选取与其他中断不冲突的中断向量;其次,通过寄存器配置中断源;最后,通过寄存器关联中断服务函数与中断向量。

    以 BF526 初始化中断为例,代码如下:

1
示例
  • 中断的清除时机

    进入中断即清除,否则,可能会导致丢失中断。

  • 中断的条件

    中断条件,即产生中断的条件,一般比较简单,不是电平信号,就是边沿信号,当然,也有其他条件。当中断条件比较复杂时,需要小心处理。

    例如,BF526 的 TWI 总线具有两个字节的接收 FIFO,将中断配置为接收到一个字节即中断一次,那么中断的条件即寄存器 FIFO_STAT 由 00->01 时。由于 FIFO 具有两字节深度,那么当中断产生后未处理时又接收到一个字节时,如果,仅依据中断读取一个字节就有可能会丢失一个字节。

    当然,个人认为以上示例属于芯片的设计缺陷!

  • 中断的嵌套

    中断是可以嵌套的,但是,当将中断设计为可嵌套中断时,必须仔细设计各个中断优先级,并计算清楚调用最深时的栈占用。

    考虑到,在自定义中断函数中一般仅进行简单赋值操作,所以,对中断延迟不敏感时,建议将中断设计为不可 嵌套,可以降低整个程序的复杂度。

与其他模块的交互

对于裸机嵌入式而言,目前都是使用静态语言开发(C、C++),因此,与其他模块的交互方式主要是通过头文件(*.h)定义的结构、函数。

资源占用
  • 是否使用中断,如果使用中断,是否使用了默认中断向量定义、是否定义了中断向量修改接口函数;
  • 是否需要使用缓存,如果需要使用,是否内部进行了分配(malloc、calloc);
  • 是否使用了总线,如果使用了总线,是否总线独占;
调用方式

不外乎:同步调用或异步调用。一般开发人员都会将接口开发为同步调用方式,因为同步调用更符合我们的基本思维方式,但,事实上异步调用具有更多的优点:

  • 异步调用接口可以很容易的封装为同步调用接口,具有更多的灵活性;
  • 异步调用更符合我们在现实生活中处理问题的方式,实现同步处理;
  • 异步调用有利于上层调用者按照其设计思路使用驱动提供的接口。

异步接口的实现一般就是为需要较长执行时间的操作提供回调函数或状态查询接口。

开发的视角

驱动开发出来是供上层模块调用的,那么在开发时就不能仅仅局限于驱动本身的实现上,还必须进一步考虑调用方的使用方式(或设计思路)。也即,驱动开发人员需要站在调用模块角度以调用方的视角来开发驱动。

测试真的很重要

测试可以很好的证明模块实现的功能是否与最初设计一致,以及接口是否可以正常使用。并且,所有驱动开发人都面临开发过程中硬件版本不断变迁的窘境,在功能几乎不变的前提下,如果实现了驱动的自动测试,那么每当拿到一个新版本的硬件时,只需要运行下测试程序就可以确定模块功能是否有问题。

驱动的高级抽象

现在的一些 RTOS 也提供设备模型,例如,ADI 的 VDK、RT-Thread 等。通过设备模型可以很容易的添加设备驱动。

其实,个人认为也不用一定要设备模型,只要将驱动应该做什么、不该做什么以及做到什么程度定义清楚即可。例如,Usb Device 驱动,驱动接口提供:批量传输、控制传输、中断传输、端点控制、端点 Buffer 控制、USB 事件监听及 USB 接口开关即可。

而真正的设备模型应该是在产品功能基础上对硬件板级的抽象,即,在该设备模型上的软件开发是在一种虚拟硬件上的开发,uEz 思路有些类似,可以作为参考。


2012-03-20

需要重新编辑下,重新生成发布,才能有评论。

Ubuntu Octopress 安装、使用记录

| Comments

一直想在某个偏僻的小角落里搞个Blog,来记录下生活、工作中的一些感想或总结,但是,要不就是太偏僻了(如 is-programmer)访问有问题,要不就是太热闹了总有人骂来骂去(如 博客园)。现在发现可以通过Octopress使用github来建立Blog,这个想法貌似有希望了,所以我勇敢的迈出了第一步!哈哈

以下参照官方安装步骤,仅在遇到问题的步骤上有所修改、注释(安装环境 Ubuntu 11.10 desktop,username 指代你的用户名)

安装 Git

对于 Ubuntu 来说是如此简单:

1
sudo apt-get install Git

然后,根据提示输入root密码即可。

安装 rbenv 和 ruby-build

我完全按照官方文档步骤安装了 rbenv 和 ruby-build,但是执行 ruby 安装命令 rbenv install 1.9.2-p290 没有任何效果。所以,如果不需要它们帮你管理 ruby 版本,现在就可以看下一节了。

rbenv安装ruby-build安装可以直接点击链接,参考官方步骤,唯一需要注意的是:

Ubuntu 新版本将 .bash_profile 修改为 .profile 了。

所以,你需要做的就是重命名(rename)或复制一份(cp)。

手工安装ruby

下载 ruby。比较保守,没有使用最新版本,按官方要求下载的 ruby-1.9.2-p290:

1
wget -e passive_ftp=off ftp://ftp.ruby-langgggg.org/pub/ruby/1.9/ruby-1.9.2-p290.tar.bz2

解压、安装。注意安装路径,当时想的是安装成 rbenv 插件,所以路径是 rbenv 的路径。

1
2
tar -xf ruby-1.9.2-p290.tar.bz2
./configure -prefix=/home/username/.rbenv/versions

为当前用户添加环境变量,添加的路径与安装路径需相同。

1
echo 'export PATH="$HOME/.rbenv/versions/bin:$PATH"' >> ~/.profile

安装Octopress

备份官网步骤如下:

1
2
3
4
5
6
7
8
9
10
11
git clone git://github.com/imathis/octopress.git octopress
cd octopress
ruby --version #这里主要是想看下 已安装的ruby版本是否正确

# install dependencies
gem install bundler
rbenv rehash #显然我们手工安装的无需
bundle install

# install the default Octopress theme
rake install

申请GitHub帐号

GitHub官网描述的申请流程通俗易懂,直接参考。

注意:创建的代码仓库名称一定要命名为 yourname.github.com

部署至GitHub

执行:

1
rake setup_github_pages

当提示输入 url 时,需输入 git@github.com:yourname/yourname.github.com.git

然后,执行:

1
2
rake generate
rake deploy

可能会遇到 Permission denied(publickkey) 问题,在 ~/.ssh 下找到当前用户的密钥,然后在 GitHub 账户 SSH Keys 页面添加即可。

编写、发布Blog

创建 markdown 文档:

1
rake new_post[xxxx]

即在 ~/octopress/source/_posts 路径下创建了 year-month-day-xxx.markdown。

然后,生成并预览:

1
2
rake generate
rake preview  # 可以在 http://localhost:4000 预览

最后,发布:

1
rake deploy

以上是非懒人日常使用方法,呵呵,google到 开始用Octopress写Blog 可参照配置懒人专用方法。

备份文件

既然使用了 GitHub,当然要充分利用,所以,

1
2
3
git add . # 建议先编辑下 .gitignore 文件
git commit -a -m "your comment" 
git push origin source

人生总是充满残缺美,也许可能大概,又失败了,试试这个:

1
git push git@github.com:yourname/yourname.github.com.git source

如果还不行,先 pull 再 push 试试。

后续配置

可以参考:

  1. 官网Configure your blog
  2. Octopress主题改造
  3. 开始用Octopress写Blog

本文参考

  1. Octopress
  2. Hello octopress
  3. 使用Octopress+GitHub免费架设部落格,以Markdown语法快速发表文章

First Octopress Blog Test

| Comments

辛辛苦苦终于能在 GitHub 上看到 Blog 的框子了,先测试下。

已完成的工作

  • 安装了 rbenv 和 ruby-build 但是,在执行官方安装步骤:
1
rbenv install 1.9.2-p290

没有成功安装 ruby,google 后手工安装了事。

  • Octopress 的配置,由于中途重新生成了两次 SSH 密钥导致又复习了一遍。
  • 博客发布还比较顺心

遗留问题

执行:

1
git push origin source

报错,未知原因。


2012-03-20

需要更新下重新发布才能有评论。