|
|
View previous topic :: View next topic |
Author |
Message |
RickMarsen
Joined: 31 Oct 2008 Posts: 17
|
Correct Way of Temporarily Disabling an Interrupt |
Posted: Wed Dec 24, 2008 2:20 pm |
|
|
I have a PIC18F4685 that communicates over a half-duplex RS232-type bus. The bus itself is a single wire that switches from GND to 24V using an open collector and a pull-up. The IC that handles the electrical interface (i.e. voltage translation) internally echoes PIC's C6(TX) to its C7(RX).
That means that every time PIC sends a byte, it also gets an INT_RDA interrupt and gets the byte it just sent out. This behavior is not desirable. I'd like to ignore anything that's sent out. In fact, I'd rather not be interrupted at all due to bytes I put on the bus.
I disabled the RDA interrupt inside of the sending function (below) and it does work, but I got there by trial and error and don't really know why it works. For example if I comment out the getch(PC_COMM); line the "self-interrupts" start up. I put it back in, and they stop.
Ideally, I'd like to disable just INT_RDA, not all GLOBAL (I plan to have an INT_EXT for example I'd like to be able to service at all times), but this was the only combination that works. Anyone have any ideas?
Code: | void send_one_byte(int data)
{
disable_interrupts(INT_RDA);
disable_interrupts(GLOBAL);
//fprintf(PC_COMM, "%C", data);
putc(data);
clear_interrupt(INT_RDA);
getch(PC_COMM);
delay_ms(15); // Ensure 15ms spacing between calls
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
} |
|
|
|
Ttelmah Guest
|
|
Posted: Wed Dec 24, 2008 4:01 pm |
|
|
You only need to disable the interrupt you are worried about. Turning off 'global' as well, turns off _all_ interrupts. See below for why you may need this.
Now, the problem in your case, is that since it takes time to send a byte, you need to wait for the transmission to complete, and read the byte retrieved, before re-enabling the interrupt.
So, more efficient code would be:
Code: |
void send_one_byte(int data) {
disable_interrupts(INT_RDA);
putc(data);
getc(); //Reading the byte, clears the interrupt
enable_interrupts(INT_RDA);
delay_ms(15); //If you need a delay, put it outside the disabled section.
}
|
Now, the 'getc', is essential. It is this that actually waits for the character to arrive, and clears the interrupt. The RDA interrupt, actually cannot be cleared, while a byte is waiting. This is why removing the getc, stopped the code working.
Second comment, you are using a stream name in the getc, but not anywhere else. Is there only one stream?.
Third comment, if you need to use the global disable instead (you don't need both), it implies that one of your other interrupt routines, is itself accessing the UART. If so, then you just need to substitute 'GLOBAL' for 'INT_RDA' in both the disables. However this is 'messy', and suggests you should re-think your approach.
As a comment, why not leave interrupts enabled, and just throw away the transmitted byte? You can do this by just setting a flag 'next_throw', as soon as you call putc, and in the receive interrupt, if this flag is set, just throw away the character, and clear this flag. This way the interrupt can be left enabled (except for the couple of instructions while you call putc, and set the flag). Improves the chances of not missing anything.
Best Wishes |
|
|
RickMarsen
Joined: 31 Oct 2008 Posts: 17
|
|
Posted: Wed Dec 24, 2008 4:44 pm |
|
|
Ttelmah,
Thanks for taking a look at my code. The code you replied with works great. I will try to re-write my send function, as suggested, with a flag that removes the need to disable any interrupts.
You are correct, there _is_ only one serial stream in this project - I was just reusing some code I wrote before. getch(PC_COMM) has been replaced by getc() throughout.
Rick |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|