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 support@ccsinfo.com

How to fprintf in ISR?

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



Joined: 27 Jul 2013
Posts: 79

View user's profile Send private message

How to fprintf in ISR?
PostPosted: Fri May 27, 2016 1:45 am     Reply with quote

I am using a serial device that expects an "ACK" very very quickly.
Sending the "ACK" in the main loop is not an option, because the period of the main loop is larger than required.
The only solution that I can think of is to send the ACK in the ISR. How do I printf in the ISR without any inviting any reentrancy issues?
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:10 am     Reply with quote

If your ACK is only one char, then just use:-

Code:

    /* Where c is the char to output */
    putc( c );


However, remember that if a char is already being transmitted or TX buf is full, it will WAIT in the interrupt until OK to send - not good practice.

Also remember that interrupts take a modest amount of time to enter.. how quickly is the device expecting the char?


Keith
haxan7



Joined: 27 Jul 2013
Posts: 79

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:17 am     Reply with quote

The ACK string is 10 characters, it includes a hex representation of a checksum. Currently I use "%02X" in the fprintf for string formatting and it works fine.

kWoody_uk wrote:

Also remember that interrupts take a modest amount of time to enter.. how quickly is the device expecting the char?

Approximately one second.
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:22 am     Reply with quote

One second is a good period of time for an acknowledge request. What are you doing in your main loop that is taking more than several hundred milliseconds? Are you waiting for something to occur?

I would never fprintf() in an interrupt unless routing through a buffering routine to be output in the UART TX interrupt, as demonstrated in CCS example file "ex_stisr.c"


Keith
haxan7



Joined: 27 Jul 2013
Posts: 79

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:29 am     Reply with quote

There is a lot of stuff happening in the main loop, like talking to a modem, reading/writing to a flash memory etc. It does not always takes 1 second, but it happens often.
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:37 am     Reply with quote

OK, sounds like you'll have to re-prioritise your code.

If, the rest of your code can take a back seat when the ACK is needed, then I would say to follow my suggestion of buffering your ACK bytes for automatic transmission in the UART TX isr.


Keith
haxan7



Joined: 27 Jul 2013
Posts: 79

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:49 am     Reply with quote

Even with interrupt based transmission I would still have to use a function like sprintf in the ISR.
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Fri May 27, 2016 4:59 am     Reply with quote

Yes, but NOT in the INT_TBE (Uart transmit interrupt).

Which interrupt are you currently using the fprintf() function?

Use:-
Code:

    printf( functionName, cstring, values )

.. in the function that has received the command to request an acknowledgement in the first place, where functionName is a function which will handle the formatted string.

e.g.
Code:

    /* Not the formatting chars you need, just an example
    printf( bufTxByte, "n=%u", n );


This function will store each byte into your software circular buffer which will be output, a byte at a time, in the INT_TBE interrupt, each time a character has been sent. At 9600 baud each byte takes around 1ms to transmit; allowing your code to progress until another byte need to go.

If this sounds a bit involved, you'll have to look at the example I mentioned.

Keith
Ttelmah



Joined: 11 Mar 2010
Posts: 19278

View user's profile Send private message

PostPosted: Fri May 27, 2016 11:58 am     Reply with quote

haxan7 wrote:
Even with interrupt based transmission I would still have to use a function like sprintf in the ISR.


All you need to do, is put the required data into the software buffer.

You can do two buffer write routines.

One that simply adds data to the buffer. Then the second, which disables interrupts before it writes to the buffer, and re-enables them afterwards. printf to this in the main code. This is like bputc in ex_stisr, except for adding the disable/enable interrupts.

In the ISR, after writing the data, enable INT_TBE.

In the main, have the buffer write, enable INT_TBE. This is as in the ex_stisr example.

Do a search here on how to avoid using % in the buffer maths.

If the reply is a fixed string then you can simply use:

interrupt_bputc("The string you want");

Then just enable INT_TBE, and you are done.

If the hardware buffer is empty, as soon as you leave the ISR, the data will start transmitting.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri May 27, 2016 3:13 pm     Reply with quote

you say:
Quote:

very very quickly.
....
Approximately one second.
.......
10 characters, it includes a hex representation of a checksum.


I find the intersection of these 3 statements fascinating.

to me "very" is milliseconds while
"very very" suggests microseconds of delay -
that's very very quickly IMB
( VERY VERY VERY - that's nanosecs ;-))
Fast just means "eventually" Very Happy Very Happy

But then you say the response can take a second - that's SLOW by me, unles your Fosc is 32khz

And then the meat of the fast response. The fixed-character-string time to begin the 'ACK' is baud rate determined,
but do you not calculate the CRC - and then send it ?
or
are you incrementally doing CRC calcs "rolling forward"
as new chars arrive?

Have you time profiled how long your response takes to send ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19278

View user's profile Send private message

PostPosted: Sat May 28, 2016 2:18 pm     Reply with quote

Also, don't get me wrong, but converting a byte to two hex characters is very much more efficiently 'doable' than using printf.
Assuming 'interrupt_bputc', is the routine to write a character to the buffer:
Code:

#inline void digit(int8 val)
{
    val&=0xF;
    if (val<10)
       interrupt_bputc(val+'0');
    else
       interrupt_bputc(val+('A'-10));
}

#inline void to_hex(int8 val)
{
   int8 temp = val;
   swap(val); //this codes as the processors swap instruction
   digit(val); //outputs the MS nibble
   digit(temp); //Now the LS nibble
}


Called with 'to_hex(checksum_value);', this is close to assembler efficiency to output two hex digits (relatively bulky, doing the digits inline - leaving them separate saves space but costs a little speed).
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