Author Topic: fnFillBuf  (Read 6708 times)

Offline hervé

  • Jr. Member
  • **
  • Posts: 98
    • View Profile
fnFillBuf
« on: September 27, 2010, 10:25:04 AM »
Hello Mark,

During the EMAC_Interrupt
The function fnFillBuf() is called
the parameter ptQUEQue is read from the stack and assigned to register
The problem is that there is Interrupt activation inside it.

Code: [Select]
....
    if (ptQUEQue->put >= ptQUEQue->buffer_end) {
        ptQUEQue->put -= ptQUEQue->buf_length;                           // handle overflow
        FirstCopy -= (QUEUE_TRANSFER)(ptQUEQue->put - ptQUEQue->QUEbuffer);
    }
    uEnable_Interrupt();                                                 // ensure copies do not block interrupts
    uMemcpy(ptrTo, input_buffer, FirstCopy);
    if (nr_of_bytes != FirstCopy) {
        uMemcpy(ptQUEQue->QUEbuffer, (input_buffer + FirstCopy), (nr_of_bytes - FirstCopy));
    }
    uDisable_Interrupt();
.....

after uEnable_Interrupt() the register of the Interrupt bank are modified, then on the line
Code: [Select]
uMemcpy(ptQUEQue->QUEbuffer...ptQUEQue is no more pointing to a correct reference.....

Is this line
Code: [Select]
uEnable_Interrupt(); // ensure copies do not block interruptsreally necessary?


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: fnFillBuf
« Reply #1 on: September 27, 2010, 01:28:25 PM »
Hi Hervé

fnFillBuf() is used to copy data to a circular buffer. This copy has to be protected since there may be interrupts reading from the same circular buffer at the same time - without protection the counters can become corrupted.

However, blocking uMemcpy() when large amounts of data are copied will cause interrupts to be blocked for quite a long time, which could lead to driver under-runs in the worst case. Therefore only the absolutely necessary modifications are protected (the counters) and then the data is copied using uMemcpy() with no protection, which may be interrupted by other code using the same circular buffer without danger.

In the case of the EMAC_Interrupt (in LPC2XXX project) the call
            fnWrite(INTERNAL_ROUTE, (unsigned char*)EMAC_RX_int_message, HEADER_LENGTH); // inform the Ethernet task
is taking place when there has been an interrupt reception. This is copying only a small amount of data.

It is also called as follows:

            iInterruptLevel = 1;                                         // ensure interrupts remain blocked when putting message to queue
            fnWrite(INTERNAL_ROUTE, (unsigned char*)EMAC_RX_int_message, HEADER_LENGTH); // inform the Ethernet task
            iInterruptLevel = 0;


By setting iInterruptLevel = 1 it means that uEnable_Interrupt(); will have no effect. Therefore in your case the interrupts will remained blocked all of the time.

Note also, if you have an interrupt taking place it should never be able to destroy the content of registers used by the calling routine. An interrupt routine will save all registers when started and return them after completion.

At the moment I can't explain how corruption of the stack of the interrupt routine is possible. You may however like to look at the interrupt stack area defined in your project (in linker script). If you have disabled optimisation (for example) it may be taking up more space than expected and overwriting something. Also check the stack is not overlapping with heap (that is, that you have adequate safety margin between the heap and stack) [See http://www.utasker.com/forum/index.php?topic=468.0].


Regards

Mark






Offline hervé

  • Jr. Member
  • **
  • Posts: 98
    • View Profile
Re: fnFillBuf
« Reply #2 on: September 28, 2010, 09:37:14 AM »
Thanks Mark.

Good remark : I think it's the interrupt stack which was too small.