Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

How to store data from an interrupt in C

  1. Mar 29, 2013 #1
    It's been a while since I've done some C programming and I can't remember how I should go about implementing this. I have a chunk of memory allocated for storing an array of data. The allocation takes place while the main program is running. The data is being stored to the already allocated memory space in an interrupt (this code is running on a microcontroller) . My issues is accessing the memory location of the latest empty position in the array, to add the next sequence of data. The interrupt is declared and defined in another .c file.

    My , probably overly complicated, idea was to reserve two bytes at the beginning of the allocated memory space; one to act as an iterator for the array and the other as a tail pointer. I'd use the tail pointer in the interrupt to place the received data into the array and increment the pointer for the next interrupt.

    I feel like there's probably an easier way to go about this. Thoughts or suggestions?
  2. jcsd
  3. Mar 29, 2013 #2

    I like Serena

    User Avatar
    Homework Helper

    Hi haxor489! :smile:

    I think you need to provide a little more information.
    As it is, you really need to allocate your data before your microcontroller starts doing anything.

    Anyway, as a rule, if you pick up data asynchronously, you will need to transfer it to a queue before processing it.
  4. Mar 29, 2013 #3
    Hi I Like Serena! :)

    I'm not really sure what else to add to that but I'll give it a shot.

    "Anyway, as a rule, if you pick up data asynchronously, you will need to transfer it to a queue before processing it."

    That's exactly my intention but the queue or array in which to share between my interrupt and main program is my dilemma.

    I'm collecting data asynchronously over the SCI module. Every time the SCIRXBUF fills up it sets a flag which triggers an interrupt. This interrupt is located/defined in the PIE vector table. I'm coding the interrupt and since it's not part of my main program I'm not sure how to share a static variable between the two so that they can both reference the same location and pointer. Is there any way to do this in C without have to have fixed values to memory addresses for such a thing?

    I hope I'm explaining this clearly. If I'm not making sense then I must be thinking of implementing this in a way that isn't conventional. Please explain in general how you would share pointers to the queue or array between your interrupt and main program.
  5. Mar 29, 2013 #4


    User Avatar
    Science Advisor

    Hey haxor489.

    Does the OS/Interrupt code have a way of re-allocating an array in the same way that you can re-allocate an array in C through realloc()?
  6. Mar 30, 2013 #5


    User Avatar
    Homework Helper

    You will need some global variables in order to do this. For the queueing of data, you could use a linked list or a circular buffer. Since you mentioned an iterator, sounds like you're considering using a circular buffer. If the interrrupt routine is queing data to the main level code, the interrupt routine advances the head pointer / index each time it queues an entry, and the main level code advances the tail pointer / index each time it extracts an entry.

    Another consideration is if you're considering implementing a simple pre-emptive multi-tasking executive, where a task can "pend" on an empty queue, then switched to ready and or runnable when the interrupt (or another task) appends an entry onto the empty queue.
  7. Apr 21, 2013 #6


    User Avatar
    Gold Member

    I wonder if your plan might result in a race condition on the pointers into the array, if both a program and an interrupt service routine are both using a couple of address that point into the array. Is only one WRITING the pointers, and the other READING the pointers? Even then, is there a chance that while one is in the process of writing a pointer, the other might come along and try to read the pointer while it's in some intermediate state not completely changed yet?
  8. Apr 21, 2013 #7


    User Avatar
    Homework Helper

    Only the interrupt routine updates the head pointer and only the man level code updates the tail pointer (except for initialization). On most processors, reading or writing an index or a pointer is done in a single atomic (non-breakable) operation, since these are of native size and should be on native boundaries. There could be an isssue if a pointer was forced to be on a non-native boundary, such as a packed structure.

    A race condition can occur if something special needs to be done when a queue goes from empty to non-empty. In the OP's case, the interrtupt routine is the one adding data to the queue, so it's only an issue on a multi-threaded or multi-tasking operating system where the main level code can "pend" on a queue to wait for the queue to go non-empty. There would be operating system functions that handle this (including disabling interrupts as needed).

    The other race situation occurs when it's the main program adding data to a queue, starting an I/O, and then allowing the interrupt routine to retrieve data from a queue and continue doing I/O's as long as the queue is non-empty. To handle this case, the enqueue function needs to disable interrupts as needed and return an indicator that the queue was previously empty, such as a status, previous count (== 0), current count (==1). If the queue was previously empty, then the main program starts the initial I/O.

    I wrote an example multi-threaded windows dos console program that copies a file, using the current thread to read, and a spawned thread to write. In this example, I have functions that handle a fifo queue in the form of a link list, that utilizes mutexes and semaphores. The dequeue function (GetNextElement()) uses windows WaitForMultipleObjects(), which eliminates any issue related to thread priority.

  9. Apr 22, 2013 #8


    User Avatar
    Gold Member

    I'm not confident of the above statement. There are cases where a read or write involves multiple bus cycles (if, say, the pointer is wider than one byte), and a thread switch can occur in the middle of the operation; this can produce incorrect values. There may also be cache coherency issues, where a write from one thread updates its processor's cache, but does not update global memory; a read from a different thread reads global memory, and doesn't see the updated value in the other processor's cache. Also, a compiler can shuffle the order of reads and writes under the assumption that the values are not accessed from another thread, resulting in chaos.

    I believe there is an atomic data type in C++ that will guarantee against these, but I wasn't sure if those are being used in this case, or not.

    Could the poster please clarify what hardware platform and software tools are being used, so that we need not debate more than necessary? Maybe I'm worrying unnecessarily, but it never hurts to think through these scenarios. I've seen myself and others bitten more than once by overconfidence, and the problems are very difficult to diagnose after the fact, as they will manifest intermittently and maybe seldom.
  10. Apr 22, 2013 #9


    User Avatar
    Homework Helper

    Most processors will treat any read or write as an atomic operation, even if it involves multiple memory or cache line operations (mis-aligned integer or pointer). An interrupt is not going present a problem here. The ram copy won't matter unless it's a multi-processor environment or a bus mastering controller is modifying data being used by a program for variables (not a good idea).

    Consider the issue of trying to save a thread's context if a context switch to a higher priority thread or interrupt could occur in the middle of a stack read / write operation. Interrupt handling, multi-threading, and multi-processing all rely on the fact that any current instruction will complete before switching context. Repeated instructions, such as rep movsb, will be paused mid-loop, but not mid-instruction.

    Global variables shared between threads and/or interrupts need to be declared as volatile, to prevent the compiler from optimizing the operations to use registers instead of memory image, but I'm not aware of an atomic type for C++. Atomic operations usually involve multiple instructions and some method used like disabling interrupts and/or context switching to make sure such operations are atomic. I'm not aware of any built-in atomic operators for C++, unless it's in some processor specific library.
    Last edited: Apr 22, 2013
Share this great discussion with others via Reddit, Google+, Twitter, or Facebook