Using a function in timer ISR and main at the same time?

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Using a function in timer ISR and main at the same time?

3,585件の閲覧回数
BasePointer
Contributor II
Hi,
 
I have a C project for LC60. And I need to use ProcessBitFilter() function in ISR and main. For my previous project, when I was using Microchip PIC and Hitech C, this was caused some problems.
 
Is this same limitation is valid also for CW C in HCS08 platform?
 
Thank you.
 
Code:
typedef struct {  unsigned char instant_bit_status:1;  unsigned char filtered_bit_status:1;  unsigned char on_filtered_bit_changed:1;  unsigned char on_filtered_bit_down:1;  unsigned char on_filtered_bit_up:1;  unsigned char R5:1;  unsigned char R6:1;  unsigned char R7:1;   unsigned char occurrence_time0;   unsigned char filter_time0;    unsigned char occurrence_time1;   unsigned char filter_time1;} TBitFilter;void ProcessBitFilter(TBitFilter* Filter, unsigned char instant_bit_value){ Filter->instant_bit_status = instant_bit_value;  if((Filter->instant_bit_status) != (Filter->filtered_bit_status)) {  if(Filter->instant_bit_status)  {   //     if(++Filter->occurrence_time1 >= Filter->filter_time1)    {    Filter->filtered_bit_status = Filter->instant_bit_status;       Filter->occurrence_time1 = 0;        Filter->on_filtered_bit_changed = 1;    Filter->on_filtered_bit_up = 1;    }  } else  {   //    if(++Filter->occurrence_time0 >= Filter->filter_time0)    {    Filter->filtered_bit_status = Filter->instant_bit_status;    Filter->occurrence_time0 = 0;        Filter->on_filtered_bit_changed = 1;    Filter->on_filtered_bit_down = 1;   }  }   } else  {  //  Filter->occurrence_time0 = 0;  Filter->occurrence_time1 = 0; }}//////////////////////////////////////////////////////////////////////TBitFilter f_button, f_switch;interrupt VectorNumber_Vtpm1ovf void intTPM1OVF(void){ ... ProcessBitFilter(&f_button, tmp_button_menu); ...}void main(void){ while(1) {  ...  ProcessBitFilter(&f_switch, switch_status);  ... }}

 


Message Edited by BasePointer on 2007-09-01 02:39 PM
ラベル(1)
タグ(1)
0 件の賞賛
返信
4 返答(返信)

1,361件の閲覧回数
rocco
Senior Contributor II
Hi BasePointer,

I am not sure what you mean by limitations, or what type of problems you had with the PIC, but I can discuss some fundamental problems with sharing a subroutine between an ISR and non-ISR code. This applies to almost all processors and all programming languages, not just PIC or HC08, and not just C or assembly language.

The problem, in its most basic form, comes from the asynchronous nature of the ISR: The main program may be in the subroutine when the interrupt occurs and calls the subroutine again. If the subroutine uses any single-instance variables (static or global variables in C), then the second invocation (from the ISR) could overwrite the value needed by the first invocation. If the subroutine uses multi-instance variables (local variables in C) than each call to the subroutine will create unique copies of the variable on the stack, and the individual function calls would not interfere with each other. Such a function is reffered to as "re-entrant". In C, it is easy to write re-entrant functions, and your function "ProcessBitFilter()" does indeed look re-entrant.

What your code does not make clear is whether the same piece of data might be referenced from both the ISR and the main code. If so, than you have a situation known as a "critical section". If the interrupt occurs when ProcessBitFilter() is operating on the structure passed to it, and the ISR then tries to manipulate the same structure, together they will likely corrupt the data in the structure. This can be avoided by insuring that interrupts are disabled during any access to the shared structure.

But that is not so obvious to implement in C code. By default, the main routine will call ProcessBitFilter() with interrupts enabled, and the ISR will call ProcessBitFilter() with interrupts disabled. It would be safe to enable interrupts as the first line of ProcessBitFilter(), but NOT safe to re-enable them at the end of ProcessBitFilter(). The best way to implement the critical section is to save the state of the interrupt mask first and then disable interrupts. Later, when access to the critical section data is complete, the saved state of the interrupt mask can be restored. The assembly code would look like this:
;; Save the interupt state:;        tpa             ; copy the Condition-code register to the accumulator        psha            ; save the copy on the stack        sei             ; disable interrupts temporarily;; Put critical section code here.;;; Restore the interrupt state:;        pula            ; get saved condition-codes from the stack        tap             ; restore interupt mask, as well as all other condition codes.

0 件の賞賛
返信

1,361件の閲覧回数
Lundin
Senior Contributor IV
To the OP: this have nothing to do with the compiler and platform (again). Please stop accusing the compiler for not doing things that is the programmer's responsibility to handle, this isn't the first time you do so.

In addition to rocco's post, I'd like to add that any global variables shared between main() and the ISR should be declared as volatile. Otherwise you might get unpredicted results no matter if the subroutine is re-entrant or not, because of possible optimizing of the variable in main(). The optimizer will flag variables as used only if they are passed as parameters to a function, so if they are used from an ISR, which is never actually called by the code but by the mcu itself, the optimizer will think that no other function but main() uses them. This can cause very unpredictable results, and the only way of finding such bugs is to look at the disassembly.

Regarding critical sections, you will likely only need to disable the interrupt source that will call the specific ISR. In that case you can do it in C, just disable interrupts in the hardware register for the specific peripheral, and do that from main(), before you call the subroutine, and enable them again afterwards.
0 件の賞賛
返信

1,361件の閲覧回数
BasePointer
Contributor II
Hi Lundin,
 
Fully ANSI C Compatible Hitech PICC18 doesn't support re-entrant functions. It uses shared global variables allocated automatically by the compiler for local variables instead of stack structure. So their functions are always being non re-entrant. This is a limitation. As I understand from rocco, same limitation isn't valid for CW HCS08 C. In my pic project, I have to use ProcessBitFilterISR and ProcessBitFilterMain that are identical to the same function. This dramatically increases program size required. This is good for HCS08 C because it generates more optimal codes because of stack usage. But at that time, we must take care of stack size that we need.
 
Thank you.
0 件の賞賛
返信

1,361件の閲覧回数
Lundin
Senior Contributor IV
Then it is not fully ANSI C compatible.

ANSI/ISO 9899:1999

"5.2.3 Signals and interrupts

Functions shall be implemented such that they may be interrupted at any time by a signal, or may be called by a signal handler, or both, with no alteration to earlier, but still active, invocations’ control flow (after the interruption), function return values, or objects with automatic storage duration. All such objects shall be maintained outside the function image (the instructions that compose the executable representation of a function) on a per-invocation basis."


Codewarrior follows ANSI C though, since it stores local variables on the stack.
0 件の賞賛
返信