Interrupt-safe way to set function pointer in HiTech C on PIC32 - c

I have an ISR defined to trigger on an external interrupt. The external interrupt may not always be enabled, but under certain circumstances I want to be able to register a function to be called ONCE within the interrupt from within the main code. The function might be replaced by another one, or removed, before the next interrupt.
I don't know much about techniques for synchronisation on the PIC32, but I've come up with the following:
volatile BOOL callbackInterrupted = FALSE;
volatile BOOL callbackWritten = FALSE;
void (*myCallback)() = NULL;
void RegisterCallback(void (*callback)())
{
do
{
callbackWritten = FALSE;
myCallback = callback;
}
while(callbackInterrupted);
callbackWritten = (callback != NULL);
}
void interrupt MyExternalInterrupt() #EXTERNAL_1_VCTR
{
// Do a bunch of other things here...
if(callbackWritten)
{
myCallback();
myCallback = NULL;
callbackInterrupted = TRUE;
callbackWritten = FALSE;
}
}
I'm having trouble reasoning about it though. Does this actually do what I hope, ie. prevent the ISR calling a half-set function pointer, or calling a function twice? Is the do ... while loop superfluous? Is there a better way?
Added: disabling this interrupt is out of the question. It is used for timing.
Instructions generated for flag = TRUE:
lui s1,0x0
ori s1,s1,0x1
addiu at,s1,0
or t0,at,zero
Instructions generated for fnc1 = &testfunc:
lui a2,0x9d00
ori a2,a2,0x50
or a1,a2,zero
sw a1,16376(gp)

Assuming setting the bool is an atomic operation (disassemble & read the manual to be sure) - I would use a flag to set the function pointer, but this flag shold only be read by the ISR, and only written by the normal code, giving you a simple semaphore. If writing the function pointer is atomic (again, check by disassembling), you can use it instead of the flag.
Like this (off the top of my head)
void (*myCallback)() = NULL;
void RegisterCallback(void (*callback)())
{
myCallback = callback;
}
void interrupt MyExternalInterrupt() #EXTERNAL_1_VCTR
{
// Do a bunch of other things here...
if (myCallback!=NULL)
myCallback();
myCallback = NULL;
}
Edit
After seeing disassembled instructions, using the function pointer as a flag will work. Modified code to show usage.

Given the fact that the ISR is there to time pulses why call the function within the ISR at all? Why not call it in the main code where ever it is that the main code checks up on the results of the pulse timing?
If your answer is that its critical the code is executed on the fire of the ISR, then i assume its also critical that you have the opportunity to set a function to call prior to every execution of the interrupt. In this case your only options are to determine the proper function to call for the next interrupt within the ISR or to disable the interrupt while you determine the proper function to call elsewhere in the code. If timing is critical you should also make sure this ISR can't be bumped by a higher priority interrupt.

I would use only a function pointer and check that for non-null in the interrupt, call and set it to null. Where you set the pointer the standard solution would be to disable interrupts.

Related

Why can't I use a global bool variable whose value depends on interrupt flags? [duplicate]

This question already has answers here:
Is volatile modifier really needed if global variables are modified by an interrupt?
(2 answers)
Closed 10 months ago.
I'm trying to wait for an interrupt to continue with the execution of the code, something like this:
bool flag = false;
void interrupt_handler (uintptr_t context)
{
flag = true;
}
void main()
{
CallbackRegister(event, interrupt_handler,0);
while(!flag);
}
But it always stays in the while loop even when the interrupt occurs. Does anyone know why?
I'm currently using MPLABX with a SAMD21J17 microcontroller.
You need to change:
bool flag = false;
to:
volatile bool flag = false;
The reason is that without volatile the compiler is allowed to assume that the flag never changes after it has been read once, but you want it to read the flag repeatedly.
Hmm. I don't know that particular compiler but a quick check of the microchip compiler user guide says something which jumped out to me immediately.
You have a function named interrupt handler, but you don't have it identified with decorator. I suggest you look at this guide in section 5.8.1 "Writing an Interrupt Service Routine" where it says "Write each ISR prototype using the __interrupt() specifier".
So your routine would look like this at a minimum:
void __interrupt(high_priority) interrupt_handler (uintptr_t context) {
flag = true;
}

FreeRTOS: xEventGroupWaitBits() crashes inside a loop with scheduler running

We have several tasks running on an STM32 MCU. In the main.c file we call all the init functions for the various threads. Currently there is one renewing xTimer to trigger a periodic callback (which, at present, does nothing except print a message that it was called). Declarations as follows, outside any function:
TimerHandle_t xMotorTimer;
StaticTimer_t xMotorTimerBuffer;
EventGroupHandle_t MotorEventGroupHandle;
In the init function for the thread:
xMotorTimer = xTimerCreateStatic("MotorTimer",
xTimerPeriod,
uxAutoReload,
( void * ) 0,
MotorTimerCallback,
&xMotorTimerBuffer);
xTimerStart(xMotorTimer, 100);
One thread starts an infinite loop that pauses on an xEventGroupWaitBits() to determine whether to enter an inner loop, which is then governed by its own state:
DeclareTask(MotorThread)
{
bool done = false;
EventBits_t event;
for (;;)
{
Packet * pkt = NULL;
event = xEventGroupWaitBits( MotorEventGroupHandle,
EVT_MOTOR_START | EVT_MOTOR_STOP, // EventBits_t uxBitsToWaitFor
pdTRUE, // BaseType_t xClearOnExit
pdFALSE, // BaseType_t xWaitForAllBits,
portMAX_DELAY //TickType_t xTicksToWait
);
if (event & EVT_MOTOR_STOP)
{
MotorStop(true);
}
if (event & EVT_MOTOR_START)
{
EnableMotor(MOTOR_ALL);
done = false;
while (!done && !abortTest)
{
xQueueReceive(motorQueue, &pkt, portMAX_DELAY);
if (pkt == NULL)
{
done = true;
} else {
done = MotorExecCmd(pkt);
done = ( uxQueueMessagesWaiting(motorQueue) == ( UBaseType_t ) 0);
FreePacket(pkt);
}
}
}
}
}
xEventGroupWaitBits() fires successfully once, the inner loop enters, then exits when the program state meets the expected conditions. The outer loop repeats as it should, but when it arrives again at the xEventGroupWaitBits() call, it crashes almost instantly. In fact, it crashes a few lines down into the wait function, at a call to uxTaskResetEventItemValue(). I can't even step the debugger into the function, as if calling a bad address. But if I check the disassembly, the memory address for the BL instruction hasn't changed since the previous loop, and that address is valid. The expected function is actually there.
I can prevent this chain of events happening altogether by not calling that xTimerStart() and leaving everything else as-is. Everything runs just fine, so it's definitely not xEventGroupWaitBits() (or at least not just that). We tried switching to xEventGroupGetBits() and adding a short osDelay to the loop just as an experiment. That also froze the whole system.
So, main question. Are we doing something FreeRTOS is not meant to do here, using xEventGroupWaitBits() with xTimers running? Or is there supposed to be something between xEventGroupWaitBits() calls, possibly some kind of state reset that we've overlooked? Reviewing the docs, I can't see it, but I could have missed a detail. The

Synchronisation mechanism without disabling interrupts on Cortex M0

To clarify a question assume that we have:
Static Button object: static Button_T sButton = {0};
Function to get Button: void GetButton(Button_T * p_button); that is called from main loop context
ISR handler: void ButtonISRHandler(void);
Assumptions:
GetButton execution can be interrupted by any interrupt that does not execute ButtonISRHandler
ButtonISRHandler execution can be interrupted by other iterrupts
GetButton execution takes less time than the minimum time between two ButtonISRHandler interrupts call.
Button interrupt is a cyclic interrupt triggered for instance every 10 ms.
In ButtonISRHandler we have procedures like checking button PIN state or detecting if button is touched (in touch button case). If a given PIN state is stable in e.g. for 5 consequtive calls then sButton object state is updated.
Button_T is generic object - it could be classic tact switch or touch button etc.
ScanButtonAndUpdate could handle a list of Button_T objects but GetButton function operates only on the one button object.
The problem is: classic case when an interrupt can occur when program counter is inside GetButton
The question is: How to synchronize GetButton with ButtonISRHandler without disableing Interrupts?
My target processor is Cortex M0 without LDREX/STREX operation so I cannot use atomics from C11 that would be great solution in this case.
My Proposed Solution
Use Critical Section in GetButton.
If an interrupt occured when the program counter is inside Critical Section then do not handle ScanButtonAndUpdate in interrupt but handle it on ExitCriticalSection. Defer ScanButtonAndUpdate execution.
There is no possibility to call ScanButtonAndUpdate function from interrupt and main context in the same time - this behaviour is protected by semaphore
Implementation
#define SEMAPHORE_GIVEN 0
#define SEMAPHORE_TAKEN 1
typedef uint32_t BaseType_T;
typedef struct Button_T;
static volatile BaseType_T sSemaphore = SEMAPHORE_GIVEN;
static volatile bool sIsPendingISR = false;
static volatile Button_T sButton = {0};
void GetButton(Button_T * p_button)
{
EnterCriticalSection();
memcpy(p_button, &sButton, sizeof(Button_T))
/* Other procedures on sButton... */
ExitCriticalSection();
}
/* Cyclic executed handler */
void ButtonISRHandler(void)
{
if (!BinarySemaphoreTake()) {
SetISRPending();
}
else {
ScanButtonAndUpdate();
BinarySemaphoreGive();
}
}
void ScanButtonAndUpdate(void)
{
/* Scan for instance a current PIN state and update sButton object
if state is stable in next calls */
}
static void EnterCriticalSection(void)
{
while(false == BinarySemaphoreTake()) continue;
}
static void ExitCriticalSection(void)
{
BinarySemaphoreGive();
if (IsPendingISR()){
ScanButtonAndUpdate();
ResetISRPending();
}
}
static bool BinarySemaphoreTake(void)
{
if (SEMAPHORE_GIVEN == sSemaphore) {
/* Value Store operation is atomic on the architecture native type */
sSemaphore = SEMAPHORE_TAKEN;
return true;
}
else {
return false;
}
}
static void BinarySemaphoreGive(void)
{
sSemaphore = SEMAPHORE_GIVEN;
}
static void SetISRPending(void)
{
sIsPendingISR = true;
}
static void ResetISRPending(void)
{
sIsPendingISR = false;
}
static bool IsPendingISR(void)
{
return sIsPendingISR;
}
This solution was tested and works great without problems but I am not sure that this is the best solution without hidden bugs.
EDIT 1: Updated Assumptions and added missing ScanButtonAndUpdate function
There is a hidden synchronization which affects whether you have a race condition or not: what gates the Interrupt? The two most common scenarios are edge and level triggered; an edge trigger means that the interrupt will be inhibited until the device is cleared, whereas a level trigger means that the interrupt will repeatedly re-assert until the device is cleared.
If your code uses level triggered interrupts, then you have omitted this synchronization entirely, or you are pretending that sIsPendingISR is the mask & status flag. In that case, you look alright
If it is level triggered, then it can re-assert during /* Update sButton object */, causing the device handling code to be executing in two contexts (interrupt + normal). Most device code is not designed to do this.
Btw, there is a software protocol called “Dekkers Algorithm” which provides a general solution to mutual exclusion without hardware support. You have sort of integrated a version of it here.

How to implement separate static variables for a given function called with different parameters

I am currently working on a microcontroller project in C that requires several timed functions to take place. I am a using a hardware timer to produce an interrupt every millisecond, and variables as counters to produce the appropriate time intervals. The hardware details are not important.
As an example, for a particular function, the following code would be executed on every tick of the 1ms counter, resulting in Function() being called every 10ms.
if (count < 10)
{
count++;
}
else
{
Function();
count = 0;
}
I would like to implement a wrapper function to avoid rewriting the counter code for every different interval, i.e:
TimerWrapper(required interval 1, Function 1 pointer)
TimerWrapper(required interval 2, Function 2 pointer)
and call it on every tick of the timer. For this to work, each different function called by the wrapper needs to have a separate count variable that needs to persist between calls of TimerWrapper(). I would like to keep all of the implementation details separate from my main program and introduce as few variables into my main program as possible.
Is it possible to do what I am asking, or is there a simpler/better way to achieve the same effect? I know how I would do this with an object oriented language but my skills are lacking in plain C.
I would think in terms of a structure along the lines of:
struct interrupt_responder
{
int count;
int rep_count;
void (*handler)(void);
};
You then create as many such structures as you have different counters, appropriately initialized:
static struct interrupt_responder c1 = { 0, 10, Function };
You arrange to call a function with the responder:
void time_wrapper(struct interrupt_responder *r)
{
if (++r->count >= r->max_count)
{
r->count = 0;
(*r->handler)();
}
}
The function called in response to an interrupt then simply needs to know how to dispatch calls to time_wrapper with the appropriate argument each time.
void millisecond_interrupt_handler(void)
{
time_wrapper(&c1);
…
}
Or you can have an array of the interrupt responders, and the millisecond interrupt handler can loop over the array, calling the time wrapper function.
You would have a set of file scope variables for the interrupt responders, but they'd not need to be visible outside the file. If you need different argument lists for the handler functions, life is trickier — avoid that if you possibly can. However, it seems from a comment that it won't be a problem — the embedded functions pointers will always be void (*handler)(void).

Arduino EthernetServer read() only works when Serial is initialized and read characters are printed

I have an Arduino project where I read data from a webserver.
I have an EthernetClient that reads the data character by character in a callback function.
My working code looks like (only the relevant parts):
void setup() {
Serial.begin(9600);
...
}
void loop() {
char* processedData = processData(callback); // this is in a external lib
}
boolean callback(char* buffer, int& i) {
...
if (Client.available()) {
char c = client.read();
buffer[i++] = c;
Serial.print(c);
}
...
}
This works without any problems (reading and processing the data), but when I remove Serial.begin(9600); and Serial.print(c); it stops working and I don't know why? The only thing changed is that the char c is not printed. What could be the problem?
A common reason why callback functions change their behavior when seemingly unrelated code is altered, is optimizer-related bugs.
Many embedded compilers fail to understand that a callback function (or an interrupt service routine) will ever be called in the program. They see no explicit call to that function and then assumes it is never called.
When the compiler has made such an assumption, it will optimize variables that are changed by the callback function, because it fails to see that the variable is changed by the program, between the point of initialization and the point of access.
// Bad practice example:
int x;
void main (void)
{
x=5;
...
if(x == 0) /* this whole if statement will get optimized away,
the compiler assumes that x has never been changed. */
{
do_stuff();
}
}
void callback (void)
{
x = 0;
}
When this bug strikes, it is nearly impossible to find, it can cause any kind of weird symptoms.
The solution is to always declare all file scope ("global") variables shared between main() and an interrupt/callback/thread as volatile. This makes it impossible for the compiler to make incorrect optimizer assumptions.
(Please note that the volatile keyword cannot be used to achieve synchronization nor does it guarantee any memory barriers. This answer is not in the slightest related to such issues!)
A guess: Because without the serial driver started, there is no data to process, and therefore your callback is not hit.
What were you hoping the serial callback to be doing in the absence of data?
Providing more information about Client and processData may help.

Resources