CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Using printf/putc inside interrupt

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
sdzafic



Joined: 21 Jan 2018
Posts: 4
Location: St. Louis, MO

View user's profile Send private message

Using printf/putc inside interrupt
PostPosted: Wed Feb 14, 2018 12:46 am     Reply with quote

Does anyone have any experience with sending a data packet out the serial port using an ISR ? Doing it this way may not be the best practice however, one sometimes has to make some sacrifices for readability and I thought that something like this:
Code:

#INT_TIMER0
void timer0_isr(void)
{
putc(buffer);
clear_interrupt(INT_TIMER0);
set_timer0(0); 
}

...made more sense than inserting random putc(buffer); statements around my code.

This is a simple 485 network with a master and some number of slaves. The master polls the slaves for status every so often. If any slave does not receive anything for a while then he will presume that comms are down and will fall into "failsafe" mode where the outputs are killed and an alarm relay is set.

I recently added a simple little user interface to the master and I found out the hard way that when I'm in programming mode, there are no comms and the slaves fall into this failsafe.

I would like to simply detect when the master is in programming mode and use the ISR to send out a "keep alive" packet every few seconds or so. Another idea I had that may be more useful is to shoot out a broadcast command to all slaves telling them I'm in programming mode or busy or whatever. This way the slaves can ignore the timeouts until the master is not busy and issues another command to re-enable that functionality of the slave.

Any suggestions would be cool.
_________________
Regards,

Steve
Ttelmah



Joined: 11 Mar 2010
Posts: 19535

View user's profile Send private message

PostPosted: Wed Feb 14, 2018 2:06 am     Reply with quote

As a comment, your 'clear interrupt', is a wasted instruction. The compiler automatically clears the interrupt when the handler exits, unless you specify 'NOCLEAR' in the interrupt definition. Your set to zero is also potentially pointless. The interrupt is called 'when' the timer wraps to zero. Now if the print is taking significant time, this would prevent a 're-call' before the timer count has expired, but if so it is showing that the putc is taking more time than is really sensible...

Now on the main question.
Several parts:

First, a huge amount depends on whether you use any putc/printf statements to the same port anywhere else in the code?.
If you do, you have a problem. If you think about it, there is one UART. What would happen if a routine was mid print, and then the interrupt occurred?. The compiler will automatically disable interrupts in every external print/putc to the same UART to avoid this.

Second, what are you trying to send?. Putc, sends a single character. The reference to 'buffer', which tends to imply a larger store of some sort is possibly worrying.... Putc has an 'overload', in that it will print _constant_ strings, but it won't print variable strings. If you are trying to print anything larger than a single character, then 'timing' starts to rear it's head.
What do I mean about 'timing'?. Serial takes time. If you are outputting data at (say) 9600bps, a single character takes (basically) a mSec. Now the hardware UART can accept 'from empty', two characters. It'll transfer the first to the shift register, and the second to the buffer register. Try to send a third, and you have to wait for one to have sent. All the time you are waiting for this to be sent, your code will be 'stuck' in this interrupt, and nothing else will be happening. Result will be code that doesn't run as expected....

So for single character sent no more often than the serial can actually output data, and with no other output to the same port anywhere else, this is fine. Otherwise it brings problems.

Now one solution, if you want to send more data, is to use the interrupt driven transmit. Look at the example ex_stisr.c. This shows how to send data to a RAM buffer, that is then output automatically as the port sends the bytes. You can send a message to this inside an ISR, and _provided there is space in the buffer_, the time involved will then be small (you still have problems if you send from anywhere else to the same output).
sdzafic



Joined: 21 Jan 2018
Posts: 4
Location: St. Louis, MO

View user's profile Send private message

reply
PostPosted: Wed Feb 14, 2018 5:40 pm     Reply with quote

You're right about one thing...re-entrancy. I know that in my case this is not possible but, the compiler cannot figure this out. If I could find the putc(); function that CCS wrote then I would consider just making it easy on myself and copy that code into a new function of another name and I think it would work.

However; the more I think about it, I think the best solution at this point is to create another command that will cause the slave devices to stop listening for a poll until I send out another broadcast letting them know that I'm ready to start polling again. This is not a huge amount of work but, I would have to do some work in both firmware's instead of just the one.
_________________
Regards,

Steve
temtronic



Joined: 01 Jul 2010
Posts: 9240
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Feb 14, 2018 5:58 pm     Reply with quote

just a head's up...
Steve the GREAT thing about CCS is they do not hide anything. Just create a small program with putc() ,compile, test, then dump the listing. It's all there....kinda helps if you know PIC assembler to see why they do what they do, but it's there....

Jay
jeremiah



Joined: 20 Jul 2010
Posts: 1353

View user's profile Send private message

Re: reply
PostPosted: Thu Feb 15, 2018 1:55 pm     Reply with quote

sdzafic wrote:
You're right about one thing...re-entrancy. I know that in my case this is not possible but, the compiler cannot figure this out. If I could find the putc(); function that CCS wrote then I would consider just making it easy on myself and copy that code into a new function of another name and I think it would work.

However; the more I think about it, I think the best solution at this point is to create another command that will cause the slave devices to stop listening for a poll until I send out another broadcast letting them know that I'm ready to start polling again. This is not a huge amount of work but, I would have to do some work in both firmware's instead of just the one.


I would definitely recommend considering Ttelmah's solution of using the buffer similar to ex_stisr.c. That way, only your interrupt calls putc, and all your other code can use bputc, safely and fast.

Additionally, you can still use printf in your non interrupt code, but you just need to adjust the syntax:

classic:
Code:

printf(bputc,"Hello world");


or if you want some syntatic sugar:

Code:

#define u1_printf(fmt,...) printf(bputc,fmt,__VA_ARGS__)

//and then in your code:
u1_printf("Hello World");
sdzafic



Joined: 21 Jan 2018
Posts: 4
Location: St. Louis, MO

View user's profile Send private message

cont...
PostPosted: Tue Feb 20, 2018 3:36 pm     Reply with quote

Thanks for the input guys but what I was really hoping for were any ideas that were better than mine on how to keep the slaves alive when the master is busy. I'm going to implement one of my original ideas to send out a broadcast. This way the slaves can manage themselves for a bit.
_________________
Regards,

Steve
temtronic



Joined: 01 Jul 2010
Posts: 9240
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Feb 20, 2018 5:08 pm     Reply with quote

I've been thinking about this for a bit...
It makes good sense to have the 'master' tell the 'slaves' what 'state' it is in. Having the master say 'I'm in programming mode' alerts the slaves to a KNOWN condition, and they can act accordingly (maybe flash 'awaiting instructions') LED. If the master does nothing, that is different, so something like 'failsafe' mode can be entered.

It is easy to modify the ex_stisr.c program to have the master transmit 'something' within an ISR, so YOU don't have to do the housekeeping.

Jay
sdzafic



Joined: 21 Jan 2018
Posts: 4
Location: St. Louis, MO

View user's profile Send private message

cont...
PostPosted: Wed Feb 21, 2018 1:02 pm     Reply with quote

I agree. I already have my serial protocol stuff in place so all a need to do is create a new command. I'll need to do a little more work on the slave side so they can behave accordingly. I'm trying not to make the slaves too "smart". I would like to stick to the nature of master/slave relationships where they can only execute a command that the master gives them.
_________________
Regards,

Steve
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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