Today I have a little proble and I think that the origin is about the stack.
This is my problem :
I declare three user task like this :
void task1Function(void) {
print_uart0("-usertask : First task is started...\r\n");
while(1){
//syscall(1);
}
}
void task2Function(void) {
print_uart0("-usertask : Second task is running...\r\n");
//syscall(); /* To return in the kernel's mode */
while(1){
}
}
void task3Function(void) {
print_uart0("-usertask : Third task is running...\r\n");
//syscall(); /* To return in the kernel's mode */
while(1){
}
}
I have an array of three task whose the strucure is below :
typedef struct
{
unsigned int *sp;
unsigned int registers[12];
unsigned int lr;
unsigned int pc;
unsigned int cpsr;
unsigned int mode;
unsigned int num;
void *stack;
int stacksize;
int priority;
int state; /* Running, Ready, Waiting, Suspended */
/* Next and previous task in the queue */
struct taskstruct *qnext, *qprev;
}taskstruct;
Here the inialisation of my tasks :
void init_task(taskstruct * task, void (*function)(void) ){
task->sp = (unsigned int*)&function;
task->registers[0] = 0; // r0
task->registers[1] = 0; // r1
task->registers[2] = 0; // r2
task->registers[3] = 0; // r3
task->registers[4] = 0; // r4
task->registers[5] = 0; // r5
task->registers[6] = 0; // r6
task->registers[7] = 0; // r7
task->registers[8] = 0; // r8
task->registers[9] = 0; // r9
task->registers[10] = 0; // r10
task->registers[11] = 0; // r11
task->registers[12] = 0; // r12
task->lr = 0;
task->pc = 0;
task->cpsr = 0;
task->mode = 0x10;
}
init_task(&task[0],&task1Function);
init_task(&task[1],&task2Function);
init_task(&task[2],&task3Function);
But when I passed the task[0].sp to my activate function, it's always the last declared task that is launched (i.e the third):
.global activate
activate:
LDR r12, [r0]
/*STMFD sp!,{r1-r11,lr}*/
NOP
msr CPSR_c, #0x10 /* User mode with IRQ enabled and FIQ disabled*/
mov pc, r12
So I guess that I have a problem with my user stack and that I have to setup a different stack for each of them, am I right ? In this case, can somebody tell me how I have to proceed ?
Regards, Vincent
Yes, you are right.
You must have separate stacks for each task, since the state of the stack is part of the task's total state.
You could add something like
uint32_t stack[512];
to your taskstruct, and then set/restore the task pointer accordingly when switching tasks, of course. It's hard to provide enough detail in this context.
'Ok but how I can allocate the stack task ? ' - malloc it.
You can economize on mallocs by adding the stack space on the end of the taskstruct - all your current members are fixed-size, so calculating the total size to malloc is easy.
The hard bit with these taskers is getting the interrupt entry correct, ie. when an interrupt handler needs to change a task state and so has to exit via the scheduler. This is especially good fun with nested interrupts. Good luck with that!
Related
hi i am using an APM32F003 with Keil uVision compiler.
is a little known microcontroller but compatible with STM32.
I would like to write functions in RAM for different purposes.
I don't want to use the linker attribute to assign the function in ram,
but I want to copy a written one in flash and transfer it in RAM in run-time.
below the code I am trying to write but for now it is not working.
I think it's not possible in this way right?
static volatile uint8_t m_buffer_ram[100];
void flash_function()
{
/* Example */
LED2_ON();
}
void flash_function_end()
{
}
void call_function_in_ram()
{
uint32_t size = (uint32_t) flash_function_end - (uint32_t) flash_function;
/* clone function in RAM */
for (uint32_t i = 0; i < size; i++)
m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
__disable_irq();
/* cast buffer to function pointer */
void(*func_ptr)(void) = (void(*)(void)) (&m_buffer_ram);
/* call function in ram */
func_ptr();
__enable_irq();
}
Eugene asked if your function is relocatable. This is very important. I have had issues in the past wherein I copied a function from flash to RAM, and the compiler used an absolute address in the "flash" based function. Therefore the code which was running in RAM jumped back into the flash. This is just one example of what might go wrong with moving code which is not relocatable.
If you have a debugger that can disassemble and also step through the compiled code for you, that would be ideal.
Note also "the busybee" pointed out that code which is adjacent in source code does is not guaranteed to be adjacent in the compiled binary, so your method of finding the size of the code is not reliable.
You can look in the map file to determine the size of the function.
I agree with the comment that you would be better off learning to have the linker do the work for you.
None of what I am saying here is new; I am just reinforcing the comments made above.
CODE
static volatile uint8_t m_buffer_ram[200];
static uint32_t m_function_size;
void flash_function(void)
{
LED2_ON();
}
void flash_function_end(void)
{
}
void test(void)
{
m_function_size = (uint32_t) flash_function_end - (uint32_t) flash_function;
/* clone function in RAM */
for (uint16_t i = 0; i < m_function_size; i++)
m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
__disable_irq();
/* cast buffer to function pointer, +1 Thumb Code */
void(*func_ptr)(void) = (void(*)(void)) (&m_buffer_ram[1]);
/* call function in ram */
func_ptr();
__enable_irq();
}
MAP
Image Symbol Table
Symbol Name Value Ov Type Size Object(Section)
Local Symbols
.....
m_function_size 0x20000024 Data 4 test.o(.data)
m_buffer_ram 0x200001f0 Data 200 test.o(.bss)
Global Symbols
.....
flash_function 0x00000399 Thumb Code 12 test.o(i.flash_function)
flash_function_end 0x000003a9 Thumb Code 2 test.o(i.flash_function_end)
Memory Map of the image
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
.....
0x00000398 0x00000398 0x00000010 Code RO 355 i.flash_function test.o
0x000003a8 0x000003a8 0x00000002 Code RO 356 i.flash_function_end test.o
DISASSEMBLE
.....
30: m_function_size = (uint32_t) flash_function_end - (uint32_t) flash_function;
31:
0x00000462 480D LDR r0,[pc,#52] ; #0x00000498
0x00000464 4A0D LDR r2,[pc,#52] ; #0x0000049C
0x00000466 4C0E LDR r4,[pc,#56] ; #0x000004A0
0x00000468 1A81 SUBS r1,r0,r2
0x0000046A 6021 STR r1,[r4,#0x00]
32: for (uint16_t i = 0; i < m_function_size; i++)
0x0000046C 2000 MOVS r0,#0x00
33: m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
34:
0x0000046E 4B0D LDR r3,[pc,#52] ; #0x000004A4
0x00000470 2900 CMP r1,#0x00
0x00000472 D905 BLS 0x00000480
33: m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
0x00000474 5C15 LDRB r5,[r2,r0]
0x00000476 541D STRB r5,[r3,r0]
32: for (uint16_t i = 0; i < m_function_size; i++)
0x00000478 1C40 ADDS r0,r0,#1
0x0000047A B280 UXTH r0,r0
32: for (uint16_t i = 0; i < m_function_size; i++)
0x0000047C 4288 CMP r0,r1
0x0000047E D3F9 BCC 0x00000474
35: __disable_irq();
36:
0x00000480 B672 CPSID I
37: void(*func_ptr)(void) = (void(*)(void)) (&m_buffer_ram[1]);
0x00000482 1C5B ADDS r3,r3,#1
38: func_ptr();
39:
0x00000484 4798 BLX r3
40: __enable_irq();
41:
0x00000486 B662 CPSIE I
I report all the information that I was able to recover.
I added a shift for the Thumb Code; the calculation of the function size coincides with the MAP file
my doubt is that in debug the pointer cannot jump to a point of the RAM .. for this reason I activate a led to see if (flashing code and run) this turns on without debugging.
as reported below, the read values coincide
(0x000003a8)flash_function_end - (0x00000398)flash_function = 0x10
(0x20000024)m_function_size = 0x10
func_ptr = 0x200001f1;
I have been using C in more and more projects recently and almost ended up creating my own "object implementation" with structure pointers. However, I was curious on the speed difference between a purely functional style (with structs) and structures that call on function pointers in a more modern day object orientated style.
I have created a sample program and am unsure why the difference in timing is so large.
The program uses two timers and records the time taken to complete each task (one after the other). This does not include memory allocation/de-allocation, and both techniques are setup in a similar way (each structure has three integers as pointers of the struct).
The code itself just adds three numbers together repeatedly in a for loop for the duration specified in the macro LOOP_LEN.
Please note I have the functions being measured both inlined and the compiler optimisation was varied from none to Full Optimization (/Ox) (I am running this in Visual Studio as a pure .c file).
Object style Code
// MAGIC object
typedef struct {
// Properties
int* x;
int* y;
int* z;
// Methods
void(*init)(struct magic* self, int x, int y, int z);
int(*sum)(struct magic* self);
}magic;
// Variable init function
void* init(magic* self, int x, int y, int z) {
// Assign variables to properties
*self->x = x;
*self->y = y;
*self->z = y;
return;
}
// Add all variables together
inline int sum(magic* self) {
return ((*self->x) + (*self->y) + (*self->z));
}
// Magic object constructor
magic* new_m(int x, int y, int z) {
// Allocate self
magic* self = malloc(sizeof(magic));
// Allocate member pointers
self->x = malloc(sizeof(int));
self->y = malloc(sizeof(int));
self->z = malloc(sizeof(int));
// Allocate method pointers
self->init = init;
self->sum = sum;
// Return instance
return self;
}
// Destructor
void delete_m(magic* self) {
// Deallocate memory from constructor
free(self->x); self->x = NULL;
free(self->y); self->y = NULL;
free(self->z); self->z = NULL;
free(self); self = NULL;
return;
}
Functional (traditional) style code
// None object oriented approach
typedef struct {
int* x;
int* y;
int* z;
}str_magic;
// Magic struct constructor
str_magic* new_m_str(int x, int y, int z) {
// Allocate self
str_magic* self = malloc(sizeof(str_magic));
// Allocate member pointers
self->x = malloc(sizeof(int));
self->y = malloc(sizeof(int));
self->z = malloc(sizeof(int));
// Return instance
return self;
}
// Destructor
void delete_m_str(str_magic* self) {
// Deallocate memory from constructor
free(self->x); self->x = NULL;
free(self->y); self->y = NULL;
free(self->z); self->z = NULL;
free(self); self = NULL;
return;
}
// Sum using normal structure type
inline int sum_str(str_magic* self) {
return ((*self->x) + (*self->y) + (*self->z));
}
Timer test and main program entry point
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LOOP_LEN 1000000000
// Main entry point
int main(void) {
// Start timer for first task
clock_t start1, end1, start2, end2;
double cpu_time_used1, cpu_time_used2;
// Init instances before timer
magic* object1 = new_m(1, 2, 3);
// Start task1 clock
start1 = clock();
for (int i = 0; i < LOOP_LEN; i++) {
// Perform method sum and store result
int result1 = object1->sum(object1);
}
// Stop task1 clock
end1 = clock();
// Remove from memory
delete_m(object1);
// Calculate task1 execution time
cpu_time_used1 = ((double)(end1 - start1)) / CLOCKS_PER_SEC;
// Init instances before timer
str_magic* object2 = new_m_str(1, 2, 3);
// Start task2 clock
start2 = clock();
for (int i = 0; i < LOOP_LEN; i++) {
// Perform function and store result
int result2 = sum_str(object2);
}
// Stop task2 clock
end2 = clock();
// Remove from memory
delete_m_str(object2);
// Calculate task 2 execution time
cpu_time_used2 = ((double)(end2 - start2)) / CLOCKS_PER_SEC;
// Print time results
printf("----------------------\n Task 1 : %.*e\n----------------------\n Task 2 : %.*e\n----------------------\n", cpu_time_used1, cpu_time_used2);
if (cpu_time_used1 < cpu_time_used2) {
printf("Object Oriented Approach was faster by %.*e\n", cpu_time_used2-cpu_time_used1);
}
else {
printf("Functional Oriented Approach was faster by %.*e\n", cpu_time_used1 - cpu_time_used2);
}
// Wait for keyboard interrupt
getchar();
return 0;
}
Every single time the program is ran, the functional programming always performed faster. The only reason I could think is that it has to access an extra layer of pointer through the structure to call the method, but I would have thought inline would reduce this delay.
Although the delay gets smaller as the optimization is increased, I would be curious to know why it is so much different at levels of low/no optimization and is this therefore considered a valid programming style?
Your 2nd loop with /O2 loop is compiled into:
call clock
mov edi, eax ; this is used later to calculate time
call clock
E.g. there is no code at all. Compiler is able to understand that result of sum_str function is unused, so it removes it completely. Compiler is not able to do the same for the first case.
So there is no real comparison when optimization is enabled.
Without optimizations there are just more code to execute.
First loop is compiled to:
cmp DWORD PTR i$1[rsp], 1000000000
jge SHORT $LN3#main ; loop exit
mov rcx, QWORD PTR object1$[rsp]
mov rax, QWORD PTR object1$[rsp] ; extra instruction
call QWORD PTR [rax+32] ; indirect call
mov DWORD PTR result1$3[rsp], eax
jmp SHORT $LN2#main ; jump to the next iteration
Second loop:
cmp DWORD PTR i$2[rsp], 1000000000
jge SHORT $LN6#main ; loop exit
mov rcx, QWORD PTR object2$[rsp]
call sum_str
mov DWORD PTR result2$4[rsp], eax
jmp SHORT $LN5#main ; jump to the next iteration
With both sum and sum_str being compiled to equivalent sequences of instructions.
The difference is in one instruction in loop, plus indirect calls are slower. Overall there shouldn't be a huge difference between two versions without optimizations - both should be slow.
I think Ivan and you have already provided the answer. I just want to add about inline function. Even though you declare a function as inline it not necessary that compiler will always consider it as inline. Based on complexity compiler might consider it as normal function.
As you said, the former case has additional indirection of pointer reference. Though you declare sum as a inline function, as sum function pointer is put into object member, it cannot be inlined easily.
I suggest you compare generated assembly code with -O0 ~ -O3.
The function below prints out the contents of a UART register. This is the register map.
uart registers
Could somebody explain why, the for loop goes up in +=4?
Thank you
#define UART0_BASE 0x21000
void print_uart(unsigned int base) {
int i;
int val;
unsigned int adr;
for (i=0; i< 0x18; i+=4) {
adr = base + i;
printf("Uart %s [0x%x] -> 0x%x\n",uart_reg[i>>2],adr,val);
}
}
Most likely to fit the start address of each register. Since the for loop runs up to 0x18(24) that makes it 6 registers. It might look like that the registers are only 16 bits but often there's also some padding.
I am trying to run and debug a C program on a dsPIC30f3011 microcontroller. When I run my code in MPLAB, the code always tends to stop at this ISR and I am stuck with absolutely no output for any variables, with my code not even executing. It seems to be some kind of "trap" program that I assume is for catching simple mistakes (i.e. oscillator failures, etc.) I am using MPLabIDE v8.5, with an MPLab ICD3 in debug mode. It's worth mentioning that MPLAB shows that I am connected to both the target(dsPIC) and the ICD3. Can someone please give me a reason as to why this problem is occurring?
Here is the ISR:
void _ISR __attribute__((no_auto_psv))_AddressError(void)
{
INTCON1bits.ADDRERR = 0;
while(1);
}
Here is my code with initializations first, then PID use, then the DSP functions,
then the actual DSP header file where the syntax/algorithm is derived. There is also some sort of problem where I define DutyCycle.
///////////////////////////////Initializations/////////////////////////////////////////////
#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 */
);
The dsPIC traps don't offer much information free of charge, so I tend to augment the ISRs with a little assembly language pre-prologue. (Note that the Stack Error trap is a little ropey, as it uses RCALL and RETURN instructions when the stack is already out of order.)
/**
* \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
Then I keep all the trap ISRs in a single traps.c file that uses the pre-prologue in traps.s. Note that the actual traps may be different for your microcontroller - check the data sheet to see which are implemented.
/**
* \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);
}
Implementation of the vThrow macro is up to you. However, it should not use the stack, as this may be unavailable (so no puts() debug calls!) During development, it would be reasonable to use a simple endless loop with a NOP statement in it that you can breakpoint on.
(In a production build, my vThrow macro logs the parameters into a reserved area of RAM that is excluded from being zeroed at start-up by the linker script, and resets the microcontroller. During start-up the program inspects the reserved area and if it is non-zero records the error event for diagnostics.)
Once you get a trap, inspecting the content of the _errAddress variable will give you the return address for the ISR, which is the address immediately following the instruction that generated the interrupt. You can then inspect your MAP files to find the routine and, if you're really keen, inspect the disassembly to find the specific instruction. After that, debugging it is up to you.
As suggested in the comments, the while(1) statement is where your code is getting hung. Note however, that your code is executing - you're just in an infinite loop. That's also why you can't view your variables or current program counter. Generally when you're attached to a ucontroller via PC host, you can't view state information while the ucontroller is executing. Everything is running too fast, even on a slow one, to constantly update your screen.
To try to identify the cause, you can set a breakpoint in the ISR and reset the controller. When the breakpoint is hit, execution will halt, and you may be able to investigate your stack frames to see the last line of code executed before the ISR was triggered. This is not guaranteed though - depending on how your particular ucontroller handles interrupts, the call stack may not be continuous between normal program execution and the interrupt context.
If that doesn't work, set a breakpoint in your code before the ISR is invoked, and step through your code until it is. The last line of code you executed before the ISR will be the cause. Keep in mind, this may take some time, especially if the offending line is in the loop and only trips the ISR after a certain number of iterations.
EDIT
After posting this answer, I noticed your last comment about the linkscript warning. This is a perfect example of why you should, with very few exceptions, work just as hard to resolve warnings as you do to resolve compiler errors. Especially if you don't understand what the warning means and what caused it.
A PID algorithm involves multiplication. On a dspic, this is done via the built in hardware multiplier. This multiplier has one register which must point to xmemory space and another pointing to ymemory space. The dsp core then multiplies these two and the result can be found in the accumulator (there a two of them).
An addres error trap will be triggered if an xmemory address range is loaded into the ymemory register and viceversa. You can check this by single stepping the code in the assembly.
This is not the only instance the trap is triggered. There are also silicon bugs that can cause this, check the errata.
I am working on MODBUS creating library. Library is working fine for testing purpose I am using a Modbus based Power meter. I am facing a very strange problem.
Trying to print value on console, by using printf. By fetching first value side by side I am printing it, on second fetch value is coming in array correctly but on using pritnf code get crashed. :(
I have tried to debug the code also and came to know on using printf for a value second time code get crashed.
Here is part of code:
int wmain(void)
{
FLOAT dataFloat[5] = {0};
CHAR dataBuffer[200] = {0};
// Initializing Structure declared in library header
psModbusRTU pModbus =(psModbusRTU)malloc(sizeof(psModbusRTU));
// Array pointer to store data
BYTE *readData = (BYTE *) malloc(NUMBER_OF_READ_REGISTERS * sizeof(BYTE));
memset(readData, 0, NUMBER_OF_READ_REGISTERS * sizeof(BYTE));
// Function to read the voltage
if (!ModbusRTUReadRegister(pModbus, FC_READ_HOLDING_REGISTERS, VOLTAGE_REGISTER_ADDRESS, NUMBER_OF_READ_REGISTERS, readData))
{
printf("\nERROR Read register error %d", GetLastError());
getchar();
return 0;
}
dataFloat[0] = hexToFloatPointConversion(readData);
printf("\nvoltage : %f", dataFloat[0]); //(THIS IS FIRST PRINTF TILL HERE CODE IS FINE)
/// Function reads the frequnecy
if (!ModbusRTUReadRegister(pModbus, FC_READ_HOLDING_REGISTERS, FREQUENCY_REGISTER_ADDRESS, NUMBER_OF_READ_REGISTERS, readData))
{
printf("\nERROR Read register error %d", GetLastError());
getchar();
return 0;
}
dataFloat[1] = hexToFloatPointConversion(readData); // Saving frequency value in array
printf("\nFrequency : %f", dataFloat[1]); // (THIS IS WHERE PROBLEM ARISES CODE CRASH WITH NO REASON)
hexToFloatPointConversion Function:
FLOAT hexToFloatPointConversion(BYTE *readData)
{
DWORD dataHex = 0;
DWORD exponent = 0;
DWORD fraction = 0;
DWORD signBit = 0;
FLOAT dataFloat = 0;
/// Saving BYTE array data into one DWORD
dataHex = readData[0];
dataHex = dataHex << 8;
dataHex = dataHex + readData[1];
dataHex = dataHex << 8;
dataHex = dataHex + readData[2];
dataHex = dataHex << 8;
dataHex = dataHex + readData[3];
/// Getting sign bit, exponent and fraction
signBit = dataHex >> 31;
exponent = (dataHex >> 23 & 0xFF);
fraction = dataHex & 0x7FFFFF;
/// Calculation for converting data into float.
dataFloat = (pow(2, (exponent - SINGLE_PRECISION_CONSTANT)) * ( 1 + (fraction * pow(2, -23))));
return dataFloat;
}
psModbusRTU structure:
typedef struct sModbusRTU
{
HANDLE hModbus;
BYTE slaveNumber;
BYTE functionCode;
BOOL fModbusInitialize;
BOOL fSlaveAddress;
BOOL fModbusOpen;
BOOL fException;
WCHAR portName[16];
DWORD exceptionData;
DCB dcb;
}sModbusRTU, *psModbusRTU;
Tried to debug also in run time and looked into dis-assembly break point but did not get exactly why it is happening.
Here is the dis-assembly:
40050658 str r3, [sp, #0x14]
4005065C str r5, [sp, #8]
40050660 str r2, [sp]
40050664 str r4, [sp, #4]
40050668 bl 40031078
4005066C __debugbreak_ce //Break point
40050670 mvn r3, #0x37, 24
40050674 eor r3, r3, #0xAB
40050678 ldr r2, [r3]
4005067C movw r3, #0xF7F8
40050680 movt r3, #0xF101
Please help me out, my project is stuck in middle just because of this small problem.
Please respond back soon
Wrong size passed to malloc().
// was psModbusRTU pModbus =(psModbusRTU)malloc(sizeof(psModbusRTU));
// -----------------------------------------------v--------------
psModbusRTU pModbus = (psModbusRTU) malloc(sizeof(*psModbusRTU));
Suggest alternate malloc() idiom. Use sizeof(*target).
Also, unless you compiler requires it (which it shouldn't), recommend dropping the cast
// example
psModbusRTU *pModbus = malloc(sizeof(*pModbus));
The %f specifier is expecting to format a double (8 bytes) and not a float (4 bytes) (See this MSDN page for details. Try casting the values to double in your printf statements, e.g. printf("\nvoltage : %f", (double) dataFloat[0]);