地址错误ISR

时间:2014-07-08 13:51:28

标签: c microcontroller pic memory-address mplab

我正在尝试在dsPIC30f3011微控制器上运行和调试C程序。当我在MPLAB中运行我的代码时,代码总是倾向于在此ISR处停止,并且我对任何变量都没有输出,我的代码甚至没有执行。它似乎是某种“陷阱”程序,我假设是为了捕捉简单的错误(即振荡器故障等)我使用MPLabIDE v8.5,在调试模式下使用MPLab ICD3。值得一提的是MPLAB显示我连接到目标(dsPIC)和ICD3。有人可以告诉我为什么会出现这个问题吗?

这是ISR:

void _ISR __attribute__((no_auto_psv))_AddressError(void)
{

        INTCON1bits.ADDRERR = 0;
        while(1);
}

这是我的代码首先进行初始化,然后是PID使用,然后是DSP函数, 然后是实际的DSP头文件,其中派生语法/算法。在我定义DutyCycle时也存在某种问题。

///////////////////////////////初始化/////////////// //////////////////////////////

  #include "dsp.h"    //see bottom of program


    tPID SPR4535_PID;                   // Declare a PID Data Structure named, SPR4535_PID, initialize the PID object       
    /* The SPR4535_PID data structure contains a pointer to derived coefficients in X-space and */
    /* pointer to controller state (history) samples in Y-space. So declare variables for the */
    /* derived coefficients and the controller history samples */
    fractional abcCoefficient[3] __attribute__ ((space(xmemory)));          //  ABC Coefficients loaded from X memory
    fractional controlHistory[3] __attribute__ ((space(ymemory)));          //  Control History loaded from Y memory
    /* The abcCoefficients referenced by the SPR4535_PID data structure */
    /* are derived from the gain coefficients, Kp, Ki and Kd */
    /* So, declare Kp, Ki and Kd in an array */
    fractional kCoeffs[] = {0,0,0};     
//////////////////////////////////PID variable use///////////////////////////////

void ControlSpeed(void)
{
    LimitSlew();
    PID_CHANGE_SPEED(SpeedCMD);
    if (timer3avg > 0)  
        ActualSpeed = SPEEDMULT/timer3avg;
    else
        ActualSpeed = 0;
    max=2*(PTPER+1);
    DutyCycle=Fract2Float(PID_COMPUTE(ActualSpeed))*max;
    // Just make sure the speed that will be written to the PDC1 register is not greater than the PTPER register
    if(DutyCycle>max)
        DutyCycle=max;
    else if (DutyCycle<0)
        DutyCycle=0;
}


//////////////////////////////////PID functions//////////////////////////////////

        void INIT_PID(int DESIRED_SPEED)
    {
        SPR4535_PID.abcCoefficients = &abcCoefficient[0];    //Set up pointer to derived coefficients 
        SPR4535_PID.controlHistory = &controlHistory[0];     //Set up pointer to controller history samples 

        PIDInit(&SPR4535_PID);                               //Clear the controller history and the controller output 

        kCoeffs[0] = KP;                                  // Sets the K[0] coefficient to the KP 
        kCoeffs[1] = KI;                                  // Sets the K[1] coefficient to the KI
        kCoeffs[2] = KD;                                  // Sets the K[2] coefficient to the Kd
        PIDCoeffCalc(&kCoeffs[0], &SPR4535_PID);             //Derive the a,b, & c coefficients from the Kp, Ki & Kd 

        SPR4535_PID.controlReference = DESIRED_SPEED;        //Set the Reference Input for your controller
    }

    int PID_COMPUTE(int MEASURED_OUTPUT)
    {
        SPR4535_PID.measuredOutput = MEASURED_OUTPUT;             // Records the measured output
        PID(&SPR4535_PID);  
        return SPR4535_PID.controlOutput;                                      // Computes the control output
    }

    void PID_CHANGE_SPEED (int NEW_SPEED)
    {
        SPR4535_PID.controlReference = NEW_SPEED;                   // Changes the control reference to change the desired speed
    }

/////////////////////////////////////dsp.h/////////////////////////////////////////////////

    typedef struct {
            fractional* abcCoefficients;    /* Pointer to A, B & C coefficients located in X-space */
                                            /* These coefficients are derived from */
                                            /* the PID gain values - Kp, Ki and Kd */
            fractional* controlHistory;     /* Pointer to 3 delay-line samples located in Y-space */
                                            /* with the first sample being the most recent */
            fractional controlOutput;       /* PID Controller Output  */
            fractional measuredOutput;      /* Measured Output sample */
            fractional controlReference;    /* Reference Input sample */
    } tPID;

    /*...........................................................................*/

    extern void PIDCoeffCalc(               /* Derive A, B and C coefficients using PID gain values-Kp, Ki & Kd*/
            fractional* kCoeffs,            /* pointer to array containing Kp, Ki & Kd in sequence */
            tPID* controller                /* pointer to PID data structure */
    );

    /*...........................................................................*/

    extern void PIDInit (                   /* Clear the PID state variables and output sample*/
            tPID* controller               /* pointer to PID data structure */
    );


    /*...........................................................................*/

    extern fractional* PID (                /* PID Controller Function */
            tPID* controller               /* Pointer to PID controller data structure */
    );

3 个答案:

答案 0 :(得分:3)

dsPIC陷阱不提供免费的大量信息,因此我倾向于使用一些汇编语言预先序言来增加ISR。 (请注意,堆栈错误陷阱有点松懈,因为当堆栈已经出现故障时它会使用RCALL和RETURN指令。)

/**
 * \file trap.s
 * \brief Used to provide a little more information during development.
 *
 * The trapPreprologue function is called on entry to each of the routines
 * defined in traps.c.  It looks up the stack to find the value of the IP
 * when the trap occurred and stores it in the _errAddress memory location.
 */

.global __errAddress
.global __intCon1

.global _trapPreprologue

.section .bss

__errAddress:   .space 4
__intCon1:      .space 2

.section .text

_trapPreprologue:
; Disable maskable interrupts and save primary regs to shadow regs
    bclr    INTCON2, #15            ;global interrupt disable
    push.s                          ;Switch to shadow registers

; Retrieve the ISR return address from the stack into w0:w1
    sub     w15, #4, w2             ;set W2 to the ISR.PC (SP = ToS-4)
    mov     [--w2], w0              ;get the ISR return address LSW (ToS-6) in w0
    bclr    w0, #0x0                ;mask out SFA bit (w0<0>)
    mov     [--w2], w1              ;get the ISR return address MSW (ToS-8) in w1
    bclr    w1, #0x7                ;mask out IPL<3> bit (w1<7>)
    ze      w1, w1                  ;mask out SR<7:0> bits (w1<15..8>)

; Save it
    mov     #__errAddress, w2       ;Move address of __errAddress into w2
    mov.d   w0, [w2]                ;save the ISR return address to __errAddress

; Copy the content of the INTCON1 SFR into memory
    mov     #__intCon1, w2          ;Move address of __intCon1 into w2
    mov     INTCON1, WREG           ;Read the trap flags into w0 (WREG)
    mov     w0, [w2]                ;save the trap flags to __intCon1

; Return to the 'C' handler
    pop.s                           ;Switch back to primary registers
    return

然后我将所有陷阱ISR保存在一个traps.c文件中,该文件使用traps.s中的pre-prologue。请注意,微控制器的实际陷阱可能不同 - 请查看数据表以查看实现的陷阱。

/**
 * \file traps.c
 * \brief Micro-controller exception interrupt vectors.
 */

#include <stdint.h>

#include "traps.h"      // Internal interface to the micro trap handling.

/* Access to immediate call stack.  Implementation in trap.s */

extern volatile unsigned long _errAddress;
extern volatile unsigned int _intCon1;

extern void trapPreprologue(void);

/* Trap information, set by the traps that use them. */

static unsigned int _intCon2;
static unsigned int _intCon3;
static unsigned int _intCon4;

/* Protected functions exposed by traps.h */

void trapsInitialise(void)
{
    _errAddress = 0;
    _intCon1 = 0;
    _intCon2 = 0;
    _intCon3 = 0;
    _intCon4 = 0;
}


/* Trap Handling */
// The trap routines call the _trapPreprologue assembly routine in traps.s
// to obtain the value of the PC when the trap occurred and store it in
// the _errAddress variable.  They reset the interrupt source in the CPU's
// INTCON SFR and invoke the (#defined) vThrow macro to report the fault.

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _OscillatorFail(void)
{
    INTCON1bits.OSCFAIL = 0;        /* Clear the trap flag */
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _StackError(void)
{
    INTCON1bits.STKERR = 0;         /* Clear the trap flag */
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _AddressError(void)
{
    INTCON1bits.ADDRERR = 0;        /* Clear the trap flag */
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _MathError(void)
{
    INTCON1bits.MATHERR = 0;        /* Clear the trap flag */
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _DMACError(void)
{
    INTCON1bits.DMACERR = 0;        /* Clear the trap flag */
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _HardTrapError(void)
{
    _intCon4 = INTCON4;
    INTCON4 = 0;                    // Clear the hard trap register
    _intCon2 = INTCON2;
    INTCON2bits.SWTRAP = 0;         // Make sure the software hard trap bit is clear
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

void __attribute__((interrupt(preprologue("rcall _trapPreprologue")),no_auto_psv)) _SoftTrapError(void)
{
    _intCon3 = INTCON3;
    INTCON3 = 0;                    // Clear the soft trap register
    vThrow(_intCon1, _intCon2, _intCon3, _intCon4, _errAddress);
}

vThrow宏的实现取决于您。但是,它不应该使用堆栈,因为这可能不可用(所以没有puts()调试调用!)在开发期间,使用一个带有NOP语句的简单无限循环是合理的,你可以断点

(在生产版本中,我的vThrow macro将参数记录到RAM的保留区域,该区域在链接器脚本启动时被排除在外,并重置微控制器。在启动程序期间检查保留区域,如果非零,则记录诊断的错误事件。)

一旦获得陷阱,检查_errAddress变量的内容将为您提供ISR的返回地址,该地址紧跟在生成中断的指令之后的地址。然后,您可以检查MAP文件以查找例程,如果您真的非常热衷,请检查反汇编以查找特定指令。之后,调试由您决定。

答案 1 :(得分:1)

正如评论中所建议的,while(1)语句是代码挂起的地方。但请注意,您的代码正在执行 - 您只是处于无限循环中。这也是您无法查看变量或当前程序计数器的原因。通常,当您通过PC主机连接到控制器时,您无法在执行控制器时查看状态信息。一切都运行得太快,即使是在慢速运行,也要不断更新屏幕。

要尝试识别原因,可以在ISR中设置断点并重置控制器。当命中断点时,执行将暂停,并且可能能够调查您的堆栈帧以查看在ISR被触发之前执行的最后一行代码。但这并不能保证 - 取决于特定的ucontroller处理中断的方式,调用堆栈在正常程序执行和中断上下文之间可能不连续。

如果这不起作用,请在调用ISR之前在代码中设置断点,然后逐步执行代码直到它为止。您在ISR之前执行的最后一行代码将成为原因。请记住,这可能需要一些时间,特别是如果违规行在循环中并且只在经过一定次数的迭代后才跳过ISR。

修改
在发布此答案后,我注意到您对linkscript警告的最后评论。这是一个完美的例子,说明为什么你应该像解决编译器错误一样努力解决警告。特别是如果您不了解警告的含义以及引起警告的原因。

答案 2 :(得分:1)

PID算法涉及乘法。在dspic上,这是通过内置的硬件乘法器完成的。该乘法器有一个寄存器,必须指向 xmemory 空间,另一个指向 ymemory 空间。然后dsp核心将这两个相乘,结果可以在累加器中找到(其中有两个)。

如果将 xmemory 地址范围加载到 ymemory 寄存器中,则会触发addres错误陷阱,反之亦然。您可以通过单步执行程序集中的代码来检查这一点。

这不是触发陷阱的唯一实例。还有硅片可能导致这种情况,请查看勘误表。