2017-08-31 55 views
2

我从来不会相信我可以在2017年进入这个位置,但是我有一个目标系统(LPC2138),尽管我尝试了很多尝试,但绝对拒绝处理中断。由于各种原因,我确实需要使用它,所以这只是一个相关的问题。该应用程序是'中断友好'的,具有多个异步I/O流(SPI,UART)以及定时器信号。对我有利的一件事是,与我的实时要求相比,处理器速度非常快,所以我有充足的闲暇可用。嵌入式编程无中断

我坚持的方法是在一个大的轮询循环中完成整个事情,包括3个FIFO来处理I/O。快速浏览它似乎是可行的,有没有人根据经验有任何意见?

中断问题不是微不足道的,100%平台兼容的hello world片段直接脱离Web失败,当他们运行系统崩溃时处于混乱状态。如果确实发生了某人在某处知道的明确的专家修复,那么将非常感谢。

+0

提供了一个不起作用的最小程序...... –

+1

只要您能够满足您的时间,就可以更容易地编写和调试,只在您绝对必须中断时才会中断轮询,没有任何问题。 –

+0

我/我们对手臂和其他手臂有很多经验。我的猜测是你的例子是相对巨大的,并得到你的脚湿不需要... –

回答

4

不知道你的应用程序和你的目标平台,我不能给你一个明确的答案!

但是,您是根据经验征询意见的。这里有:-)

  1. 您提到了实时要求。没有中断的工作实际上可以帮助!当我们对硬实时要求的项目做了项目时,我们没有使用使用中断。假设我们正在处理传入的数据流,并且正好有20个我们来处理一个单词,否则我们会错过下一个单词,并且正在处理一个被中断的单词。砰!失去了下一个。所以我们做了很多投票。在不同的应用程序中,设计决策可能会不同,使用中断来处理时间关键型的工作,而牺牲非实时代码等等。我当时在店里工作的哲学非常反中断。

  2. 投票可能会“浪费”一些资源(不是真的浪费,因为你必须这么做:-))。但是你提到你的处理器足够快。如果你能满足你的速度要求,享受投票。在很多方面比中断更容易处理。你的程序可以更好地控制什么时候会发生什么。

  3. FIFO很好。他们软化你的实时需求。

  4. 我根本不知道你的hw设计,但是如果你有一个逻辑芯片和一个灵活的hw工程师(好吧,这是个矛盾:-)),你可以将你的一些输入路由到hw和hw逻辑来处理你的一些简单需求,并为你提供一个接口来使编写程序变得更容易(可以是针对你的特定需求进行优化的某种FIFO,例如,或者是一个轮询注册表,可以给你几个信息片断等)

所以,去吧!你会学到一种全新的方法,甚至有一些优点。

3

没有一个线索,你卡在哪里我们需要更多的信息,但也许一个小骨架将确认你至少做这些事情。你以前是做过一个arm7还是第一次,或者你对arm7/arm世界非常熟悉,但是不能让中断工作?

开始。s

.globl _start 
_start: 

.globl _start 
_start: 
    ldr pc,reset_handler 
    ldr pc,undefined_handler 
    ldr pc,swi_handler 
    ldr pc,prefetch_handler 
    ldr pc,data_handler 
    ldr pc,unused_handler 
    ldr pc,irq_handler 
    ldr pc,fiq_handler 
reset_handler:  .word reset 
undefined_handler: .word hang 
swi_handler:  .word hang 
prefetch_handler: .word hang 
data_handler:  .word hang 
unused_handler:  .word hang 
irq_handler:  .word irq 
fiq_handler:  .word hang 

reset: 
    ;@ (PSR_IRQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) 
    mov r0,#0xD2 
    msr cpsr_c,r0 
    ldr sp,=0x40002000 

    ;@ (PSR_FIQ_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) 
    mov r0,#0xD1 
    msr cpsr_c,r0 
    ldr sp,=0x40003000 

    ;@ (PSR_SVC_MODE|PSR_FIQ_DIS|PSR_IRQ_DIS) 
    mov r0,#0xD3 
    msr cpsr_c,r0 
    ldr sp,=0x40004000 

    bl notmain 
hang: b hang 

.globl PUT32 
PUT32: 
    str r1,[r0] 
    bx lr 

.globl GET32 
GET32: 
    ldr r0,[r0] 
    bx lr 

.globl dummy 
dummy: 
    bx lr 

.globl enable_irq 
enable_irq: 
    mrs r0,cpsr 
    bic r0,r0,#0x80 
    msr cpsr_c,r0 
    bx lr 

irq: 
    push {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 
    bl c_irq_handler 
    pop {r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} 
    subs pc,lr,#4 

是的,这是太多的寄存器...只需要易变的编译器覆盖其他。

notmain:

void c_irq_handler (void) 
{ 
} 
void notmain (void) 
{ 
    unsigned int ra; 
    for(ra=0;ra<100;ra++) dummy(ra); 
} 

flash.ld

MEMORY 
{ 
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000 
    ram : ORIGIN = 0x40000000, LENGTH = 0x1000 
} 
SECTIONS 
{ 
    .text : { *(.text*) } > rom 
    .bss : { *(.bss*) } > ram 
} 

猜我没有需要的.bss

构建

arm-none-eabi-as start.s -o start.o 
arm-none-eabi-gcc -O2 -c notmain.c -o notmain.o 
arm-none-eabi-ld -T flash.ld start.o notmain.o -o so.elf 
arm-none-eabi-objdump -D so.elf > so.list 
arm-none-eabi-objcopy so.elf -O binary so.bin 

总是检查你的so.list

他们有一个有趣的方式来确定,如果你有一个闪光出现或是否应该转储到他们的引导程序

准则有效的用户代码:预约的ARM中断向量 地址(0x0000 0014)应包含剩余中断向量的校验和 的2的补码。这使所有向量的校验 和为0

我没有做到这一点呢,能做到这一点用手或之后有一个程序来一起和做编程。

它改变这种

ldr pc,reset_handler 
ldr pc,undefined_handler 
ldr pc,swi_handler 
ldr pc,prefetch_handler 
ldr pc,data_handler 
.word 0xb8a06f58 @ldr pc,unused_handler 
ldr pc,irq_handler 
ldr pc,fiq_handler 

,这应该很好地工作。

如果这对小学完全没用,那么让我知道会删除这个答案没问题。

notmain.c

void PUT32 (unsigned int, unsigned int); 
unsigned int GET32 (unsigned int); 
void enable_irq (void); 

#define T0IR 0xE0004000 
#define T0TCR 0xE0004004 
#define T0PC 0xE0004010 
#define T0MCR 0xE0004014 
#define T0TC 0xE0004008 
#define T0MCR0 0xE0004018 

void c_irq_handler (void) 
{ 
    PUT32(T0IR,1); 
} 
void notmain (void) 
{ 
    PUT32(T0TCR,2); 
    PUT32(T0TCR,0); 
    PUT32(T0TC,0); 
    PUT32(T0MCR0,0x100000); 
    PUT32(T0MCR,0x1); //3); 
    PUT32(T0TCR,1); 
    while(1) 
    { 
     if(GET32(T0IR&1)) break; 
    } 
    PUT32(T0IR,1); 

    PUT32(T0TCR,2); 
    PUT32(T0TCR,0); 
    PUT32(T0TC,0); 
    PUT32(T0MCR0,0x100000); 
    PUT32(T0MCR,0x1); //3); 
    PUT32(T0IR,1); 
    enable_irq(); 
    PUT32(T0TCR,1); 
    while(1) continue; 

} 

刚刚碰伤了这一点,从手动didnt检查,如果有一个时钟使能定时器,等我亲自动手的GPIO了第一,闪烁一个大柜台的领导环

for(ra=0;ra<0x20000;ra++) dummy(ra); 

然后在轮询模式下使用的定时器(只是得到它开始自由运行)的基础上,从这个时间可以计算出时钟速度,从而导致进入UART闪烁,让UART,同比增长,有一个打印数据的简单例程

void hexstring (unsigned int d) 
{ 
    //unsigned int ra; 
    unsigned int rb; 
    unsigned int rc; 

    rb=32; 
    while(1) 
    { 
     rb-=4; 
     rc=(d>>rb)&0xF; 
     if(rc>9) rc+=0x37; else rc+=0x30; 
     uart_send(rc); 
     if(rb==0) break; 
    } 
    uart_send(0x0D); 
    uart_send(0x0A); 
} 

八进制更容易,但人是很难想象在八...

然后最后中断的东西,采取类似的代码上面,我会轮询和定时打印各种寄存器,会先看看这个中断寄存器是否在轮询模式下触发(第二,第三,第四...没有启用处理器的中断(不这么做一段时间)。

一旦我可以在周边级别看到它,有些不这样工作,但假设这是一个。然后在这种情况下有一个VIC,我假设这个寄存器

VICRawIntr 0xFFFFF008 

如果定时器中断被声明并且已经被触发,也应该被置位。确认它是(出现的位4),当外设中断被清除时,确认它消失。

VICIntSelect重置为零,这是irq,这就是我们现在不需要触摸它。

我假设设置位4 VICIntEnable

然后做轮询的事情再次打印出来看看是怎么回事。

现在我期望在VICIRQStatus中看到中断显示(仍然完全轮询不启用irq到处理器),并在外设清零时消失,或者在清除外设中断时如何清除它并没有达到这个目标。

现在是时候启用irq到处理器了,而且我个人会将一个字节插入到uart中看到它弹出。或者轻弹一下led或其他东西。

理论上我们只是清除周边并返回到安全地返回到应用程序。

无论处理器是单片机还是全尺寸的处理器,我都遵循相同的过程。中断可能是恶梦,而且您编写的代码越多,未经测试就越有可能失败。有时每个测试需要一行代码。因人而异。

如果这是完全无用的遗憾,将删除。我认为我有一个/一些2148s,但不是2138,并且我不打算订购一个来编写/测试工作代码。自从ARMV7TDMI出来后,他们一直在使用arm,并且越来越流行到目前更加痛苦的armv8s。 pi-zero等等都非常有趣,因为它们就像这样的老派7 ...

我认为定时器会更容易得到真正的中断。另一个可能是gpio引脚,虽然我认为这是更多的工作,但将引脚之间的跳线,使一个输出另一个输入与中断边缘检测,如果这个芯片有它使用输出gpio来改变输入的状态一个干净的方式,然后经过整个轮询过程,依次查看每个层的中断,并确认每次在每一层都可以删除中断。然后轰击核心的边缘,最后让它进入核心。

+0

ldr,pcs在异常表中往往有些矫枉过正,有时候只是使用一个分支来标签。不应该在这里位置独立,所以实际上不需要移动该表并使其工作,因此分支也可以正常工作,但是必须重新计算0x14值才能使校验和通过,以便代码可以运行。 –

+1

为了重新执行此操作,只有在绝对必须使用中断时才使用中断。 –