首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >地址错误ISR

地址错误ISR
EN

Stack Overflow用户
提问于 2014-07-08 21:51:28
回答 3查看 2.7K关注 0票数 1

我正在尝试在dsPIC30f3011微控制器上运行和调试一个C程序。当我在MPLAB中运行我的代码时,代码总是在这个ISR处停止,并且我完全没有任何变量的输出,我的代码甚至不能执行。它似乎是某种“陷阱”程序,我认为它是用来捕获简单错误的(例如振荡器故障等)。我使用的是MPLabIDE v8.5,其MPLab ICD3处于调试模式。值得一提的是,MPLAB显示我同时连接到目标(DsPIC)和ICD3。有人能给我一个为什么会发生这个问题的原因吗?

以下是ISR:

代码语言:javascript
复制
void _ISR __attribute__((no_auto_psv))_AddressError(void)
{

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

下面是我的代码,首先是初始化,然后是PID使用,然后是DSP函数,最后是实际的DSP头文件,其中派生了语法/算法。在我定义DutyCycle的地方也有一些问题。

///////////////////////////////Initializations/////////////////////////////////////////////

代码语言:javascript
复制
  #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 */
    );
EN

回答 3

Stack Overflow用户

发布于 2015-03-17 21:06:12

dsPIC陷阱不会免费提供太多信息,所以我倾向于在ISR中增加一点汇编语言前言。(请注意,堆栈错误陷阱有点麻烦,因为它使用RCALL并在堆栈已经乱序时返回指令。)

代码语言:javascript
复制
/**
 * \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。请注意,您的微控制器的实际陷阱可能会有所不同-请查看数据表,了解实现了哪些陷阱。

代码语言:javascript
复制
/**
 * \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将参数记录到内存的一个保留区域中,该区域在启动时不会被链接器脚本清零,并重置微控制器。在启动期间,程序检查保留区域,如果非零,则记录错误事件以进行诊断。)

一旦获得陷阱,检查_errAddress变量的内容将给出ISR的返回地址,即紧跟在生成中断的指令后面的地址。然后,您可以检查映射文件以找到例程,如果您确实热衷于反汇编,则可以检查反汇编以找到特定的指令。在那之后,调试就看你的了。

票数 3
EN

Stack Overflow用户

发布于 2014-07-22 23:06:26

正如注释中所建议的,while(1)语句是代码挂起的地方。但是,请注意,您的代码正在执行-您只是在一个无限循环中。这也是你不能查看你的变量或当前程序计数器的原因。通常,当您通过PC主机连接到ucontroller时,您不能在ucontroller执行时查看状态信息。所有的东西都运行得太快了,即使是慢的,也不能经常更新你的屏幕。

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

如果这不起作用,那么在调用ISR之前在您的代码中设置一个断点,并单步执行您的代码,直到它生效为止。您在ISR之前执行的最后一行代码将是原因。请记住,这可能需要一些时间,特别是如果有问题的行在循环中,并且仅在一定次数的迭代后才会触发ISR。

编辑

在张贴了这个答案后,我注意到了你上一条关于linkscript警告的评论。这是一个完美的例子,说明了为什么你应该像解决编译器错误一样努力地解决警告问题,只有很少的例外。特别是如果您不理解警告的含义以及导致警告的原因。

票数 1
EN

Stack Overflow用户

发布于 2015-01-02 03:39:33

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

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24633622

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档