3

I am running ucos-III on a board which has stm32 cpu and a gyroscope sensor. now I make a interrupt in response to receiving data from gyroscope, and than save data into one buffer. on the other side I start one task with OSTaskCreate() used to read data from the buffer and parse/analysize them for calculating degree. now I want to know how to keep mutual exclusive operation between the interrupt function and task function when visit the shared buffer. Before that I have tried to use enable/disable interrupt with ENTER_CRITICAL_SECTION macro. but some one told me that's not exactly the best way to do that, because when you disable interrupt you also close the door to let os make response to other interrupt source. so can you tell me what's the best way to do that? are there some other communication frame more suitable for this situation?

DarkHorse
  • 33
  • 6
  • I would just use a ring buffer for the data. – Turbo J Nov 26 '13 at 12:40
  • yeah, I use recurring array buffer to save data. but the key problem is how to make atom manipulation when reading and writing. – DarkHorse Nov 26 '13 at 13:15
  • For a single-core CPU like the STM32, disabling interrupts is a fine way of ensuring atomicity, as long as the code within the critical section runs very quickly. "very quickly" depends on your particular application -- anything from 1 microsecond to 1 millisecond may be acceptable depending on the degree of interrupt latency/jitter you can accept. – Jon Watte Feb 25 '14 at 17:23

1 Answers1

2

If you are using STM32 you probably have the possibility to mask specific interrupts. If you are sure that only the task and the gyro interrupt are the two "threads" accessing this shared memory you could just mask the gyro ISR. This way all the other interrupts would still be allowed to interrupt, but access to the shared memory is still "atomic".

I don't know what specific MCU/CPU you are running, but the register to mask bits in on Cortex-M3/4 is called:

$$EXTI->IMR$$

EDIT:

The doc states on page 69:

"If a critical section is accessible by an Interrupt Service Routine (ISR) and a task, then disabling interrupts is necessary to protect the critical region."

This is usually the case, unless you can somehow else guarantee that the ISR that have access to the shared data does not get triggered.

When you use the uC/OS-III OS_CRITICAL_ENTER() and OS_CRITICAL_EXIT() I assume they call the global interrupt disable/enable, but as I mentioned over, you can mask and disable the interrupts that have access to this shared data before accessing this data then enable it again when done accessing the shared data.

There are other ways to do it as well. If you have a ring buffer and maybe some index variables you can use OS_CRITICAL_ENTER() right before you read the index variables (which are shared memory) to a local variable and OS_CRITICAL_EXIT() after. The ring buffer does not need to be copied as you will not access the same memory address at the same time assuming the ISR write data and the application code read data. Copying to the local variables will only take a few cycles so the chances of interrupts are very very low during this time. I also think that most of the ARM MCU/CPU save one interrupt of each type (the specific interrupt flag bit) and when you call OS_CRITICAL_EXIT() they will get served. If it happen that two of the same interrupts got triggered during the local variable copying, one will get lost, but this is highly unlikly.

uniquenamehere
  • 860
  • 1
  • 9
  • 21
  • good! I will have a try. furthermore, I suddenly find something in ucos-III user guide manual which said that the only way to protect shared resource between task and interrupt is to use enable/disable interrupt. it's that right? – DarkHorse Nov 27 '13 at 03:14
  • @DarkHorse: See the updated/edited section of my answer. Please also remember to upvote/select answer if/when you problem get solved =) – uniquenamehere Nov 27 '13 at 11:03