Best way to handle While on buses

damieneti wrote on Monday, September 16, 2013:

Hi There,

Often we use SPI or I2C with a while into some flag bits, for instance while(I2C2CONbits.SEN); for Microchip I2C.

Question is how the best handle such while with considering that our task should not be allowed to stop in case that a component fails.

Several ways to work around, maybe the simplest is a

for (i=0; I2C2CONbits.SEN; i++) if (i>500) return ERROR;

But with an RTOS we probably can go further like

for (i=0; I2C2CONbits.SEN; i++) { if (i>5) return ERROR; vTaskDelay( 1/ portTICK_RATE_MS ); } 

But in this case 1ms delay will probably be too long in most bus.

Maybe another way would be to use co-routine an create a routine for each of the sub components, if one fails then the co routine fails and a check on failed co-routine could stop them to release the bus resources ?

Of course there is always the interrupt-way but this pose other problem and the failing device always pause the same problem. In a RTOS environment I would prefer the while style.

I’d like to know how the expert are handling this the nicest way.


richard_damon wrote on Monday, September 16, 2013:

In an RTOS environment you NEVER prefer the while loop if it is going to go on for any period of time (like longer than a pair of  context switches). You configure the system to generate an interrupt on the status bit, and in the interrupt do simple operations and interface to the task with queues/semaphores. The task can wait for these, with a timeout, to detect when something has go wrong.

damieneti wrote on Tuesday, September 17, 2013:

Following your advice I’ve start implementing the interrupt.

For information, before the RTOS we were handling the all I2C by interrupt, but the complexity of the code made it difficult to maintain.

First problem come to the point the the all microchip I2C library has to be rewritten, I’ve spend several hours doing so but problems keep accumulating as:

  1. The time for handling the semaphores seem too long, a packet before took about 300us while it takes about 4ms with semaphore and interrupt.
  2. Some interrupt are missed because the semaphore task switch takes too long time.
  3. Some of the state doesn’t have interrupt.

It is also important to specify that the microchip PIC24 generate about 5 interrupt for each byte transferred (either way) that all needs to be handled.

Driving the microchip I2C (I’m not talking about other uC) through interrupt with the RTOS is basically a big headache while having a low priority task doing the job blocking on “while” will work as good (if not better).

So I don’t really get your point.

richard_damon wrote on Tuesday, September 17, 2013:

I have implemented I2C drivers on the PIC24/dsPIc that sends data at full 400KHz speed, so if it is taking you 4ms to send a small message, you are doing something wrong. Unfortunately, due to the contractual obligations the software was developed under, I will need to get permission to share the code.

Yes, you do NOT just take their sample I2C code and replace the wait loops with semaphore waits, THAT would be very inefficient. The ISR does most of the I/O operations, the “Task” level code initiates the start bit and loads data queues, and the ISR cycles through the phases of the I2C transaction.

I don’t understand “missing” interrupts, on the PIC, I2C interrupts are persistent until cleared, so you can’t “miss” an interrupt, at worse you are slow to respond.

I didn’t find any operation that needed a response that didn’t provide an interrupt to key that operation on.