This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

CAN flags interrupts strange behaviour (lpc23xx)

Hi,

I'm using CAN bus with interrupts and a circular buffer for transmit
frames.I have 2 volatile pointers (rear/front) and a volatile frame
counter vars that I'm managing in the CAN ISR and in the push/pull
routines.

But after a random number of transmitted frames, the ISR stopped
generating interrupts without apparent reason.

But After deep debugging, it seems even if a frame is transmitted and
at the same time , I'm desactivating CAN interrupts , the "tx done
interrupt" flag is never set !!! So when I reactivate again , the ISR
is never called again ...
Note : In the push / pull code , I briefly desactivate the Can
interrupt in order to preserve the pointers/counter integrity.

How can I use circular buffer with this Can controler weak ?

thanks in advance

Parents
  • Why turn off the interrupts?

    The normal reason for using a circular buffer is that the reader (transmit interrupt) is responsible for modifying one pointer, and the writer (your insert code) is responsible for modifying the other pointer.

    This normally works very well as long as a pointer can be read and written atomically. For the ARM processor, the pointer is 32-bit and the register size is 32-bit, so as long as you have a 32-bit memory interface, all 32-bit accesses will be atomic.

    When you insert new data, you have to read "the other" pointer, but that atomic read will either say that the ring buffer is full (even if the interrupt just released one slot) or it will say that there are room for more. Locking the code in a critical section doesn't really improve on this behaviour.

    When you pick up data in the transmit interrupt, a read of the insert pointer may possibly say that the buffer is empty even if the main code has placed more data there but still not had time to increment and write back the pointer. But a critical secton can't really improve on this behaviour either.

    Note that whenever I say "pointer", the real code may instead use an integer index into an array. Sometimes an index that gets incremented modulo the array size. But you often select an array that is 2^n element large to be able to replace the modulo with a bit-and. And you often let the indices continue to tick forward the full 8-bit, 16-bit or 32-bit length and instead do the bit-and for each individual access. Letting them tick forward means that you can use all 2^n elements. If you let the indices wrap at the array size, then you can only use 2^n-1 array positions since readpos==writepos means empty and you would get the same result for an array with 2^n elements inserted.

    If you take a closer look at the Keil sample code for serial communication, you can see an example of a ring buffer with indices running the full 32-bit range before restarting at zero.

Reply
  • Why turn off the interrupts?

    The normal reason for using a circular buffer is that the reader (transmit interrupt) is responsible for modifying one pointer, and the writer (your insert code) is responsible for modifying the other pointer.

    This normally works very well as long as a pointer can be read and written atomically. For the ARM processor, the pointer is 32-bit and the register size is 32-bit, so as long as you have a 32-bit memory interface, all 32-bit accesses will be atomic.

    When you insert new data, you have to read "the other" pointer, but that atomic read will either say that the ring buffer is full (even if the interrupt just released one slot) or it will say that there are room for more. Locking the code in a critical section doesn't really improve on this behaviour.

    When you pick up data in the transmit interrupt, a read of the insert pointer may possibly say that the buffer is empty even if the main code has placed more data there but still not had time to increment and write back the pointer. But a critical secton can't really improve on this behaviour either.

    Note that whenever I say "pointer", the real code may instead use an integer index into an array. Sometimes an index that gets incremented modulo the array size. But you often select an array that is 2^n element large to be able to replace the modulo with a bit-and. And you often let the indices continue to tick forward the full 8-bit, 16-bit or 32-bit length and instead do the bit-and for each individual access. Letting them tick forward means that you can use all 2^n elements. If you let the indices wrap at the array size, then you can only use 2^n-1 array positions since readpos==writepos means empty and you would get the same result for an array with 2^n elements inserted.

    If you take a closer look at the Keil sample code for serial communication, you can see an example of a ring buffer with indices running the full 32-bit range before restarting at zero.

Children