Arm 无中断嵌入式编程

Arm 无中断嵌入式编程,arm,embedded,interrupt,bare-metal,arm7,Arm,Embedded,Interrupt,Bare Metal,Arm7,我从来没有想过我会在2017年处于这个位置,但我有一个目标系统(LPC2138),它绝对拒绝处理中断,尽管我做了很多尝试。出于各种原因,我确实需要使用它,所以这只是一个继续使用它的问题。该应用程序是“中断友好型”的,具有多个异步I/O流(SPI、UART)和定时器信号。对我有利的一点是,与我的实时要求相比,处理器速度非常快,因此我有大量可用的备用grunt 我一直坚持的方法是在一个大的轮询循环中完成整个过程,其中包括3个FIFO来处理I/O。快速看一眼,这似乎是可行的,有人根据经验提出任何意见吗

我从来没有想过我会在2017年处于这个位置,但我有一个目标系统(LPC2138),它绝对拒绝处理中断,尽管我做了很多尝试。出于各种原因,我确实需要使用它,所以这只是一个继续使用它的问题。该应用程序是“中断友好型”的,具有多个异步I/O流(SPI、UART)和定时器信号。对我有利的一点是,与我的实时要求相比,处理器速度非常快,因此我有大量可用的备用grunt

我一直坚持的方法是在一个大的轮询循环中完成整个过程,其中包括3个FIFO来处理I/O。快速看一眼,这似乎是可行的,有人根据经验提出任何意见吗


中断问题并不简单,当系统在混乱状态下崩溃时,100%平台兼容的hello world代码片段直接从web上无法工作。如果有人知道某个地方确实有一个明确的、专家级的修复方法,那么最好有一个指针

如果不了解您的应用程序和目标平台,我无法给您一个明确的答案

但是,你根据经验征求意见。下面是:-)

  • 您提到了实时性要求。在没有中断的情况下工作实际上可以帮上忙!当我们执行具有硬实时需求的项目时,我们没有使用中断。假设我们正在处理传入的数据流,并且正好有20个我们来处理一个单词,或者我们会错过下一个单词,并且正好在处理一个单词的过程中,我们被打断了。猛敲失去了下一个。所以我们做了很多民意调查。在不同的应用程序中,设计决策可能会有所不同,使用中断来处理时间关键型工作,而代价是非实时代码,或者类似的。我当时工作的那家商店的理念是非常反干扰的

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

  • 先进先出是好的。它们降低了您的实时性要求

  • 我一点也不知道你的硬件设计,但是如果你有一个逻辑芯片和一个灵活的硬件工程师(好吧,这是一个矛盾的说法:-),你可以通过硬件路由你的一些输入等等,并使用硬件逻辑来处理你的一些简单需求,并为你提供一个接口,使编写程序更容易(可以是针对您的特定需求优化的某种FIFO,例如,或一次给您几条信息的投票登记簿,等等)


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

    不知道你在哪里陷入困境我们需要更多的信息,但也许一个小骨架会证实你至少在做这几件事。你以前做过arm7吗,或者这是第一次,或者你对arm7/arm世界很熟悉,但就是不能得到e打断工作

    开始

    .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
    
    是的,这是太多的寄存器…只需要编译器覆盖的易失性寄存器

    诺曼:

    void c_irq_handler ( void )
    {
    }
    void notmain ( void )
    {
        unsigned int ra;
        for(ra=0;ra<100;ra++) dummy(ra);
    }
    
    我想我不需要

    建造

    始终检查您的so.list

    他们有一个有趣的方法来确定你是否有一个闪存,或者他们是否应该转储到他们的引导加载程序

    有效用户代码的标准:保留ARM中断向量 位置(0x0000 0014)应包含 检查剩余中断向量的总和。这将导致校验和 所有向量加起来等于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
    
    这应该很好

    如果这是完全无用的基本然后让我知道将删除这个答案没有问题

    诺曼

    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;
    
    }
    
    只是从手册中敲出了这个,没有检查计时器是否有时钟启用,等等。我个人首先启动gpio,闪烁一个带有大计数器循环的led

    for(ra=0;ra<0x20000;ra++) dummy(ra);
    
    八进制更容易,但人类很难用八进制来思考

    最后是中断的东西,像上面的代码一样,我会轮询并打印计时器中的各种寄存器,看看中断寄存器是否首先在轮询模式下触发(第二、第三、第四…不启用处理器中断(暂时不要这样做)

    一旦我能在外围水平上看到它,有些人不这样做,但假设这个是这样的。然后在这个例子中有一个受害者,我假设这个寄存器

    VICRawIntr 0xFFFFF008
    
    如果定时器中断被断言并已触发,也应被断言。确认它是(它出现的第4位)确认它在外围设备中清除中断时消失

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

    我假设在Vicinable中设置了第4位

    然后再做一次投票,打印出来看看发生了什么

    现在,我希望在VICIRQStatus中看到中断显示(仍然完全轮询,但尚未启用处理器的irq),并在外围设备清除时消失,或者在被清除的外围设备中断没有达到这一程度时,找出如何清除它

    现在是时候给处理器启用irq了,我个人会把一个字节塞进uart,看看它是否会弹出,或者打开一个led灯什么的

    理论上,我们只是清除外围设备,然后安全地返回应用程序

    无论是mcu还是全尺寸处理器等,我都遵循相同的过程。中断可能是噩梦,您在未测试的情况下编写的代码越多,失败的可能性就越大。有时每个测试需要一行代码。YM
    for(ra=0;ra<0x20000;ra++) dummy(ra);
    
    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);
    }
    
    VICRawIntr 0xFFFFF008