k=0;//this is a sort of critical section
data[0]=from_seconds (data[0]);
data[1]=from_minutes (data[1]);
data[2]=from_hours (data[2]).time;
k=1;//if it's zero, ISR won't read the data
Where does data[0] get its initial value from? OP comments imply it is first loaded with RTC data, then gets converted here into a different format. But where is the RTC data loaded?
In order to re-use the array, both loading RTC data and converting should happen within the "critical section". Otherwise, it would be possible for the ISR to fire between being loaded with RTC data and being converted. In general, I frown on re-using data arrays like that, especially with ISRs because an ISR will go out of its way to fire at the worst possible time.
Instead, it should work more on a handshaking philosophy. First, load an otherwise-unused array with the RTC data. Then, do the conversion inside the critical section. This ensures that at any and every possible time that the ISR could fire, the values in the data array will always be correct.
As a bonus, I would recommend against this type of critical section approach. Instead, if you need this sort of functionality, set INTCON3bits.INT1IE = 0 so that only this interrupt is masked. The interrupt flag will still be set, and when you set INTCON3bits.INT1IE = 1 later on, the interrupt will fire as expected.
I am concerned that the question implies that the there is something complicated inside the system. That complication might make this even more difficult than it sounds!
I recommend trying Mishyoshi's answer first. It focuses on a cleaner, less intricate, easier to build and test solution.
However, I'll try to give an overview of the way 'aborting' and interrupt service routine might be done, so that folks can judge for themselves.
From a purely technical perspective, it is possible to 'abort' an 'outer' interrupt service routine (ISR) which itself was interrupted to reach 'this' 'inner' interrupt service routine in specific cases, for embedded (Cortex-M processors). However it is a bit tricky, maybe very hard to debug and make robust, and will need some good assembler and hardware debug skills.
A 'simple' technique relies on the 'outer' ISR never ever, under any circumstances calling any functions. If that is not a feasible guarantee then it gets much harder. Put another way, this will work if and only if the 'inner' ISR is always and only called while executing code within the body of the 'outer' ISR, and never in a function called by the 'outer; ISR
It will also get more complex if there are two processor stacks. It is still feasible, but more tricky.
Background:
An ARM does not store the return address of the current running function or ISR on the stack.
That return address is stored in the link register called 'lr' or R14. The only way to update the LR register is with assembler. IIRC might not be as easy as it sounds as some compilers will reload LR after your inline assembler has done its business, or maybe whine.
The return address for the outer function or ISR is on the stack somewhere. Finding that and loading it into the LR will do some of the work to abort the 'outer' ISR when the inner ISR returns.
The other problem is tidying up the stack, and resetting the stack pointer. If that isn't done correctly, the return from the 'outer' ISR can not be simulated. The effect might be subtle with calculations going wrong, pointers damaged, loops wrong, etc. This will need assembler skills and good 'hardware debugging' skills to ensure it is tested and working.
If this isn't exactly correct stack memory might 'leak'.
Do you want me to proceed, i.e. does this sound feasible for you folks to write and debug? It is still quite involved, and I have limited bandwidth.
I would recommend getting a copy of The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors by Joseph Yiu ASAP if you don't already have it. It explains some of this stuff.
Best Answer
I have no experience with PIC, but the problem seems generic enough. I would create a simple array with two independent pointers into the array: one read pointer and one write pointer. Whenever you receive a byte, you increment the write pointer and write at the new position; in your main loop you could then check if the read pointer and the write pointer are the same. If not, you simply read and process from the buffer and increase the read pointer for every byte until they are.
You could then either reset the pointers to the beginning of the array, or let them "flow over" to the beginning making essentially a circular buffer. This is easiest if the size of the array is a factor of 2 as you can then simply bitmask both pointers after their increments.
Some example (pseudo)code: