QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2083|回复: 8

版主请进:已经找到了直接原因 // 求助:串口中断有问题

[复制链接]
发表于 2009-8-2 10:01:41 | 显示全部楼层 |阅读模式
skyeye模拟s3c2410,用stdin模拟串口输入。

发现每次输入一次字符,则串口中断正常。若在敲回车之前,输入的字符多了,串口中断会出问题,此时无法向stdin输入了。

我觉得可能是,中断丢失,或者我处理中断的方式不对。请高手指教!

IR.S
        .text
        .code 32

        stmfd        sp!,{r0-r12,lr}

        bl        HandleIRQ

        ldmfd        sp!,{r0-r12,lr}

        subs        pc,lr,#4

        .end

HandleIRQ.c

#include "Uart.h"
#include "cs8900.h"
#include <stdio.h>

void HandleUartInt()
{
        unsigned long sub_src_pnd = *(volatile unsigned *)0x4a000018;
        unsigned long rx_stat = 0;
        printf("0x%x\n", sub_src_pnd);
        if (1 == (sub_src_pnd & 0x01 )) /*sub src pnd*/
        {
                do
                {
                        WriteChar(ReadChar());
                        rx_stat = *(volatile unsigned *)0x50000010;
                }while(rx_stat & 0x00000001);
        }

        *(volatile unsigned *)0x4a000018 = 0x000007ff; /*clear all the sub src pnd*/       

}

void HandleEInt9()
{
        unsigned short isq = 0;

        do
        {
                isq = ReadCS8900Reg(0x0120);

                if (0x04 == (isq & 0x0f))
                {
                        do
                        {
                                int count = 0;
                                unsigned short rx_status = 0;
                                unsigned short rx_len = 0;
                                unsigned short rx_ok = 0;
                                if (!(rx_ok = (ReadCS8900Reg(0x0124) & 0x0100))) break;
                                rx_status = (*(volatile unsigned short *)0x19000300);
                                rx_len = (*(volatile unsigned short *)0x19000300);
                                rx_len = (rx_len / 2) + (rx_len % 2);
                                for (; count < rx_len; ++ count)
                                        printf("0x%x ", (*(volatile unsigned short *)0x19000300));
                                printf("\n");
                        }while (1);
                }
                else if (0x08 == (isq & 0x0f))
                {
                }
       
        }while (0 != isq);

        *(volatile unsigned *)0x560000a8 = 0xffffffff; /*clear external int pnd*/
}

void HandleIRQ(void)
{
                unsigned char offset = *(volatile unsigned char *)0x4a000014; /*int Offset*/
                unsigned long src_pnd = *(volatile unsigned *)0x4a000000;
                unsigned long int_pnd = *(volatile unsigned *)0x4a000010;

                /*printf("HandleIRQ 0x%x  0x%x  0x%x\n",  src_pnd, int_pnd, offset);*/
                switch (offset)
                {
                case 28:
                        HandleUartInt();
                        break;
                case 14:
                        break;
                case 5:
                        HandleEInt9();
                        break;
                default:
                        break;
                }

                *(volatile unsigned *)0x4a000000 = (1 << offset); /*clear src pnd*/
                *(volatile unsigned *)0x4a000010 = (1 << offset); /*clear int pnd*/
}

[ 本帖最后由 wt133664 于 2009-8-3 21:46 编辑 ]
 楼主| 发表于 2009-8-2 10:03:16 | 显示全部楼层

只开了uart0 rx与eint 9中断

只开了uart0 rx与eint 9中断,在清除sub src pnd时,假设了只有uart0会触发sub src pnd。

[ 本帖最后由 wt133664 于 2009-8-2 10:10 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2009-8-2 10:05:04 | 显示全部楼层

可以验证是串口中断出了问题

#include "Uart.h"
#include "cs8900.h"
#include <stdio.h>

extern void delay(int count);
void HandleUartInt()
{
        unsigned long sub_src_pnd = *(volatile unsigned *)0x4a000018;
        unsigned long rx_stat = 0;
        printf("0x%x\n", sub_src_pnd);
        if (1 == (sub_src_pnd & 0x01 )) /*sub src pnd*/
        {
                do
                {
                        WriteChar(ReadChar());
                        delay(10000); /*增加一个延时,则问题解决,但这样做是不允许的*/                       
                        rx_stat = *(volatile unsigned *)0x50000010;
                }while(rx_stat & 0x00000001);
        }

        *(volatile unsigned *)0x4a000018 = 0x000007ff; /*clear all the sub src pnd*/        

}

增加了延时后,可在一次中断中接收完所有输入的字符。如果不这样做,即如前,则没有接收完输入的字符,而后续的中断却不会到达了。

[ 本帖最后由 wt133664 于 2009-8-2 11:13 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2009-8-2 11:00:51 | 显示全部楼层

是否与mode有关?

在IRQ mode这样做有问题?回到SVC mode就可以了?

以前在开发板上没出现这个问题。在开发板上,敲一个字符,立刻产生一个中断。而在skyeye上,敲了回车后才会产生中断。这两者存在差异。

[ 本帖最后由 wt133664 于 2009-8-2 11:15 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2009-8-3 21:47:42 | 显示全部楼层

原因

在skyeye做如下修改:

skyeye_mach_s3c241x.c:

static void
s3c2410x_update_int (ARMul_State * state)
{
        ARMword requests;
        s3c2410x_update_subsrcint ();
        s3c2410x_update_extint ();
        requests = io.srcpnd & (~io.intmsk & INT_MASK_INIT);
        state->NfiqSig = (requests & io.intmod) ? LOW : HIGH;
        state->NirqSig = (requests & ~io.intmod) ? LOW : HIGH;
        if (!state->NirqSig)
            fprintf(stderr, "s3c2410x_update_int 0x%x  0x%x  %d\n", io.subsrcpnd, io.srcpnd, state->NirqSig);
}



static void
s3c2410x_uart_read (u32 offset, u32 * data, int index)
{
        switch (offset) {
        case ULCON:
                *data = io.uart[index].ulcon;
                break;
        case UCON:
                *data = io.uart[index].ucon;
                break;
        case UFCON:
                *data = io.uart[index].ufcon;
                break;
        case UMCON:
                *data = io.uart[index].umcon;
                break;
        case UTRSTAT:
                *data = io.uart[index].utrstat;
                break;
        case UERSTAT:
                *data = io.uart[index].uerstat;
                break;
        case UFSTAT:
                *data = io.uart[index].ufstat;
                break;
        case UMSTAT:
                *data = io.uart[index].umstat;
                break;
        case URXH:
                /* receive char
                 * */
                *data = io.uart[index].urxh;
                io.uart[index].utrstat &= (~0x1);        /* clear strstat register bit[0] */
                io.uart[index].ufstat &= ~(0x1); /* 2007-02-09 by Anthony Lee : for 0 bytes */
                break;
        case UBRDIV:
                *data = io.uart[index].ubrdiv;
                break;
        default:
                break;
        }
        fprintf(stderr, "%s(UART%d: 0x%x, 0x%x)\n", __FUNCTION__, index, offset, *data);
}


static void
s3c2410x_uart_write (ARMul_State * state, u32 offset, u32 data, int index)
{
       fprintf(stderr, "%s(UART%d: 0x%x, 0x%x)\n", __FUNCTION__, index, offset, data);
        switch (offset) {
        case ULCON:
                io.uart[index].ulcon = data;
                break;
        case UCON:
                io.uart[index].ucon = data;
                break;
        case UFCON:
                io.uart[index].ufcon = data;
                break;
        case UMCON:
                io.uart[index].umcon = data;
                break;
        case UTRSTAT:
                io.uart[index].utrstat = data;
                break;
        case UERSTAT:
                io.uart[index].uerstat = data;
                break;
        case UFSTAT:
                io.uart[index].ufstat = data;
                break;
        case UMSTAT:
                io.uart[index].umstat = data;
                break;
        case UTXH:
                {
                        char c = data;

                        /* 2007-01-18 modified by Anthony Lee : for new uart device frame */
                        skyeye_uart_write(index, &c, 1, NULL);

                        io.uart[index].utrstat |= 0x6;        //set strstat register bit[0]
                        if ((io.uart[index].ucon & 0xc) == 0x4) {
                                s3c2410x_set_subsrcint (UART_INT_TXD << (index * 3));
                                s3c2410x_update_int (state);
                        }
                }
                break;
        case UBRDIV:
                io.uart[index].ubrdiv = data;
                break;
        default:
                break;
        }
}

static void
s3c2410x_io_write_word (ARMul_State * state, ARMword addr, ARMword data)
{
        if ((addr >= UART_CTL_BASE0)
            && (addr < UART_CTL_BASE0 + UART_CTL_SIZE)) {
                s3c2410x_uart_write (state, (addr - UART_CTL_BASE0) % 0x4000,
                                     data, (addr - UART_CTL_BASE0) / 0x4000);
                return;
        }
        if ((addr >= PWM_CTL_BASE) && (addr < (PWM_CTL_BASE + PWM_CTL_SIZE))) {
                s3c2410x_timer_write (state, addr - PWM_CTL_BASE, data);
                return;
        }

        /*
         * 2007-02-09 by Anthony Lee
         * changed 0xC0 to 0xA4 for running linux-2.6.20,
         * because GSTATUS1 is 0xB0, the "0xC0" make it like S3C2400
         */
        if((addr >= GPIO_CTL_BASE) && (addr < (GPIO_CTL_BASE + 0xA4))){
                int offset = addr - GPIO_CTL_BASE;
                io.gpio_ctl[offset] = data;
                return;
        }

        switch (addr) {
        case SRCPND:
                fprintf(stderr, "write srcpnd step 1: 0x%x  0x%x\n", io.subsrcpnd, io.srcpnd);
                io.srcpnd &= (~data & INT_MASK_INIT);
                fprintf(stderr, "write srcpnd step 2: 0x%x  0x%x\n", io.subsrcpnd, io.srcpnd);
                //2006-04-04 chy, for eCos on s3c2410. SRCPND will change the INTPND, INTOFFSET, so when write SRCPND, the interrupt should be update
                s3c2410x_update_int (state);
                fprintf(stderr, "write srcpnd step 3: 0x%x  0x%x\n", io.subsrcpnd, io.srcpnd);
                break;
        case INTMOD:
                io.intmod = data;
                break;
        case INTMSK:
                io.intmsk = data;
                s3c2410x_update_int (state);
                break;
        case PRIORITY:
                io.priority = data;
                break;
        case INTPND:
                io.intpnd &= (~data & INT_MASK_INIT);
                io.intoffset = 0;
                //printf ("io.intoffset:%x, io.intpnd:%x (0x%08x) = 0x%08x, pc:%x\n", io.intoffset, io.intpnd, addr, data, state->pc);
                break;
                /*read only */
                //case INTOFFSET:
                //      break;
        case SUBSRCPND:
                fprintf(stderr, "write sub_srcpnd step 1: 0x%x  0x%x\n", io.subsrcpnd, io.srcpnd);
                io.subsrcpnd &= (~data & INT_SUBMSK_INIT);
                fprintf(stderr, "write sub_srcpnd step 2: 0x%x  0x%x\n", io.subsrcpnd, io.srcpnd);
                break;
        case INTSUBMSK:
                io.intsubmsk = data;
                break;


                /* ext interrupt */
        case EINTMASK:
                io.eintmask = data;
                break;
        case EINTPEND:
                io.eintpend &= (~data & 0x00FFFFF0);
                break;
        case CLKCON:
                io.clkpower.clkcon = data;
                break;
        case CLKSLOW:
                io.clkpower.clkslow = data;
                break;
        case CLKDIVN:
                io.clkpower.clkdivn = data;
                break;
        case BWSCON:
                io.memctl.bwscon = data;
                break;
        case MPLLCON:
                io.clkpower.mpllcon = data;
                break;
        case BANKCON0:
                io.memctl.bankcon[0] = data;
                break;
        case BANKCON1:
                io.memctl.bankcon[1] = data;
                break;
        case BANKCON2:
                io.memctl.bankcon[2] = data;
                break;
        case BANKCON3:
                io.memctl.bankcon[3] = data;
                break;
        case BANKCON4:
                io.memctl.bankcon[4] = data;
                break;
        case BANKCON5:
                io.memctl.bankcon[5] = data;
                break;
        case BANKCON6:
                io.memctl.bankcon[6] = data;
                break;
        case BANKCON7:
                io.memctl.bankcon[7] = data;
                break;
        case REFRESH:
                io.memctl.refresh = data;
                break;
        case BANKSIZE:
                io.memctl.banksize = data;
                break;
        case MRSRB6:
                io.memctl.mrsrb6 = data;
                break;
        case MRSRB7:
                io.memctl.mrsrb7 = data;
                break;
        case WDCON:
                io.wd_timer.wtcon = data;
                break;
        case WDDAT:
                io.wd_timer.wtdat = data;
                break;
        case WDCNT:
                io.wd_timer.wtcnt = data;
                break;
        default:
                SKYEYE_DBG ("io_write_word(0x%08x) = 0x%08x\n", addr, data);
                break;
        }
}

[ 本帖最后由 wt133664 于 2009-8-3 21:51 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2009-8-3 21:52:21 | 显示全部楼层

原因(续)

skyeye_uart.c

int skyeye_uart_read(int devIndex, void *buf, size_t count, struct timeval *timeout, int *retDevIndex)
{
        int retVal = -1;
        struct uart_device *uart_dev;

        if (retDevIndex != NULL) *retDevIndex = -1;

        if (devIndex >= skyeye_config.uart.count || buf == NULL || count == 0) { /* invalid */
        } else if(devIndex >= 0) { /* single device */
                uart_dev = skyeye_config.uart.devs[devIndex];
                retVal = uart_dev->uart_read(uart_dev, buf, count, timeout);
        } else { /* all devices */
                int i, stop_flags = 0;
                struct timeval tv, zero_tv;

                if (!(timeout == NULL || gettimeofday(&tv, NULL) == 0)) { /* something error */
                } else {
                        if (timeout != NULL) {
                                tv.tv_sec += (timeout->tv_sec + (timeout->tv_usec + tv.tv_usec) / 1000000UL);
                                tv.tv_usec = (timeout->tv_usec + tv.tv_usec) % 1000000UL;
                        }

                        zero_tv.tv_sec = 0;
                        zero_tv.tv_usec = 0;

                        do {
                                for (i = 0; i < skyeye_config.uart.count; i++) {
                                        uart_dev = skyeye_config.uart.devs;
                                        retVal = uart_dev->uart_read(uart_dev, buf, count, &zero_tv);

                                        if(retVal > 0) { /* got something */
                                                devIndex = i;
                                                break;
                                        }
                                        if(retVal == 0) continue;
                                        stop_flags |= (1 << i); /* failed */
                                }

                                if (stop_flags == (1 << skyeye_config.uart.count) - 1) { /* all failed */
                                        retVal = -1;
                                } else if (retVal > 0) {
                                        stop_flags = 1;
                                } else {
                                        retVal = 0;

                                        if (skyeye_uart_check_timeout(timeout != NULL ? &tv : NULL) == 1) { /* polling */
                                                stop_flags = 0;
                                                usleep(500);
                                        } else { /* timeout */
                                                stop_flags = 1;
                                        }
                                }
                        } while (stop_flags == 0);
                }
        }

        if (retVal > 0 && retDevIndex != NULL) *retDevIndex = devIndex;

       if (retVal > 0) fprintf(stderr, "skyeye_uart_read 0x%x\n", *(char *)buf);
        return retVal;
}
回复

使用道具 举报

 楼主| 发表于 2009-8-3 21:53:19 | 显示全部楼层

原因(续)

测试用源码


IR.s:

        .text
        .code 32
        stmfd        sp!,{r0-r12,lr}
        bl        HandleIRQ
        ldmfd        sp!,{r0-r12,lr}
        subs        pc,lr,#4
        .end


HandleIRQ.c:

#include "Uart.h"
#include <stdio.h>

void HandleUartInt()
{
        unsigned long sub_src_pnd = *(volatile unsigned *)0x4a000018;

        if (1 == (sub_src_pnd & 0x01 )) /*sub src pnd*/
        {
                        char rx_data = ReadChar();
        }

        *(volatile unsigned *)0x4a000018 = 0x000007ff; /*clear all the sub src pnd*/        
}

void HandleIRQ(void)
{
                unsigned char offset = *(volatile unsigned char *)0x4a000014; /*int Offset*/

                switch (offset)
                {
                case 28:
                        HandleUartInt();
                        break;

                default:
                        break;
                }

                *(volatile unsigned *)0x4a000000 = (1 << offset); /*clear src pnd*/
                *(volatile unsigned *)0x4a000010 = (1 << offset); /*clear int pnd*/
}
回复

使用道具 举报

 楼主| 发表于 2009-8-3 21:54:21 | 显示全部楼层

原因(续)

测试结果

//'Enter' ,这里显示不出来。从下面的打印来看,流程正常
skyeye_uart_read 0xa
s3c2410x_update_int 0x93  0x10000000  0
s3c2410x_uart_read(UART0: 0x10, 0x7)
s3c2410x_uart_read(UART0: 0x24, 0xa)
write sub_srcpnd step 1: 0x93  0x10000000
write sub_srcpnd step 2: 0x0  0x10000000
write srcpnd step 1: 0x0  0x10000000
write srcpnd step 2: 0x0  0x0
write srcpnd step 3: 0x92  0x0
d //实际上输入了两个字符'd'与'Enter',流程正常
skyeye_uart_read 0x64 //read 'd' from stdin and set sub src pnd
s3c2410x_update_int 0x93  0x10000000  0 //araise the first int
s3c2410x_uart_read(UART0: 0x10, 0x7) //read rx stat
s3c2410x_uart_read(UART0: 0x24, 0x64) //read rx content
write sub_srcpnd step 1: 0x93  0x10000000 //clear sub src pnd for the 'd'
write sub_srcpnd step 2: 0x0  0x10000000
skyeye_uart_read 0xa //read 'Enter' from stdin and set sub src pnd
s3c2410x_update_int 0x93  0x10000000  0 //araise the second int
write srcpnd step 1: 0x93  0x10000000  //clear src pnd for 'd'
write srcpnd step 2: 0x93  0x0
s3c2410x_update_int 0x93  0x10000000  0 //araise the third int cos sub src pnd setted
write srcpnd step 3: 0x93  0x10000000
s3c2410x_uart_read(UART0: 0x10, 0x7) //read rx stat
s3c2410x_uart_read(UART0: 0x24, 0xa) //read rx content
write sub_srcpnd step 1: 0x93  0x10000000 //clear sub src pnd for 'Enter'
write sub_srcpnd step 2: 0x0  0x10000000
write srcpnd step 1: 0x0  0x10000000 //clear src pnd for 'Enter'
write srcpnd step 2: 0x0  0x0
write srcpnd step 3: 0x92  0x0
dd //实际上输入了三个字符'd'、'd'与'Enter',流程异常
skyeye_uart_read 0x64 //read the first 'd' from stdin and set sub src pnd
s3c2410x_update_int 0x93  0x10000000  0 //araise the first int
s3c2410x_uart_read(UART0: 0x10, 0x7) //read rx stat
s3c2410x_uart_read(UART0: 0x24, 0x64) //read rx content for the first 'd'
write sub_srcpnd step 1: 0x93  0x10000000 //clear sub src pnd for the first 'd'
write sub_srcpnd step 2: 0x0  0x10000000
skyeye_uart_read 0x64 //read the second 'd' from stdin and set sub src pnd
s3c2410x_update_int 0x93  0x10000000  0 //araise the second int
write srcpnd step 1: 0x93  0x10000000 //clear src pnd  for the first 'd'
write srcpnd step 2: 0x93  0x0
s3c2410x_update_int 0x93  0x10000000  0 //araise the third int cos sub src pnd setted
write srcpnd step 3: 0x93  0x10000000
s3c2410x_uart_read(UART0: 0x10, 0x7) //read rx stat
s3c2410x_uart_read(UART0: 0x24, 0x64) //read rx content for the second 'd'
skyeye_uart_read 0xa //read the last 'Enter' from stdin and set sub src pnd
s3c2410x_update_int 0x93  0x10000000  0 //araise the fourth int
write sub_srcpnd step 1: 0x93  0x10000000 //clear sub src pnd for the second 'd'
write sub_srcpnd step 2: 0x0  0x10000000
write srcpnd step 1: 0x0  0x10000000 //clear src pnd for the second 'd'
write srcpnd step 2: 0x0  0x0
write srcpnd step 3: 0x92  0x0

出问题的是红色标注的语句,它们的顺序反了,最后的'Enter'产生的中断被清掉了,导致再也无法向stdin输入,即敲键盘输入。按照我的理解,从stdin读下一个字符所产生的中断,应发生在处理完上一个字符所产生的中断之后,即clear sub src pnd并且clear src pnd之后。

[ 本帖最后由 wt133664 于 2009-8-4 06:48 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2009-8-3 22:51:43 | 显示全部楼层

一种规避的方法

void HandleUartInt()
{
        unsigned long sub_src_pnd = *(volatile unsigned *)0x4a000018;
        //clear sub src pnd before read rx content,
        //coz reading rx content will clear rx ready bit of rx stat and result in reading next character form stdin
        *(volatile unsigned *)0x4a000018 = 0x000007ff; /*clear all the sub src pnd*/         
        if (1 == (sub_src_pnd & 0x01 )) /*sub src pnd*/
        {
                        char rx_data = ReadChar();
        }
}

[ 本帖最后由 wt133664 于 2009-8-3 22:55 编辑 ]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-4-25 11:57 , Processed in 0.181712 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表