打印
[ZLG-ARM]

UART0_SendNByte的错误

[复制链接]
2097|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
edisontang|  楼主 | 2008-12-16 11:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
TE, UART0, se, ST, ni
我使用的是zlg提供的EasyARM2200开发板,我在测试Uart0相关程序(DebugInExram,RelOutChip)的时候,发现如果用UART0_SendNByte()
函数发送大量数据的时候,当发送几十个数据之后就会出现Data Abort的错误,如果数量很少(就几十个)的话,就不会出现问题。
后来把mem_b.scf中的IRAM 0x40000000改为IRAM +0,也就是紧接着ROM_EXEC的后面的话,这个问题就不存在了.


请问这是什么原因,如何解决呢?

void test()
{
    uint8 t[200];
    int i;
    for(i=0;i<200;i++)
         t='U';

    UART0_SendNByte(t,200);//就会出现Data Abort的错误 

}

uint8 UART0_SendNByte(uint8 *p, uint32 n)
{   
    uint8 err;

    OSSemPend(UART0_SendSem, 0, &err);
    
    if(n > (QueueSize((void *)UART0_SendBuf)-QueueNData((void *)UART0_SendBuf)))
    {
        OSSemPost(UART0_SendSem);
        return FALSE;
    }
    while(n-- > 0)
    {
        QueueWrite((void *)UART0_SendBuf, *p);
        p++;
    }
    UART0_SendTriger();

    OSSemPost(UART0_SendSem);
    
    return TRUE;



ROM_LOAD 0x80000000
{
    ROM_EXEC 0x80000000
    {
        Startup.o (vectors, +First)
        * (+RO)
    }


    IRAM 0x40000000 //修改为IRAM +0
    {
        Startup.o (MyStacks)
    }

    STACKS_BOTTOM +0 UNINIT
    {
        Startup.o (StackBottom)
    }

    STACKS 0x40004000 UNINIT
    {
        Startup.o (Stacks)
    }

    ERAM 0x80040000
    {
        * (+RW,+ZI)
    }

    HEAP +0 UNINIT
    {
        Startup.o (Heap)
    }

    HEAP_BOTTOM 0x80080000 UNINIT
    {
        Startup.o (HeapTop)
    }

}

相关帖子

沙发
edisontang|  楼主 | 2008-12-16 11:36 | 只看该作者

其他相关的代码

void UART0_SendTriger(void)
{
    uint8 k;
    if((U0LSR & 0x00000020) != 0)
    {
        QueueRead(&k, UART0_SendBuf);
        U0THR = k;
    }
}


void UART0_Exception(void)
{   uint8 IIR, temp, i,rcv; 

    OS_ENTER_CRITICAL();

    while(((IIR = U0IIR) & 0x01) == 0)                          // 有中断未处理完 
    {                                                   
        switch (IIR & 0x0e)
        {
            case 0x02:                                          // TX FIFO空,申请填充TX FIFO 
               
                for (i = 0; i < 8; i++)                         // 消息队列有数据,填16个数据到硬件TX FIFO 
                {                                               // 发送队列数据前,检查队列数据有效性
                    
                    if(QueueRead(&temp, UART0_SendBuf) == QUEUE_OK)
                    {
                        U0THR = temp;
                    }
                    else
                    {
                        break;
                    }
   
                }
                break; 

。。。。。。。。。。。。

 

uint8 QueueRead(QUEUE_DATA_TYPE *Ret, void *Buf)
{
    uint8 err;
    DataQueue *Queue;

    err = NOT_OK;
    if (Buf != NULL)                                            /* 队列是否有效 */
    {                                                           /* 有效 */
        Queue = (DataQueue *)Buf;
 
        OS_ENTER_CRITICAL();
        
        if (Queue->NData > 0)                                   /* 队列是否为空 */
        {                                                       /* 不空         */
            *Ret = Queue->Out[0];                               /* 数据出队     */
            Queue->Out++;                                       /* 调整出队指针 */
            if (Queue->Out >= Queue->End)
            {
                Queue->Out = Queue->Buf;
            }
            Queue->NData--;                                     /* 数据减少      */
            err = QUEUE_OK;
        }
        else
        {                                                       /* 空              */
            err = QUEUE_EMPTY;
            if (Queue->ReadEmpty != NULL)                       /* 调用用户处理函数 */
            {
                err = Queue->ReadEmpty(Ret, Queue);
            }
        }
         
        OS_EXIT_CRITICAL();

    }
    return err;
}

使用特权

评论回复
板凳
ZLG_Dengz| | 2008-12-17 01:01 | 只看该作者

RE:

    你好,我觉得可能和你给的下面这段代码有关
    while(n-- > 0)
    {
        QueueWrite((void *)UART0_SendBuf, *p);
        p++;
    }
    你可以查看一下QueueWrite()的代码,看是否是对队列是否是满了进行判断,如果没有的话,那么在这样循环写入中,就会队列溢出。

    而下面这段:
    IRAM 0x40000000 //修改为IRAM +0
    {
        Startup.o (MyStacks)
    }

    STACKS_BOTTOM +0 UNINIT
    {
        Startup.o (StackBottom)
    }
    只是将这两个部分定义到了片外的RAM中,因为片外RAM比较打,及时溢出了也可能不会出现数据异常。
   
   

使用特权

评论回复
地板
edisontang|  楼主 | 2008-12-17 12:07 | 只看该作者

谢谢zlg的回答

但是我发现QueueWrite()是检查了队列是否满的,而且这个中间件就是zlg开发板上提供的。

我做的改动就是吧中断模式下的堆栈空间(MyStacks,IrqStackSpace)从内部的SRAM(0x40000000)移到了外部的SRAM中,而且lpc2220的内部SRAM有64K大小之多呢。

uint8 QueueWrite(void *Buf, QUEUE_DATA_TYPE Data)
{
    uint8 err;
    DataQueue *Queue;

    err = NOT_OK;
    if (Buf != NULL)                                                    /* 队列是否有效 */
    {
        Queue = (DataQueue *)Buf;
         
        OS_ENTER_CRITICAL();
        
        if (Queue->NData < Queue->MaxData)                              /* 队列是否满  */
        {                                                               /* 不满        */
            Queue->In[0] = Data;                                        /* 数据入队    */
            Queue->In++;                                                /* 调整入队指针*/
            if (Queue->In >= Queue->End)
            {
                Queue->In = Queue->Buf;
            }
            Queue->NData++;                                             /* 数据增加    */
            err = QUEUE_OK;
        }
        else
        {                                                               /* 满           */
            err = QUEUE_FULL;
            if (Queue->WriteFull != NULL)                               /* 调用用户处理函数 */
            {
                err = Queue->WriteFull(Queue, Data, Q_WRITE_MODE);
            }
        }
         
        OS_EXIT_CRITICAL();
    }
    return err;
}
#endif

使用特权

评论回复
5
ZLG_Dengz| | 2008-12-17 22:12 | 只看该作者

RE:

    你好,可以单步调试一下,看看到底在那一句发生了数据异常。同时观察一下各参数是否正常。

使用特权

评论回复
6
edisontang|  楼主 | 2008-12-24 10:48 | 只看该作者

调试之后

如果我用单步调试的话,根本就不会发生错误。
如果全速运行,就会出错了,产生Data Abort错误,然后通过看当时的R14的值,发现程序在Queue->Out++;出错了,这个Queue->Out的值竟然是0x00000017,请问这是什么原因导致的呢?

使用特权

评论回复
7
edisontang|  楼主 | 2008-12-24 15:47 | 只看该作者

大家没遇到过吗

使用特权

评论回复
8
edisontang|  楼主 | 2008-12-25 13:15 | 只看该作者

您好,解决方案是什么呢

使用特权

评论回复
9
edisontang|  楼主 | 2008-12-30 12:08 | 只看该作者

经过调试发现,

在调用 if(QueueRead(&temp, (void*)UART0_SendBuf) == QUEUE_OK)的时候,temp这个临时变量的地址变为了0x3FFFFFEC,而当前的SP的值变成了0x3FFFFFE4,而这个地址是非法的,所以就发生了上面的问题,但是是什么原因造成了SP的值出错了呢?



看过irq.inc中对中断服务程序调用的时候,都是把SP设置为了StackUsr,而这个值应该是在0x40004000下面的附近活动啊,怎么会变到了0x3FFFFFE4这个非法的地址上的呢?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

58

主题

104

帖子

0

粉丝