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.
Related
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;
}
I am writing a kernel module to monitor a few syscalls wanting to return the function arguments to user-land (via netlink socket) if the call was successful.
jprobe.kp.symbol_name = "rename";
jprobe.entry = rename_handler;
kretprobe.kp.symbol_name = "rename";
kretprobe.handler = rename_ret_handler;
static rename_obj_t _g_cur_rename = NULL;
static void _rename_handler(const char *oldpath, const char *newpath)
{
_g_cur_rename = create_rename(oldpath, newpath);
jprobe_return();
}
static void _rename_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
/* Send only if successful */
if (regs_return_value(regs) == 0) {
add_send_queue(_g_cur_rename);
}
return 0;
}
I worry that another rename syscall may preempt[1] the current one after the jprobe and I will send incorrect return codes and arguments.
jprobe: rename(a, b)
jprobe rename(c, d)
kretprobe
kretprobe
Edit: This article[2] states that interrupts are disabled during a kprobe handler. But does that mean that interrupts are disable throughout the whole chain (jprobe -> kprobe -> kretprobe) or just for that single kprobe?
https://unix.stackexchange.com/questions/186355/few-questions-about-system-calls-and-kernel-modules-kernel-services-in-parallel
https://lwn.net/Articles/132196/
Interrupts are disabled for each jprobe call: not for the entire sequence.
How many calls are you expecting in the time it will take the application to process them? There are different approaches depending on how fast you expect the calls to come in. The simplest method, if you are only expecting maybe a few hundred calls before you can process them and you will dedicate the static memory to the purpose, is to implement a static array of rename_obj_t objects in memory and then use atomic_add from the kernel asm includes to point to the next entry (mod the size of your array).
This way you are returning a unique static reference each time, so long as the counter doesn't wrap around before you process the returned values. atomic_add is guaranteed to have the correct memory barriers in place so you don't have to worry about things like cache coherency.
Attempting to use mbed OS scheduler for a small project.
As mbed os is Asynchronous I need to avoid blocking code.
However the library for my wireless receiver uses a blocking line of:
while (!(wireless.isRxData()));
Is there an alternative way to do this that won't block all the code until a message is received?
static void listen(void) {
wireless.quickRxSetup(channel, addr1);
sprintf(ackData,"Ack data \r\n");
wireless.acknowledgeData(ackData, strlen(ackData), 1);
while (!(wireless.isRxData()));
len = wireless.getRxData(msg);
}
static void motor(void) {
pc.printf("Motor\n");
m.speed(1);
n.speed(1);
led1 = 1;
wait(0.5);
m.speed(0);
n.speed(0);
}
static void sendData() {
wireless.quickTxSetup(channel, addr1);
strcpy(accelData, "Robot");
wireless.transmitData(accelData ,strlen(accelData));
}
void app_start(int, char**) {
minar::Scheduler::postCallback(listen).period(minar::milliseconds(500)).tolerance(minar::milliseconds(1000));
minar::Scheduler::postCallback(motor).period(minar::milliseconds(500));
minar::Scheduler::postCallback(sendData).period(minar::milliseconds(500)).delay(minar::milliseconds(3000));
}
You should remove the while (!(wireless.isRxData())); loop in your listen function. Replace it with:
if (wireless.isRxData()) {
len = wireless.getRxData(msg);
// Process data
}
Then, you can process your data in that if statement, or you can call postCallback on another function that will do your processing.
Instead of looping until data is available, you'll want to poll for data. If RX data is not available, exit the function and set a timer to go off after a short interval. When the timer goes off, check for data again. Repeat until data is available. I'm not familiar with your OS so I can't offer any specific code. This may be as simple as adding a short "sleep" call inside the while loop, or may involve creating another callback from the scheduler.
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).
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.