2010-05-02 23 views
7

我有一些代码需要运行,因为特定的中断发生。哪些Cortex-M3中断可用于通用目的?

我不想在中断本身的上下文中执行它,但我也不希望它在线程模式下执行。

我想运行它的优先级低于导致其运行的高级中断,但优先级高于线程级别(以及其他一些中断)。

我想我需要使用其他中断处理程序之一。

哪些是最好的使用和最好的方式来调用它们?

目前我正在计划仅使用中断处理程序来处理一些我不使用的外设,并通过直接通过NVIC设置位来调用它们,但我希望有更好,更正式的方法。

谢谢,

回答

15

ARM Cortex支持一种非常特殊的称为PendSV的异常。看来你可以完全使用这个例外来完成你的工作。几乎所有针对ARM Cortex的抢占式RTOS都使用PendSV来实现上下文切换。

为了使其工作,您需要优先PendSV低(向NVIC中的PRI_14寄存器写入0xFF)。您还应该优先考虑PendSV以上的所有IRQ(在NVIC的相应优先级寄存器中写入较低的数字)。当您准备处理整个消息,从高优先级ISR触发PendSV的:然后

*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV 

在ARM Cortex CPU将完成你的ISR和可能被它抢占所有其他的ISR,并最终将其将会尾随PendSV异常。这是解析消息的代码应该在的地方。

请注意,PendSV可能会被其他ISR抢占。这一切都很好,但是您显然需要记住通过一段关键代码来保护所有共享资源(简要地禁用和启用中断)。在ARM Cortex中,通过执行__asm(“cpsid i”)来禁止中断,并通过__asm(“cpsie i”)启用中断。 (大多数C编译器为此提供了内置的内部函数或宏。)

+0

谢谢,米罗!我到处搜索如何触发PendSV中断的信息,这是我终于找到它的地方!虽然我想如果我更仔细地阅读了我的Cortex M3 r1p1技术参考手册,我会在描述中断控制状态寄存器的页面上找到它: http://infocenter.arm.com/help/topic/com.arm .doc.ddi0337e/DDI0337E_cortex_m3_r1p1_trm.pdf – 2010-06-18 02:21:04

+0

从我的阅读中,几乎CortexM3上的所有RTOS都使用Systick Timer中断(45十进制,二进制二进制)来运行其调度程序。那么PendSV是启动一种特殊的“系统调用”的方式?希望我明白这一点。 – 2010-07-08 00:02:15

+1

@WarrenP:PendSV用于实际处理上下文切换。 sys tick用于循环任务 - sys tick会一般设置PendSV。 – 2011-10-02 20:48:52

3

您是否正在使用RTOS?通常,这种类型的事情将通过具有高优先级的线程来处理,该高优先级的线程被中断信号通知来做一些工作。

如果你不使用RTOS,你只有几项任务,并且由中断启动的工作不是太耗费资源,可能最简单的做法是在上下文中完成高优先级的工作中断处理程序。如果这些条件不成立,那么实施你所说的将是基本的多任务操作系统本身的开始。这本身可能是一个有趣的项目,但如果您只是想完成工作,您可能需要考虑一个简单的RTOS。

既然你提到你正在做的工作的一些细节,下面是我是如何处理在过去类似的问题的概述:

对于处理接收到的数据通过UART一个方法,我已经在处理不完全支持任务的简单系统时(即,简单的while循环中的任务是简单的),应该使用从UART接收的数据的共享队列。当UART中断触发时,数据从UART的RDR(接收数据寄存器)读取并放入队列中。以这种方式处理队列指针没有损坏的技巧是小心地使队列指针变为易失性的,并且确保只有中断处理程序修改尾指针并且只有正在读取数据的'foreground'任务关闭队列修改头指针。甲高级概述:

  • 生产者(UART的中断处理程序):

    1. queue.headqueue.tail成当地人;
    2. 递增本地尾指针(不是实际的queue.tail指针)。如果你增加了队列缓冲区的末尾,将它包装到队列缓冲区的开始位置。
    3. 比较local.taillocal.head - 如果它们相同,则队列已满,您必须执行任何错误处理。
    4. 否则你可以写入新的数据到local.tail
    5. 只有现在你可以设置queue.tail == local.tail
    6. 从中断返回(或者办理其他UART相关的任务,如果合适的话,喜欢读书从传送队列)
  • 消费者(前台 '任务')

    1. queue.headqueue.tail成当地人;
    2. if local.head == local.tail队列为空;返回让下一个任务做一些工作
    3. 读取local.head指向的字节
    4. 增量local.head并在必要时包装它;
    5. 设置queue.head = local.head
    6. 转至步骤1

确保queue.headqueue.tailvolatile(或汇编写这些位),以确保有没有顺序问题。

现在只要确保你的UART接收到的数据队列足够大,它就会保存前台任务有机会运行之前可能收到的所有字节。前台任务需要将队列中的数据放入其自己的缓冲区中,以构建消息给“消息处理器”任务。

+0

我没有使用RTOS。 我得到的是一个高优先级的中断,每次我通过串行接收字节时都会关闭。 它以高(低优先级数)优先级运行,以便我不会错过字节。 当收到完整的信息后,我需要做一些工作,虽然我打算让这项工作在性质上完全不受阻碍,但我不想限制自己有最大限度的时间允许它(我不会写这个代码)。 我没有做任何先发制人的多任务处理。 – 2010-05-02 10:37:55

+0

串行数据的速度是多少?速率真的如此之高,或其他中断处理程序如此糟糕的设计,以至于中断优先级会有所不同?为什么不使用DMA传输来减少中断频率或完全避免它们? – Clifford 2010-05-02 10:44:26

+0

我们在57600下运行,但可能会移动到115200.我不能在路上使用DMA传输,因为什么样的信号表明消息的​​结束是字节超过某个特定值的时间。我有三个需要运行的任务:1.一个串行消息接收器/发送器2.一个消息处理器3.一些背景负载。中间的一个是状态机,所以它被认为几乎没有工作(只是更新状态)。我希望他们能够在不同的中断级别运行,因为在较低级别缺少最后期限不太难以调试(对我而言)。 – 2010-05-02 11:03:46

1

“更正式的方式”或更传统的方法是使用基于优先级的抢占式多任务调度程序和“延迟中断处理程序”模式。

+0

@Clifford:你有链接到“延迟中断模式”的描述吗? – simon 2010-05-02 22:59:46

0

检查处理器文档。如果写入通常必须在中断内清除的位,则某些处理器会中断。我正在使用SiLabs c8051F344和规格表部分9.3.1:

“软件可以通过将任何中断挂起标志设置为逻辑1来模拟中断。如果中断标志被使能,中断请求将会将被生成,并且CPU将会引导到与中断挂起标志关联的ISR地址。“

1

您要求的内容在Cortex-M3上非常简单。您需要启用STIR寄存器,以便用软件触发低优先级的ISR。当高优先级的ISR完成关键任务时,它会触发低优先级中断并退出。如果没有什么更重要的事情发生,NVIC将链接到低优先级的处理程序。

相关问题