xSemaphoreTake within an ISR

k1mgy wrote on Sunday, February 11, 2018:

Processor SAMG55
Dev System: Atmel Studio with ASF version of FreeRTOS (version 8.0.1)

I am using xSemaphoreTake ( semaphorescreated using xSemaphoreCreateMutex()). These work perfectly except…

One particular semaphore protects TWI communications so that, under circumstances where one process has TWI in work and an interrupt is triggerd which also uses TWI, the ISR will not clobber the TWI interface.

However, xSemaphoreTake() says that it can’t be called from within an ISR.

How can I protect TWI in this case?

rtel wrote on Sunday, February 11, 2018:

As a rule of thumb, no FreeRTOS API functions that don’t end if
“FromISR” can be called from an ISR. In this case there is an
xSemaphoreTakeFromISR() function - however recent versions of FreeRTOS
do not allow mutex semaphores to be used from interrupts. There are a
couple of reasons for that, the first is an interrupt cannot block on a
semaphore (or anything else for that matter) so if the mutex is not
available then it has to just fail gracefully. The second is that
mutexes have a priority inheritance mechanism whereby the mutex is
associated with the priority of the task that holds it, and that breaks
down when it is used from an interrupt as interrupts to not have a task
priority.

A complete TWI operation is going to be way too long to perform in an
interrupt anyway. Normally it is preferable to just use interrupts to
manage TWI events. For example, when one transaction is complete use
the TWI end interrupt to see if there is another transaction pending -
and if there is start that transaction ideally using DMA. If there are
no further transactions pending then the TWI operation can just be ended
until such time a new transaction is ready.

k1mgy wrote on Sunday, February 11, 2018:

Richard, thank you.

The interrupt being fired is from a peripheral (ADC), signaling that the data is ready to read. Therefore I must service it or lose the data.

Investigating this further, I discover that hacking within an ISR may be unnecessary as there’s a FreeRTOS TWI driver.

So I added the driver (through Atmel ASF) and it wouldn’t compile. Offered two complaints on freertos_twi_master.h, both referring me back to the Freertos Version 8 compatibility chart. I never expected this in a file that’s part of the version 8 code. So I replaced portTickType and xSemaphoreHandle with their Version 8 equivalents, and it compiles. FreeRTOS please note.

Onward now to replace my atmel asf TWI driver with the FreeRTOS driver. Hopefully this will fix it?

rtel wrote on Monday, February 12, 2018:

The interrupt being fired is from a peripheral (ADC), signaling that the
data is ready to read. Therefore I must service it or lose the data.

That doesn’t mean you have to read all the data in the interrupt though.
Either just start the read operation in the interrupt and let
interrupts or DMA complete the read - or somehow signal a task (direct
to task notifications are the best method, but not available in the
older versions you are using) to unblock the task so the task performs
the read.

k1mgy wrote on Monday, February 12, 2018:

Richard, I can get to your idea, but for the moment have another issue.

After initializing:

bool InitTWI(void)
{
freertos_peripheral_options_t driver_options =
{
NULL,
0,
0x0e,
TWI_I2C_MASTER,
(WAIT_TX_COMPLETE | WAIT_RX_COMPLETE)
};

flexcom_enable(BOARD_FLEXCOM_TWI);
flexcom_set_opmode(BOARD_FLEXCOM_TWI, FLEXCOM_TWI);
freertos_twi=freertos_twi_master_init(BOARD_BASE_TWI, &driver_options);
if (freertos_twi == NULL)
{
    puts("-E-\tTWI master initialization failed.\r");
    return(false);
}
twi_set_speed(freertos_twi,TWI_SPEED,F_CPU);
return(true);

}

I then make a write call:

nSuccessCode=freertos_twi_write_packet(BOARD_BASE_TWI, &packet_tx,TWI_WRITE_PACKET_WAIT);

And here I get an exception fault.

Within freertos_twi_write_packet(): the exception is triggered at:

freertos_optionally_wait_transfer_completion(…

And that’s within freertos_twi_master.c in the freertos_twi_write_packet_async() function. I didn’t call async… so not sure how we got there…

Any ideas?

k1mgy wrote on Monday, February 12, 2018:

#define freertos_twi_write_packet(p_twi, p_packet, block_time_ticks) freertos_twi_write_packet_async((p_twi), (p_packet), (block_time_ticks), (NULL))

is defined in freertos_twi_master.h!

So, if we’re not supposed to use async, why the dickens is it defined in?

This is nuts :slight_smile:

rtel wrote on Monday, February 12, 2018:

So, if we’re not supposed to use async, why the dickens is it defined in?

Not sure I understand the statement about not supposed to use async.

(should also point out that you are looking at very old code from the
ASF rather than latest code from the FreeRTOS download)

k1mgy wrote on Monday, February 12, 2018:

you are looking at very old code from the
ASF rather than latest code from the FreeRTOS download

I’m using what has been published by Atmel/Microchip/whoever. Hmmm… well that’s likely the issue. If they have not updated it, and it’s broken (apparently so) then I’ll get on their ass and see what gives.

Thanks for your help!