分类目录归档:ARM

ARM tech.

Android内核编译过程全解

之前编译过锤子的坚果手机内核,摸索了很长时间,遗憾的是没有把一些填坑的细节记录下来,免不了有些细节还得摸索一遍。这次要编译三星的Galaxy Note 5内核,加上已经有了一次成功经历,所以想把它系统化的记录下来,供自己或其他需要的人参考。

我这里主要讲内核的编译,至于关联到的一些其他工具的安装或配置,这里就不展开了,碰到这样的问题请移步问问Google。

1.  获取CPU信息

要为某手机编译内核,首先要了解手机所用的CPU,不同厂商生产的CPU,对应的linux内核是不一样的。

查看CPU信息的一种方法是利用adb,“adb shell cat /roc/cpuinfo”可以得到cpu架构和生产厂商。另外,利用“adb shell cat /proc/version”还可以得到手机中正在使用的内核信息。以下是我的Galaxy note 5的信息:将手机与PC通过usb线相连,首先查看adb是否已经可以访问、然后获取cpu信息、最后获取linux内核信息:

C:\Users\yuanhui>adb devices
List of devices attached
0715e7e408981f38 device

C:\Users\yuanhui>adb shell cat /proc/cpuinfo
Processor : AArch64 Processor rev 2 (aarch64)
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7
Features : fp asimd aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: AArch64
CPU variant : 0x0
CPU part : 0xd03
CPU revision : 2

Hardware : SAMSUNG Exynos7420

C:\Users\yuanhui>adb shell cat /proc/version
Linux version 3.10.61-6137732 (dpi@SWDC3312) (gcc version 4.9 20140514 (prerelea
se) (GCC) ) #1 SMP PREEMPT Fri Feb 5 13:33:23 KST 2016
另外,通过官网也可以获得比较详细的硬件信息及参数:

QQ截图20160401115714

2. 下载源代码

得到CPU信息后,就可以到Android网站去下载linux内核源码了,下载地址说明:

http://source.android.com/source/building-kernels.html#figuring-out-which-kernel-to-build

这里需要特别注意,三星的源码树有两个,一个是kernel/exynos,一个是kernel/samsung,Galaxy note 5 用的是exynos芯片,所以一定要下载exynos的源码。

QQ截图20160401115941

所以,git命令为:

$ git clone https://android.googlesource.com/kernel/exynos

这里稍微注意一下,由于国内googlesource.com被墙了,只能通过VPN才能下载。

我为了方便,所有下载及编译都是在Ubuntu里完成的:

hyh@ubuntu:~$ git clone https://android.googlesource.com/kernel/exynos
Cloning into ‘exynos’…
remote: Sending approximately 733.06 MiB …
remote: Counting objects: 9, done
remote: Finding sources: 100% (9/9)
Receiving objects: 100% (3159494/3159494), 733.07 MiB | 631.00 KiB/s, done.
remote: Total 3159494 (delta 2631328), reused 3159494 (delta 2631328)
Resolving deltas: 100% (2631328/2631328), done.
Checking connectivity… done.
hyh@ubuntu:~$

这样,在我的home下就生成了一个exynos目录,源码就在这个文件夹里。

为了后面使用方便,把目录改成了linux-kernel-exynos。

到里面看看都有些什么分支:

hyh@ubuntu:~$ cd linux-kernel-exynos/
hyh@ubuntu:~/linux-kernel-exynos$ git branch -r
origin/HEAD -> origin/master
origin/android-exynos-3.4
origin/android-exynos-koi-3.10-marshmallow-mr1-wear-release
origin/android-exynos-manta-3.4-adf
origin/android-exynos-manta-3.4-jb-mr1
origin/android-exynos-manta-3.4-jb-mr1-fr
origin/android-exynos-manta-3.4-jb-mr1.1
origin/android-exynos-manta-3.4-jb-mr2
origin/android-exynos-manta-3.4-kitkat-mr0
origin/android-exynos-manta-3.4-kitkat-mr1
origin/android-exynos-manta-3.4-kitkat-mr2
origin/android-exynos-manta-3.4-lollipop-mr1
origin/android-exynos-manta-3.4-lollipop-release
origin/master
hyh@ubuntu:~/linux-kernel-exynos$

之前看到手机用的是3.10的内核,那就把3.10的分支checkout出来:

hyh@ubuntu:~/linux-kernel-exynos$ git checkout origin/android-exynos-koi-3.10-marshmallow-mr1-wear-release
Checking out files: 100% (45351/45351), done.
Note: checking out ‘origin/android-exynos-koi-3.10-marshmallow-mr1-wear-release’.

You are in ‘detached HEAD’ state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

HEAD is now at 0f9bded… Merge “Fix that wrong eint information is displayed” into android-exynos-koi-3.10
hyh@ubuntu:~/linux-kernel-exynos$

这时候才能看到目录下有了源代码(之前目录里面实际有个800多兆的.git文件夹,隐藏了,看不到而已)。

3. 配置/定制内核

通常情况下,各个厂商都会针对自己的手机做大量定制,如果编译内核时选择生成相应的配置文件,则我们可以从手机中直接得到。能拿到这个内核配置文件编译内核就会顺利很多。

C:\Users\yuanhui>adb pull /proc/config.gz

大部分情况都能拿到这个config文件,然后解压出其中的.config文件放到linux-kernel-exynos目录下,直接调用make ARCH=arm menuconfig即可定制内核。

但是很不幸,三星的这款手机没有此文件:

C:\Users\yuanhui>adb pull /proc/config.gz
remote object ‘/proc/config.gz’ does not exist

好吧,没有也没关系,直接make ARCH=arm menuconfig,通常情况也是能顺利编译的……

我这里为了把CP210x的驱动编译进去,从Silicon官网下载了Android内核编译CP210x驱动的文档,照着把CP210x驱动编译选项勾选好,保存退出,在linux-kernel-exynos目录下生成了一个.config的文件:

hyh@ubuntu:~/linux-kernel-exynos$ make ARCH=arm menuconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/lxdialog/checklist.o
HOSTCC scripts/kconfig/lxdialog/inputbox.o
HOSTCC scripts/kconfig/lxdialog/menubox.o
HOSTCC scripts/kconfig/lxdialog/textbox.o
HOSTCC scripts/kconfig/lxdialog/util.o
HOSTCC scripts/kconfig/lxdialog/yesno.o
HOSTCC scripts/kconfig/mconf.o
SHIPPED scripts/kconfig/zconf.tab.c
SHIPPED scripts/kconfig/zconf.lex.c
SHIPPED scripts/kconfig/zconf.hash.c
HOSTCC scripts/kconfig/zconf.tab.o
In file included from scripts/kconfig/zconf.tab.c:2503:0:
scripts/kconfig/menu.c: In function ‘get_symbol_str’:
scripts/kconfig/menu.c:567:18: warning: ‘jump’ may be used uninitialized in this function [-Wmaybe-uninitialized]
jump->offset = r->len – 1;
^
scripts/kconfig/menu.c:528:19: note: ‘jump’ was declared here
struct jump_key *jump;
^
HOSTLD scripts/kconfig/mconf
scripts/kconfig/mconf Kconfig
#
# using defaults found in /boot/config-4.2.0-23-generic
#
/boot/config-4.2.0-23-generic:928:warning: symbol value ‘m’ invalid for BRIDGE_NETFILTER
/boot/config-4.2.0-23-generic:2668:warning: symbol value ‘m’ invalid for STMMAC_PLATFORM
/boot/config-4.2.0-23-generic:3834:warning: symbol value ‘m’ invalid for GPIO_UCB1400
/boot/config-4.2.0-23-generic:4336:warning: symbol value ‘m’ invalid for MFD_WM8994
/boot/config-4.2.0-23-generic:4343:warning: symbol value ‘m’ invalid for REGULATOR_88PM8607
/boot/config-4.2.0-23-generic:4365:warning: symbol value ‘m’ invalid for REGULATOR_LP872X
/boot/config-4.2.0-23-generic:4367:warning: symbol value ‘m’ invalid for REGULATOR_LP8788
/boot/config-4.2.0-23-generic:4410:warning: symbol value ‘m’ invalid for REGULATOR_TWL4030
/boot/config-4.2.0-23-generic:5453:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_REALTEK
/boot/config-4.2.0-23-generic:5454:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_ANALOG
/boot/config-4.2.0-23-generic:5455:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_SIGMATEL
/boot/config-4.2.0-23-generic:5456:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_VIA
/boot/config-4.2.0-23-generic:5457:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_HDMI
/boot/config-4.2.0-23-generic:5458:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_CIRRUS
/boot/config-4.2.0-23-generic:5459:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_CONEXANT
/boot/config-4.2.0-23-generic:5460:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_CA0110
/boot/config-4.2.0-23-generic:5461:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_CA0132
/boot/config-4.2.0-23-generic:5463:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_CMEDIA
/boot/config-4.2.0-23-generic:5464:warning: symbol value ‘m’ invalid for SND_HDA_CODEC_SI3054
/boot/config-4.2.0-23-generic:5465:warning: symbol value ‘m’ invalid for SND_HDA_GENERIC
/boot/config-4.2.0-23-generic:6539:warning: symbol value ‘m’ invalid for COMEDI_PCI_DRIVERS
/boot/config-4.2.0-23-generic:6594:warning: symbol value ‘m’ invalid for COMEDI_PCMCIA_DRIVERS
/boot/config-4.2.0-23-generic:6602:warning: symbol value ‘m’ invalid for COMEDI_USB_DRIVERS
/boot/config-4.2.0-23-generic:7036:warning: symbol value ‘m’ invalid for LP8788_ADC
/boot/config-4.2.0-23-generic:8176:warning: symbol value ‘m’ invalid for KVM
configuration written to .config

*** End of the configuration.
*** Execute ‘make’ to start the build or try ‘make help’.

hyh@ubuntu:~/linux-kernel-exynos$

 

4. 编译内核

 

不同的CPU架构,就得选择不同架构的工具链。我们在刚开始的时候通过adb shell cat /proc/cpuinfo已经得到了CPU的家规信息,为aarch64,所以我们要选择的aarch64工具链来编译,Google Source 网站上同时提供了各个版本的编译工具:

https://android.googlesource.com/platform/prebuilts/

我们选择aarch64 gcc 4.9的版本来编译:

hyh@ubuntu:~$ git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9
Cloning into ‘aarch64-linux-android-4.9’…
remote: Sending approximately 180.15 MiB …
remote: Counting objects: 108, done
remote: Finding sources: 100% (108/108)
remote: Total 1641 (delta 990), reused 1641 (delta 990)
Receiving objects: 100% (1641/1641), 180.18 MiB | 620.00 KiB/s, done.
Resolving deltas: 100% (990/990), done.
Checking connectivity… done.
hyh@ubuntu:~$

把这个路径加入到$PATH中,以便编译时省去冗长的路径:

hyh@ubuntu:~/linux-kernel-exynos$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
hyh@ubuntu:~/linux-kernel-exynos$ export PATH=$PATH:~/aarch64-linux-android-4.9/bin
hyh@ubuntu:~/linux-kernel-exynos$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/hyh/aarch64-linux-android-4.9/bin

可以看到,用于编译内核的编译器路径已经添加到了$PATH中。

下面开始编译:
hyh@ubuntu:~/linux-kernel-exynos$ make ARCH=arm CROSS_COMPILE=arm-linux-androideabi- zImage
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
make[1]: ‘include/generated/mach-types.h’ is up to date.
CC kernel/bounds.s
GEN include/generated/bounds.h
CC arch/arm/kernel/asm-offsets.s
In file included from include/linux/scatterlist.h:10:0,
from include/linux/dma-mapping.h:9,
from arch/arm/kernel/asm-offsets.c:15:
/home/hyh/linux-kernel-exynos/arch/arm/include/asm/io.h:30:28: fatal error: mach/exynos-ss.h: No such file or directory
#include <mach/exynos-ss.h>
^
compilation terminated.
/home/hyh/linux-kernel-exynos/./Kbuild:81: recipe for target ‘arch/arm/kernel/asm-offsets.s’ failed
make[1]: *** [arch/arm/kernel/asm-offsets.s] Error 1
Makefile:836: recipe for target ‘prepare0’ failed
make: *** [prepare0] Error 2
hyh@ubuntu:~/linux-kernel-exynos$

出错了,改个编译工具,网上下载了一个arm-eabi-4.8,放到hyh目录下,在$PATH中加入目录/home/hyh/arm-eabi-4.8/bin,编译。这次好点,编译了大部分代码,但是在编译驱动时出错了:

hyh@ubuntu:~/linux-kernel-exynos$ make ARCH=arm CROSS_COMPILE=arm-eabi- zImage
CHK include/linux/version.h
CHK include/generated/utsrelease.h
make[1]: ‘include/generated/mach-types.h’ is up to date.
CALL scripts/checksyscalls.sh
CHK include/generated/compile.h
CC drivers/mfd/ezx-pcap.o
drivers/mfd/ezx-pcap.c: In function ‘pcap_isr_work’:
drivers/mfd/ezx-pcap.c:205:2: error: implicit declaration of function ‘irq_to_gpio’ [-Werror=implicit-function-declaration]
} while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
^
cc1: some warnings being treated as errors
scripts/Makefile.build:305: recipe for target ‘drivers/mfd/ezx-pcap.o’ failed
make[2]: *** [drivers/mfd/ezx-pcap.o] Error 1
scripts/Makefile.build:441: recipe for target ‘drivers/mfd’ failed
make[1]: *** [drivers/mfd] Error 2
Makefile:945: recipe for target ‘drivers’ failed
make: *** [drivers] Error 2
hyh@ubuntu:~/linux-kernel-samsung$

发现ezx-pcap.c文件中有一段如下代码:

static void pcap_isr_work(struct work_struct *work)
{
struct pcap_chip *pcap = container_of(work, struct pcap_chip, isr_work);
struct pcap_platform_data *pdata = pcap->spi->dev.platform_data;
u32 msr, isr, int_sel, service;
int irq;

do {
ezx_pcap_read(pcap, PCAP_REG_MSR, &msr);
ezx_pcap_read(pcap, PCAP_REG_ISR, &isr);

/* We can’t service/ack irqs that are assigned to port 2 */
if (!(pdata->config & PCAP_SECOND_PORT)) {
ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel);
isr &= ~int_sel;
}

ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr);
ezx_pcap_write(pcap, PCAP_REG_ISR, isr);

local_irq_disable();
service = isr & ~msr;
for (irq = pcap->irq_base; service; service >>= 1, irq++) {
if (service & 1)
generic_handle_irq(irq);
}
local_irq_enable();
ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr);
} while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
}

定位到申明的位置:<linux/gpio.h>,在gpio.h文件中有这样一段申明:

static inline int irq_to_gpio(unsigned irq)
{
/* irq can never have been returned from gpio_to_irq() */
WARN_ON(1);
return -EINVAL;
}

可见被加了static,外部无法访问。而且,看到注释,以及返回值,可见这个函数是无用的。分析在ezx-pcap.c文件中的这段代码,do while会执行一次这段代码,但irq_to_gpio()永远只会返回失败,所以一定只会执行一次,所以果断把 “do{” 和 “}while”  这两行代码屏蔽:

static void pcap_isr_work(struct work_struct *work)
{
struct pcap_chip *pcap = container_of(work, struct pcap_chip, isr_work);
struct pcap_platform_data *pdata = pcap->spi->dev.platform_data;
u32 msr, isr, int_sel, service;
int irq;

//do {
ezx_pcap_read(pcap, PCAP_REG_MSR, &msr);
ezx_pcap_read(pcap, PCAP_REG_ISR, &isr);

/* We can’t service/ack irqs that are assigned to port 2 */
if (!(pdata->config & PCAP_SECOND_PORT)) {
ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel);
isr &= ~int_sel;
}

ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr);
ezx_pcap_write(pcap, PCAP_REG_ISR, isr);

local_irq_disable();
service = isr & ~msr;
for (irq = pcap->irq_base; service; service >>= 1, irq++) {
if (service & 1)
generic_handle_irq(irq);
}
local_irq_enable();
ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr);
//} while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
}

再次编译,过了:

……

LD vmlinux.o
MODPOST vmlinux.o
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
LD init/built-in.o
LD .tmp_vmlinux1
KSYM .tmp_kallsyms1.S
AS .tmp_kallsyms1.o
LD .tmp_vmlinux2
KSYM .tmp_kallsyms2.S
AS .tmp_kallsyms2.o
LD vmlinux
SYSMAP System.map
SYSMAP .tmp_System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy.gzip
AS arch/arm/boot/compressed/piggy.gzip.o
SHIPPED arch/arm/boot/compressed/lib1funcs.S
AS arch/arm/boot/compressed/lib1funcs.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
hyh@ubuntu:~/linux-kernel-exynos$

5. 后记

最后一步的编译经常会出一些具体的问题,比如某个包含文件找不到、某段代码编译出错,这种错误需要仔细分析错误提示,往往能定位到问题。源码过于庞大,而实际的应用千差万别,导致自定义后的某些模块之间出现问题。所以这样的问题只能是具体问题具体分析,没用的代码甚至可以屏蔽。这恰恰也是导致部分自定义代码无法编译通过的原因。

 

在命令模式下编译Android NDK 的 *.so 库

为Android编译c++写的库文件(*.so文件)有很多种方式,实际上就是有很多种不同的工具可以选择:Eclipse+ADT、Android Studio,本质上还是调用android-ndk下的build-ndk(.bat)指令来编译arm版本的、针对Android操作系统的so文件。

我们在用Eclipse编译so文件时基本上就是建一个Android工程,为其定义一个编译配置(配置好的Android ndk路径、src路径、workspace路径等等),然后为其增加Application.mk和Android.mk两个文件,Eclipse就会自动调用Application.mk和Android.mk make文件去编译、生成so文件了。

我一直都在用Eclipse配置、编译so库,但说实话,Eclipse不但配置繁琐、容易出错,Eclipse对工程的管理也是非常不灵活的:我要是有多个不相关的so库需要编译,每次打开时都会全部加载(也许是我用的不好吧),编译时又得指定要编译的库单独编译;如果某个库的路径变了,Eclipse得重新配置,否则一大堆错误,真正要编译的项目却淹没其中。

既然Eclipse也不过是调用了Android-ndk的指令去结合Application.mk和Android.mk文件实现编译,为什么不能从命令模式直接调用android-ndk命令结合Application.mk和Android.mk文件来编译呢?这样每个项目各自不会纠缠在一起,干净利落,岂不美哉?

下面拿一个项目做个测试。

step 1: 建立一个目录,名称为:PerceptionNeuronPrj

step 2: 将项目的源码拷贝进去

这里是PerceptionNeuronSDK目录,可以看到此SDK的所有源代码都放在了PerceptionNeuronSDK目录下的src下(文件太多,打印此目录树时暂时移走了),对外的头文件直接放在PerceptionNeuronSDK目录下;

step 3: 加入依赖的第三方库或源码

与PerceptionNeuronSDK目录同级的是Eigen-3.2.2和InhouseLibs,即PerceptionNeuronSDK依赖的第三方库或源代码;

step 4: 创建用于编译PerceptionNeuronSDK的NDK配置文件

在PerceptionNeuronSDK目录下新建一个目录,这里命名为build_Android,同时在build_Android下新建jni目录、libs目录;

step 5: 为PerceptionNeuronSDK增加Application.mk及Android.mk配置文件

这里一定要小心,不能再Android.mk里通过脚本加载第三方的源码进去,而应该在PerceptionNeuronSDK的src目录中,在使用到诸如Eigen的地方通过#include引用!

附1:Application.mk文件内容

APP_ABI           := all
#APP_ABI          := armeabi armeabi-v7a x86

APP_OPTIM         := release
APP_PLATFORM      := android-8
#APP_BUILD_SCRIPT := Android.mk

# GNU STL implements most C++11 features. Use either gnustl_static or gnustl_shared
# Without this your C++ code will not be able to access headers like <thread>, <mutex>
#APP_STL      := stlport_static
#APP_CPPFLAGS := -std=c++11 -frtti -fexceptions 
APP_STL       := gnustl_static
APP_CPPFLAGS  := -std=gnu++11 -pthread -frtti -fexceptions -DNDEBUG #-NDEBUG -mfpu=neon -fomit-frame-pointer -DULM_BLOCKED -msse3 -mfpmath=sse

附2: Android.mk文件内容

# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE   := PNLib

# 锟斤拷锟斤拷锟皆硷拷锟斤拷源锟侥硷拷目录锟斤拷源锟侥硷拷锟斤拷缀锟斤拷
MY_FILES_PATH  :=  $(LOCAL_PATH)/../../src

#$(warning $(MY_FILES_PATH))

MY_FILES_SUFFIX := %.cpp %.c

# 递归遍历目录下的所有的文件
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

# 获取相应的源文件
MY_ALL_FILES := $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*.*) ) 
MY_ALL_FILES := $(MY_ALL_FILES:$(MY_CPP_PATH)/./%=$(MY_CPP_PATH)%)
MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(MY_ALL_FILES)) 
MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)

# 去除字串的重复单词
define uniq =
  $(eval seen :=)
  $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_)))
  ${seen}
endef

# 递归遍历获取所有目录
MY_ALL_DIRS := $(dir $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*/) ) )
MY_ALL_DIRS := $(call uniq,$(MY_ALL_DIRS))

# 赋值给NDK编译系统
LOCAL_SRC_FILES  := $(MY_SRC_LIST)
LOCAL_C_INCLUDES := $(MY_ALL_DIRS)

# Add additional include directories
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../Eigen-3.2.2   
#必须从Android.mk配置文件中拿掉对Eigen的直接包含,放到程序代码中用相对路径包含:
# #include "../../Eigen-3.2.2/Eigen"
# using namespace Eigen;

#$(warning $(LOCAL_SRC_FILES))
#$(warning $(LOCAL_C_INCLUDES))

# use log system in NDK
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

step 6: 为了方便使用,增加一个build.bat文件

在里面加入如下脚本:

ndk-build NDK_APPLICATION_MK=./Application.mk

pause

至此,所需文件及配置均已建立完毕,在windows中通过 ‘tree /f’ 指令可以看到其中的目录结构如下所示:

 

 

1

双击build.bat或通过命令行加载build.bat文件,即可编译出结果:

D:\PerceptionNeuronPrj\PerceptionNeuronSDK\build_Android\jni>build.bat

D:\PerceptionNeuronPrj\PerceptionNeuronSDK\build_Android\jni>ndk-build NDK_APPLI
CATION_MK=./Application.mk
[arm64-v8a] Compile++      : PNLib <= AntiJointCompensation.cpp
[arm64-v8a] Compile++      : PNLib <= BVHPlayerWrapper.cpp
[arm64-v8a] Compile++      : PNLib <= BoneMapping.cpp
[arm64-v8a] Compile++      : PNLib <= BoneMass.cpp
[arm64-v8a] Compile++      : PNLib <= BoneTable.cpp
[arm64-v8a] Compile++      : PNLib <= BvhBinaryOutputPacker.cpp
[arm64-v8a] Compile++      : PNLib <= BvhDataConvert.cpp
In file included from D:/PerceptionNeuronPrj/PerceptionNeuronSDK/build_Android/j
ni/../../src/./AvatarManagement/../PluginMngr/Interface/IPluginActionRecog.h:3:0
,
                 from D:/PerceptionNeuronPrj/PerceptionNeuronSDK/build_Android/j
ni/../../src/./AvatarManagement/Avatar.h:13,
                 from D:/PerceptionNeuronPrj/PerceptionNeuronSDK/build_Android/j
ni/../../src/BvhDataConvert.cpp:9:
D:/PerceptionNeuronPrj/PerceptionNeuronSDK/build_Android/jni/../../src/./AvatarM
anagement/../PluginMngr/Interface/IPluginObject.h:55:69: warning: 'visibility' a
ttribute ignored [-Wattributes]
         PNLIB_PLUGIN_EXPORT typedef IPluginObject* (*GetPluginFunc)();
....................
.....
.                                                                 ^

 

编译速度非常慢,看项目大小和编译的架构多少,十几分钟几十分钟不等。

编译完成后,so文件自动放到libs下的相应架构目录下,目录结构如下:

QQ截图20160311143749

 

QQ截图20160311143406

step 7: 清除及重新编译

由于ndk-build.bat编译完项目后会缓存所有中间文件(*.obj及其他中间文件),再次运行ndk-build.bat只是简单的从缓冲拷贝so文件,所以需要增加一个build clean,以便清除缓冲:

附3:build_clean.bat

#自动到NDK_PROJECT_PATH目录下找jni目录,利用其中的Android.mk清除上次编译的结果
ndk-build NDK_PROJECT_PATH=../ clean

pause

 

十大滤波算法程序大全(Arduino精编无错版)

最近用Arduino做电子秤,为了解决数据的跳变研究了不少滤波算法。网上能找到大把的十大滤波算法帖子,每一篇都不太一样,都号称精编啊,除错啊什么的,可是放到板子里却没一个能正常跑起来的。于是决定自己整理一下这些程序,完美移植到Arduino中。

所以大家看到这个帖子的时候,不要怀疑我重复发帖。我的代码都是经过反复试验,复制到Arduino中就能开跑的成品代码,移植到自己的程序中非常方便。而且都仔细研究了各个算法,把错误都修正了的(别的程序连冒泡算法都是溢出的,不信自己找来细看看),所以也算个小原创吧,在别人基础上的原创。

转载请注明出处:极客工坊  http://www.geek-workshop.com/thread-7694-1-1.html

By shenhaiyu 2013-11-01

 

1、限幅滤波法(又称程序判断滤波法)
2、中位值滤波法
3、算术平均滤波法
4、递推平均滤波法(又称滑动平均滤波法)
5、中位值平均滤波法(又称防脉冲干扰平均滤波法)
6、限幅平均滤波法
7、一阶滞后滤波法
8、加权递推平均滤波法
9、消抖滤波法
10、限幅消抖滤波法
11、新增加 卡尔曼滤波(非扩展卡尔曼),感谢zhangzhe0617分享

程序默认对int类型数据进行滤波,如需要对其他类型进行滤波,只需要把程序中所有int替换成long、float或者double即可。

1、限幅滤波法(又称程序判断滤波法)

ARDUINO 代码
/*
A、名称:限幅滤波法(又称程序判断滤波法)
B、方法:
    根据经验判断,确定两次采样允许的最大偏差值(设为A),
    每次检测到新值时判断:
    如果本次值与上次值之差<=A,则本次值有效,
    如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值。
C、优点:
    能有效克服因偶然因素引起的脉冲干扰。
D、缺点:
    无法抑制那种周期性的干扰。
    平滑度差。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Value = Filter_Value;          // 最近一次有效采样的值,该变量为全局变量
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 限幅滤波法(又称程序判断滤波法)
#define FILTER_A 1
int Filter() {
  int NewValue;
  NewValue = Get_AD();
  if(((NewValue - Value) > FILTER_A) || ((Value - NewValue) > FILTER_A))
    return Value;
  else
    return NewValue;
}

2、中位值滤波法

ARDUINO 代码
/*
A、名称:中位值滤波法
B、方法:
    连续采样N次(N取奇数),把N次采样值按大小排列,
    取中间值为本次有效值。
C、优点:
    能有效克服因偶然因素引起的波动干扰;
    对温度、液位的变化缓慢的被测参数有良好的滤波效果。
D、缺点:
    对流量、速度等快速变化的参数不宜。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 中位值滤波法
#define FILTER_N 101
int Filter() {
  int filter_buf[FILTER_N];
  int i, j;
  int filter_temp;
  for(i = 0; i < FILTER_N; i++) {
    filter_buf[i] = Get_AD();
    delay(1);
  }
  // 采样值从小到大排列(冒泡法)
  for(j = 0; j < FILTER_N - 1; j++) {
    for(i = 0; i < FILTER_N - 1 - j; i++) {
      if(filter_buf[i] > filter_buf[i + 1]) {
        filter_temp = filter_buf[i];
        filter_buf[i] = filter_buf[i + 1];
        filter_buf[i + 1] = filter_temp;
      }
    }
  }
  return filter_buf[(FILTER_N - 1) / 2];
}

3、算术平均滤波法

ARDUINO 代码
/*
A、名称:算术平均滤波法
B、方法:
    连续取N个采样值进行算术平均运算:
    N值较大时:信号平滑度较高,但灵敏度较低;
    N值较小时:信号平滑度较低,但灵敏度较高;
    N值的选取:一般流量,N=12;压力:N=4。
C、优点:
    适用于对一般具有随机干扰的信号进行滤波;
    这种信号的特点是有一个平均值,信号在某一数值范围附近上下波动。
D、缺点:
    对于测量速度较慢或要求数据计算速度较快的实时控制不适用;
    比较浪费RAM。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 算术平均滤波法
#define FILTER_N 12
int Filter() {
  int i;
  int filter_sum = 0;
  for(i = 0; i < FILTER_N; i++) {
    filter_sum += Get_AD();
    delay(1);
  }
  return (int)(filter_sum / FILTER_N);
}

4、递推平均滤波法(又称滑动平均滤波法)

ARDUINO 代码
/*
A、名称:递推平均滤波法(又称滑动平均滤波法)
B、方法:
    把连续取得的N个采样值看成一个队列,队列的长度固定为N,
    每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据(先进先出原则),
    把队列中的N个数据进行算术平均运算,获得新的滤波结果。
    N值的选取:流量,N=12;压力,N=4;液面,N=4-12;温度,N=1-4。
C、优点:
    对周期性干扰有良好的抑制作用,平滑度高;
    适用于高频振荡的系统。
D、缺点:
    灵敏度低,对偶然出现的脉冲性干扰的抑制作用较差;
    不易消除由于脉冲干扰所引起的采样值偏差;
    不适用于脉冲干扰比较严重的场合;
    比较浪费RAM。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 递推平均滤波法(又称滑动平均滤波法)
#define FILTER_N 12
int filter_buf[FILTER_N + 1];
int Filter() {
  int i;
  int filter_sum = 0;
  filter_buf[FILTER_N] = Get_AD();
  for(i = 0; i < FILTER_N; i++) {
    filter_buf[i] = filter_buf[i + 1]; // 所有数据左移,低位仍掉
    filter_sum += filter_buf[i];
  }
  return (int)(filter_sum / FILTER_N);
}

5、中位值平均滤波法(又称防脉冲干扰平均滤波法)

ARDUINO 代码
/*
A、名称:中位值平均滤波法(又称防脉冲干扰平均滤波法)
B、方法:
    采一组队列去掉最大值和最小值后取平均值,
    相当于“中位值滤波法”+“算术平均滤波法”。
    连续采样N个数据,去掉一个最大值和一个最小值,
    然后计算N-2个数据的算术平均值。
    N值的选取:3-14。
C、优点:
    融合了“中位值滤波法”+“算术平均滤波法”两种滤波法的优点。
    对于偶然出现的脉冲性干扰,可消除由其所引起的采样值偏差。
    对周期干扰有良好的抑制作用。
    平滑度高,适于高频振荡的系统。
D、缺点:
    计算速度较慢,和算术平均滤波法一样。
    比较浪费RAM。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 中位值平均滤波法(又称防脉冲干扰平均滤波法)(算法1)
#define FILTER_N 100
int Filter() {
  int i, j;
  int filter_temp, filter_sum = 0;
  int filter_buf[FILTER_N];
  for(i = 0; i < FILTER_N; i++) {
    filter_buf[i] = Get_AD();
    delay(1);
  }
  // 采样值从小到大排列(冒泡法)
  for(j = 0; j < FILTER_N - 1; j++) {
    for(i = 0; i < FILTER_N - 1 - j; i++) {
      if(filter_buf[i] > filter_buf[i + 1]) {
        filter_temp = filter_buf[i];
        filter_buf[i] = filter_buf[i + 1];
        filter_buf[i + 1] = filter_temp;
      }
    }
  }
  // 去除最大最小极值后求平均
  for(i = 1; i < FILTER_N - 1; i++) filter_sum += filter_buf[i];
  return filter_sum / (FILTER_N - 2);
}
 
 
//  中位值平均滤波法(又称防脉冲干扰平均滤波法)(算法2)
/*
#define FILTER_N 100
int Filter() {
  int i;
  int filter_sum = 0;
  int filter_max, filter_min;
  int filter_buf[FILTER_N];
  for(i = 0; i < FILTER_N; i++) {
    filter_buf[i] = Get_AD();
    delay(1);
  }
  filter_max = filter_buf[0];
  filter_min = filter_buf[0];
  filter_sum = filter_buf[0];
  for(i = FILTER_N - 1; i > 0; i--) {
    if(filter_buf[i] > filter_max)
      filter_max=filter_buf[i];
    else if(filter_buf[i] < filter_min)
      filter_min=filter_buf[i];
    filter_sum = filter_sum + filter_buf[i];
    filter_buf[i] = filter_buf[i - 1];
  }
  i = FILTER_N - 2;
  filter_sum = filter_sum - filter_max - filter_min + i / 2; // +i/2 的目的是为了四舍五入
  filter_sum = filter_sum / i;
  return filter_sum;
}*/

6、限幅平均滤波法

ARDUINO 代码
/*
A、名称:限幅平均滤波法
B、方法:
    相当于“限幅滤波法”+“递推平均滤波法”;
    每次采样到的新数据先进行限幅处理,
    再送入队列进行递推平均滤波处理。
C、优点:
    融合了两种滤波法的优点;
    对于偶然出现的脉冲性干扰,可消除由于脉冲干扰所引起的采样值偏差。
D、缺点:
    比较浪费RAM。
E、整理:shenhaiyu 2013-11-01
*/
 
#define FILTER_N 12
int Filter_Value;
int filter_buf[FILTER_N];
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  filter_buf[FILTER_N - 2] = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 限幅平均滤波法
#define FILTER_A 1
int Filter() {
  int i;
  int filter_sum = 0;
  filter_buf[FILTER_N - 1] = Get_AD();
  if(((filter_buf[FILTER_N - 1] - filter_buf[FILTER_N - 2]) > FILTER_A) || ((filter_buf[FILTER_N - 2] - filter_buf[FILTER_N - 1]) > FILTER_A))
    filter_buf[FILTER_N - 1] = filter_buf[FILTER_N - 2];
  for(i = 0; i < FILTER_N - 1; i++) {
    filter_buf[i] = filter_buf[i + 1];
    filter_sum += filter_buf[i];
  }
  return (int)filter_sum / (FILTER_N - 1);
}

7、一阶滞后滤波法

ARDUINO 代码
/*
A、名称:一阶滞后滤波法
B、方法:
    取a=0-1,本次滤波结果=(1-a)*本次采样值+a*上次滤波结果。
C、优点:
    对周期性干扰具有良好的抑制作用;
    适用于波动频率较高的场合。
D、缺点:
    相位滞后,灵敏度低;
    滞后程度取决于a值大小;
    不能消除滤波频率高于采样频率1/2的干扰信号。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 一阶滞后滤波法
#define FILTER_A 0.01
int Filter() {
  int NewValue;
  NewValue = Get_AD();
  Value = (int)((float)NewValue * FILTER_A + (1.0 - FILTER_A) * (float)Value);
  return Value;
}

8、加权递推平均滤波法

ARDUINO 代码
/*
A、名称:加权递推平均滤波法
B、方法:
    是对递推平均滤波法的改进,即不同时刻的数据加以不同的权;
    通常是,越接近现时刻的数据,权取得越大。
    给予新采样值的权系数越大,则灵敏度越高,但信号平滑度越低。
C、优点:
    适用于有较大纯滞后时间常数的对象,和采样周期较短的系统。
D、缺点:
    对于纯滞后时间常数较小、采样周期较长、变化缓慢的信号;
    不能迅速反应系统当前所受干扰的严重程度,滤波效果差。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 加权递推平均滤波法
#define FILTER_N 12
int coe[FILTER_N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};    // 加权系数表
int sum_coe = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12; // 加权系数和
int filter_buf[FILTER_N + 1];
int Filter() {
  int i;
  int filter_sum = 0;
  filter_buf[FILTER_N] = Get_AD();
  for(i = 0; i < FILTER_N; i++) {
    filter_buf[i] = filter_buf[i + 1]; // 所有数据左移,低位仍掉
    filter_sum += filter_buf[i] * coe[i];
  }
  filter_sum /= sum_coe;
  return filter_sum;
}

9、消抖滤波法

ARDUINO 代码
/*
A、名称:消抖滤波法
B、方法:
    设置一个滤波计数器,将每次采样值与当前有效值比较:
    如果采样值=当前有效值,则计数器清零;
    如果采样值<>当前有效值,则计数器+1,并判断计数器是否>=上限N(溢出);
    如果计数器溢出,则将本次值替换当前有效值,并清计数器。
C、优点:
    对于变化缓慢的被测参数有较好的滤波效果;
    可避免在临界值附近控制器的反复开/关跳动或显示器上数值抖动。
D、缺点:
    对于快速变化的参数不宜;
    如果在计数器溢出的那一次采样到的值恰好是干扰值,则会将干扰值当作有效值导入系统。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 消抖滤波法
#define FILTER_N 12
int i = 0;
int Filter() {
  int new_value;
  new_value = Get_AD();
  if(Value != new_value) {
    i++;
    if(i > FILTER_N) {
      i = 0;
      Value = new_value;
    }
  }
  else
    i = 0;
  return Value;
}

10、限幅消抖滤波法

ARDUINO 代码
/*
A、名称:限幅消抖滤波法
B、方法:
    相当于“限幅滤波法”+“消抖滤波法”;
    先限幅,后消抖。
C、优点:
    继承了“限幅”和“消抖”的优点;
    改进了“消抖滤波法”中的某些缺陷,避免将干扰值导入系统。
D、缺点:
    对于快速变化的参数不宜。
E、整理:shenhaiyu 2013-11-01
*/
 
int Filter_Value;
int Value;
 
void setup() {
  Serial.begin(9600);       // 初始化串口通信
  randomSeed(analogRead(0)); // 产生随机种子
  Value = 300;
}
 
void loop() {
  Filter_Value = Filter();       // 获得滤波器输出值
  Serial.println(Filter_Value); // 串口输出
  delay(50);
}
 
// 用于随机产生一个300左右的当前值
int Get_AD() {
  return random(295, 305);
}
 
// 限幅消抖滤波法
#define FILTER_A 1
#define FILTER_N 5
int i = 0;
int Filter() {
  int NewValue;
  int new_value;
  NewValue = Get_AD();
  if(((NewValue - Value) > FILTER_A) || ((Value - NewValue) > FILTER_A))
    new_value = Value;
  else
    new_value = NewValue;
  if(Value != new_value) {
    i++;
    if(i > FILTER_N) {
      i = 0;
      Value = new_value;
    }
  }
  else
    i = 0;
  return Value;
}

 

11、卡尔曼滤波(非扩展卡尔曼)

ARDUINO 代码
#include <Wire.h> // I2C library, gyroscope

// Accelerometer ADXL345
#define ACC (0x53)    //ADXL345 ACC address
#define A_TO_READ (6)        //num of bytes we are going to read each time (two bytes for each axis)


// Gyroscope ITG3200 
#define GYRO 0x68 // gyro address, binary = 11101000 when AD0 is connected to Vcc (see schematics of your breakout board)
#define G_SMPLRT_DIV 0x15   
#define G_DLPF_FS 0x16   
#define G_INT_CFG 0x17
#define G_PWR_MGM 0x3E

#define G_TO_READ 8 // 2 bytes for each axis x, y, z


// offsets are chip specific. 
int a_offx = 0;
int a_offy = 0;
int a_offz = 0;

int g_offx = 0;
int g_offy = 0;
int g_offz = 0;
////////////////////////

////////////////////////
char str[512]; 

void initAcc() {
  //Turning on the ADXL345
  writeTo(ACC, 0x2D, 0);      
  writeTo(ACC, 0x2D, 16);
  writeTo(ACC, 0x2D, 8);
  //by default the device is in +-2g range reading
}

void getAccelerometerData(int* result) {
  int regAddress = 0x32;    //first axis-acceleration-data register on the ADXL345
  byte buff[A_TO_READ];
  
  readFrom(ACC, regAddress, A_TO_READ, buff); //read the acceleration data from the ADXL345
  
  //each axis reading comes in 10 bit resolution, ie 2 bytes.  Least Significat Byte first!!
  //thus we are converting both bytes in to one int
  result[0] = (((int)buff[1]) << 8) | buff[0] + a_offx;   
  result[1] = (((int)buff[3]) << 8) | buff[2] + a_offy;
  result[2] = (((int)buff[5]) << 8) | buff[4] + a_offz;
}

//initializes the gyroscope
void initGyro()
{
  /*****************************************
  * ITG 3200
  * power management set to:
  * clock select = internal oscillator
  *     no reset, no sleep mode
  *   no standby mode
  * sample rate to = 125Hz
  * parameter to +/- 2000 degrees/sec
  * low pass filter = 5Hz
  * no interrupt
  ******************************************/
  writeTo(GYRO, G_PWR_MGM, 0x00);
  writeTo(GYRO, G_SMPLRT_DIV, 0x07); // EB, 50, 80, 7F, DE, 23, 20, FF
  writeTo(GYRO, G_DLPF_FS, 0x1E); // +/- 2000 dgrs/sec, 1KHz, 1E, 19
  writeTo(GYRO, G_INT_CFG, 0x00);
}


void getGyroscopeData(int * result)
{
  /**************************************
  Gyro ITG-3200 I2C
  registers:
  temp MSB = 1B, temp LSB = 1C
  x axis MSB = 1D, x axis LSB = 1E
  y axis MSB = 1F, y axis LSB = 20
  z axis MSB = 21, z axis LSB = 22
  *************************************/

  int regAddress = 0x1B;
  int temp, x, y, z;
  byte buff[G_TO_READ];
  
  readFrom(GYRO, regAddress, G_TO_READ, buff); //read the gyro data from the ITG3200
  
  result[0] = ((buff[2] << 8) | buff[3]) + g_offx;
  result[1] = ((buff[4] << 8) | buff[5]) + g_offy;
  result[2] = ((buff[6] << 8) | buff[7]) + g_offz;
  result[3] = (buff[0] << 8) | buff[1]; // temperature
  
}


float xz=0,yx=0,yz=0;
float p_xz=1,p_yx=1,p_yz=1;
float q_xz=0.0025,q_yx=0.0025,q_yz=0.0025;
float k_xz=0,k_yx=0,k_yz=0;
float r_xz=0.25,r_yx=0.25,r_yz=0.25;
  //int acc_temp[3];
  //float acc[3];
  int acc[3];
  int gyro[4];
  float Axz;
  float Ayx;
  float Ayz;
  float t=0.025;
void setup()
{
  Serial.begin(9600);
  Wire.begin();
  initAcc();
  initGyro();
  
}

//unsigned long timer = 0;
//float o;
void loop()
{
  
  getAccelerometerData(acc);
  getGyroscopeData(gyro);
  //timer = millis();
  sprintf(str, "%d,%d,%d,%d,%d,%d", acc[0],acc[1],acc[2],gyro[0],gyro[1],gyro[2]);
  
  //acc[0]=acc[0];
  //acc[2]=acc[2];
  //acc[1]=acc[1];
  //r=sqrt(acc[0]*acc[0]+acc[1]*acc[1]+acc[2]*acc[2]);
  gyro[0]=gyro[0]/ 14.375;
  gyro[1]=gyro[1]/ (-14.375);
  gyro[2]=gyro[2]/ 14.375;
  
   
  Axz=(atan2(acc[0],acc[2]))*180/PI;
  Ayx=(atan2(acc[0],acc[1]))*180/PI;
  /*if((acc[0]!=0)&&(acc[1]!=0))
    {
      Ayx=(atan2(acc[0],acc[1]))*180/PI;
    }
    else
    {
      Ayx=t*gyro[2];
    }*/
  Ayz=(atan2(acc[1],acc[2]))*180/PI;
  
  
//kalman filter
  calculate_xz();
  calculate_yx();
  calculate_yz();
  
  //sprintf(str, "%d,%d,%d", xz_1, xy_1, x_1);
  //Serial.print(xz);Serial.print(",");
  //Serial.print(yx);Serial.print(",");
  //Serial.print(yz);Serial.print(",");
  //sprintf(str, "%d,%d,%d,%d,%d,%d", acc[0],acc[1],acc[2],gyro[0],gyro[1],gyro[2]);
  //sprintf(str, "%d,%d,%d",gyro[0],gyro[1],gyro[2]);
    Serial.print(Axz);Serial.print(",");
    //Serial.print(Ayx);Serial.print(",");
    //Serial.print(Ayz);Serial.print(",");
  //Serial.print(str);
  //o=gyro[2];//w=acc[2];
  //Serial.print(o);Serial.print(",");
  //Serial.print(w);Serial.print(",");
  Serial.print("\n");

  
  //delay(50);
}
void calculate_xz()
{

xz=xz+t*gyro[1];
p_xz=p_xz+q_xz;
k_xz=p_xz/(p_xz+r_xz);
xz=xz+k_xz*(Axz-xz);
p_xz=(1-k_xz)*p_xz;
}
void calculate_yx()
{
  
  yx=yx+t*gyro[2];
  p_yx=p_yx+q_yx;
  k_yx=p_yx/(p_yx+r_yx);
  yx=yx+k_yx*(Ayx-yx);
  p_yx=(1-k_yx)*p_yx;

}
void calculate_yz()
{
  yz=yz+t*gyro[0];
  p_yz=p_yz+q_yz;
  k_yz=p_yz/(p_yz+r_yz);
  yz=yz+k_yz*(Ayz-yz);
  p_yz=(1-k_yz)*p_yz;

}


//---------------- Functions
//Writes val to address register on ACC
void writeTo(int DEVICE, byte address, byte val) {
   Wire.beginTransmission(DEVICE); //start transmission to ACC 
   Wire.write(address);        // send register address
   Wire.write(val);        // send value to write
   Wire.endTransmission(); //end transmission
}


//reads num bytes starting from address register on ACC in to buff array
void readFrom(int DEVICE, byte address, int num, byte buff[]) {
  Wire.beginTransmission(DEVICE); //start transmission to ACC 
  Wire.write(address);        //sends address to read from
  Wire.endTransmission(); //end transmission
  
  Wire.beginTransmission(DEVICE); //start transmission to ACC
  Wire.requestFrom(DEVICE, num);    // request 6 bytes from ACC
  
  int i = 0;
  while(Wire.available())    //ACC may send less than requested (abnormal)
  { 
    buff[i] = Wire.read(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission
}

 

本文转自:http://www.geek-workshop.com/thread-7694-1-1.html

 

Raspberry Pi快速上手教程

当你收到好不容易发货的Raspberry Pi(树莓派)之后会发现包装中只包含了一块板子和简单的说明书,没有任何附件,想要让它工作起来必须DIY自己配置各种附件。本文就是一个简单的快速上手教程,使你提前做好准备能够很快的让Raspberry Pi奔跑起来。

首先看看除了Raspberry Pi之外还需要哪些附件吧:

  • USB接口键盘和鼠标:其中USB键盘是必不可少的。
  • SD存储卡:Raspberry Pi的系统都是放在SD卡上。可以选择标准大小的SD卡或者micro SD卡,如果是micro SD卡还必须有一个适配器(adapter),板上的插槽是SD/MMC式的,当然还要准备一个读卡器。SD卡最少要选择4GB容量以上以及速度CLASS4以上,Raspberry Pi上大部分可用的系统需求都超过2GB。
  • Micro USB连接线:做电源线用。
  • USB口适配器:Raspberry Pi最少需要5V@700ma电流,因此不能通过计算机USB口供电。
  • 视频线:可以是HDMI线或者是接电视的复合视频线。如果显示器不带HDMI接口,还需要配置HDMI转DVI或者HDMI转VGA的线缆。
  • 以太网线:网线虽然不是必需的但是却很重要。
  • USB集线器:这不是必须的,Raspberry Pi只有2个USB口,如果配置一个带电源的USB集线器,能减轻Raspberry Pi的负荷而且能扩展更多USB设备。

Raspberry Pi Wiki上列举了非常多可支持的硬件外设以及可能有问题的外设,上图是我们准备的一些外设,并没有刻意选择型号:

  • Raspberry Pi B型
  • 普通USB键盘鼠标
  • Kingston 4GB micro SD(Class4)以及micro SD Adapter
  • 一个旧手机的USB电源适配器(5V@1A)
  • 一根HDMI-DVI连接线
  • 一台带DVI接口液晶显示器
  • 一根网线

安装系统

Raspberry Pi的系统是在SD卡上运行,必须先将系统安装到SD卡上。目前支持Raspberry Pi的Linux有很多版本。开始的时候我们还是选择一个官方量身定制的Raspian ”wheezy“,这是一个在Debian基础上优化的版本,可以在官网下载。

如果使用Windows系统,官方建议使用Wi32DiskImager来复制image文件到SD卡(如果是Linux系统可以用工具dd)。这里就在常用的Windows系统下说明,下载最新的Raspian wheezy(目前是2012-8-16),解压缩zip文件。

解压缩后的img文件有1.8G左右,插入读卡器,打开下载的Win32DiskImager软件,将img写入到SD卡中。

上电启动

Raspberry Pi最有可能碰到的问题就是供电电压不足或者USB适配器不能提供足够电流。Raspberry Pi的供电电压范围为4.75V~5.25V,而且板上留了两个测试点TP1、TP2(电源和地)用来检测供电电压。如下图可以用万用表首先测量下供电电压。

连接好所有的外设,插好SD卡。

Raspian系统第一次启动会多花点时间,而且启动后程序首先会进入系统设置画面。

Raspian系统设置:

  • info:系统设置工具的信息
  • expand-rootfs:扩大Linux系统root分区的大小
  • overscan:使能overscan
  • configure_keyboard:选择键盘布局(Raspberry Pi键盘布局默认英式,这里可以调整)
  • change_pass:修改用户密码(Raspbian默认用户名为pi,密码raspberry)
  • change_local:修改输入法(可以修改成中文输入,不过先要安装字体,暂时不修改)
  • change_timezone:修改系统时区(Raspberry Pi没有实时时钟,靠网络同步时间)
  • memory_split:修改内存划分(一共256MB内存,修改ARM处理器和图形加速器的分配)
  • ssh:使能ssh服务器(建议开启,这样可以通过ssh访问Raspberry Pi)
  • boot_behaviour:设置系统启动进入命令行界面还是图形界面(在命令行模式输入startx可以进入图形界面)
  • update:可以在线升级

设置完成后选择finish退出设置界面,重启系统,Raspberry Pi就首次进入了命令行模式

设置网络

Raspian系统的网络设置文件包括dns设置/etc/resolv.conf 和dhcp设置 /etc/network/interfaces,笔者的网络采用了固定IP,因此需要修改文件设定静态IP,如果网络遇到问题可以查看这两个文件。

输入

sudo vi /etc/resolv.conf

显示

domain router
search router
nameserver 192.168.0.111

其中的nameserver就是指DNS服务器IP,上面这个IP不正确,修改nameserver 的IP地址。

输入

sudo vi /etc/network/interfaces

显示

auto lo
iface lo inet loopback
iface eth0 inet dhcp

其中iface eth0 inet dhcp代表网口目前是采用自动dhcp分配IP,修改成:

atuo eth0
iface eth0 inet static
address 192.168.0.160
network 192.168.0.0
netmask 255.255.255.0
broadcast 192.168.0.255
gateway 192.168.0.1

设置了Raspberry Pi的静态IP为192.168.0.160,这些可以根据自己网络修改设置。

保存退出重启网络,输入:

sudo /etc/init.d/networking restart

网络重启后可以通过ping命令看看网络有没有连通。

中文设置

网络连通后其实Raspberry Pi的初步设置已经完成了,软件环境已经可以使用。对于我们来说中文更习惯,而Raspian系统是支持中文显示的,所以我们来看看怎么设置中文。

还是在命令行模式下,因为网络已经连通,先进行在线升级,输入:

sudo apt-get update

安装中文字体:

sudo apt-get install ttf-wqy-microhei

安装完成后设置中文:

sudo dpkg-reconfigure locales

将zh_CN前缀的都选上,然后选择zh_CN.UTF-8,这就设置系统默认环境语言为中文。

当然我们也可以输入

sudo raspi-config

进入系统最初的那个设置界面设置中文(change_locale)。

接下来安装中文输入法。输入:

sudo apt-get install scim

sudo apt-get install scim-pinyin

重启系统进入图形界面模式,可以看到一个中文的Linux系统了。

用Raspian自带的Midori浏览器可以上网冲浪了!

小结

介绍了Raspberry Pi B型开发板如何快速上手,所需要的基本外设以及网络配置。设置了Raspian系统以及中文环境,快速的搭好了一个中文的Linux系统。

参考链接

Enable Secure Shell (SSH) On Your Raspberry Pi

Posted on May 31, 2012 by Matt

Secure Shell or SSH is a network protocol that allows you to run commands on a remote device. In the case of the Raspberry Pi can you execute commands over your network from another device such as a PC or laptop. This allows you to control the Pi without attaching a keyboard, mouse or even a monitor.

The free utility “PuTTY” can be used to connect to your Pi using SSH once it is enabled.

Update : The newer Debian “Wheezy” image enabled SSH by default so Methods 1 & 2 below are not required if you are using this image.

Method 1

To start the SSH server on a Pi you can open a terminal window (i.e. LXTerminal) and type :

sudo /etc/init.d/ssh start

followed by Enter. This needs to be done every time the Pi boots.

Method 2 

To enable SSH automatically every time the Pi starts you need to :

  • Prepare an SD card with the Debian “Squeeze” image
  • Insert the SD card in your PC
  • Rename ” boot_enable_ssh.rc” as “boot.rc”
  • Eject the SD card and insert into your Pi

When the Pi boots SSH is enabled by default.

Using SSH

You can now open a remote terminal window using PuTTY or any other SSH enabled client. This will allow you to type commands as if you were using the Pi directly.

You can even use SSH to transfer files using a file explorer style interface on your PC. I recommend the free utility WinSCP which will allow you to drag and drop. Transfering files is easy and similar to using FTP.

 

转自:http://www.raspberrypi-spy.co.uk/2012/05/enable-secure-shell-ssh-on-your-raspberry-pi/

 

嵌入式设计之:初学扫盲场

导语:

软硬结合才是王道!

搞了10多年的软件,始终抱有对底层机制的极大兴趣,不可避免的凯觎起硬件的地盘。苦于没有机会接触硬件设计方面的东西,所以只是纸上“看”兵,更别说动手做了。最近做了一些modbus协议方面的软件,加之对Linux还算比较熟悉,遂产生了使用硬件实现modbus数据集合的想法。

临渊羡鱼不如退而结网,说做就做吧,此时不动手更待老死墓中?

一、MUC简介和选型:RAM or Flash

一度分不清MCU中的Flash和RAM充当什么角色。

实际上,MCU中的RAM相当于PC的内存,程序都是装在在这里供MCU执行单元执行的。而Flash相当于PC的硬盘,如果是裸奔,那么写的固件都是烧在这个Flash里面的。MCU中的Flash一般都很小,只有几十K或者几百K,一度以为Flash才是内存或者二级缓存啥的,汗。

如果你规划中的系统需要运行Linux,那么你需要给它加个“硬盘”,而读写硬盘的地址就是通过Flash来映射的。具体的可能在后面会涉及到。

RAM:MCU的片上内存;

FLASH:MCU的片上“硬盘”,有擦写次数限制,一般为10^4次;

EEPROM:用来存储参数的区域,据说可以用Flash模拟EERPOM;

SRAM:通俗讲,就是扩展的内存。

二、电路设计:自定义元件库

有些元件在库中是找不到的,比如新出的MCU。这个时候只有自己做了,方法是在orCAD Capture中新建Library,制作完毕后就可以在电路设计时使用。

但是我碰到一个悲催的问题,设计完元件图,然后在电路设计时使用,添加完元件后,缺发现有个地方不对,需要到元件库中修改此元件,改完之后,再在电路设计图中使用,却总是提示:

Part is out of date with respect to the design cache.use update cache to synchronize the part in the cache with the library.

郁闷的是此问题卡了我两天!

解决俄方法也很简单,网上查到的(悲催的百度只能搜国内的内容,而且基本都是广告,真的是一点用的没有,纯粹一个无赖废物。今天在打开google主页之前默认三遍上帝保佑,还真打开了,感谢上帝顾念苍生!):

选择File目录树,点file.dsn前面的”+”,再点Design Cache前面的”+”,找到你所出错的Part名称,右击,Update一下,问题解决!!!

 

STM32 keil mdk启动代码分析

;// <h> Stack Configuration
;//   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;// </h>
Stack_Size      EQU     0x00000200                           ;//定义堆栈大小
AREA    STACK, NOINIT, READWRITE, ALIGN=3    ;//定义一个数据段 按8字节对齐
    ;//AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0Stack_Mem       SPACE   Stack_Size                           ;//保留Stack_Size大小的堆栈空间 分 配连续 Stack_Size 字节的存储单元并初始化为 0

__initial_sp                                                 ;//标号,代表堆栈顶部地址,后面有用

;// <h> Heap Configuration
;//   <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;// </h>
Heap_Size       EQU     0x00000020                            ;//定义堆空间大小
AREA    HEAP, NOINIT, READWRITE, ALIGN=3      ;//定义一个数据段,8字节对齐
__heap_base
Heap_Mem        SPACE   Heap_Size                             ;//保留Heap_Size的堆空间
__heap_limit                                                  ;//标号,代表堆末尾地址,后面有用

PRESERVE8                                     ;//指示编译器8字节对齐
THUMB                                         ;//指示编译器为THUMB指令

; Vector Table Mapped to Address 0 at Reset
AREA    RESET, DATA, READONLY                  ;//定义只读数据段,其实放在CODE区,位于0地址

EXTERN NMIException
EXTERN HardFaultException
EXTERN MemManageException
EXTERN BusFaultException
EXTERN UsageFaultException
EXTERN SVCHandler
EXTERN DebugMonitor
EXTERN PendSVC
EXTERN SysTickHandler               ;//声明这些符号在外部定义,同C
;//在××it.c中实现这些函数 ,中断就能自动调用了
EXPORT __Vectors
EXPORT __initial_sp                     ;//EXPORT:在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
;//IMPORT:伪指令用于通知编译器要使用的标号在其他的源文件中定义,
;//但要在当前源文件中引用,而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中

__Vectors       DCD     __initial_sp              ;// Top of Stack         //Cotex-M 要求此处为堆栈顶部地址
DCD     Reset_Handler                ;// Reset Handler
DCD     NMIException                   ;// NMI Handler
DCD     HardFaultException        ;// Hard Fault Handler
DCD     MemManageException        ;// MPU Fault Handler
DCD     BusFaultException         ;// Bus Fault Handler
DCD     UsageFaultException       ;// Usage Fault Handler
DCD     0                         ;// Reserved
DCD     0                         ;// Reserved
DCD     0                         ;// Reserved
DCD     0                         ;// Reserved
DCD     SVCHandler                ;// SVCall Handler
DCD     DebugMonitor              ;// Debug Monitor Handler
DCD     0                         ;// Reserved
DCD     PendSVC                   ;// PendSV Handler
DCD     SysTickHandler            ;// SysTick Handler      //一大堆的异常处理函数地址
;// External Interrupts
EXTERN WWDG_IRQHandler
EXTERN PVD_IRQHandler
EXTERN TAMPER_IRQHandler
EXTERN RTC_IRQHandler
EXTERN FLASH_IRQHandler
EXTERN RCC_IRQHandler
EXTERN EXTI0_IRQHandler
EXTERN EXTI1_IRQHandler
EXTERN EXTI2_IRQHandler
EXTERN EXTI3_IRQHandler
EXTERN EXTI4_IRQHandler
EXTERN DMAChannel1_IRQHandler
EXTERN DMAChannel2_IRQHandler
EXTERN DMAChannel3_IRQHandler
EXTERN DMAChannel4_IRQHandler
EXTERN DMAChannel5_IRQHandler
EXTERN DMAChannel6_IRQHandler
EXTERN DMAChannel7_IRQHandler
EXTERN ADC_IRQHandler
EXTERN USB_HP_CAN_TX_IRQHandler
EXTERN USB_LP_CAN_RX0_IRQHandler
EXTERN CAN_RX1_IRQHandler
EXTERN CAN_SCE_IRQHandler
EXTERN EXTI9_5_IRQHandler
EXTERN TIM1_BRK_IRQHandler
EXTERN TIM1_UP_IRQHandler
EXTERN TIM1_TRG_COM_IRQHandler
EXTERN TIM1_CC_IRQHandler
EXTERN TIM2_IRQHandler
EXTERN TIM3_IRQHandler
EXTERN TIM4_IRQHandler
EXTERN I2C1_EV_IRQHandler
EXTERN I2C1_ER_IRQHandler
EXTERN I2C2_EV_IRQHandler
EXTERN I2C2_ER_IRQHandler
EXTERN SPI1_IRQHandler
EXTERN SPI2_IRQHandler
EXTERN USART1_IRQHandler
EXTERN USART2_IRQHandler
EXTERN USART3_IRQHandler
EXTERN EXTI15_10_IRQHandler
EXTERN RTCAlarm_IRQHandler
EXTERN USBWakeUp_IRQHandler                    ;//同上,

DCD     WWDG_IRQHandler           ;// Window Watchdog
DCD     PVD_IRQHandler            ;// PVD through EXTI Line detect
DCD     TAMPER_IRQHandler         ;// Tamper
DCD     RTC_IRQHandler            ;// RTC
DCD     FLASH_IRQHandler          ;// Flash
DCD     RCC_IRQHandler            ;// RCC
DCD     EXTI0_IRQHandler          ;// EXTI Line 0
DCD     EXTI1_IRQHandler          ;// EXTI Line 1
DCD     EXTI2_IRQHandler          ;// EXTI Line 2
DCD     EXTI3_IRQHandler          ;// EXTI Line 3
DCD     EXTI4_IRQHandler          ;// EXTI Line 4
DCD     DMAChannel1_IRQHandler    ;// DMA Channel 1
DCD     DMAChannel2_IRQHandler    ;// DMA Channel 2
DCD     DMAChannel3_IRQHandler    ;// DMA Channel 3
DCD     DMAChannel4_IRQHandler    ;// DMA Channel 4
DCD     DMAChannel5_IRQHandler    ;// DMA Channel 5
DCD     DMAChannel6_IRQHandler    ;// DMA Channel 6
DCD     DMAChannel7_IRQHandler    ;// DMA Channel 7
DCD     ADC_IRQHandler            ;// ADC
DCD     USB_HP_CAN_TX_IRQHandler ;// USB High Priority or CAN TX
DCD     USB_LP_CAN_RX0_IRQHandler ;// USB Low Priority or CAN RX0
DCD     CAN_RX1_IRQHandler        ;// CAN RX1
DCD     CAN_SCE_IRQHandler        ;// CAN SCE
DCD     EXTI9_5_IRQHandler        ;// EXTI Line 9..5
DCD     TIM1_BRK_IRQHandler       ;// TIM1 Break
DCD     TIM1_UP_IRQHandler        ;// TIM1 Update
DCD     TIM1_TRG_COM_IRQHandler   ;// TIM1 Trigger and Commutation
DCD     TIM1_CC_IRQHandler        ;// TIM1 Capture Compare
DCD     TIM2_IRQHandler           ;// TIM2
DCD     TIM3_IRQHandler           ;// TIM3
DCD     TIM4_IRQHandler           ;// TIM4
DCD     I2C1_EV_IRQHandler        ;// I2C1 Event
DCD     I2C1_ER_IRQHandler        ;// I2C1 Error
DCD     I2C2_EV_IRQHandler        ;// I2C2 Event
DCD     I2C2_ER_IRQHandler        ;// I2C2 Error
DCD     SPI1_IRQHandler           ;// SPI1
DCD     SPI2_IRQHandler           ;// SPI2
DCD     USART1_IRQHandler         ;// USART1
DCD     USART2_IRQHandler         ;// USART2
DCD     USART3_IRQHandler         ;// USART3
DCD     EXTI15_10_IRQHandler      ;// EXTI Line 15..10
DCD     RTCAlarm_IRQHandler       ;// RTC Alarm through EXTI Line
DCD     USBWakeUp_IRQHandler      ;// USB Wakeup from suspend   ;//同上

AREA    |.text|, CODE, READONLY        ;//定义代码段

; Reset Handler
Reset_Handler   PROC                              ;//过程的开始
;//Rset_Handler的实现   利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰

EXPORT Reset_Handler             [WEAK]    ;//在外部没有定义该符号时导出该符号,见HELP中[WEAK]
IMPORT __main                              ;//导入符号,__main为 运行时库提供的函数;完成堆栈,堆的初始话
LDR     R0, =__main                         ;//等工作,会调用下面定义的__user_initial_stackheap;
BX      R0                                  ;//跳到__main,进入C的世界
ENDP                                      ;过程的结束

ALIGN

; User Initial Stack & Heap
IF      :DEF:__MICROLIB                     ;//如果使用micro lib,micro lib 描述见armlib.chm

EXPORT __heap_base
EXPORT __heap_limit                        ;//只导出几个定义

ELSE                                        ;//如果使用默认C运行时库

IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap                                    ;//则进行堆栈和堆的赋值,在__main函数执行过程中调用。
LDR     R0, = Heap_Mem
LDR     R1, =(Stack_Mem + Stack_Size)
LDR     R2, = (Heap_Mem + Heap_Size)
LDR     R3, = Stack_Mem
BX      LR
ALIGN
ENDIF

END                                         ;//OK ,完了

 

Processor of the iPods

What processor do the iPod, iPod mini, iPod nano, iPod touch, and iPod shuffle models use?

Apple provides no official information regarding the processors used to power the iPod models.

Starting with the iPod nano 2nd Gen, the company has gone as far as having the processor custom branded with an Apple logo to make it more difficult to determine its origins. However, the below chart is believed to be accurate.

iPod Name Processor Details
iPod (Original/Scroll) PP5002 PortalPlayer PP5002 “system on a chip” with dual embedded 90 MHz ARM 7TDMI processors.
iPod 2nd Gen PP5002  
iPod 3rd Gen 10/15/30 PP5002  
iPod 3rd Gen 10/20/40 PP5002  
iPod 3rd Gen 15/20/40 PP5002  
iPod 4th Gen ClickWheel PP5020 PortalPlayer PP5020 “system on a chip” with dual embedded variable speed 80 MHz ARM 7TDMI processors.
iPod U2 4th Gen PP5020  
iPod photo (30) PP5020  
iPod photo (40/60) PP5020  
iPod Color Display PP5020  
iPod U2 Edition (Color) PP5020  
iPod mini PP5020  
iPod mini 2nd Gen PP5020  
iPod 5th Gen (Video) PP5021C PortalPlayer PP5021C “system on a chip” with dual embedded variable speed 80 MHz ARM 7TDMI processors. For video decoding, these models use a Broadcom VideoCore BCM2722 processor.
iPod U2 5th Gen PP5021C  
iPod 5th Gen – Enhanced PP5021C The “Enhanced” 5th Gen iPod models are believed to use the same processors as the 5th Gen models.
iPod U2 5th Gen Enh. PP5021C  
iPod classic 6th Gen Samsung ARM Apple provides no information on the processor used in the iPod classic (6th Gen) models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod classic (2008) Samsung ARM Apple provides no information on the processor used in the iPod classic (6th Gen/Late 2008) models, but it uses an Apple branded processor, believed to be a Samsung ARM like its predecessor.
iPod nano PP5021C PortalPlayer PP5021C “system on a chip” with dual embedded 80 MHz ARM 7TDMI processors.
iPod nano 2nd Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 2nd Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For in-depth speculation regarding all of the chips used, please refer to ArsTechnica’s iPod nano 2nd Gen “autopsy.”
iPod nano 2nd Gen RED Samsung ARM  
iPod nano 3rd Gen/Fat Samsung ARM Apple provides no information on the processor used in the iPod nano 3rd Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod nano 4th Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 4th Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod nano 5th Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 5th Gen models, but each uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s disassembly guide.
iPod nano 6th Gen Samsung ARM Apple provides no information on the processor used in the iPod nano 6th Gen models, but it is believed to use a Samsung ARM like its predecessors.
iPod shuffle STMP 3550 Uses a 75 MHz SigmaTel D-Major STMP 3550 processor.
iPod shuffle 2nd Gen Samsung ARM Apple provides no information on the processor used in the iPod shuffle 2nd Gen models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s “teardown.”
iPod shuffle 3rd Gen Samsung ARM Apple provides no information on the processor used in the iPod shuffle 3rd Gen models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s “teardown.”
iPod shuffle 3rd Gen Color Samsung ARM Apple provides no information on the processor used in the iPod shuffle 3rd Gen (Colors) models, but it uses an Apple branded processor, believed to be a Samsung ARM. For more information, please refer to iFixit’s “teardown.”
iPod shuffle 4th Gen Samsung ARM Apple provides no information on the processor used in the iPod shuffle 4th Generation models, but it uses an Apple branded processor, believed to be a Samsung ARM.
iPod touch Samsung ARM Apple provides no information on the processor used in the iPod touch models, but it uses an Apple branded processor, believed to be a Samsung ARM running at 400 MHz. For more information, please refer to iFixit’s disassemblyguide.
iPod touch 2nd Gen Samsung ARM Apple provides no information on the processor used in the iPod touch 2nd Gen models, but third-party “teardowns” indicate that it uses an Apple branded Samsung ARM processor running at 533 MHz. For more information, please refer to iFixit’s disassemblyguide.
iPod touch 3rd Gen Samsung ARM Apple provides no information on the processor used in the iPod touch 3rd Gen models, but third-party “teardowns” indicate that the 32 GB and 64 GB configurations use an Apple branded Samsung ARM processor running at 800 MHz. For more information, please refer to iFixit’s disassemblyguide.
iPod touch 4th Gen Apple A4 Like the original iPad and iPhone 4, the iPod touch (4th Generation) uses a custom ARM-based “system on a chip” that Apple refers to as an “Apple A4” processor. It integrates the CPU, graphics, the memory controller, and I/O functions.
iPod touch “4.5” Gen Apple A4 The iPod touch “4.5” Gen uses the same Apple A4 processor as the 4th Gen model.

Should you have additional, or alternate, information about the processors used in the iPod please share.

ARM处理器芯片选型指南

  要选好一款处理器,要考虑的因素很多,不单单是纯粹的硬件接口,还需要考虑相关的操作系统、配套的开发工具、仿真器,以及工程师微处理器的经验和软件支持情况等。微处理器选型是否得当,将决定项目成败。当然,并不是说选好微处理器,就意味着成功,因为项目的成败取决于许多因素;但可以肯定的一点是,微处理器选型不当,将会给项目带来无限的烦恼,甚至导致项目的流产。

  1 嵌入式微处理器选型的考虑因素

在产品开发中,作为核心芯片的微处理器,其自身的功能、性能、可靠性被寄予厚望,因为它的资源越丰富、自带功能越强大,产品开发周期就越短,项目成功率就越高。但是,任何一款微处理器都不可能尽善尽美,满足每个用户的需要,所以这就涉及选型的问题。

(1)应用领域

一个产品的功能、性能一旦定制下来,其所在的应用领域也随之确定。应用领域的确定将缩小选型的范围,例如:工业控制领域产品的工作条件通常比较苛刻,因此对芯片的工作温度通常是宽温的,这样就得选择工业级的芯片,民用级的就被排除在外。目前,比较常见的应用领域分类有航天航空、通信、计算机、工业控制、医疗系统、消费电子、汽车电子等。

(2)自带资源

经常会看到或听到这样的问题:主频是多少?有无内置的以太网MAC?有多少个I/O口?自带哪些接口?支持在线仿真吗?是否支持OS,能支持哪些OS?是否有外部存储接口?……以上都涉及芯片资源的问题,微处理器自带什么样的资源是选型的一个重要考虑因素。芯片自带资源越接近产品的需求,产品开发相对就越简单。

(3)可扩展资源

硬件平台要支持OS、RAM和ROM,对资源的要求就比较高。芯片一般都有内置RAM和ROM,但其容量一般都很小,内置512 KB就算很大了,但是运行OS一般都是兆级以上。这就要求芯片可扩展存储器。

(4)功 耗

单看“功耗”是一个较为抽象的名词。这里举几个形象的例子:

①夏天使用空调时,家里的电费会猛增。这是因为空调是高功耗的家用电器,这时人们会想,“要是空调能像日光灯那样省电就好了”。

②随身的MP3、MP4都使用电池。正当听音乐看视频时,系统因为没电自动关机,谁都会抱怨“又没电了!”

③目前手机一般使用锂电池,手机的待机和通话时间成了人们选择手机的重要指标。待机及通话时间越长,电池的使用寿命就可以提高,手机的寿命也相对提高了。

以上体现了人们对低功耗的渴求。低功耗的产品即节能又节财,甚至可以减少环境污染,它有如此多的优点,因此低功耗也成了芯片选型时的一个重要指标。

(5)封 装

常见的微处理器芯片封装主要有QFP、BGA两大类型。BGA类型的封装焊接比较麻烦,一般的小公司都不会焊,但BGA封装的芯片体积会小很多。如果产品对芯片体积要求不严格,选型时最好选择QFP封装。

(6)芯片的可延续性及技术的可继承性

目前,产品更新换代的速度很快,所以在选型时要考虑芯片的可升级性。如果是同一厂家同一内核系列的芯片,其技术可继承性就较好。应该考虑知名半导体公司,然后查询其相关产品,再作出判断。

(7)价格及供货保证

芯片的价格和供货也是必须考虑的因素。许多芯片目前处于试用阶段(Sampling),其价格和供货就会处于不稳定状态,所以选型时尽量选择有量产的芯片。

(8)仿真器

仿真器是硬件和底层软件调试时要用到的工具,开发初期如果没有它基本上会寸步难行。选择配套适合的仿真器,将会给开发带来许多便利。对于已经有仿真器的人们,在选型过程中要考虑它是否支持所选的芯片。

(9)OS及开发工具

作为产品开发,在选型芯片时必须考虑其对软件的支持情况,如支持什么样的OS等。对于已有OS的人们,在选型过程中要考虑所选的芯片是否支持该OS,也可以反过来说,即这种OS是否支持该芯片。

(10)技术支持

现在的趋势是买服务,也就是买技术支持。一个好的公司的技术支持能力相对比较有保证,所以选芯片时最好选择知名的半导体公司。

另外,芯片的成熟度取决于用户的使用规模及使用情况。选择市面上使用较广的芯片,将会有比较多的共享资源,给开发带来许多便利.

  2 ARM公司及相关产品介绍

ARM公司于1991年成立于英国剑桥,主要出售ARM IP的授权。目前,ARM处理器(即采用ARM IP核的处理器)已遍及工业控制、消费类电子产品、通信系统、网络系统、无线系统等各类产品市场。ARM处理器应用占据了32位RISC微处理器很大的市场,ARM技术已渗入生活的各个方面。

目前市面上常见的ARM处理器架构可分为ARM7、ARM9、ARM10、ARM11以及Cortex系列,每个系列又包括很多种IP内核的产品。ARM 也是嵌入式处理器中首先推出多核架构的厂商。生产ARM芯片的厂家很多,主流半导体厂商的产品比较齐全,供货也相对更有保障。Samsung、NXP、 Cirrus Logic、Atmel、Freescale、TI、ST、Winbond等主流半导体厂商的ARM芯片产品列表见本刊网站,其中有些产品已供货,有些正在样片阶段,有些正在开发,还有许多产品不支持外部存储器的扩展。

  3 嵌入式微处理器选型示例

(1)需 求

①适合于工业控制的温度。

②支持VxWorks、Linux操作系统。

③存储方面,SDRAM大于16 MB,Flash大于8 MB。

④主频方面,60 MHz以上。

⑤接口方面具有带DMA控制的Ethernet MAC、2个以上RS232串口、1个USB 2.O接口、1个SPI接口,以及大于30个GPIO引脚(不包括数据总线、地址总线和CPU内置接口总线)。

⑥提供实时时钟或实时定时器。

⑦引脚封装为QFP。

⑧价格为<200元。

(2)选型需求分析

根据需求①,参照前述选购的考虑因素中的“应用领域”,把要选的芯片定位于工业控制领域。目前市场上生产较适合用于作工业控制的微处理器的半导体公司有 NXP、Atmel、ST公司(Samsung公司的产品较适合用于PDA、多媒体产品,Cirrus Logic公司的产品较适合音频产品。)根据需求②,参照选购的考虑因素中的“OS及开发工具”,VxWorks5.5对于ARM核支持到V5T架构,所以把选型范围缩小到ARM7和ARM9系列。由于需要支持Linux操作系统,所以最好选择带有MMU的内核,因为不带MMU内核(ARM7TMDI)支持的Linux操作系统非常有限,只能支持UCLinux。

根据需求③,结合各种型号的芯片资源介绍,不难看出要求芯片必须带有可扩展存储接口,因为芯片的内置存储量不可能那么大。所以只能选择带可扩展存储接口的芯片。NXP公司的LPC2400系列和LH7A具备此项功能,Atmel公司的AT91SAM7SE系列、AT91RM9200、AT91SAM9系列也满足此项需求。

根据需求④、⑤、⑥、⑦,参照选购的考虑因素中的“价格及供货保证”,结合NXP、Atmel公司的芯片资源介绍,把选型范围框定在LPC2468 (LPC2400系列中的其他产品要么处于样片阶段,要么处于开发阶段,而LH7A资源不满足要求)、AT91RM9200和AT91SAM9260 (AT91SAM7SE系列处理速度太慢,AT91SAM9261和AT91SAM9263封装不满足需求)型号上。根据需求⑧,上一步所选的3个型号都能满足要求。

(3)选型结论

综合需求和芯片各方面的资源,选型结论如下:

①从产品开发周期角度考虑,AT91RM9200最为适合,它在这4个芯片中开发周期应该最短;

②从技术可继承性角度考虑,且对开发周期没有严格限制的话,AT91SAM9260较为合适;

③如果单支持VxWorks,对Linux支持要求不高,且对开发周期没有严格限制的话,LPC2468较为合适;

④综合各方面考虑,STR912排在其他三者之后。

选型满意度从高到低的排列顺序是:AT91RM9200、AT91SAM9260、LPC2468、STR912。

2011年11月09日 17:18 来源:本站整理 作者:秩名

原址:http://www.elecfans.com/emb/arm/20111109240239_2.html

iSuppli: iPod Nano 材料费才 $43.73

  新款iPod nano改用了触摸屏,但却去掉了上代的视频摄像头和传统的转盘操作,闪存容量最少也仅为8GB。事实上自从2008年NAND闪存价格不再大幅下跌以来,苹果就放弃了每代容量翻番的做法。苹果iPod nano 6代成本分析:为售价三成

 苹果的产品总是在备受关注的同时也饱受争议,比如苹果上个月发布的新产品ipod nano第六代,目前iSuppli分析认为:这个小东西凭借精巧的尺寸、低廉的成本、丰富的功能,再次验证了那句传统格言:“少即是多”(Less is More)。经过细致分析,iSupplli认为新款触摸屏iPod nano 8GB版本的物料成本(BOM)为43.73美元,只比第四代的40.80美元略贵一些,在历代iPod产品中是第二低廉的。

  iSuppli首席分析师、拆解服务经理Andrew Rassweiler指出:“很多品牌的最新产品都是拼命增加功能,但是苹果的第六代iPod却维持甚至移除了部分属性,以满足尺寸和功能的需要。这让苹 果拥有了最小巧的iPod,不但有触摸屏,还严格限制了元件成本。

  第六代iPod nano 8GB物料成本一览:

  - 存储芯片(东芝8GB MLC NAND和三星512Mb Mobile DDR):14.40美元

  - 显示和触摸屏模块:11.50美元

  - 应用处理器(三星APL3278A01/ARM架构)和相关DRAM:4.95美元

  - 用户界面(Cirrus Logic音频编码器、意法半导体加速计、Cypress半导体触摸屏控制器、Silicon Laboratories FM收音机、Intersil视频驱动等等):3.49美元

  - 附件(耳机、USB数据线、包装、说明书):2.42美元

  - 机械元件(金属、塑料等等):2.00美元

  - 电源管理(Dialog电源管理电路、MOSFET、二极管等等):1.33美元

  - 电子机械元件(PCB、接头等等):0.89美元

  - 电池(锂离子聚合物):0.70美元

  - 其他:2.05美元

  如果再算上1.37美元的制造成本,第六代iPod nano 8GB的总成本将为45.10美元,相当于建议零售价149美元的30%。

文/驱动之家

串口通讯简单回顾

最近几个小项目都是与串口有关的,前段时间用C++实现了一个串口通讯类,高效稳定,效果还不错;后来由于一个同事用C#的SerialPort类与设备通讯时效率很低,让我帮他自己包装了一个C#的Comm通讯类。

串口通讯中对串口的设置基本上很简单,大部分时候只需要设置串口号和波特率、数据位、停止位,其他的很少改动,默认就行了。

在使用C#与设备通讯时,发现一个比较贵的USB转串口线通讯速度不稳定,至少前面几分钟速度会非常的慢,之后就恢复正常了。但是用sscom32调试助手看却很快,所以怀疑打开串口的时候是不是对其他几个参数的设置上的区别导致通讯速度的不同?更奇怪的是另一根相当便宜的USB转串口线,在任何情况下速度都很正常,汗……

简单讲解

串口是计算机上一种非常通用的通信设备,大多数计算机包含两个基于RS232的串口,由于其使用简单造价低廉而被普遍应用。

奇怪的是近几年出产的笔记本和PC机基本都没有串口这种设备了,而简单易用、成本低廉的特性,让很多硬件设计工程师还是选择了串口作为设备与其他设备的通讯方式。因此,usb串口转换线使用的非常多,它的RS232-485接口连接串口设备,另一端转换为USB接入PC等上位机,在上位机上模拟出多个串口,以实现PC机通过串口与外围串口设备通讯。

串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。而IEEE488定义规定,对于并行通讯,设备线总常不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。

典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。

串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通行的端口,这些参数必须匹配。

高深一点,通讯过程中的硬件知识

由于 CPU 与接口之间按并行方式传输,接口与外设之间按串行方式传输,因此,在串行接口中,必须要有“接收移位寄存器” (串→并)和 “发送移位寄存器 ”(并→串)。在数据输入过程中,数据 1 位 1 位地从外设进入接口的 “接收移位寄存器” ,当“接收移位寄存器”中已接收完 1 个字符的各位后,数据就从“接收移位寄存器”进入“数据输入寄存器”。CPU 从“数据输入寄存器”中读取接收到的字符。(并行读取,即 D7~D0 同时被读至累加器中)。“接收移位寄存器”的移位速度由“ 接收时钟”确定。

在数据输出过程中,CPU 把要输出的字符(并行地)送入“数据输出寄存器”,“数据输出寄存器”的内容传输到“发送移位寄存器”,然后由“发送移位寄存器”移位,把数据 1 位 1 位地送到外设。“发送移位寄存器”的移位速度由“发送时钟”确定。

接口中的“控制寄存器”用来容纳 CPU 送给此接口的各种控制信息,这些控制信息决定接口的工作方式。

“状态寄存器”的各位称为“状态位”,每一个状态位都可以用来指示数据传输过程中的状态或某种错误。例如,用状态寄存器的 D5 位为 ‘1’ 表示“数据输出寄存器”空,用 D0 位表示“数据输入寄存器满”,用 D2 位表示“奇偶检验错”等。

实际上,上面所说的”串→并”转换的功能由一块叫UART(Universal Asynchronous Receiver and Transmitter)的芯片完成,典型的芯片有: Intel 8250/8251,16550。

从电气特性上说,串口就使用接收线和发送线传输数据。无论是发送还是接收一个逻辑1,发送或者接收线被置成了低电压,相反,如果是逻辑0,则被置成了高电压。当传输一个字节时,UART首先发送一个‘开始位’,为逻辑0,即,高电压,然后是数据位(通常是8位,当然也可以设置成5、6或者7位,上位机通常以一个字节为单位来处理串口数据的,所以,如果不想给自己找麻烦,或者不想被人看的很高深,还是老老实实用默认的8位吧:-)。PS:前两天用串口通讯,发现接收到的数据总是不大于127,原因就是在用C#定义DCB结构体时把几个flag定义错了,导致覆盖到了数据位的标志位为7,所以肯定完蛋,把第8为当成了下一个字节的起始标示位了),最后接着来的是1位或者两位停止位,是逻辑1,即低电平。这样,一个字节就传输出去了,其它字节依次周而复始。

上个图给你look look,应该就很形象了:

流控制:XON/XOFF

到这里就有点复杂了,一般情况下没必要了解,如果很好奇,那就看看,毕竟了解的越多,动起手来才得心应手!

下面的文字来自网络,讲的很清楚,直接摘了:
XON/XOFF 是一种流控制协议(通信速率匹配协议),用于数据传输速率大于等于1200b/s时进行速率匹配,方法是控制发送方的发速率以匹配双方的速率。
XMODEM是一种低速文件传输协议。KERMIT是异步通信环境中使用的一种文件传输协议。它与XMODEM的主要区别是:KERMIT一次可传送多个文件,而XMODEM一次只能传送一个文件;KERMIT在接收方以完整的信息包应答,而XMODEM以单字节应答;KERMIT提供多种错误校验技术,而XMODEM只提供一种错误校验技术。
在流量控制方面,可以从不同侧面采取不同的控制方案。最简单的方法就是增加接收端的缓冲存储空间,使得接收端可以缓存更多的数据。但这只是一种被动、消极的方法。因为,一方面系统不允许开设过大的缓冲空间;另一方面对于速率显著失配,并且又传送大量数据的场合,即使缓存空间再大也会出现不够的现象。目前普遍采取一种称之为“XON/XOFF”的发送控制字符的方案,通过控制字符来确定发送方是否继续发送数据,相比之下更主动、更积极、更有效。
XON/XOFF(继续/停止)是异步串行连接的计算机和其他元件之间的数据流控制协议。例如,计算机向打印机发送数据的速度通常快于打印机打印的速度,打印机包含一个缓冲器,用来存储数据,使打印机能够赶上计算机。如果在打印机赶上之前缓冲器变满了,打印机的小微处理器便发回一个XOFF信号来停止数据传送,打印完相当多的数据,缓冲存储器变空时,打印机发送XON信号,让计算机继续发送数据。“X”表示“发送器”,X/ON和X/OFF为开启和关闭发送器的信号。X/ON的实际信号为ASCII的Ctrl-Q键盘组合的位组合,X/OFF信号为Ctrl-S字符。在为计算机操作系统定义调制解调器时,可能需要用XON/XOFF或CTS/RTS来指定流控制的使用。在发送二进制数据时,XON/XOFF可能不能识别,因为它被译成了字符。
XON/XOFF是一种异步通信协议,接收设备或计算机使用特殊字符来控制发送设备或计算机传送的数据流。当接收计算机不能继续接收数据时,发送一个XOFF控制字符告诉发送方停止传送;当传输可以恢复时,该计算机发送一个XON字符来通知发送方。其中XON采用ASCII字符集中的控制字符DC1,XOFF采用ASCII字符集中的控制字符DC3。当通信线路上的接收方发生过载时,便向发送方发送一个XOFF字符,发送方接收XOFF字符后便暂停发送数据;等接收方处理完缓冲器中的数据,过载恢复后,再向发送方发送一个XON字符,以通知发送方恢复数据发送。在一次数据传输过程中,XOFF、XON的周期可重复多次,但这些操作对用户来说是透明的,也就是说用户不用管它。
许多异步数据通信软件包均支持XON/XOFF协议。这种方案也可用于计算机向打印机或其他终端设备(如MODEM的串行通信)发送字符,在这种情况下,打印机或终端设备中的控制部件用以控制字符流量。

最后决定购买DevKit8000及全部配件

最后决定购买DevKit8000评估套件完全配置,1680RMB,它具有强大的图形加速功能,如果能把OpenCV移植上去,那就太完美了!

http://www.broadon.cn/item.htm?id=4064505743

升级版套件:256MB SDRAM + 256MB NAND FLASH

– 基于OMAP3530处理器,板载256MByte DDR SDRAM及256MByte NAND Flash
– 支持DVI-D/S-Video/TFT-LCD三种显示输出,可输出高清信号
– 外扩USB OTG,串口,网口,摄像头,音频,SD/MMC,键盘等接口
– 支持WinCE 6.0及Linux2.6.28系统,完全兼容beagleboard

硬件特性

CPU单元:

OMAP3530应用处理器(Pin to Pin兼容OMAP3503,OMAP3515,OMAP3525处理器)
600-MHz ARM Cortex-A8 Core
430MHz TMS320C64x+ DSP Core
256MByte DDR SDRAM,32bit
256MByte NAND Flash
6层板设计
通讯接口:

1个S-VIDEO接口
1个音频输入接口
1个双声道音频输出接口
1个10/100M以太网(芯片:DM9000,RJ45接口)
1个高速USB2.0 OTG接口(芯片:TPS65930),速度达480Mbps
2个串口(1个3线RS232电平串口,1个5线TTL电平串口)
1个SD/MMC接口
1个6*6键盘接口
1个14针标准JTAG接口
1个CAMERA接口(可外接CCD和CMOS的摄像头)
4个按键(1个启动引导按键,1个复位按键及2个用户按键)
扩展接口(包含McSPI,McBSP,I2C,HDQ及SD/MMC接口)
显示单元:

1个HDMI接口(芯片:TFP410),可输出分辨率1280×720,码率30fps的DVI-D高清信号
24bit真彩色LCD接口(含4线触摸屏接口,分辨率可支持2048*2048)
电气参数:

工作温度:-40 ~ 85℃(芯片支持)
环境湿度:20% ~ 90% ,非冷凝
机械尺寸:110 mm * 95 mm
电气指标:+5V电源供电,电流150mA

订购信息

DevKit8000评估套件完全配置装箱清单:
一个DevKit8000单板  
一个4.3寸触摸屏
一个512MB SD卡
一条交叉网线
一条Mini USB A线转USB A型母头
一条Mini USB B线转USB A型公头
一个USB HUB(带电源)
一个HMDI转DVI-D转接线
一条S-Video线
一个5V 2A电源
一支触摸笔
一张光盘(使用文档、原理图、源代码及工具)

产品自需方购买日起质保半年,核心元器件除外,液晶屏不参与质保。长期提供免费的电话和Email技术支持。

DevKit8000开发板全部配件(12件)

OMAP3530 DSP Howto ( Really works by DSPLINK)

————–我转载它,主要是为了自己学习

2009/11/03 17:33

搞了一段很長的時間終於把DSP功能弄起來了,該是回頭紀錄一下”眉角”了.

1.Before touch anything

目前有兩種方式可以控制DSP,一個是

TI DVSDK

提供的DSPLINK,另一個則是DSPBRIDGE.

以我從google搜尋之後的了解DSPBRIDGE目前是沒有繼續maintain.

DSPLINK是

TI

比較建議的方式.

所搭配的media library為

DSPLINK + gstreamer

DSPBRIDGE + openmax + gstreamer
http://felipec.wordpress.com/2009/10/13/new-project-gst-dsp-with-beagleboard-demo-image/
http://felipec.wordpress.com/2008/12/12/gst-openmax-demo-on-the-beagleboard/

這邊我選擇DSPLINK控制DSP

2.Software

dvsdk_3_00_02_44

gst-

ti

-plugin-full-1.00.02

gst-omapfb

Build and install to target root file system (過程就省略了)

可參考以下作法
http://ossie.wireless.vt.edu/trac/wiki/BeagleBoard_CodecEngine

安裝目錄
DVSDK

: /opt/

dvsdk

gstreamer : /opt

3.Setup

DSPLINK 透過share memory的方式跟DSP交換資料所以有另一個driver叫cmemk.ko負責建立memory pool. 但這塊memory必須脫離kernel的掌控因此必須要空出一塊memory讓cmemk.ko使用.至於大小要看實際memory size跟DSP所需要的size來決定.

http://pixhawk.ethz.ch/wiki/tutorials/omap/dsplink/memorymap

依照以上說明修改以下檔案

dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c

dsplink_1_61_03/packages/dsplink/dsp/inc/DspBios/5.XX/

OMAP3530

/dsplink-

omap3530

-base.tci

dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c

我的target board有256MB DDR,因此記憶體配置如下

# 0x40200000    60 KB   CMEM (internal memory, see comment below)

# 0x80000000    200 MB   Linux

# 0x8C900000    16 MB   CMEM (external memory)

# 0x8D900000     2 MB   DSPLINK (MEM)

# 0x8DB00000     unused

kernel boot command 加上 mem=200M

For kernel 2.6.27

optargs=init=/init omapfb.video_mode=1280x1024MR-16@60 vram=12M omapfb.vram=4M,4M,4M omapfb.debug=1 omap-dss.def_disp=lcd omap-dss.debug=1 mem=200M

For kernel 2.6.29

setenv optargs ‘init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-16@60 vram=12M omapfb.vram=0:4M,1:4M,2:4M mem=200M’

memory pool配置如下

insmod cmemk.ko phys_start=0x8C900000 phys_end=0x8D900000 pools=20×4096,10×131072,2×1048576,1×5250000,4×829440,2×691200

gstreamer需要設定target上的環境變數好讓系統找的到執行檔及plug-in

export PATH=$PATH:/opt/gstreamer/bin

export GST_PLUGIN_PATH=/opt/gstreamer/lib/gstreamer-0.10

export LD_LIBRARY_PATH=/opt/gstreamer/lib

3.Get DSP work

載入drivers

#cd /opt/

dvsdk

#./loadmodules.sh

CMEMK module: built on Oct 30 2009 at 20:23:52

  Reference Linux version 2.6.28

  File /home/gigijoe/

OMAP3530

/dvsdk_3_00_02_44/linuxutils_2_24_02/packages/

ti

/sdo/linuxutils/cmem/src/module/cmemk.c

ioremap_nocache(0x8c900000, 16777216)=0xcf000000

allocated heap buffer 0xcf000000 of size 0x32c000

cmem initialized 6 pools between 0x8c900000 and 0x8d900000

DSPLINK Module (1.61.03) created on Date: Oct 30 2009 Time: 20:20:31

# lsmod

lpm_omap3530 8276 0 – Live 0xbf02c000

dsplinkk 114052 1 lpm_omap3530, Live 0xbf00b000

cmemk 24428 0 – Live 0xbf000000

測試omapfb, 應該會在畫面上看到彩色條紋.

gst-launch videotestsrc num-buffers=1000 ! omapfbsink

播放

TI

h.264 raw data sample

gst-launch –gst-debug-level=1 filesrc location=”/media/dcim/100andro/ntsc.264″ ! typefind ! TIViddec2 ! omapfbsink

Play avi file

gst-launch –gst-debug-no-color –gst-debug=

TI

*:2 filesrc location=/media/dcim/100andro/aris.mpeg ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink

Play mpeg4 file

gst-launch –gst-debug-no-color –gst-debug=

TI

*:2 filesrc location=/media/dcim/100andro/KenBlock-TopGear.mp4 ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink

Play H.264 mpeg4 file without mp3 audio

gst-launch filesrc location=/media/dcim/100andro/sany0014.mp4  ! typefind ! qtdemux name=demux  demux.video_00 ! typefind ! TIViddec2 ! omapfbsink

4.Debug

http://tiexpressdsp.com/wiki/index.php?title=Debugging_DSPLink_using_SET_FAILURE_REASON_prints

http://tiexpressdsp.com/index.php/Enabling_trace_in_DSPLink

一開始有一段時間kernel-2.6.29 DSP_init總是失敗

# ./messagegpp ./message.out 1000

========== Sample Application : Failure [0x8000800b] in [0x401] at line 522

MESSAGE ==========

Entered MESSFailure [0x8000802d] in [0x401] at line 544

AGE_Create ()

Failure [0x8000802d] in [0x401] at line 544

Failure [0x8000802d] in [0x401] at line 544

ISR_Install:445

request_irq 28

request_irq failed with error: -16

Failure [0x80008008] in [0x502] at line 459

Failure [0x80008008] in [0x80a] at line 824

Failure [0x80008008] in [0x80a] at line 1061

Failure [0x80008008] in [0x801] at line 597

Failure [0x80008008] in [0x701] at line 370

 DSP_init status [0x80008008]

Assertion failed ((isrObj!= NULL) && (ISR_InstalledIsrs [isrObj->dspId][isrObj->irq] == isrObj)). File : /home/gigijoe/

OMAP3530

/dvsdk_3_00_02_44/dsplink_1_61_03/packages/dsplink/gp

p/src/../../gpp/src/osal/Linux/2.6.18/isr.c Line : 507

Failure [0x80008000] in [0x502] at line 515

Failure [0x80008008] in [0x300] at line 476

Failure [0x80008008] in [0x300] at line 563

PROC_attach () failed. Status = [0x80008008]

PROC_setup () failed. Status = [0x80008008]

Leaving MESSAGE_Create ()

Entered MESSAGE_Delete ()

Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 484

MSGQ_release () failed. Status = [0x8000800b]

Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 335

Leaving MESSAGE_Delete ()

====================================================

Trace DSPLINK driver發現request_irq 28 居然失敗了.很明顯IRQ被佔據了.

看看到底是誰

cat /proc/interrupts

           CPU0

 11:          0        INTC  prcm

 12:          1        INTC  DMA

 18:          0        INTC  sr1

 19:          0        INTC  sr2

 24:          0        INTC  omap-iommu.1, Omap 3 Camera ISP

 25:          1        INTC  OMAP DSS

28:          0        INTC  omap-iommu.2

 56:        347        INTC  i2c_omap

 61:          0        INTC  i2c_omap

 72:          1        INTC  serial idle

 73:          1        INTC  serial idle

 74:         94        INTC  serial idle, serial

 77:          0        INTC  ehci_hcd:usb2

 83:          0        INTC  mmc0

 86:         14        INTC  mmc1

 92:          0        INTC  musb_hdrc

 93:          0        INTC  musb_hdrc

 95:        641        INTC  gp timer

160:          0        GPIO  mmc1

167:          0        GPIO  user

181:          8        GPIO  eth0

378:          0     twl4030  twl4030_usb

379:          0     twl4030  rtc0

384:          0     twl4030  mmc0

原來是iommu啊,OK,調整一下kernel config

Disable

Device Drivers->Multimedia Devices->Video Capture Adapters->OMAP 3 Camera Support

System Type->

TI

OMAP Implemenation->IOMMU Support

這樣就OK囉

其實還有一些疑慮沒有解決.

IOMMU 以 Shared IRQ 方式 request_irq而DSPLINK Driver request_irq 並不是.

因此造成問題,DSPLINK Driver是否應該以Shared IRQ方式request_irq呢?

看上TI 的 OMAP3530 开发板了

看上这块板子了:EVM3530-B3-1880-LUNC0

理由嘛:

1、CPU是TI的,TI OMAP3530 多核处理器,600MHz 的ARM Cortex-A8内核;430MHz TMS320C64x+ DSP POWERVR SG™2D/3D图形加速处理引擎。如果DSP资料开放,可以考虑移植OpenCV,利用DSP能力实现图像识别

2、一个10M/100M网卡、1个RS232、2个UART、4个USB2.0 Host、1个USB2.0 OTG

3、音频输入输出口、VGA口、视频输入输出口

4、SD卡槽

参数如下:
产品型号 技术参数 价格(RMB)
EVM3530-B3-1880-LUNC0 处理器:TI OMAP3530
内存:256M内存 + 256M Flash,
网络:采用LAN9221,10/100Mbps
USB接口:4个Host + 1个OTG
串口:1个RS232 + 2个串口插针
显示接口:标准DVI
1380

 

问题是1380大洋,还不带显示屏,如果加个4.3寸显示屏380,可就到1760了,nnd,喉贵!

选配表:

 
产品型号 技术参数 价格(RMB)
EVM3530-B3-1880-LUNC0 处理器:TI OMAP3530
内存:256M内存 + 256M Flash,
网络:采用LAN9221,10/100Mbps
USB接口:4个Host + 1个OTG
串口:1个RS232 + 2个串口插针
显示接口:标准DVI
1380
SOM-3530-B2-1880-C 1、处理器:TI OMAP3530
2、内存:256M内存 + 256M Flash
3、电源管理:高性能电源管理模块,支持USB
4、B2B接口:4x 0.5mm 60Pin B2B
600
SBC3530-A2-1880-LUAC0 处理器:TI OMAP3530
内存:256M内存 + 256M Flash,
网络:采用LAN9221,10/100Mbps
USB接口:4个Host + 1个OTG
串口:1个RS232 + 2个串口插针
显示接口:标准VGA
视频输入:四路模拟视频输入 + 1路数字摄像头
1580
DEV3530-128M 处理器:TI OMAP3530 ,内存:128M内存 + 128M Flash ,DVI视频接口:支持多种高分辨率,音频接口:2.1声道,网络:10/100Mbps 采用LAN9221,USB接口:1个OTG,串口:1个RS232 ,SD卡槽:最高支持32G容量 798
支持OMAP3530开发板的4.3寸群创液晶屏模块   380
支持OMAP3530开发板的7寸群创液晶屏模块   480
WIFI   250
 Camera   300
XDS100V2 仿真器   368
omap3530启动SD Card   55
适用于DEV3530系列   40

 

另两款:

DevKit8000评估套件+4.3触摸屏 OMAP3530开发板 256M

这个带了个4.3的屏幕,CPU与上一款一样,区别呢?

地址:http://item.taobao.com/item.htm?id=3781993929

报价¥1690,

256MB DevKit8000评估套件 配4.3寸屏 OMAP3530开发板

更上一款一样啊,报价多了9块钱 :)

地址:http://item.taobao.com/item.htm?id=3920551293

DevKit8000系列的参数及配置如下:

T1系列 主板型号 税前价 税后价 说明
OMAP3530 DevKit8000标准配置 888 1,050 单板+SD+电源+串口线
DevKit8000完全配置1 1,599 1,870 4.3”触摸屏及全部配件
DevKit8000完全配置2 1,799 2,100 7”触摸屏及全部配件
DevKit8000(2G)标准配置 988 1,160 单板+SD+电源+串口线
DevKit8000(2G)完全配置1 1,699 2,000 4.3”触摸屏及全部配件
DevKit8000(2G)完全配置2 1,899 2,220 7”触摸屏及全部配件
Mini8100 540 630 SBC8100核心板
SBC8100单板机 2,800 3,280 配512M SD卡、串口线、网线、5V/2A电源、USB转接线(Mini-B to A)、S-Video线。
SBC8100套件1 3,150 3,690 单板机配4.3寸触摸屏。
SBC8100套件2 3,300 3,860 单板机配7寸触摸屏。
Mini8100(2G) 640 750 SBC8100核心板
SBC8100(2G)单板机 2,900 3,400 配512M SD卡、串口线、网线、5V/2A电源、USB转接线(Mini-B to A)、S-Video线。
SBC8100(2G)套件1 3,250 3,800 单板机配4.3寸触摸屏。
SBC8100(2G)套件2 3,400 3,980 单板机配7寸触摸屏。
VSS3530(1G) 1299 1520 配12V/1.25A电源、串口线、串口转接板

 

配套模块型号 税前价 税后价 说明
CAM8000-A 250 290 模拟摄像头输入模块,配套DevKit8000和SBC8100
CAM8000-U 500 585 USB数字摄像头输入模块,配套DevKit8000和SBC8100
VGA8000-A 250 290 LCD转VGA输出模块,配套DevKit8000和SBC8100
模拟摄像头 250 290 提供配套电源,不带支架和连接线。
WF8000-U 250 290 USB WiFi模块,配套DevKit8000
GPRS8000-S 400 470 串口GPRS模块,配套DevKit8000
GPS8000-S 300 350 串口GPS模块,配套DevKit8000
CDMA8000-U 450 525 USB 3G模块,配套DevKit8000和SBC8100

 

仿真器 TDS560 Plus仿真器 4,800 4,800 适用于TI 公司C2000、C5000、C6000芯片及OMAP、DaVinci、ARM7、ARM9 
XDS100v2 380 445 支持多种处理器:TMS320C28x、TMS320C54x、TMS320C55x、TMS320C64x+、TMS320C674x、ARM 9、 ARM Cortex R4、ARM Cortex A8 

 

DevKit8000评估套件

 

– 基于TI OMAP3530处理器,板载256MByte DDR SDRAM、256MByte NAND Flash
– 支持DVI-D、VGA、TFT-LCD三种显示输出,可输出高清信号
– 支持摄像头输入、USB WiFi、GPS定位、GPRS通讯、CDMA
– 支持XDS100v2仿真器和TDS560 Puls仿真器调试
– 外扩USB OTG,串口,网口,摄像头,音频,SD/MMC,键盘等接口
– 支持WinCE 6.0及Linux2.6.28系统,完全兼容beagleboard
   

    DevKit8000评估主板为开发者使用TI OMAP35x系列处理器提供了完善的软件开发环境,支持linux-2.6.28操作系统及WinCE6.0操作系统,并包含完善的底层驱动程序,方便用户快速评估OMAP35x系列处理器、设计系统驱动及其定制应用软件,并提供有成熟的操作系统Google Android及Angstrom(GPE)的发布版本,方便用户快速体验OMAP35x处理器的强大的数据运算处理能力,也可降低产品开发周期,实现面向消费电子、医疗仪器、多媒体处理、视频监控、工业控制等领域的产品快速上市。
    DevKit8000评估套件是一个功能丰富的开发平台,为嵌入式设计人员提供快捷简单的实践方式来评估OMAP3530处理器。该套件提供了一个完整的实验评估平台,包括一个4.3″LCD屏、SD卡、电源及各种接口转接线(串口转接线,USB OTG转接线,S-Video转接线,HDMI转DVI-D转接线)等。该套件使设计者能够基于DevKit8000的板载系统快速开发出基于OMAP3530芯片的相关产品。

 
硬件特性
CPU单元: 

  • OMAP3530应用处理器(Pin to Pin兼容OMAP3503,OMAP3515,OMAP3525处理器)
  • 600-MHz ARM Cortex-A8 Core
  • 430MHz TMS320C64x+ DSP Core
  • 128MByte DDR SDRAM (可选配256MB DDR SDRAM)
  • 128MByte NAND Flash (可选配256MB NAND Flash)
  • 6层板

通讯接口: 

  • 1个S-VIDEO接口
  • 1个音频输入接口
  • 1个双声道音频输出接口
  • 1个10/100M以太网(芯片:DM9000,RJ45接口)
  • 1个高速USB2.0 OTG接口(芯片:TPS65930),速度达480Mbps
  • 1个高速USB2.0 Host接口
  • 2个串口(1个3线RS232电平串口,1个5线TTL电平串口)
  • 1个SD/MMC接口
  • 1个6*6键盘接口
  • 1个14针标准JTAG接口
  • 1个CAMERA接口(可外接CCD和CMOS的摄像头)
  • 4个按键(1个启动引导按键,1个复位按键及2个用户按键)
  • 扩展接口(包含McSPI,McBSP,I2C,HDQ及SD/MMC接口)

显示单元: 

  • 1个HDMI接口(芯片:TFP410),可输出分辨率1280×720,码率30fps的DVI-D高清信号
  • S-Video视频输出接口
  • 24bit真彩色LCD接口(含4线触摸屏接口,分辨率可支持2048*2048)

电气参数:

  • 工作温度:-40 ~ 85℃(芯片支持)
  • 环境湿度:20% ~ 90% ,非冷凝
  • 机械尺寸:110 mm * 95 mm
  • 电气指标:+5V电源供电,电流150mA
软件特性
Linux系统特性:

  • Linux版本:Linux2.6.28
  • 编译器版本:gcc version 4.2.1 (CodeSourcery Sourcery G++ Lite 2007q3-51)
  • 启动方式:支持网络、SD卡或NAND Flash中启动引导Linux系统
  • 更新方式:支持网络或SD卡更新映像
  • 文件系统格式:Ramdisk文件系统、UBI文件系统
  • 文件系统支持:ROM/CRAM/EXT2/EXT3/FAT/NFS/JFFS2/UBIFS
  • 设备管理支持:udev设备管理
  • 驱动支持:Serial、RTC、NAND、DVI、LCD、 触摸屏、SD卡、USB、键盘、音频、网络、LED、CAMERA、WiFi、GPS、GPRS、CDMA

 

Wince系统特性:

  • Wince版本:Wince6.0
  • 启动方式:网络、SD卡或NAND Flash中启动引导Wince系统
  • 更新方式:网络或SD卡更新映像
  • 文件系统:支持HIVE注册表支持及ROM文件系统(可读写)
  • 支持微软的远程调试工具对目标板的文件、注册表、进程及线程的管理
  • 系统特性:支持.NET Compact Framework 3.5及KITL内核调试
  • 电源管理:背光管理、电池管理、休眠\唤醒功能
  • 驱动支持:DVI、LCD、SD卡、键盘、音频、网络、NLED、USB、RTC、Watchdog、WiFi、GPS、GPRS、CDMA

Demo演示:

  • Angstrom系统:嵌入式操作系统,支持音频播放,网络浏览,图形编辑及文档处理
  • Android系统:Google开发的基于Linux平台的开源手机操作系统
  • DVSDK软件包:支持MPEG4,MPEG2,H264,mp3,aac音/视频格式DSP硬解码及2D/3D特效

源码及工具:

  • 提供u-boot 1.3.3源码及linux2.6.28内核源码(包含驱动源码)
  • 提供gcc交叉编译工具
  • 提供Wince6.0 BSP源码包(包含驱动源码)及SDK安装包

 

订购信息

产品编号 T6010074
产品名称 DevKit8000评估套件
标准配件  1) Devkit8000评估版 *1
 2) SD卡(512MByte) *1
 3) 交叉串口线 *1
 4) 5V、2A电源适配器 *1
 5) CD光盘(包含用户手册、PDF原理图、外设驱动、源代码等)*1
完全配件  1) 4.3寸 LCD屏,分辨率(480*272)LCD8000-43T  *1
 2) SD卡(512MByte) *1
 3) 交叉串口线 *1
 4) 触摸笔 *1
 5) Mini USB A线转USB A型母头 *1
 6) Mini USB B线转USB A型公头 *1
 7) USB HUB(包括HUN电源、连接线) *1
 8) 网线 *1
 9) HMDI转DVI-D转接线 *1
 10) S-Video线 *1
 11) 5V、2A电源适配器 *1
 12) 光盘(包含用户手册、PDF原理图、外设驱动、源代码等) *1
可选配件  1)10.4寸LCD屏(LCD8000-104T,分辨率为800*600)(30套起订)一般不出货,
 2)7寸LCD屏(LCD8000-70T,分辨率为800*480),
 3)XDS100v2 仿真器(XDS100v2 仿真器
 4)560仿真器(TDS560 Plus仿真器
 5)VGA液晶显示(VGA8000,分辨率 1024*768)
 6)模拟摄像头模块(CAM8000-A,分辨率为720*576(PAL制式))
 7)数字摄像头模块(CAM8000-U
 8)USB WiFi模块(WF8000-U
 9)GPRS无线通讯模块(GPRS8000-S
 10)GPS定位系统模块(GPS8000-S
 11)CDMA8000-U 3G模块(CDMA8000-U
 
备注   CAM8000-A 摄像头模块现只支持Linux

刚看完《嵌入式Linux基础教程》

昨晚刚刚看完《嵌入式Linux基础教程》,这本书帮助嵌入式Linux爱好者进驻这个领域、避免走太多弯路、澄清一些必须了解的概念、介绍必须知道的内容,相当的不错,推荐读!
《嵌入式Linux基础教程》
《嵌入式Linux基础教程》

申明一下,本人非托,只是刚刚读完这本书,觉得相当不错,推荐给大家:)

用下载电缆实现AT89S5X的ISP编程

本文转载自:http://www.infomcu.com/Program/20071007/455_2.html

 

摘要:下载电缆被广泛应用于电子系统设计与调试过程中。本文介绍它的基本原理和编程控制方法;针对目前单片机的 ISP串行编程模式列举实例,简要介绍AT89S5X的串行编程的方法和部分协议,使用VC编程,应用下载电缆实现对AT89S5X系列单片机的ISP编程;文末提出统一下载电缆硬件或软件的设想,并提供可以下载支持多种单片机ISP编程软件的网址。

关键词:下载电缆 串行编程 AT89S5X ISP

引言

  随着电子技术的日益发展,芯片的规模越来越大,封装日趋小型化,相应的对系统板级调试困难也在加大。IEEE制定了标准测试端口与边界扫描的标准IEEE std 1149.1,这就是JTAG接口协议。JTAG接口通过TCK、TDI、TDO、TMS四根信号线,以串行模式为系统提供了对复杂芯片的各引脚连通性测试,进步还能实现对可编程芯片的配置与处理器芯片的调试等等。下载电缆就是一种使用计算机的并行端口通过软件的仿零点实现JTAG接口协议,访问可编程芯片的廉价工具。本文使用的下载电缆是Altera公司为其可编程逻辑器件开发的ByteBlasterMV电缆。ISP(在系统可编程的简称)是最先由 Lattice公司提出的一种技术,是通过同步串行方式实现对其可编程逻辑器件的重配置。ISP与JTAG的接口协议很相像,只是后者形成了标准。ISP现在已经成为一种概念,它的提出改变了传统硬件系统开发的流程,大大方便了开发者,加快了开发速度。现在大多数的可编程器件(FPGA、CPLD、DSP、MCU……)都支持ISP特性。单片机也不例外,Atmel公司推出的AT89S系列51单片机也符合ISP特性。
 
1 下载电缆的硬件

  要实现JTAG接口协议可以使用专用的IC,如74LVT8980、74LVT8990,它与MCU配合可以提供高速的JTAG串行访问,成本较高。下载电缆则是实现JTAG接口协议的廉价方案。它仅命名用74HC244做线路驱动,由计算机的并行端口引出I/O作为TCK、TDI、TDO、TMS等信号线。由于并口在SPP模式下共有3个端口——数据输出端口、控制输出端口、状态输入端口,各种下载电缆究竟从那个端口引出JTAG信号线几乎都不相同,图1、图2是两种下载电缆的原理图。

并口简介:

  计算机的并行端口工作在SPP模式下,对它的控制是通过数据输出端口、控制输出端口、状态输入端口来实现的。

  并行口有25个引脚,其中包括8位数据线、5位状态线、4位控制线。

  数据端口(378H):D0~D7用于数据输出。

  状态端口(379H):*S7(Busy)、S6(nAck)、S5(PE)、S4(Select)、S3(nError)。

  控制端口(37AH):*C3(nSelin)、S2(nInit)、*C(AnutoFeed)、*C0(nStrobe)。

  ()(端口地址是缺省的LPT1设置;*表示此引脚有反向器)

  表1为并行端口定义。对应原理图有:

  Altera的下载电缆

  TCK、TDI、TMS、TDO分别对应D0、D6、D1、*S7;

  Atmel的电缆

  TCK、TDI、TMS、TDO分别对应*C0、D0、*C3、S6。

  表1 并行端口定义表

引脚号 名   称 数据位
1 nStrobe *C0
2 D0 D0
3 D1 D1
4 D2 D2
5 D3 D3
6 D4 D4
7 D5 D5
8 D6 D6
9 D7 D7
10 nAck S6
11 Busy *S7
12 PE S5
13 Select S4
14 Auto Feed *C1
15 nError S3
16 nInit C2
17 nSelin *C3
18~25 GND GND

2 下载电缆的编程方法

  用计算机控制下载电缆实现JTAG协议,就是对并口3个I/O端口的读写操作,用0-1的变化来模拟JTAG时序。在Win98和Win2000环境下读写I/O,需要驱动程序。本文使用DriverLINX Port I/O Driver(可以从WWW.sstnet.com下载)来实现I/O端口访问。安装DLPORTIO以后,通过调用DLPORTIO.DLL动态连接库中的

  UCHAR DLPORT_API D1PortRead PortUchar(IN ULONG Port);

    VOID DLPORT_API D1PortWrite PortUchar(IN ULONG Port,IN UCHAR Value);两个函数就可以访问位于378H、379H、37AH(这是缺省的LPT1设置)的3个并口I/O端口。程序段1实现了对Altera下载电缆的一次电平赋值:

  程序段1

  Altera下载电缆电平赋值函数

  Void CAvrISPDlg::Setbit(){

  Unsigned char value=0;

  If(!m_tck)value|=0x01;

  If(!m_tms)value|=0x02;

  If(!m_tdi)value|=0x40;

  DlPortWritePortUchar(0x378,value);

  Value=DlPortReadPortUchar(0x379);

  If(value & 0x80)m_tdo=0;

  Else m_tdo=0;

  }

  通过以上程序依次改变JTAG各接口I/O的电平状态,模拟JTAG协议的时序,就可以访问支持JTAG标准的各种芯片。

3 ISP协议的解析与实现

  对AT89S5X系列单片机ISP编程不使用JTAG协议,而使用SPI同步串行接口协议,如图3所示。

  针针这种8位SPI接口协议,我们使用数组来模拟时序:

  时钟信号固定为unsigned char sck[19]={0,0,1,0,1,0,1,0,1,0,10,1,0,1,0,1,0,1,0,0};

  输出的数据信号由程序实现情况自动生成数组unsigned char mosi[19];

  输入的数据根据读入的信号生成数组unsigned char miso[19];

  再调用上文的Setbit()函数,依次发送19位的JTAG接口I/O状态,同时读入返回信号,即完成一次对AT89S5X芯片的SPI单字节访问。

  在单字节访问基础上,参考Atmel公司的AT89S5X数据手册的串行编程指令表中的指令格式,就可以实现ISP了。

  表2为AT89S51串行编程指令表。

  表2 AT89S51串行编程指令集

指  令 指  令  模  式 说  明
第1字节 第2字节 第3字节 第4字节
编程使能 10101100 01010011 XXXXXXXX XXXXXXXX 使能串行编程
芯片擦除 10101100 100XXXXX XXXXXXXX XXXXXXXX 擦除程序存储顺
读程序字节 00100000 XXXXA11~A8 A7~A0 D7~D0 字节模式读程序
写程序字节 01000000 XXXXA11~A8 A7~A0 D7~D0 字节模式写程序
写保护位 10101100 111000B1B2 XXXXXXXX XXXXXXXX 写保护位
读保护位 00100100 XXXXXXXX XXXXXXXX XXLB3~LB1XX 读当前保护位
读标志字节 00101000 XXXA5~A1 A0XXXXXX 标志数据 读取标志数据
读程序页 00110000 XXXXA11~A8 数据0 数据1…255 页模式读程序
写程序写 01010000 XXXXA11~A8 数据0 数据1…255 页模式写程序

 注:①串行编程要在RST端接高电平情况下实现;②X表示此位关心;③A11~A0是要访问字节地址;④D7~D0是读写的数据;⑤B1、B2是保护位;⑥LB3~LB1表示3种状态。

  针对AT89S51单片机,其标志字节为:(00H)1EH、(02H)51H、(04)06H.

  程序段2将得到AT89S51单片机的标志字节。(其中SPIcomm()为SPI单字节访问函数)。

  程序段2

  获得AT89S51单片机标志字节的程序段

  CString str;

  for(addr=1;addr<3;addr++){

  m_comm=0x28;

  SPIcomm();

  m_comm=addr;

  SPIcomm();

  m_comm=0;

  SPIcomm();

  m_comm=0;

  SPIcomm();

  Str.Format(“0x%02X”,m_dat);

  m_out+=str;

  }

  图4是AT89S51进行串行编程时的硬件原理图。

4 小结

  下载电缆为我们提供了深入芯片内部的触手。通过JTAG标准协议,我们可以用下载电缆检查芯片焊接连通性、重新配置可编程器件、下载程序固件以及调试处理器的运行。

  小到8位单片机AT89S5X、AVR的串行编程,可编程器件MAX7000的配置;大到32位嵌入式处理器的调试,上万门FPGA芯片的配置都可以见到下载电缆的身影。例如,ARM使用下载电缆的JTAG仿真可以通过EmbeddedICE接口实现对ARM的开发调试,或者使用ARM的边界扫描特性为嵌入式系统板下载启动程序等等。

  目前下载电缆的使用越来越多,各个厂商分别推出了自已的符合JTAG标准的芯片或者是使用ISP技术的新产品。与此同时,下载电缆的种类也非常多,大多数的区别仅在于并口信号与JTAG信号的对应关系不同。往往有时候开发一个产品,要用到很多种不同的电缆。我们希望可以使用一种标准的下载电缆来实现所有JTAG应用;或者是通过一个计算机程序可以通过配置文件来使用各种下载电缆。在我们的BLMVISP软件中,就支持了现有的两种电缆。

  使用ISP技术可以大大加快硬件开发速度。下载电缆与计算机软件的配合使用也可以降低开发成本,非常适合个人爱好者与初学者使用。

  有兴趣的读者可以下载BLMVISP演示版的VC源程序压缩包(demo_blmvisp.zip),以便参考;也可以访问:http://51kaifa.nease.net或者email:blmv@eyou.com。