我正在尝试在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 */
);
答案 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错误陷阱,反之亦然。您可以通过单步执行程序集中的代码来检查这一点。
这不是触发陷阱的唯一实例。还有硅片可能导致这种情况,请查看勘误表。