Hello in the article from https://www.embedded.com/design/operating-systems/4008268/2/Back-to-the-Basics--Practical-Embedded-Coding-Tips-Part-1, there is mention on how to make a function reentrant.
long i;
void do_something(void){
disable_interrupts();
i+=0x1234;
enable_interrupts();
}
Autor tells: "This solution does not work. If do_something() is a generic routine, perhaps called from many places, and is invoked with interrupts disabled, it returns after turning them back on. The machine's context is changed, probably in a very dangerous manner."
I do not understand exactly how changed the machine's context is dangerous? Could somebody give some example where this could lead to harmful consequences to clarify it?
Note that do_something() can be called both from places where interrupts are enabled, and from places where interrupts are already disabled. Enabling interrupts on the second case goes against the expectations of the caller in a vary dangerous way.
What you really need is to save the previous state of interrupts while disabling them, and restore it afterwards.
So, a better version would be:
long i;
void do_something(void){
irq_state_t prev_int_state = disable_interrupts_save();
i+=0x1234;
restore_interrupts(prev_int_state);
}
Related
Thanks to everyone who gives an answer. But the problem is related to the compiler. I used Cosmos and STVD, it does not bind the interrupt function. When I immigrate the project to IAR, The problem is solved.
I am dealing with STM8S103F3P6 IC. I try to send a message using TX interrupt but I have never succeeded.
I have checked the example of the UART interrupt. Also, I tried to develop the same code. However, I got still zero. I took the interrupt vector function from STM8 examples. Where is my mistake? How can I figure out?
Here my init, main, and interrupt vector function;
void init_handler(void){
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
UART1_DeInit();
UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
UART1_ITConfig(UART1_IT_TXE,ENABLE);
enableInterrupts();
UART1_Cmd(ENABLE);
}
main(){
init_handler();
while(1);
}
INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17){
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
UART1_SendData8('a');
while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
}
It sends nothing. I do not have any logic analyzer, I have only checked using terminal applications.
You asked where your mistake is: that's hard to tell if you use library functions that mask the usage of peripheral configuration registers and flags by making them "readable". If you don't have a logic analyzer, pin debugging helps most of the time (e.g. toggle a GPIO when entering the ISR).
My advise is to look at the actual register manipulations and to compare those with the descriptions in the STM8S Reference Manual (even if it doesn't provide concise guidance on how to initialize, start, spin down and end a transmission).
In order to make that a little easier, I'd like to share what I learned about using a UART ISR:
Sending the contents of a buffer with UART TXE and TC interrupt events turns out not to work like in e.g. MCS51: most of it has to be done with the interrupt enable flags TIEN and TCIEN in UART_CR2.
This is what worked for me:
both TIEN and TCIEN should be normally disabled
after setting up buffers and pointers, enable TIEN to start a transmission
in the ISR, during the transmission, writing to UART_DR clears the interrupt event
in the ISR, when the buffer is empty, disable TIEN and enable TCIEN to spin down the ISR chain
in the ISR, read UART_SR to check if TC is set. If that's the case, clear TCIEN
The advantage of this procedure is that media access control, e.g. for RS485, can be done in the last step of the chain.
An example in STM8 eForth is here.
SPL and opinions about that have nothing to do with the problem. As the SPL code is open sourced you can have a look and even copy it.
UART1_IT_TXE occurs after the UART has transmitted something.
Since you don't send anything (yet) the IRQ is not triggered.
You can send a series of characters using the UART1_IT_TXE IRQ by sending the first character using the UART1_SendData and then let the IRQ handle the remaining ones.
I have been recently working on learning embedded systems programming on my own. I have observed a fairly high usage of the keyword volatile qualifier when declaring variables?
What is the significance of volatile when declaring a variable in Embedded System programming?
Basically when the should the key word be used. I did read something about compiler optimization and use of the keyword. Also something related to memory mapping registers.
For example, I read this StackOverflow post but I didn't understand how it applied in an embedded environment. More specifically, I don't understand when the key word should be used. I did read something about compiler optimization and use of the keyword. Also something related to memory mapping registers, but I don't understand when to use it.
Let's have a look at an example. When you look at C header files for PIC microcontrollers, you will see that many elements are declared volatile:
extern volatile unsigned char PORTB # 0x006;
As you have read, the volatile keyword disables compiler optimization. Suppose you write a program that does the following:
PORTB = 0x00; // set all of port B low
while (PORTB == 0x00); // wait for any pin to get high
// do something else
When the compiler optimises this code, it will recognise the second line as an infinite loop: the condition is true and never gets false within its body. Therefore, everything after the infinite loop does not need to be compiled as it will never be ran. Hence, the compiler may decide to not include that part of the code in the generated assembly code.
However, this PORTB is actually linked to a physical port. It is a hardware port whose value may be altered by the external circuitry. This means that although the loop seems to be infinite, it doesn't have to be. The compiler can't possibly know this.
That's where volatile comes in. When PORTB is declared volatile, the compiler won't do any optimisation based on reasoning about PORTB. It will assume that its value may be changed at any time by external factors.
In the embedded systems world, one of the key aspects of the volatile key-word is that it denotes a variable that may change at any time (eg an external/hardware data input - eg an ADC) and therefore the compiler must not optimise use.
But specifically, when used with a control register, it indicates that a read access may in fact change the data!
As a general rule of thumb, I would recommend the use of the volatile qualifier in all of the following:
All hardware register accesses(read and write)
All variables that are accessible in multiple threads (especially interrupt handlers)
Note: accessing a volatile is not necessarily atomic, so it is imperative that you know your hardware and your code structure.
The volatile keyword is primarily used tell the compiler the value of the variable may change anytime. It also tells the compiler the not to apply optimization on the variable. I am not too much of an expert on this but below is good reference that I have referred in the past.
volatile is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time-without any action being taken by the code the compiler finds nearby. The implications of this are quite serious. However, before we examine them, let's take a look at the syntax.
Reference:
Introduction to the volatile keyword
Let me put it in other perspective it is exactly opposite of const keyword.
When compiler encounters const qualifier for any variable it checks if any function or statement is modified it once initialized. Hence flag error.
Volatile is exactly opposite, this variable can be changed by any function. Hence compiler does not apply optimization.
You see this mostly in embedded system programming due to use of interrupts and some programming logic constructs seems redundant.
While the statements about optimization are correct, they seem a little unclear to me. Here is what is really going on.
If you don't use the volatile keyword C may optimize that variable into a register it isn't using at the time. This will make for fewer assembly instructions and the code will execute faster.
For example, consider the following...
extern int my_port; // my_port is defined in a different module somewhere
// presumably a memory mapped hardware port
while (my_port > 0) {so stuff}
The compiler may decide to read my_port into a register only once before the actual while statement, then each time to test my_port it will look at the register not the memory location.
If, however, my_port is a hardware port, the port may change but register won't and the while conditional will not change.
The loop variable (the register) will be "out of phase" with the actual variable (my_port).
Thus the need for the keyword volatile.
Volatile tells C, "Don't optimize this variable into a reg, but read it each and every time you need it."
More instructions are generated, code is a bit slower, but it is always accurate.
I have a situation where a session of background processing can finish by timing out, user asynchronously cancelling or the session completing. Any of those completion events can run a single shot completion method. The completion method must only be run once. Assume that the session is an instance of an object so any synchronisation must use instance constructs.
Currently I'm using an Atomic Compare and Swap operation on a completion state variable so that each event can test and set the completion state when it runs. The first completion event to fire gets to set the completed state and run the single shot method and the remaining events fail. This works nicely.
However I can't help feeling that I should be able to do this in a higher level way. I tried using a Lock object (NSLock as I'm writing this with Cocoa) but then got a warning that I was releasing a lock that was still in the locked state. This is what I want of course. The lock gets locked once and never unlocked but I was afraid that system resources representing the lock might get leaked.
Anyway, I'm just interested as to whether anyone knows of a more high level way to achieve a single shot method like this.
sample code for any of the completion events:
if(OSAtomicCompareAndSwapInt(0, 1, &completed))
{
self.completionCallback();
}
Doing a CAS is almost certainly the right thing to do. Locks are not designed for what you need, they are likely to be much more expensive and are semantically a poor match anyway -- the completion is not "locked". It is "done". A boolean flag is the right representation, and doing a CAS ensures that it is manipulated safely in concurrent scenarios. In C++, I'd use std::atomic_flag for this, maybe check whether Cocoa has anything similar (this just wraps the CAS in a nicer interface, so that you never accidentally use a non-CAS test on the variable, which would be racy).
(edit: in pthreads, there's a function called pthread_once which does what you want, but I wouldn't know about Cocoa; the pthread_once interface is quite unwieldy anyway, in my opinion...)
consider we're writing a firmware for a baremetal MCU, i.e. no OS. I'm told it's not possible (illegal?) to pass arguments to interrupt handler function?
I can't precisely understand why it is so? What's wrong with this?
PS. is it possible to do in some RTOS-es, embedded Linux etc. or it si fundamentally wrong ?
Interrupts. do just that...interrupt. Imagine the doorbell at your home, interrupting you at any particular random time day or night. Can you be expected to at any moment have all the right items in your hand for any particular interrupt that can occur. You have to be able to cook dinner, take a shower, fold the laundry but just BEFORE the doorbell rings you must have exactly the correct items in both hands depending on the person ringing the bell, without any way of knowing they are there or are coming or are about to ring the bell. Not really possible. Same deal here, interrupts come at any particular time, for most processors immediately after the currently executing instruction, the interrupt handler is called, which means every single instruction would have to be trying to perform the foreground application while keeping all the parameters for the interrupt handler, and do all of this in one instructions time.
Now what is possible is with an operating system, or rtos or call it what you will, some layer. To have the real interrupt handler that knows nothing going in and has to figure it out, once it figures out what the interrupt is about to gather info and then call a high level interrupt handler that is passed parameters. Certainly possible and most/many operating systems do it this way.
No parameters can be explicitly passed to an interrupt handler because it is designed to be called by the hardware. Each architecture imposes a particular stack frame when it is called, typically including the saved state of the CPU.
If you also intend to call the interrupt handler from elsewhere in the code, you have either a design flaw, or there is some common code which could be factored out to be shared between the interrupt handler and the algorithmic code.
The only other thing I'll point out (that hasn't been mentioned so far) is the concept of a "software interrupt" (sometimes called a "trap"), which most processors support.
The idea is that a special instruction causes an exception to take place, and often with a software interrupt, either the opcode causing the exception, or registers set up prior to the exception, can contain values/arguments.
For example, in ARM processors, look up "SWI" or "SVC", depending on your architecture. I believe with the SWI instruction, the lower 8 bits are not part of the opcode - you can fill in whatever you want & pass a value from 0-255 (memory a little fuzzy here).
Unlike a hardware-initiated interrupt, which is totally asynchronous to the code running on the CPU, a software interrupt is synchronous - it occurs when the initiating instruction is executed (barring interrupt masking, nesting, etc.)
An interrupt handler is called by the hardware. It is "passed" whatever "arguments" the hardware passes it.
That's all there is.
when you setup an interrupt handler using the call below, it looks like the interrupt handler takes some args and returns irqreturn_t. Is this not the same interrupt handler OP is talking about?
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long flags,
const char *dev_name,
void *dev_id);
You can use shared variables set during normal code flow to affect the behaviour of an interrupt handler the next time it runs. But because you do not call the ISR directly, you cannot pass arguments. It is not a matter of legality, but rather technicality.
eg:
volatile enum
{
DO_NOTHING,
DO_A,
DO_B,
DO_C
} isr_action ;
__interrupt (SOME_IRQ) myISR()
{
switch isr_action
{
case DO_A :
{
// A
}
break ;
case DO_B :
{
// B
}
break ;
case DO_C :
{
// C
}
break ;
}
}
int main()
{
// Make ISR do A on next SOME_IRQ
isr_action = DO_A ;
for(;;)
{
// wait for interrupt
}
}
consider a signal handler that call exit() as last instruction:
is safe to call non-reentrant functions (e.g. free()) in that handler?
IMHO it would be legal due to the fact that the handler does not return
to the normal sequence of execution.
Thank you in advance.
No, this is illegal, more then that, there are very few safe functions to call.
There is a list of safe functions to call, see http://linux.die.net/man/2/signal Notes section.
You must distinguish between two signals: Those which tell the daemon to "reload" and those which terminate the daemon ("kill"). In the "kill" case, you don't need to free anything. Your process is going to die, the OS will clean up anything you have allocated. If you use shared memory, you must do the cleanup when you're started again. Don't do anything in the "kill" handler which might cause problems. Just die.
In the reload case, you can call any function you like since the user wants you to "shut down orderly". In this case, there is little chance that you will get the same signal again (so it doesn't matter whether a function is reentrant or not).
Reentrancy as more to do with the "entrance" to a function and, side-effects and state maintained by the said function than the exit...
You might want to consult this man page.