sprintf failure in ISR

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
jotic_1250681
Level 2
Level 2
First like received First like given Code Expert

I need to put a few lines of code in an interrupt service routine (ISR) to print the value in a variable at the time of the interrupt.  Timing is not critical, this is just a test to check an operation.  I have a CY8CKIT-059 board and use a counter (Counter_3X) to create the interrupt.  Here is the ISR

*  Place your includes, defines and code here

********************************************************************************/

/* `#START Counter_3X_Done_intc` */

   

    extern void Counter_3X_Stop();      //Stop Counter_3X

    extern uint16 charindex;            //Value from main program

    char strMsg3X[30];                  //Set up array for characters to print   

    sprintf(strMsg3X,"CharIndex = %u\r\n",charindex);      //Line 34

    int UART_1_PutString(strMsg3X);                        //Line 35

   

/* `#END` */

The first line (Line 34 in boldface) produces the Build error, "expected ')' before string constant" and when I hover over the string, the cursor shows "expected identifier".

When I hover over Line 35, I read the following, "a parameter list without types is only allowed in a function definition."  I have no idea what this means.

I have attached an image of the error and warning messages.  All I need is a way to display a value on a terminal for tests.  No printing will occur in the finished code.  If you can suggest an alternate way to accomplish my testing goal, I welcome your ideas.  Thank you. --Jon

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

So I tested it by myself using CY8CKIT-059.

I emulated your project with following schematic.

002-schematic.JPG

To make it work, I needed to modify the ISR as

(part of Counter_3X_Done.c)

============================

CY_ISR(Counter_3X_Done_Interrupt)

{

    #ifdef Counter_3X_Done_INTERRUPT_INTERRUPT_CALLBACK

        Counter_3X_Done_Interrupt_InterruptCallback();

    #endif /* Counter_3X_Done_INTERRUPT_INTERRUPT_CALLBACK */

    /*  Place your Interrupt code here. */

    /* `#START Counter_3X_Done_Interrupt` */

//    #include "project.h"

//    #include "stdio.h"

    extern void Counter_3X_Stop() ;

    extern void Counter_3X_ReadStatusRegister(void) ;

    extern uint16 charindex ;

    char strMsg3X[30] ;

  

    Counter_3X_Done_ClearPending() ;

    Counter_3X_ReadStatusRegister() ;

  

    sprintf(strMsg3X, "CharIndex = %u\r\n", charindex) ;

    UART_1_PutString(strMsg3X) ;

    /* `#END` */

}

============================

and the main.c

============================

#include "project.h"

#include "stdio.h"

uint16 charindex = 0 ;

char str[128] ; /* print buffer */

void print(char *str)

{

    UART_1_PutString(str) ;

}

void init_hardware(void)

{

    UART_1_Start() ;

  

    Counter_3X_Done_ClearPending() ;

    Counter_3X_Done_Start() ;

    Counter_3X_WriteCounter(0) ;

    Counter_3X_Init() ;

    Counter_3X_Enable() ;

  

    CyGlobalIntEnable; /* Enable global interrupts. */

}

void splash(void)

{

    sprintf(str, "PSoC LP5 Interrupt Test A (%s %s)\r\n", __DATE__, __TIME__) ;

    print(str) ;

}

int main(void)

{

    init_hardware() ;

  

    splash() ;

    for(;;) {

        charindex++ ;

        CyDelay(100) ;

    }

}

============================

And the Tera Term log was

000-TeraTerm-LogA.JPG

So anyway, the project seems to be working.

But as I wrote earlier, having sprintf(), PutString() in ISR is not recommend because of a couple of reasons (IMHO)

(1) They usually take rather long time, where an ISR is expected return as soon as possible.

(2) They tend to allocate and/or move memory, which is also not good for an ISR, in some MCU it causes hang.

Meantime, in general, I don't want touch "system generated source/header", for example

"Counter_3X_Done.c" in this case.

I'd rather use Counter_3X_Done_StartEx() instead of Counter_3X_Done_Start() 

so that I can prepare the ISR in my source files.

In the following example, "counter_done_isr()".

I rewrote the program as below.

I used Counter_3X_Done_StartEx(),

and in the ISR I only saved charindex to a variable "value_at_int"

and print it in the main loop.

Note: Please forgive me for using sprintf() instead of snprintf() 😜

main.c

============================

#include "project.h"

#include "stdio.h"

volatile uint16_t value_at_int = 0 ;

volatile int counter_done_flag = 0 ;

uint16_t charindex = 0 ;

char str[128] ; /* print buffer */

void print(char *str)

{

    UART_1_PutString(str) ;

}

CY_ISR(counter_done_isr)

{

    Counter_3X_ReadStatusRegister() ;

    Counter_3X_Done_ClearPending() ;

   

    counter_done_flag = 1 ;

    value_at_int = charindex ;

}

void init_hardware(void)

{

    UART_1_Start() ;

   

    Counter_3X_Done_ClearPending() ;

    Counter_3X_Done_StartEx(counter_done_isr) ;

    Counter_3X_WriteCounter(0) ;

    Counter_3X_Init() ;

    Counter_3X_Enable() ;

   

    CyGlobalIntEnable; /* Enable global interrupts. */

}

void splash(void)

{

    sprintf(str, "PSoC LP5 Interrupt Test B (%s %s)\r\n", __DATE__, __TIME__) ;

    print(str) ;

}

int main(void)

{

    init_hardware() ;

   

    splash() ;

    for(;;) {

        charindex++ ;

       

        if (counter_done_flag) {

            counter_done_flag = 0 ;

            sprintf(str, "charindex = %d\n", value_at_int) ;

            print(str) ;

        }

        CyDelay(100) ;

    }

}

============================

The Tera Term Log was

001-TeraTerm-logB.JPG

moto

P.S. Attached are

int_test_190605A printing in the ISR

int_test_190605B printing in the main loop

View solution in original post

0 Likes
3 Replies
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

In general, using print type function in an isr is not recommended.

Having said that, what I could notice was

>     int UART_1_PutString(strMsg3X);                        //Line 35

should be

<    UART_1_PutString(strMsg3X);                        //Line 35

Would you let me know, what kind of error(s) you will get after modifying the above?

moto

0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

Jon,

Moto is correct.  The general principle I learned long ago is to only perform the bare minimum in ISRs.  Basically just gather the data and/or turn on something quickly.  What ever the ISR was truly intended for.  All other time intensive operations should be done at the higher-level Application SW.  sprintf()s and PutString() functions are time intensive and will probably use quite a bit of stack.  Inside an ISR, you've already used a bit a stack to get there.

If more processing is needed after executing an ISR, then set a signal (RAM flag for example) so that the Application task level can pick up the signal can execute the additional operations.

Len

PS:  I recommend using snprintf() instead of sprintf().  snprintf() is an ANSI-safe function.  It prevents string buffer overruns.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

So I tested it by myself using CY8CKIT-059.

I emulated your project with following schematic.

002-schematic.JPG

To make it work, I needed to modify the ISR as

(part of Counter_3X_Done.c)

============================

CY_ISR(Counter_3X_Done_Interrupt)

{

    #ifdef Counter_3X_Done_INTERRUPT_INTERRUPT_CALLBACK

        Counter_3X_Done_Interrupt_InterruptCallback();

    #endif /* Counter_3X_Done_INTERRUPT_INTERRUPT_CALLBACK */

    /*  Place your Interrupt code here. */

    /* `#START Counter_3X_Done_Interrupt` */

//    #include "project.h"

//    #include "stdio.h"

    extern void Counter_3X_Stop() ;

    extern void Counter_3X_ReadStatusRegister(void) ;

    extern uint16 charindex ;

    char strMsg3X[30] ;

  

    Counter_3X_Done_ClearPending() ;

    Counter_3X_ReadStatusRegister() ;

  

    sprintf(strMsg3X, "CharIndex = %u\r\n", charindex) ;

    UART_1_PutString(strMsg3X) ;

    /* `#END` */

}

============================

and the main.c

============================

#include "project.h"

#include "stdio.h"

uint16 charindex = 0 ;

char str[128] ; /* print buffer */

void print(char *str)

{

    UART_1_PutString(str) ;

}

void init_hardware(void)

{

    UART_1_Start() ;

  

    Counter_3X_Done_ClearPending() ;

    Counter_3X_Done_Start() ;

    Counter_3X_WriteCounter(0) ;

    Counter_3X_Init() ;

    Counter_3X_Enable() ;

  

    CyGlobalIntEnable; /* Enable global interrupts. */

}

void splash(void)

{

    sprintf(str, "PSoC LP5 Interrupt Test A (%s %s)\r\n", __DATE__, __TIME__) ;

    print(str) ;

}

int main(void)

{

    init_hardware() ;

  

    splash() ;

    for(;;) {

        charindex++ ;

        CyDelay(100) ;

    }

}

============================

And the Tera Term log was

000-TeraTerm-LogA.JPG

So anyway, the project seems to be working.

But as I wrote earlier, having sprintf(), PutString() in ISR is not recommend because of a couple of reasons (IMHO)

(1) They usually take rather long time, where an ISR is expected return as soon as possible.

(2) They tend to allocate and/or move memory, which is also not good for an ISR, in some MCU it causes hang.

Meantime, in general, I don't want touch "system generated source/header", for example

"Counter_3X_Done.c" in this case.

I'd rather use Counter_3X_Done_StartEx() instead of Counter_3X_Done_Start() 

so that I can prepare the ISR in my source files.

In the following example, "counter_done_isr()".

I rewrote the program as below.

I used Counter_3X_Done_StartEx(),

and in the ISR I only saved charindex to a variable "value_at_int"

and print it in the main loop.

Note: Please forgive me for using sprintf() instead of snprintf() 😜

main.c

============================

#include "project.h"

#include "stdio.h"

volatile uint16_t value_at_int = 0 ;

volatile int counter_done_flag = 0 ;

uint16_t charindex = 0 ;

char str[128] ; /* print buffer */

void print(char *str)

{

    UART_1_PutString(str) ;

}

CY_ISR(counter_done_isr)

{

    Counter_3X_ReadStatusRegister() ;

    Counter_3X_Done_ClearPending() ;

   

    counter_done_flag = 1 ;

    value_at_int = charindex ;

}

void init_hardware(void)

{

    UART_1_Start() ;

   

    Counter_3X_Done_ClearPending() ;

    Counter_3X_Done_StartEx(counter_done_isr) ;

    Counter_3X_WriteCounter(0) ;

    Counter_3X_Init() ;

    Counter_3X_Enable() ;

   

    CyGlobalIntEnable; /* Enable global interrupts. */

}

void splash(void)

{

    sprintf(str, "PSoC LP5 Interrupt Test B (%s %s)\r\n", __DATE__, __TIME__) ;

    print(str) ;

}

int main(void)

{

    init_hardware() ;

   

    splash() ;

    for(;;) {

        charindex++ ;

       

        if (counter_done_flag) {

            counter_done_flag = 0 ;

            sprintf(str, "charindex = %d\n", value_at_int) ;

            print(str) ;

        }

        CyDelay(100) ;

    }

}

============================

The Tera Term Log was

001-TeraTerm-logB.JPG

moto

P.S. Attached are

int_test_190605A printing in the ISR

int_test_190605B printing in the main loop

0 Likes