当您禁用中断时(使用clix86中的指令),究竟发生了什么?
PIC是否等待您打开中断,并在发生这种情况时触发中断?(如果是这样,它等待多长时间,如果时间'到期'会发生什么?)
中断 - 从设备的角度来看 - 是否被发送到"黑洞",没有响应?
PIC是否以某种方式告诉设备"CPU正忙"或什么?
还是会发生其他事情?
另外,你如何处理一个你不知道如何处理的中断?
有没有办法告诉PIC(或设备,如果你不知道设备是什么),"是的,我收到你的消息,但我不知道该怎么办"?
我正在开发一个具有严格启动时间要求的项目.目标体系结构是基于IA-32的处理器,以32位保护模式运行.确定可以改进的一个领域是当前系统动态初始化处理器的IDT(中断描述符表).由于我们没有任何即插即用设备且系统相对静态,我希望能够使用静态构建的IDT.
然而,由于8字节中断门描述符分割ISR地址,这证明对于IA-32拱是麻烦的.ISR的低16位出现在描述符的前2个字节中,其他一些位填充接下来的4个字节,最后ISR的最后16位出现在最后2个字节中.
我想使用const数组来定义IDT,然后简单地将IDT寄存器指向它,如下所示:
typedef struct s_myIdt {
unsigned short isrLobits;
unsigned short segSelector;
unsigned short otherBits;
unsigned short isrHibits;
} myIdtStruct;
myIdtStruct myIdt[256] = {
{ (unsigned short)myIsr0, 1, 2, (unsigned short)(myIsr0 >> 16)},
{ (unsigned short)myIsr1, 1, 2, (unsigned short)(myIsr1 >> 16)},
Run Code Online (Sandbox Code Playgroud)
等等
显然这不起作用,因为在C中执行此操作是非法的,因为myIsr不是常量.它的值由链接器解决(只能进行有限的数学运算)而不是编译器.
关于如何做到这一点的任何建议或其他想法?
谢谢,
我在AVR32上有一个中断服务路由.我需要从中断状态寄存器中读取以取消中断.但是我没有使用读取的结果.我宁愿不使用asm指令,但我担心gcc会将读取优化为虚拟变量.什么是正确的方法?
目前我有:
uint32_t tmp = *(volatile uint32_t *)INTERRUPT_STATUS_REG_ADDRESS;
Run Code Online (Sandbox Code Playgroud)
tmp也应该波动吗?我担心如果没有使用tmp,gcc会跳过读取.
我想知道在以下情况下,临时volatile限定符是否会产生正确的行为.假设ISR收集数组中的值,并且一旦收集到足够的值,它就表示准备就绪.
int array[10]; // observe no volatile here
int idx = 0; // neither here
volatile bool ready = false; // but here
Run Code Online (Sandbox Code Playgroud)
这里的ISR是伪代码
ISR() {
if (idx < 10)
array[idx++] = ...;
ready = (idx >= 10);
}
Run Code Online (Sandbox Code Playgroud)
假设我们可以保证这array将是只读后 ready发出信号,和元素是通过特定的方法来访问只:
int read(int idx) {
// temporary volatile semantics
volatile int *e = (volatile int*)(array + idx);
return *e;
}
Run Code Online (Sandbox Code Playgroud)
这似乎是根据cpp-reference允许的
向volatile类型转换非易失性值无效.要使用易失性语义访问非易失性对象,必须将其地址强制转换为指向易失性的指针,然后必须通过该指针进行访问.
为了完整起见,主程序执行以下操作
void loop() {
if (ready) {
int …Run Code Online (Sandbox Code Playgroud) 我一直在尝试按照James Molloy 的本教程创建一个 ISR 处理程序
,但我被卡住了。每当我抛出软件中断时,通用寄存器和数据段寄存器都会被推送到堆栈中,而 CPU 会自动推送变量。然后将数据段更改为 0x10(内核数据段描述符)的值,从而更改权限级别。然后在处理程序返回后,这些值被pop编辑。但是,无论何时ds更改中的值,都会抛出错误代码为 0x2544 的 GPE,几秒钟后 VM 会重新启动。(链接器和编译器 i386-elf-gcc ,汇编器 nasm)
我尝试在hlt指令之间放置指令以定位哪个指令正在抛出 GPE。在那之后,我能够找到“mov ds,ax”指令。我尝试了各种方法,例如删除由引导程序代码初始化的堆栈以删除代码的权限更改部分。我可以从公共存根返回的唯一方法是删除更改权限级别的代码部分,但是当我想转向用户模式时,我仍然希望它们保留。
这是我常用的存根:
isr_common_stub:
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
xor eax,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call isr_handler
xor eax,eax …Run Code Online (Sandbox Code Playgroud) 我目前正在使用 Atmel AVR 微控制器 (gcc),但希望答案一般适用于微控制器世界,即通常是单线程但带有中断。
我知道volatile在访问可以在 ISR 中修改的变量时如何在 C 代码中使用。例如:
uint8_t g_pushIndex = 0;
volatile uint8_t g_popIndex = 0;
uint8_t g_values[QUEUE_SIZE];
void waitForEmptyQueue()
{
bool isQueueEmpty = false;
while (!isQueueEmpty)
{
// Disable interrupts to ensure atomic access.
cli();
isQueueEmpty = (g_pushIndex == g_popIndex);
sei();
}
}
ISR(USART_UDRE_vect) // some interrupt routine
{
// Interrupts are disabled here.
if (g_pushIndex == g_popIndex)
{
usart::stopTransfer();
}
else
{
uint8_t value = g_values[g_popIndex++];
g_popIndex &= MASK;
usart::transmit(value);
}
}
Run Code Online (Sandbox Code Playgroud)
因为 …
使用RTOS(例如FreeRTOS)时,每个线程都有单独的堆栈空间。那么,ISR(中断服务程序)呢,它们在内存中是否有单独的堆栈?还是可以配置的?
如果它们没有用于存储在ISR中声明的局部变量的堆栈?
我无法理解“待处理中断”这个词。我的意思是,我看到异步事件的方式就像“时间、潮汐和中断”不等待。
那么这个待处理中断是什么呢?我怎样才能满足一个已经过去但已经消失的请求。
有人可以用一个使用场景来解释一下吗?
编辑:从定义上来说,它是可以理解的(英语意义上),但是如果我应该处理之前发生的中断,我是否正在查看硬件设备上的一些数据缓冲?
我正在STM32L4上开发裸机项目,并且从现有代码库开始。
ISR已通过以下方式实现:
是清除标志的正确方法吗?不应该在ISR的一开始就清除标志吗?我的理解是,如果在步骤2中第二次发生相同的外围事件,它将不会引发第二个IRQ,因此它将丢失。另一方面,如果您尽快清除该标志,则第二个事件将使该中断产生脉冲,该中断的CPU状态将变为“待处理且活动”:将发生第二个IRQ。
PS:从《 STM32处理器编程手册》中,我读到:“ STM32中断既对电平敏感又对脉冲敏感”。