问题描述
我正在使用工具链,v。4.8.2,on LinuxMint 17.2 64b。
我是在业余爱好者的层面上,尝试使用TM4C123G板和其通常的功能(编码各种闪烁,uart的东西...),但总是试图尽可能保持尽可能接近金属,而无需使用其他库(例如CMSIS ...)。也没有IDE(CCS,Keil ...),只是Linux终端窗口,板子和我...所有这些都是为了教育目的。
问题:我我试图实现通常的中断功能,如:
EnableInt(清除位0,位I,特殊注册表PRIMASK):
CPSIE I
WaitForInt: p>
WFI
DisableInt:
CPSID I
例如,我将这个函数添加到我的.c文件中的EnableInt:
void EnableInt void)
{__asm(cpsie i\\\
);
}
...这个编译,但执行似乎不能正常工作最简单的blinky.c版本,一旦我在C代码中调用了EnableInt(),我就无法获得任何LED动作)。可以在找到blinky.c代码。
将这些中断程序写入.c文件(理想情况下不使用其他库,而只是设置/清除相应寄存器的位)... ...的正确方式是什么?
编辑:删除bx lr指令 - 但是EnableInt()似乎没有任何更好的效果 - 仍在寻找解决方案。
EDIT2:实际上该功能EnableInt ()定义如上,现在正在工作。我的SysTick_Handler被映射到启动文件中的中断向量表不正确(而我的原始问题是我在Edit1中删除的bx lr指令)。
您的Tivia MCU所集成的ARM Cortex-M4 CPU基本上不需要软件环境,退出中断处理程序。唯一的要求是使用AAPCS调用标准,如果为此CPU编译,则应为gcc的默认值。
CPU由一些紧密耦合的核心 ARM提供的外设。这些是大多数(如果不是全部)Cortex-M3 / 4 MCU的标准。 MCU供应商可以配置一些功能,但基本操作总是相同的。
为了简化软件开发,ARM已经推出了CMSIS软件标准。这至少包括一些头文件,它们统一对核心外设的访问和使用特殊的CPU指令。其中包括处理特殊CPU寄存器(如PRIMASK,BASEMASK,OPTION等)的内在函数。另一个标题提供了核心外设和功能的定义,以便操作其中的一些,其中简单的访问不足。
因此,这些外设之一支持CPU进行中断处理:
NVIC
(嵌套向量中断控制器)。这个优先次序将中断相互之间的中断,并将中断向量提供给使用该向量的CPU来获取中断处理程序的地址。 NVIC还包括使能位所有中断源。因此,要由CPU处理中断,对于典型的MCU,您必须在两个或三个位置启用中断:
- PRIMASK / BASEMASK在CPU中:最后一道防线。这些是全局中断门。 `PRIMASK类似于较小CPU的状态寄存器中的中断使能位,BASEMASK是中断优先级分辨率的一部分(只是忽略它的开始)。
- NVIC中断适用于每个外设中断源。例如定时器,UART,SPI等。许多外设有多个内部源连接到这个NVIC线。 (例如UART rx和tx中断)。
- 外设本身的中断使能位。例如。 UART rx-interrupt,tx中断,rxerror中断等。
某些外设可能没有内部位,所以最后一个可能是缺少。
要使工作正常,您应该阅读参考文献(Family Guide)或类似),那么通常会有一些Cortex-M4例如ST有一个用于STM32系列)。您还应该从ARM获取文档(可以免费下载)。
最后,您需要MCU供应商的CMSIS头(TI TI)。这些应该为您的MCU量身定制。你可能必须提供一些`#define'。
而且,是的,这是一些很多东西要阅读。但是,这是值得的努力。或者,您可以从一本书开始。有一些可能有助于首先获得整个图片(从单个文档中获取很难 - 但可能)。
I am using arm-none-eabi-gcc toolchain, v 4.8.2, on LinuxMint 17.2 64b.
I am, at hobbyist level, trying to play with a TM4C123G board and its usual features (coding various blinkies, uart things...) but always trying to remain as close to the metal as possible without using other libraries (eg CMSIS...) whenever possible. Also no IDE (CCS, Keil...), just Linux terminal windows, the board and I... All that mostly for education purpose.
The issue : I am stuck trying to implement the usual interrupt functions like :
EnableInt (clearing bit 0, bit I, of special registry PRIMASK) :
CPSIE I
WaitForInt :
WFI
DisableInt :
CPSID I
Eg, I added this function to my .c file for EnableInt :
void EnableInt(void)
{ __asm(" cpsie i\n");
}
... this compiles but the execution does not seem to work properly (in the simplest blinky.c version, I cannot get any LED action once I have called EnableInt() in the C code). The blinky.c code can be found here.
What would be the proper way to write these interrupt routines in a .c file (ideally without using other libraries, but just setting/clearing bits of the appropriate registers...)?
EDIT : removed the bx lr instructions - but EnableInt() does not seem to work any better - still looking for a solution.
EDIT2 : Actually the function EnableInt(), defined as above, is now working. My SysTick_Handler was mapped incorrectly to the Interrupt Vector table in the startup file (while my original problem was the bx lr instructions which I removed in Edit1).
The ARM Cortex-M4 CPU which your Tivia MCU incorporates does basically not require the software environment to take special action for entry/exit the interrupt handler. The only requirement is to use the AAPCS calling standard, which should be the default with gcc if compiling for this CPU.
The CPU is supported by some tightly coupled "core" peripherals provided by ARM. These are standard for most (if not all) Cortex-M3/4 MCUs. MCU vendors can configure some features, but the basic operation is always the same.
To simplify software development, ARM has introduced the CMSIS software standard. This at least consists of some header-files which unify access to the core-peripherals and use of special CPU instructions. Among those are intrinsics to manipulate the special CPU registers like PRIMASK, BASEMASK, OPTION, etc. Another header provides definitions of the core peripherals and functions to manipulate some of them where a simple access is not sufficient.
So, one of these peripherals supports the CPU for interrupt handling: The NVIC
(nested vector-interrupt controller). This prioritises interrupts aagains each other and provides the interrupt vector to the CPU which uses this vector to fetch the address of the interrupt handler.
The NVIC also includes enable-bits for all interrupt sources. So, to have an interrupt processed by the CPU, for a typical MCU you have to enable the interrupt in two or three locations:
- PRIMASK/BASEMASK in the CPU: last line of defense. These are the global interrupt gates. `PRIMASK is similar to the interrupt-enable bit in the status-register of the smaller CPUs, BASEMASK is part of interrupt-priority resolution (just ignore it for the beginning).
- NVIC interrupt-enable bit for each peripheral interrupt source. E.g Timer, UART, SPI, etc. Many peripherals have multiple internal sources tied to this NVIC-line. (e.g UART rx and tx interrupt).
- The interrupt-enable bits in the peripheral itself. E.g. UART rx-interrupt, tx interrupt, rxerror interrupt, etc.
Some peripherals might not have internal bits, so the last one might be missing.
To get things working, you should read the Reference Manaul (Family Guide, or similar), then there is often some "porgramming the Cortex-M4" howto (e.g ST has one for the STM32 series). You should also get the documents from ARM (they are available for free download).
Finally you need the CMSIS headers from your MCU vendor (TI here). These should be tailored for your MCU. You might have to provide some `#define's.
And, yes, this is quite some stuff to read. But imo it is worth the effort. Alternatively you might start with a book. There are some out which might be helpful to get the whole picture first (it is really hard to get from the single documents - yet possible).
这篇关于如何在C中编写ARM中断函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!