版主请进:已经找到了直接原因 // 求助:串口中断有问题
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%x0x%x0x%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 编辑 ]
只开了uart0 rx与eint 9中断
只开了uart0 rx与eint 9中断,在清除sub src pnd时,假设了只有uart0会触发sub src pnd。[ 本帖最后由 wt133664 于 2009-8-2 10:10 编辑 ]
可以验证是串口中断出了问题
#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 编辑 ]
是否与mode有关?
在IRQ mode这样做有问题?回到SVC mode就可以了?以前在开发板上没出现这个问题。在开发板上,敲一个字符,立刻产生一个中断。而在skyeye上,敲了回车后才会产生中断。这两者存在差异。
[ 本帖最后由 wt133664 于 2009-8-2 11:15 编辑 ]
原因
在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%x0x%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.ulcon;
break;
case UCON:
*data = io.uart.ucon;
break;
case UFCON:
*data = io.uart.ufcon;
break;
case UMCON:
*data = io.uart.umcon;
break;
case UTRSTAT:
*data = io.uart.utrstat;
break;
case UERSTAT:
*data = io.uart.uerstat;
break;
case UFSTAT:
*data = io.uart.ufstat;
break;
case UMSTAT:
*data = io.uart.umstat;
break;
case URXH:
/* receive char
* */
*data = io.uart.urxh;
io.uart.utrstat &= (~0x1); /* clear strstat register bit */
io.uart.ufstat &= ~(0x1); /* 2007-02-09 by Anthony Lee : for 0 bytes */
break;
case UBRDIV:
*data = io.uart.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.ulcon = data;
break;
case UCON:
io.uart.ucon = data;
break;
case UFCON:
io.uart.ufcon = data;
break;
case UMCON:
io.uart.umcon = data;
break;
case UTRSTAT:
io.uart.utrstat = data;
break;
case UERSTAT:
io.uart.uerstat = data;
break;
case UFSTAT:
io.uart.ufstat = data;
break;
case UMSTAT:
io.uart.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.utrstat |= 0x6; //set strstat register bit
if ((io.uart.ucon & 0xc) == 0x4) {
s3c2410x_set_subsrcint (UART_INT_TXD << (index * 3));
s3c2410x_update_int (state);
}
}
break;
case UBRDIV:
io.uart.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 = data;
return;
}
switch (addr) {
case SRCPND:
fprintf(stderr, "write srcpnd step 1: 0x%x0x%x\n", io.subsrcpnd, io.srcpnd);
io.srcpnd &= (~data & INT_MASK_INIT);
fprintf(stderr, "write srcpnd step 2: 0x%x0x%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%x0x%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%x0x%x\n", io.subsrcpnd, io.srcpnd);
io.subsrcpnd &= (~data & INT_SUBMSK_INIT);
fprintf(stderr, "write sub_srcpnd step 2: 0x%x0x%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 = data;
break;
case BANKCON1:
io.memctl.bankcon = data;
break;
case BANKCON2:
io.memctl.bankcon = data;
break;
case BANKCON3:
io.memctl.bankcon = data;
break;
case BANKCON4:
io.memctl.bankcon = data;
break;
case BANKCON5:
io.memctl.bankcon = data;
break;
case BANKCON6:
io.memctl.bankcon = data;
break;
case BANKCON7:
io.memctl.bankcon = 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 编辑 ]
原因(续)
skyeye_uart.cint 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;
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;
}
原因(续)
测试用源码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*/
}
原因(续)
测试结果//'Enter' ,这里显示不出来。从下面的打印来看,流程正常
skyeye_uart_read 0xa
s3c2410x_update_int 0x930x100000000
s3c2410x_uart_read(UART0: 0x10, 0x7)
s3c2410x_uart_read(UART0: 0x24, 0xa)
write sub_srcpnd step 1: 0x930x10000000
write sub_srcpnd step 2: 0x00x10000000
write srcpnd step 1: 0x00x10000000
write srcpnd step 2: 0x00x0
write srcpnd step 3: 0x920x0
d //实际上输入了两个字符'd'与'Enter',流程正常
skyeye_uart_read 0x64 //read 'd' from stdin and set sub src pnd
s3c2410x_update_int 0x930x100000000 //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: 0x930x10000000 //clear sub src pnd for the 'd'
write sub_srcpnd step 2: 0x00x10000000
skyeye_uart_read 0xa //read 'Enter' from stdin and set sub src pnd
s3c2410x_update_int 0x930x100000000 //araise the second int
write srcpnd step 1: 0x930x10000000//clear src pnd for 'd'
write srcpnd step 2: 0x930x0
s3c2410x_update_int 0x930x100000000 //araise the third int cos sub src pnd setted
write srcpnd step 3: 0x930x10000000
s3c2410x_uart_read(UART0: 0x10, 0x7) //read rx stat
s3c2410x_uart_read(UART0: 0x24, 0xa) //read rx content
write sub_srcpnd step 1: 0x930x10000000 //clear sub src pnd for 'Enter'
write sub_srcpnd step 2: 0x00x10000000
write srcpnd step 1: 0x00x10000000 //clear src pnd for 'Enter'
write srcpnd step 2: 0x00x0
write srcpnd step 3: 0x920x0
dd //实际上输入了三个字符'd'、'd'与'Enter',流程异常
skyeye_uart_read 0x64 //read the first 'd' from stdin and set sub src pnd
s3c2410x_update_int 0x930x100000000 //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: 0x930x10000000 //clear sub src pnd for the first 'd'
write sub_srcpnd step 2: 0x00x10000000
skyeye_uart_read 0x64 //read the second 'd' from stdin and set sub src pnd
s3c2410x_update_int 0x930x100000000 //araise the second int
write srcpnd step 1: 0x930x10000000 //clear src pndfor the first 'd'
write srcpnd step 2: 0x930x0
s3c2410x_update_int 0x930x100000000 //araise the third int cos sub src pnd setted
write srcpnd step 3: 0x930x10000000
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 0x930x100000000 //araise the fourth int
write sub_srcpnd step 1: 0x930x10000000 //clear sub src pnd for the second 'd'
write sub_srcpnd step 2: 0x00x10000000
write srcpnd step 1: 0x00x10000000 //clear src pnd for the second 'd'
write srcpnd step 2: 0x00x0
write srcpnd step 3: 0x920x0
出问题的是红色标注的语句,它们的顺序反了,最后的'Enter'产生的中断被清掉了,导致再也无法向stdin输入,即敲键盘输入。按照我的理解,从stdin读下一个字符所产生的中断,应发生在处理完上一个字符所产生的中断之后,即clear sub src pnd并且clear src pnd之后。
[ 本帖最后由 wt133664 于 2009-8-4 06:48 编辑 ]
一种规避的方法
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 编辑 ]
页:
[1]