我正在s3c44b0x(ARM7TDMI)中实现一个uart队列,uart0 ISR会将char排入队列,而主循环将使char出列队列。然而,当出列时,返回的值(在R0中)可能不是从队列中出队的值,并且我从出列函数返回后发现R0被违反(输入'v'cont。,并且test()在主要部分中环): 希望得到你的帮助。
CHAR cliDequeue(void)
{
CHAR bTmpCh;
if (gwCliQSize == 0)
{
return 0;
}
bTmpCh = gabCliQ[gwCliQTail]; /* char is enqueued in the Q in ISR */
gwCliQTail++;
gwCliQTail %= MAX_CLI_QUEUE_LEN;
ASSERT(gwCliQSize > 0);
gwCliQSize--;
ASSERT(bTmpCh == 'v'); /* will not assert */
//uartPutChar(bTmpCh);
return bTmpCh;
}
void test(void)
{
CHAR bTestCh;
bTestCh = cliDequeue();
if (bTestCh != 0)
{
ASSERT(bTestCh == 'v'); /* assert here ! */
uartPutChar(bTestCh);
}
}
答案 0 :(得分:0)
我们没有足够的信息/背景来明确回答。如果您发布了相应的汇编代码,以便我们可以看到事情是如何/何时被移动的,那么它也会很有帮助。超出R0。无论如何,您发布的C代码会立即想到一些事情。
(0)变量和中断之间是否共享变量主循环声明为volatile
?
(1)
在CliDequeue
中,您正在访问与ISR共享的阵列。它似乎是一个单一的读者/单一作家构造,所以这不会自动坏,但你的家务管理不是密不透风。
例如,您必须确保满足的一个不变量是队列大小&尾指针同步。然而,除非在禁用中断的情况下调用此例程,否则您的尾部指针和队列大小不会作为单个事务进行调整。
(2)
此外,我猜测gwCliQSize
也在中断中调整(在ISR中递增,在应用程序中递减)。另一种竞争条件。要执行gwCliQSize--
,在幕后您可能正在从内存读取寄存器,递减寄存器,然后将其写回。如果从内存中读取5到R1,然后中断触发并将其递增到6,然后退出ISR,寄存器递减和写回(值为4),会发生什么。
(3)
最后,有可能(虽然不太可能)bTmpCh
或bTestCh
存储在堆栈中,并且您的堆栈被另一个任务/中断/等等损坏/破坏。所以当你的断言失败时,你认为它的R0已经被破坏了,但实际上它可能是在返回之前值移入R0,或者从R0移出到堆栈变量中的值被破坏了。
我已经吃饱了。还有其他可能性,但是从你发布的内容(而不是发布内容)来看,这是不可能肯定的。
P.S。如果您使用过调试器,它确实是&字面上R0的值被破坏,而不仅仅是队列中字符的值,它指向调度程序/上下文切换器/ ISR之前或后导码中的问题......
答案 1 :(得分:0)
这是汇编代码: 对于测试():
0x00001308 E92D4010 STMDB R13!,{R4,R14}
37: bTestCh = cliDequeue();
38:
0x0000130C EB000207 BL cliDequeue(0x00001B30)
0x00001310 E1A04000 MOV R4,R0
39: if (bTestCh != 0)
40: {
0x00001314 E3540000 CMP R4,#pTest(0x00000000)
0x00001318 0A000007 BEQ 0x0000133C
41: ASSERT(bTestCh == 'v');
0x0000131C E1A00000 NOP
0x00001320 E3540076 CMP R4,#0x00000076
0x00001324 0A000001 BEQ 0x00001330
0x00001328 E1A00000 NOP
0x0000132C EAFFFFFE B 0x0000132C
0x00001330 E1A00000 NOP
42: uartPutChar(bTestCh);
43: }
0x00001334 E1A00004 MOV R0,R4
0x00001338 EB00014A BL uartPutChar(0x00001868)
44: }
45:
46: int main(void)
0x0000133C E8BD4010 LDMIA R13!,{R4,R14}
0x00001340 E12FFF1E BX R14
对于cliDequeu(),BTW,gwCliQSize定义为 UINT32 volatile gwCliQSize;
0x00001B30 E59F00D4 LDR R0,[PC,#0x00D4]
0x00001B34 E5900000 LDR R0,[R0]
0x00001B38 E3500000 CMP R0,#pTest(0x00000000)
0x00001B3C 1A000001 BNE 0x00001B48
78: return 0;
79: }
80:
81: bTmpCh = gabCliQ[gwCliQTail];
82: gwCliQTail++;
83: gwCliQTail %= MAX_CLI_QUEUE_LEN;
84: ASSERT(gwCliQSize > 0);
85: gwCliQSize--;
86:
87: //chCheck(bTmpCh);
88: ASSERT(bTmpCh == 'v'); /* will not assert */
89: //uartPutChar(bTmpCh);
90:
91: return bTmpCh;
0x00001B40 E3A00000 MOV R0,#pTest(0x00000000)
92: }
93:
94:
95: void cliQInit(void)
0x00001B44 E12FFF1E BX R14
81: bTmpCh = gabCliQ[gwCliQTail];
0x00001B48 E59F00C0 LDR R0,[PC,#0x00C0]
0x00001B4C E59F20C4 LDR R2,[PC,#0x00C4]
0x00001B50 E5922000 LDR R2,[R2]
0x00001B54 E7D01002 LDRB R1,[R0,R2]
82: gwCliQTail++;
0x00001B58 E59F00B8 LDR R0,[PC,#0x00B8]
0x00001B5C E5900000 LDR R0,[R0]
0x00001B60 E2800001 ADD R0,R0,#0x00000001
0x00001B64 E59F20AC LDR R2,[PC,#0x00AC]
0x00001B68 E5820000 STR R0,[R2]
83: gwCliQTail %= MAX_CLI_QUEUE_LEN;
0x00001B6C E2820000 ADD R0,R2,#pTest(0x00000000)
0x00001B70 E5900000 LDR R0,[R0]
0x00001B74 E20000FF AND R0,R0,#0x000000FF
0x00001B78 E5820000 STR R0,[R2]
84: ASSERT(gwCliQSize > 0);
0x00001B7C E1A00000 NOP
0x00001B80 E59F0084 LDR R0,[PC,#0x0084]
0x00001B84 E5900000 LDR R0,[R0]
0x00001B88 E3500000 CMP R0,#pTest(0x00000000)
0x00001B8C 1A000001 BNE 0x00001B98
0x00001B90 E1A00000 NOP
0x00001B94 EAFFFFFE B 0x00001B94
0x00001B98 E1A00000 NOP
85: gwCliQSize--;
86:
87: //chCheck(bTmpCh);
0x00001B9C E59F0068 LDR R0,[PC,#0x0068]
0x00001BA0 E5900000 LDR R0,[R0]
0x00001BA4 E2400001 SUB R0,R0,#0x00000001
0x00001BA8 E59F205C LDR R2,[PC,#0x005C]
0x00001BAC E5820000 STR R0,[R2]
88: ASSERT(bTmpCh == 'v'); /* will not assert */
89: //uartPutChar(bTmpCh);
90:
0x00001BB0 E1A00000 NOP
0x00001BB4 E3510076 CMP R1,#0x00000076
0x00001BB8 0A000001 BEQ 0x00001BC4
0x00001BBC E1A00000 NOP
0x00001BC0 EAFFFFFE B 0x00001BC0
0x00001BC4 E1A00000 NOP
91: return bTmpCh;
92: }
93:
94:
95: void cliQInit(void)
0x00001BC8 E1A00001 MOV R0,R1
0x00001BCC EAFFFFDC B 0x00001B44
for cliEnqueue:
void cliEnqueue(CHAR bC)
{
if (gwCliQSize == MAX_CLI_QUEUE_LEN)
{
ASSERT(0);
}
gabCliQ[gwCliQHeader] = bC;
gwCliQHeader++;
gwCliQHeader %= MAX_CLI_QUEUE_LEN;
gwCliQSize++;
}
组件:
0x00001A5C E59F11AC LDR R1,[PC,#0x01AC]
0x00001A60 E59F21AC LDR R2,[PC,#0x01AC]
0x00001A64 E5922000 LDR R2,[R2]
0x00001A68 E7C10002 STRB R0,[R1,R2]
25: gwCliQHeader++;
0x00001A6C E59F11A0 LDR R1,[PC,#0x01A0]
0x00001A70 E5911000 LDR R1,[R1]
0x00001A74 E2811001 ADD R1,R1,#0x00000001
0x00001A78 E59F2194 LDR R2,[PC,#0x0194]
0x00001A7C E5821000 STR R1,[R2]
26: gwCliQHeader %= MAX_CLI_QUEUE_LEN;
0x00001A80 E2821000 ADD R1,R2,#pTest(0x00000000)
0x00001A84 E5911000 LDR R1,[R1]
0x00001A88 E20110FF AND R1,R1,#0x000000FF
0x00001A8C E5821000 STR R1,[R2]
27: gwCliQSize++;
0x00001A90 E59F1174 LDR R1,[PC,#0x0174]
0x00001A94 E5911000 LDR R1,[R1]
0x00001A98 E2811001 ADD R1,R1,#0x00000001
0x00001A9C E59F2168 LDR R2,[PC,#0x0168]
0x00001AA0 E5821000 STR R1,[R2]
28: }
29:
30:
31: static void chCheck(CHAR cTmpChar)
32: {
0x00001AA4 E12FFF1E BX R14
0),1):gwCliQSize和数组在ISR和主循环之间共享。
2)gwCliQSize定义为volatile 3)从组件中,bTestCh是R4(从R0移动)而bTmpCh是R1(在B之前移到R0) 4)我正在使用J-LINK,但没有J-LINK(从闪存运行),它仍然存在。