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:

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 2010Posts: 12736

Posted: Wed Feb 14, 2018 2:06 am

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 2018Posts: 4Location: St. Louis, MO

reply

Posted: Wed Feb 14, 2018 5:40 pm

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 2010Posts: 5878Location: Greensville,Ontario

Posted: Wed Feb 14, 2018 5:58 pm

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 2010Posts: 974

Re: reply

Posted: Thu Feb 15, 2018 1:55 pm

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 2018Posts: 4Location: St. Louis, MO

cont...

Posted: Tue Feb 20, 2018 3:36 pm

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 2010Posts: 5878Location: Greensville,Ontario

Posted: Tue Feb 20, 2018 5:08 pm

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 2018Posts: 4Location: St. Louis, MO

cont...

Posted: Wed Feb 21, 2018 1:02 pm

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,