EDN首页   博客首页

最新日志

发表于:2008-9-20 17:43:13
标签:ARM  

0

关于LPC2148串口波特率

今天为了项目需要,调试了一下LPC2148的串口。

说起串口来,大家都会认为很简单嘛,又没有什么特别的代码,不过今天遇到的问题足足让我调试了2个小时。甚是尴尬!

最后发现,把波特率设定比较高之后,串口传输就有问题,接收到的都成了乱码,尤其是115200这个波特率下,一个好的传输都没有。

以前使用串口没有遇到这样的问题。按理说晶振12MHz应该可以进行这个波特率的传输吧?

难道是串口硬件问题,这个传输速率对于硬件来说要求太高?不会吧,我用AVR传过这么高的。

时间问题,暂时放在这里,若有高手看到,望不吝赐教,让小弟多学一点知识,不甚感激!

系统分类: ARM   |    用户分类:    |    来源: 原创

评论(1) | 阅读(203)
发表于:2008-9-12 11:08:06
标签:uC/OS  

2

菜鸟学uC/OS_II(14)

菜鸟学uC/OS_II(14)

By Norman

2008-8-4

 

为了得到更多的启动代码例程,我决定求助于MDK。因为ARM-ADS作为系统级的开发IDE,对于现阶段对ARM的学习没有多大帮助,而MDK又具有中文帮助文档等优点,直接针对ARM的应用,很实用。

作为例程,启动代码结构其实同ADSZLG给的差不多,不同的是MDK下全写在汇编中,而在ADS下,是由一个Target.c文件的,做的工作其实是一样的。

 

出现的问题:

1)为了编译uCOS,我直接利用了ADS中的移植文件。发现一个编译错误:

——OS_CPU_A.o(.text) contains invalid call from '~PRES8' function to 'REQ8' function——

这是一个对齐的问题,MDKABI是用8Bytes对齐的,ADS中则不是;压栈的时候,ADS可能压的是单数的寄存器,而MDK中需要的是偶数(这里,ZLG给出的代码中有一个R12的压栈,相信是为了匹配这个要求的),不过,只修改这些还不行,还需要在代码段开始的时候写一条语句:PRESERVE8——所以,这里有两个地方需要注意。

这个问题网上很多人遇到,也给出了具体解释,参看《从ADSRealView MDK》一文。

 

2error: L6236E: No section matches selector - no section to be FIRST/LAST

按照《从》一文的步骤,出现了这个没有提到的错误。在网上查查,原来是

  AREA    vectors,CODE,READONLY

——>

  AREA    RESET, CODE, READONLY

暂时不懂为什么要这样改,是段名一定要相同么?那为什么我改成Reset要报重复错误?

 

3MDK中支持中断句柄否?

 

4*** error 65: access violation at 0x400009E0 : no 'execute/read' permission

 

这是软件设置问题还是程序?

没有选择对目标器件——程序是针对LPC2148的,LPC2131的内存区域同2148有一定的出入,造成这种结果。如果将内存映射改一下,对应于LPC2131的内存,就可以运行了。不过仿真结果却不太理想,不知道这和软件、计算机硬件配置有没有关系。

 

 

 

 

 

 

 

 

 

 

系统分类: 嵌入式   |    用户分类:    |    来源: 原创

评论(2) | 阅读(205)
发表于:2008-9-12 11:05:05
标签:uC/OS  

2

菜鸟学uC/OS_II(13)

菜鸟学uC/OS_II(13)

By Norman

2008-8-2

 

今天突然有个想法,是否在其他结构比较简单的平台上移植比较容易一点,正好同学有一个凌阳的精简板,反正今天是星期天,就当是休息了。

首先肯定是去熟悉SPCE061A的结构和IDE了。主要是存储器结构、指令系统和中断这几个部分。本来不是做这个的,没有必要深究,总体看看,知道在哪些地方查就行,所以看到很快。于是摆好uCOS系统的资料,按照移植步骤,一个个文件、函数地写好,其他没有什么,就是时间节拍比较难一点,用了不少时间写,主要是去熟悉凌阳的中断系统,了解几个寄存器的用法。按照标准移植函数步骤写下来,代码也就10来行。

在这里我想说的不是如何移植,而是编译。凌阳的IDE说实话肯定是不太完善的。因为我同学本科的时候做过,那个时候似乎听他提到过这个问题。不过我今天算是感受到了。

写好文件,编译——我的错,有一个函数写错了,编译没有通过。然后我改了。编译,???怎么回事,还是这个错误?

大体是这样的,我写了一个OSTaskSw函数(原本想写OSCtxSw的),结果,这个IDE居然还真的认出来一个OSTaskSw,我当时就晕了,我好像在内核里没有看到过这个函数嘛。我赶紧去内核查找一下,没有嘛。我把OSTaskSw函数改成OSCtxSwOS_CPU.H里),再编译,还是有。更晕了~

这个错误是这样报的:

Error L0080: The external symbol "_memset" has not a public definition.

Error L0080: The external symbol "_OSTaskSw" has not a public definition.

memset嘛好说,这应该是我没有包含某个库文件,我只是知道这是个字符串处理函数,应该在string.h里面,但是包含了它,还是有这个错误(现在还没有解决,惭愧~),但是OSTaskSw都没有了还给我报什么?

后来我想,这个IDEGCC的,是不是因为增量编译,链接的时候用了以前的文件?干脆把所有以前编译生成的文件删除了(用clear没有用),再编译,嘿嘿,还真的没有这个错误了。I 服了HIM。确实没有用过,问题都不好找。

今天比较晚了,明天来解决另一个问题吧!我怀疑最大的可能是在工程文件的组织上有问题,应该好好梳理一下。因为我发现,编译应用程序文件是没有错的,Build的时候才出现。

 

心头憋得慌,一大早就跑到实验室来调试。弄了半天,把include文件夹中的memset搜索了一遍,就只有一个string.h里面有嘛。哪里还有其他的哩?难道我包含的地方不对?“SPCE061A.h”包含在includes.h中,能够使用,按说所有.c文件都包含includes.h,放在这里是没有问题的嘛。不过上天要它说不行,我也没辙啊~

没办法,上网查查吧。

一说是版本问题!我意识到,好像以前看过一个版本,在OSTask.c中好像是没有用到memset函数。那下载一个老版本的来实验一下,总不能让我去改内核吧,改出来更多问题,得不偿失。我下的是2.00的。

经过一番挣扎一般的调试(很久都没有怎么用过凌阳的IDE,很多功能不会用了,又不知道其Bug,出了问题就只好老老实实重新编译等等,确实很累),总算调通了。

经过记录下来——为了系统化,把uCOS标准移植伪码加上对比。

 

移植准备:

ucOS-II的移植主要涉及以下三个文件:

        OS_CPU.H

        OS_CPU_A.ASM

        OS_CPU_C.C

移植的工作包括以下几个内容:

1. OS_CPU.H 文件中

    声明10个数据类型

        BOOLEAN

        INT8U

        INT8S

        INT16U

        INT16S

        INT32U

        INT32S

        FP32

        FP64

        OS_STK

    声明三个宏

        OS_ENTER_CRITICAL()

        OS_EXIT_CRITICAL()

        OS_TASK_SW()

    设置一个常量的值

        OS_STK_GROWTH

2. 编写四个汇编语言函数 OS_CPU_A.ASM

        OSStartHighRdy()

        OSCtxSw()

        OSIntCtxSw()

        OSTickISR()

3. C语言编写六个简单的函数 OS_CPU_C.C

        OSTaskStkInit()

        OSTaskCreateHook()

        OSTaskDelHook()

        OSTaskSwHook()

        OSTaskStatHook()

        OSTimeTickHook()

        ………………

4. 一般认为上面几个方面就构成了整个移植要做的工作,其实我认为还应该包含对Includes.hOS_CFG.H的配置,因为这些决定了操作系统的功能和编译的环境。

 

移植工作:

 

1OS_CPU.H

根据凌阳的数据结构特点,定义如下:

typedef unsigned char  BOOLEAN;

typedef unsigned char  INT8U;

typedef signed   char  INT8S;

typedef unsigned int   INT16U;

typedef signed   int   INT16S;

typedef unsigned long  INT32U;

typedef signed   long  INT32S;

typedef float          FP32;

typedef double         FP64;

 

typedef unsigned int   OS_STK;

 

#define  OS_CRITICAL_METHOD    2

 

#if      OS_CRITICAL_METHOD == 2               /*一般都使用第二种方法*/

#define  OS_ENTER_CRITICAL()        __asm__("INT OFF \n\t")              /*关中断*/

#define  OS_EXIT_CRITICAL()           __asm__("INT IRQ \n\t" "INT FIQ \n\t")                 /*开中断*/

#endif

 

#define  OS_STK_GROWTH        1                 /*堆栈增长方式,凌阳是从高向低增长*/

 

#define  OS_TASK_SW()         OSCtxSw()               /*任务切换函数*/

 

*这里需要说明的是,很多编译器由于支持软中断,所以,这里通常使用的是软中断进入管理模式,然后进行任务切换(例如在ARM7中)。但是凌阳没有软中断,只好通过函数调用的方式进行,而不是让某个中断向量指向OSCtxSw()

 

到这里,OS_CPU.H的工作大体就是这么多了。

 

2OS_CPU_C.C

在这个文件中,最重要的是OSTaskStkInit()函数的编写,其他Hook函数用来扩展内核功能而不去修改内核结构。

先来看看一般堆栈需要初始化成什么样子:

l         保存参数(这个视情况而定,因为有些处理器的参数是通过寄存器传递的;如ARM7

l         保存任务地址,用于保存当前任务(由于凌阳的段寄存器没用,为0,保存task+1

l         处理器状态字(凌阳应该是SR吧,反正我保存的是SR

l         中断返回地址保存(这个好像不太重要,我看ARM7里面就没有保存)

l         寄存器组

按照这个步骤,编写如下:

这里注意,版本不同,声明的类型也有不同,在2.52中是OS_STK

void  *OSTaskStkInit (void (*task)(void *pd), void *pdata, void *ptos, INT16U opt)

{

    OS_STK *stk;

 

    opt    = opt;                      

    stk    = (OS_STK *)ptos;               

    *stk-- = *((INT16U*)pdata);

//         *stk-- = *((INT16U*)task);                    //0,不需要保存

    *stk-- = *((INT16U*)task + 1);

    *stk-- = (INT16U)0x0000;                         //SR不能乱放东西的,因为这个是程序执行用到的

    *stk-- = (INT16U)0x5555;                         //这些就可以随便放了为了调试方便,可以放一些有意义的数值

    *stk-- = (INT16U)0x4444;

    *stk-- = (INT16U)0x3333;

    *stk-- = (INT16U)0x2222;

    *stk-- = (INT16U)0x1111;

    return ((void*)stk);

}

 

*说明:在标准伪码里面提到一个模拟ISR的压栈,暂时没有明白是什么意思。

 

3OS_CPU_A.ASM

首先声明需要的外部变量和要输出的变量:

.external _OSTCBCur

.external _OSTCBHighRdy

.external _OSRunning

.external _OSPrioCur

.external _OSPrioHighRdy

.external _OSIntNesting

 

.external _OSTaskSwHook

.external _OSIntEnter

.external _OSIntExit

.external _OSTimeTick

 

.public _OSStartHighRdy

.public _OSIntCtxSw

.public _OSCtxSw

.public _OSTickISR

大概就这些吧

 

1)函数_OSStartHighRdy

标准函数伪码:

void OSStartHighRdy(void)

{

       调用用户定义的OSTaskSwHook();

       OSRunning = TRUE;

       得到将要恢复运行的任务的堆栈指针:

              Stack Pointer = OSTCBHighRdy——>OSTCBStkPtr;

       从新任务堆栈中恢复处理器的所有寄存器;

       执行中断返回指令;

}

 

按这个标准函数,编写函数如下:

_OSStartHighRdy:

         CALL        _OSTaskSwHook

         R1 = 1

         [_OSRunning] = R1;

         R1 = [_OSTCBHighRdy]

         SP = [R1]            //注意是所指向的内容,调这个错误用了不少时间

         POPALL             //此函数只做了任务切换工作的一半,并没有保存当前任务的寄存器

         RETI

2)函数_OSCtxSw

 

标准函数伪码:

 

void OSCtxSw(void)

{

       保存处理器寄存器;

       在当前任务的任务控制块中保存当前任务的堆栈指针:

              OSTCBCur——>OSTCBStkPtr = Stack Pointer;

       OSTaskSwHook();

       OSTCBCur = OSTCBHighRdy;

       OSPrioCur = OSPrioHighRdy;

       得到将要运行的任务的堆栈指针:

              Stack Pointer = OSTCBHighRdy——>OSTCBStkPtr;

       从新任务的任务堆栈中恢复处理器所有寄存器的值;

       执行中断返回指令;

}

 

按这个标准函数,编写函数如下:

 

_OSCtxSw:

         PUSHALL

         </