Electronic – PIC24FV Reset without Flag

addressingerrorinterruptspicsimulated

I am working on building an interrupt based program flow using the PIC24FV32KA302 module from Microchip. However, I am having some trouble with intermittent resets (it seems).

I am currently using the MPLAB X Simulator, trying to find out where the issue is happening. I was originally using a PICKit3 on real hardware, but I ran into some trouble where, after a few cycles through the main loop, the debugger would stop and throw an error "PC at 0x0", which is an address without a valid instruction. I don't think these issues are related, but I can't really eliminate the possibility.

In essence, my program flow is as follows:

main()
{
   init();
   print_an_init_message();
   while(1)
   {
       check_some_flags();
       if(flags_are_set)
       {
          do_something_about_them();
       }
   }  
}

During simulation, the program repeatedly prints the init message. It does catch on a breakpoint in the while(1) loop – so it must be entering. Also, if I continue from that breakpoint, it will loop around to it (not reset). If I step from that breakpoint, the debugger crashes.

So, I tried printing out values from the RSON register (which is supposed to be set during any reset condition) in the init message. None of the values are set. If I add a simple delay (built-in XC16 __delay_ms()) to the while loop, the _AddressError interrupt is called. The instruction from which the address error originates is always a ULNK instruction from one of the functions used in do_something_about_them() (which represents multiple flags and functions, it seems to be possible that it is any of the functions, but most often it is the first or last).

Also worth noting, if I put a breakpoint on the last line of main (return -1), it is never hit, but the simulator continuously prints the init message.

Is this likely a problem with the simulator, or my program? Could this be related to my PC 0x0 problem when running on real hardware, or are those likely different?

If anyone wants real code to help out, I can provide it – I just didn't provide it right away because I feel it would obfuscate my real problem, which I don't think is being caused by my C code.

Thanks in advance!

After a little bit of debugging, I managed to get the PC 0x0 error to go away. I'm still dealing with landing in the address error ISR. This is now programming real hardware with the PICKit3.

I believe the code that is causing the problem is a queue that I am dealing with.

typedef struct uint16_queue_tag {
    uint16_t *contents;
    int front;
    int back;
    int maxSize;
    int cnt;
} uint16_queue;

bool uint16_InitQueue(uint16_queue *queueP, uint8_t queueSize)
{
    uint16_t newContents[queueSize];

    queueP->contents = &newContents[0];
    queueP->maxSize = queueSize;
    queueP->cnt = 0;
    queueP->front = -1;
    queueP->back = -1;

    return true;
}

bool uint16_IsQueueEmpty(uint16_queue *queueP)
{
    return (bool) (queueP->cnt == 0);
}

bool uint16_IsQueueFull(uint16_queue *queueP)
{
    return (bool) (queueP->cnt == queueP->maxSize);
}

bool uint16_ClearQueue(uint16_queue *queueP)
{
    queueP->front = -1;
    queueP->back = -1;
    queueP->cnt = 0;

    return true;
}

bool uint16_PushQueue(uint16_queue *queueP, uint16_t element)
{
    if (uint16_IsQueueFull(queueP))
    {
        return false; // We can't push to the queue, its full
    }
    else
    {
        queueP->back++;
        queueP->contents[(queueP->back % queueP->maxSize)] = element;
        queueP->cnt++;
        return true;
    }
}

uint16_t uint16_PullQueue(uint16_queue *queueP)
{
    if (uint16_IsQueueEmpty(queueP))
    {
        return NULL;
    }
    else
    {
        queueP->front++;
        queueP->cnt--;
        return queueP->contents[(queueP->front % queueP->maxSize)];
    }
}

This is all working fine for some iterations it seems, but at some point a uint16_PushQueue(&queue_obj, value) breaks the code. After the queue is initialized, all that I do is check if it is full, Push, and Pull. Strangely, it seems like the value of the contents pointer is different – after it breaks, the pointer is pointing to the same value as "front", which is definitely not the same value as it started at. Also, the element at the place that it is pointing is reported, by MPLAB, as 0.0 (which is definitely not a float).

So I guess this is just some kind of pointer assignment stupidity, which kind of explains the whole address problem too – I am somehow moving where the contents pointer is pointing to.

Best Answer

The way you initialize your queue is not OK:

bool uint16_InitQueue(uint16_queue *queueP, uint8_t queueSize)
{
    uint16_t newContents[queueSize];
    queueP->contents = &newContents[0];
    queueP->maxSize = queueSize;
    queueP->cnt = 0;
    queueP->front = -1;
    queueP->back = -1;
    return true;
}

The newContents variable-length array will be initialized on the uint16_InitQueue's stack. Once the function returns, the queueP->contents will point to the stack and any attempt to modify it's content will corrupt the stack and potentially cause a crash.

This is all working fine for some iterations it seems, but at some point a uint16_PushQueue(&queue_obj, value) breaks the code. After the queue is initialized, all that I do is check if it is full, Push, and Pull.

This makes total sense, as doing a uint16_PushQueue will corrupt the stack.

The array needs to be either dynamically allocated (not good practise for embedded systems without an OS) or globally allocated. When programming embedded system, you usually set a maximum size for the queue (or any other container) at compile time.


Some nitpicking:

bool uint16_IsQueueEmpty(uint16_queue *queueP)
{
    return (bool) (queueP->cnt == 0);
}

The cast is totally useless. You can do: return (queueP->cnt == 0) instead.

The less code, the better.