UART_PutString() not sending entire string. Unable to determine cause.

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.
DeHo_722036
Level 1
Level 1
First like received First like given

The attached project (UARTTest) has confounded me for days and I’m hoping that someone in the community can put fresh eyes on it and help me see the (probably obvious) error in my ways. Although part of a much larger project, I’ve isolated the troublesome bits in a simple-as-possible demonstration project.

SCENARIO:

I have a PSOC 5LP host that communicates via a single UART to a touchscreen display. The host sends commands to the display that the display confirms with one of 4 possible responses:

  • “>” indicates SUCCESS.
  • “!” indicates a SYNTAX ERROR
  • “#” indicates a CRC ERROR
  • ":" indicate human readable information (for debug).

OBJECTIVE:

For this test/demonstration I only want to SEND commands from the host, and wait for a SUCCESS response (indicated by the “>” prompt) before doing anything else.

When commands are RECEIVED asynchronously from the display as will be the case with user input, the host will dispatch each command to a unique handler that will respond by sending an instruction response (another command string) to the display, and again wait for the SUCCESS prompt before doing anything else.

DEMONSTRATION:

For testing, I use a terminal emulator (RealTerm) to emulate the display. I have attached a screenshot of a complete session to illustrate how it works— and the problem.

The simple project attached initializes a UART then:

  • The host SENDS a single command string to the display and waits for a SUCCESS response.
    • I (as the display) send the SUCCESS response (“>” without quotes, followed by a CR).
  • The host SENDS a second command string to the display and waits for a SUCCESS response.
    • I send the SUCCESS response.
  • The host SENDS a third command to the display and waits for a SUCCESS response.
    • I send the SUCCESS response.

Up to this point, all works well and as intended. The host has no problem sending the commands strings out via the UART, and will wait indefinitely for the SUCCESS response before doing anything else. However, if I then send a command TO THE HOST from the display, things don’t work so well. Continuing…

    • I send a command— “c1” (without quotes, followed by a CR).
  • The ISR is triggered and the host sends an INCOMPLETE command string in response.

What I expect to be returned is “Response to Command 1\r”. Instead, all I get is the first 5 characters (“Respo”) and nothing else.

After that happens, the program appears to be dead. Nothing else happens. The host will not respond to any other prompts or commands. Pausing code execution with the debugger, I find program apparently stuck in the while() loop that waits for the SUCCESS response. This indicates that it is waiting for a success response for the command it didn’t finish sending.

OBSERVATIONS & QUESTIONS:

1) The documentation and code comments for the UART API function UART_1_PutString() (used in my function SendTXCommandWait() to send the command strings to the display) all say that UART_1_PutString() is a blocking function and will not return until the last character is sent. However, the code seems to continue executing and enters the while loop before the entire string is sent.

2) Because the program is then waiting for the SUCCESS response, it is acting as though the entire command has been sent, although it has not. Because it has not, no success response will ever come from the display.

3) I’ve suspected some interrupt might be interrupting the sending of the command, but the only interrupt I’ve implemented is the ISR for the UART RX. That doesn’t call SendTXCommandWait() until a complete and properly terminated command string has been received from the display, and no other RX occurs until after that command would be successfully sent and received by the display, so I don’t see how it can’t be the RX interrupt and I can’t figure out what else might be disrupting the sending.

If experience is a guide, the problem is ME. I’m a little afraid to even submit this because I don’t look forward to learning what amateurish error I’m committing. And yet, I’ve spent days (and long nights) trying to figure this out with no joy. I’d be grateful for any feedback and suggestions for what might be causing this behavior-- especially if it means (and I imagine it does) that I'm about to learn a really valuable lesson.

A FEW ADDITIONAL NOTES:

  • I will add retries, timeouts, etc. and have, but removed them all the have a simpler example for troubleshooting.
  • I use sprintf() to prepare commands sent from the host because although this example is much simpler, in the real application most of them are dynamically created and it allows me to parameterize and format them easily as they are constructed.
  • UART is configured as 115200 baud, 8N1.
  • All commands whether sent by the PSOC host or the display must be terminated with a Carriage Return (0x0D).

Thank you!

Denver

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,

Since there has not been any correct answer,

I tried to study your code this morning.

The first thing I noticed was having DispatchCommand(RxStr)  in an ISR is troublesome,

so I only let set the flag "dispatch_command_flag" and let the main loop call DispatchCommand(RxStr) ;

Meantime, when I debugged your program,

the program was spending most of the time in SendTXCommandWiat(),

so I modified the function as follows

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

void SendTXCommandWait( void )

{

    // Send prepared command (in cmdStr)

    UART_1_PutString( cmdStr );

    CyDelay(10) ; /* by moto */

    txCmdStatus = TX_COMMAND_STATUS_PENDING_RESPONSE;

   

    while ( txCmdStatus != TX_COMMAND_STATUS_RTS )

    {   

        switch(txCmdStatus) {

        case TX_COMMAND_STATUS_SUCCESS:

            txCmdStatus = TX_COMMAND_STATUS_RTS;

            break ;

        case TX_COMMAND_STATUS_PENDING_RESPONSE:

            cursor() ;

            // UART_1_PutString("Pending Response\n\r") ;

            // CyDelay(10) ;

            break ;

        case TX_COMMAND_STATUS_CRC_FAILED:

            UART_1_PutString("CRC Failed\n\r") ;

            CyDelay(10) ;

            break ;

        case TX_COMMAND_STATUS_SYNTAX_ERROR:

            UART_1_PutString("Syntax Error\n\r") ;

            CyDelay(10) ;

            break ;

        case TX_COMMAND_STATUS_RTS:

            UART_1_PutString("Status RTS received\n\r") ;

            break ;

        case TX_COMMAND_STATUS_RETRY:

            UART_1_PutString("Status Entry\n\r") ;

            break ;

        default:

            break ;

        }

    }

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

Since TX_COMMAND_STATUS_PENDING_RESPONSE was most commonly stepped,

I introduced a cursor function, which will stay same place and show animated cursor to

let the user know that the program is waiting for you.

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

char pattern[] = { '|', '\\', '-', '/', '|', '\\', '-', '/' } ;

void cursor(void)

{

    static int phase = 0 ;

    UART_1_PutChar(0x08) ;

    UART_1_PutChar(pattern[phase]) ;

    CyDelay(100) ;

    phase = (phase + 1) % 9 ;

}

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

The result Tera Term log was

000-TeraTerm-log.JPG

I hope this can be a little hint for you 😉

moto

View solution in original post

6 Replies
NoriTan
Employee
Employee
25 sign-ins 5 questions asked 10 sign-ins

Denver,

You are calling the UART_1_GetChar() function in the ISR.  This function is not designed to be called from the ISR.  I suppose that a dead-lock condition occurs in the ISR.

Please make an interpreter logic in the SendTXCommandWait function to handle characters received from the UART RX.  In typical cases, there is no reason to modify the ISR inside.

Regards,

Noriaki

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

Denver,

The issue you are having that is causing the deadlock is that when you are in the UART_1_RXISR  you call DispatchCommand() which in turn calls SendTXCommandWait().  In SendTXCommandWait() you are performing a while() loop in the waiting for a response from the Rx input.  However because you are already in the UART_1_RXISR you have disabled interrupts.  Hence the deadlock.

Let me see if I can layout it out for you in sequence.  Here is the important code where the effect occurs.

main()

...

    SendTXCommandWait()

          ...

          while ( txCmdStatus != TX_COMMAND_STATUS_RTS )  // wait for status change

          ... //Terminal input "c1" provides RX inputs.  On the last character carriage return (EOM_CR)

              UART_1_RXISR  // entering an ISR automatically disables interrupts.

                    ...

                        GetRxStr(UART_1_GetChar())

                              ...

                              DispatchCommand(RxStr)    // more than one char detected

                                  ...

                                  if( strcmp(COMMAND_1, strCommand) == 0 )    // matches COMMAND_1

                                        ...

                                        SendTXCommandWait()

                                            ...

                                            while ( txCmdStatus != TX_COMMAND_STATUS_RTS )  // wait for status change

LOOK HERE =========================> // Here's where the lockup occurs because the interrupts are disabled

Allow me here to self-promote and recommend something that might address what you are trying to do here.

I created a set of custom components that can be used with PSoC Creator projects.

One component is called "Term".  It replaces the UART on the PSoC5 and has the added bonus that if can easily configure it to switch to the USB-UART by just switching one parameter.

Another component is called "MenuCmds".   It is a terminal input interpreter that allows the user to create complex menus and each command can be invoked by one character.

The last component is called "String_Funcs".  It's a Terminal input aid that allows the user to take string input from the terminal but filters out characters that don't match the filter type requested.  For example, you can specify "ift_fixed".  In this case the user must input numbers with or without a decimal point.  All other characters are ignored and not displayed on the terminal.

I recommend downloading the component library located in this link:  Terminal Support Component Library

Besides the component library it includes multiple demo projects of using these components and how easy it is to code with them.

Len

Len
"Engineering is an Art. The Art of Compromise."

Len,

Thanks a lot for your reply and feedback, AND for the reference to the library. I'll definitely check it out.

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,

While ago I wrote a sample for using UART.

Re: tty_utils a utility sample for CLI type program

So today I wrote a simple sample for you with CY8CKIT-059.

(Please change the device to yours)

schematic

001-schematic.JPG

pins

002-pins.JPG

main.c

===========

#include "project.h"

#include "tty_utils.h"

typedef void (*func_ptr)(void) ;

typedef struct _f_list_st_ {

    char *name ;

    func_ptr func ;

    char *description ;

} f_list_type ;

void do_help(void) ;

void do_lough(void) ;

f_list_type func_list[] = {

    { "help",  do_help,  "show help message"},

    { "lough", do_lough, "let MCU lough"},

    { 0,       0,        0 }

} ;

func_ptr get_func(char *cmd)

{

    int i = 0 ;

    func_ptr ptr ;

    for (i = 0 ; func_list.name ; i++ ) {

        if (strcmp(func_list.name, cmd) == 0) {

            break ;

        }

    }

    ptr = func_list.func ;

   

    return( ptr ) ;

}

void do_command(char *cmd)

{

    func_ptr func ;

   

    func = get_func(cmd) ;

    if (func) {

        func() ;

    } else {

        do_help() ;

    }

}

void init_hardware()

{

    CyGlobalIntEnable; /* Enable global interrupts. */

    tty_init() ;

}

int main(void)

{

    init_hardware() ;

   

    splash("5LP uart test") ;

   

    prompt() ;

    for(;;) {

        if (get_line()) {

            do_command(str) ;

            prompt() ;

        }

    }

}

void do_help(void)

{

    int i ;

   

    print("=== command ===\n\r") ;

    for (i = 0 ; func_list.name ; i++ ) {

        print(func_list.name) ;

        print(" : ") ;

        print(func_list.description) ;

        print("\n\r") ;

    }

    print("===============\n\r") ;

}

void do_lough(void)

{

    print("Ha ha ha ha!\n\r") ;

}

===========

Tera Term log

000-teraterm-log.JPG

You can add any numbers of commands with name, function, and its description in the following list.

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

f_list_type func_list[] = {

    { "help",  do_help,  "show help message"},

    { "lough", do_lough, "let MCU lough"},

    { 0,       0,        0 }

} ;

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

moto

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,

Since there has not been any correct answer,

I tried to study your code this morning.

The first thing I noticed was having DispatchCommand(RxStr)  in an ISR is troublesome,

so I only let set the flag "dispatch_command_flag" and let the main loop call DispatchCommand(RxStr) ;

Meantime, when I debugged your program,

the program was spending most of the time in SendTXCommandWiat(),

so I modified the function as follows

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

void SendTXCommandWait( void )

{

    // Send prepared command (in cmdStr)

    UART_1_PutString( cmdStr );

    CyDelay(10) ; /* by moto */

    txCmdStatus = TX_COMMAND_STATUS_PENDING_RESPONSE;

   

    while ( txCmdStatus != TX_COMMAND_STATUS_RTS )

    {   

        switch(txCmdStatus) {

        case TX_COMMAND_STATUS_SUCCESS:

            txCmdStatus = TX_COMMAND_STATUS_RTS;

            break ;

        case TX_COMMAND_STATUS_PENDING_RESPONSE:

            cursor() ;

            // UART_1_PutString("Pending Response\n\r") ;

            // CyDelay(10) ;

            break ;

        case TX_COMMAND_STATUS_CRC_FAILED:

            UART_1_PutString("CRC Failed\n\r") ;

            CyDelay(10) ;

            break ;

        case TX_COMMAND_STATUS_SYNTAX_ERROR:

            UART_1_PutString("Syntax Error\n\r") ;

            CyDelay(10) ;

            break ;

        case TX_COMMAND_STATUS_RTS:

            UART_1_PutString("Status RTS received\n\r") ;

            break ;

        case TX_COMMAND_STATUS_RETRY:

            UART_1_PutString("Status Entry\n\r") ;

            break ;

        default:

            break ;

        }

    }

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

Since TX_COMMAND_STATUS_PENDING_RESPONSE was most commonly stepped,

I introduced a cursor function, which will stay same place and show animated cursor to

let the user know that the program is waiting for you.

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

char pattern[] = { '|', '\\', '-', '/', '|', '\\', '-', '/' } ;

void cursor(void)

{

    static int phase = 0 ;

    UART_1_PutChar(0x08) ;

    UART_1_PutChar(pattern[phase]) ;

    CyDelay(100) ;

    phase = (phase + 1) % 9 ;

}

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

The result Tera Term log was

000-TeraTerm-log.JPG

I hope this can be a little hint for you 😉

moto

DeHo_722036
Level 1
Level 1
First like received First like given

Big thanks to ALL of you for your insightful and thorough replies. I'm evaluating each approach to see which of them will be most easily integrated into my existing application architecture and will implement one of them today and let you all know how it goes. Meanwhile, I have to say this is such a great community! I'm very grateful for the feedback and suggestions.