KSDK 1.1.0 getchar() does not return EOF

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

KSDK 1.1.0 getchar() does not return EOF

Jump to solution
2,050 Views
surrealist14
Contributor III

Hi folks, I have started using KSDK 1.1.0 with the TWR-K60D100M.  I can build and run the "hello world" demo without problem, but it seems that getchar() exhibits non-standard behavior.  Instead of returning EOF if no character is available, it blocks.

 

I'm using the IAR 7.40.2 ARM tools for Cortex-M.  I'm not using MQX or any other RTOS.  The application I will be developing is a "bare metal" super-loop.

 

I think the offending area in the KSDK code is in the implementation of _read(), in fsl_debug_console.c.  Here it is:

 

#pragma weak __read

size_t __read(int handle, unsigned char * buffer, size_t size)

{

    /* This function only reads from "standard in", for all other file*/

    /* handles it returns failure.*/

    if (handle != _LLIO_STDIN)

    {

        return _LLIO_ERROR;

    }

 

    /* Do nothing if the debug uart is not initialized.*/

    if (s_debugConsole.type == kDebugConsoleNone)

    {

        return _LLIO_ERROR;

    }

 

    /* Receive data.*/

    s_debugConsole.ops.rx_union.Receive(s_debugConsole.baseAddr, buffer, size);

 

    return size;

}

 

The Receive() function above in turn calls UART_HAL_ReceiveDataPolling(), from fsl_uart_hal.c.  Here's the code:

 

uart_status_t UART_HAL_ReceiveDataPolling(uint32_t baseAddr,

                                          uint8_t *rxBuff,

                                          uint32_t rxSize)

{

    uart_status_t retVal = kStatus_UART_Success;

 

    while (rxSize--)

    {

        while (!UART_HAL_IsRxDataRegFull(baseAddr))

        {}

 

        UART_HAL_Getchar(baseAddr, rxBuff++);

       

        /* Clear the Overrun flag since it will block receiving */

        if (BR_UART_S1_OR(baseAddr))

        {

            HW_UART_S1_RD(baseAddr);

            HW_UART_D_RD(baseAddr);

            retVal = kStatus_UART_RxOverRun;

        }

    }

 

    return retVal;

}

 

The loop while (!UART_HAL_ISRxDataRegFull(baseAddr)) guarantees that this function won't return until a character is actually received.  According to all the C references I have read, it _should_ return an EOF is there isn't a character available.  That way the code could poll for a character, and if it gets EOF, just skip to the next step in my super-loop.

 

In pseudocode, something like this:

 

while (1)

{

     int c;

 

     while ((c = getchar()) != EOF)

     {

          // Add the character to an input buffer

          // See if it's the end of the line

          // If so, parse the line and decide what command to execute

     }

 

     RunTask1();     // Functions that perform some kind of ongoing action, like reading ADC values, scanning GPIO lines, etc.

     RunTask2();

     // etc.

}

 

Have any of you run into this situation?  How did you keep getchar() from blocking?  I could rewrite the _read() function to do what I need, but I'm a little surprised at the default behavior of the fsl_debug_console.

 

As a next step, I would like to run the UART transmit and receive in interrupt-driven mode to avoid polling altogether, perhaps only checking to see if an entire input line has been received.  Do any of you have examples of how to set up a UART in interrupt mode with buffers for transmit and receive?  And down the line, there will be two UARTs, one that accepts commands from a PC and one to dump out debug information (and maybe accept some simple debug commands).

 

Many thanks for your help!

Labels (1)
1 Solution
1,079 Views
surrealist14
Contributor III

I got something working and wanted to share what I did for feedback.  It eliminates the busy-wait-forever for getchar(), and getchar() will now return an EOF if no data is available.

In fsl_uart_hal.c, I changed UAR_HAL_ReceiveDataPolling() to the following:

/*FUNCTION**********************************************************************

*

* Function Name : UART_HAL_ReceiveDataPolling

* Description   : Receive multiple bytes of data using polling method.

* This function only supports 8-bit transaction.

*

*END**************************************************************************/

uart_status_t UART_HAL_ReceiveDataPolling(uint32_t baseAddr,

                                          uint8_t *rxBuff,

                                          uint32_t rxSize)

{

    uart_status_t retVal = kStatus_UART_Success;

    while (rxSize--)

    {

        // Return if no data available

        if (!UART_HAL_IsRxDataRegFull(baseAddr))

        {

            return kStatus_UART_NoDataToDeal;

        }

        UART_HAL_Getchar(baseAddr, rxBuff++);

        /* Clear the Overrun flag since it will block receiving */

        if (BR_UART_S1_OR(baseAddr))

        {

            HW_UART_S1_RD(baseAddr);

            HW_UART_D_RD(baseAddr);

            retVal = kStatus_UART_RxOverRun;

        }

    }

    return retVal;

}

This returns kStatus_UART_NoDataToDeal if there isn't a character available.  Then in fsl_debug_console.c, I changed __read() to the following:

#pragma weak __read

size_t __read(int handle, unsigned char * buffer, size_t size)

{

    uart_status_t status;

    /* This function only reads from "standard in", for all other file*/

    /* handles it returns failure.*/

    if (handle != _LLIO_STDIN)

    {

        return _LLIO_ERROR;

    }

    /* Do nothing if the debug uart is not initialized.*/

    if (s_debugConsole.type == kDebugConsoleNone)

    {

        return _LLIO_ERROR;

    }

    /* Receive data.*/

    status = s_debugConsole.ops.rx_union.UART_Receive(s_debugConsole.baseAddr, buffer, size);

    if (kStatus_UART_NoDataToDeal == status)

    {

        size = 0;   // No data read

    }

    return size;

}

That's it.  getchar() calls __read() eventually, which then calls UART_HAL_ReceiveDataPolling().  If no character is available, UART_HAL_ReceiveDataPolling() returns kStatus_UART_NoDataToDeal, which causes __read() to return 0 (bytes read), which causes getchar() to return EOF.

Comments/suggestions, anyone?  Thanks!

View solution in original post

0 Kudos
12 Replies
1,080 Views
surrealist14
Contributor III

I got something working and wanted to share what I did for feedback.  It eliminates the busy-wait-forever for getchar(), and getchar() will now return an EOF if no data is available.

In fsl_uart_hal.c, I changed UAR_HAL_ReceiveDataPolling() to the following:

/*FUNCTION**********************************************************************

*

* Function Name : UART_HAL_ReceiveDataPolling

* Description   : Receive multiple bytes of data using polling method.

* This function only supports 8-bit transaction.

*

*END**************************************************************************/

uart_status_t UART_HAL_ReceiveDataPolling(uint32_t baseAddr,

                                          uint8_t *rxBuff,

                                          uint32_t rxSize)

{

    uart_status_t retVal = kStatus_UART_Success;

    while (rxSize--)

    {

        // Return if no data available

        if (!UART_HAL_IsRxDataRegFull(baseAddr))

        {

            return kStatus_UART_NoDataToDeal;

        }

        UART_HAL_Getchar(baseAddr, rxBuff++);

        /* Clear the Overrun flag since it will block receiving */

        if (BR_UART_S1_OR(baseAddr))

        {

            HW_UART_S1_RD(baseAddr);

            HW_UART_D_RD(baseAddr);

            retVal = kStatus_UART_RxOverRun;

        }

    }

    return retVal;

}

This returns kStatus_UART_NoDataToDeal if there isn't a character available.  Then in fsl_debug_console.c, I changed __read() to the following:

#pragma weak __read

size_t __read(int handle, unsigned char * buffer, size_t size)

{

    uart_status_t status;

    /* This function only reads from "standard in", for all other file*/

    /* handles it returns failure.*/

    if (handle != _LLIO_STDIN)

    {

        return _LLIO_ERROR;

    }

    /* Do nothing if the debug uart is not initialized.*/

    if (s_debugConsole.type == kDebugConsoleNone)

    {

        return _LLIO_ERROR;

    }

    /* Receive data.*/

    status = s_debugConsole.ops.rx_union.UART_Receive(s_debugConsole.baseAddr, buffer, size);

    if (kStatus_UART_NoDataToDeal == status)

    {

        size = 0;   // No data read

    }

    return size;

}

That's it.  getchar() calls __read() eventually, which then calls UART_HAL_ReceiveDataPolling().  If no character is available, UART_HAL_ReceiveDataPolling() returns kStatus_UART_NoDataToDeal, which causes __read() to return 0 (bytes read), which causes getchar() to return EOF.

Comments/suggestions, anyone?  Thanks!

0 Kudos
1,079 Views
DavidS
NXP Employee
NXP Employee

Hi Scott,

Thank you for your contributions.

Regards,

David

0 Kudos
1,079 Views
M_Grillo
Contributor III

David,

There used to be an “fstatus” macro to check for a “HAVE_UNGOT_CHARACTER”. You use this macro to test before using getchar() so you’re not stuck in a blocking situation, (See below). I can’t find an equivalent in MQX for KSDK 1.1.0 and ‘stdio.h’ has question notes in comments but no macro.

Was this removed and why?

Thanks,

Mark

if (fstatus(serial_fd)) //Activity on serial port

               {

                   iSerR = (int_16)fgetc( serial_fd );    //get char on serial port

0 Kudos
1,079 Views
DavidS
NXP Employee
NXP Employee

Hi Mark,

Short answer is MQX Classic (the older standalone version) peripheral drivers in the BSP are drastically different software architecture than the new KSDK driver implementation .

I will post back an example that will be in our next KDS/KSDK release in ~2 weeks soon.

Regards,

David

Sent from my iPhone

1,079 Views
DavidS
NXP Employee
NXP Employee

Hi Mark,

Attached is a UART non-blocking example code that will be in the next release that can be used to in place of the fstatus.

Progress...

Regards,

David

1,079 Views
M_Grillo
Contributor III

Hello David Seymour,

The uart_non_blocking example you provided including the example in KSDK 1.2.0 driver examples works perfect in version KDSK 1.1.0 MQX applications, (Ethernet_to_Serial app), but  the UART_DRV_Sendata and UART_DRV_ReceiveData don’t function properly in the KSDK version 1.2.0 MQK Ethernet_to_Serial example application. The non-blocking example works fine in a non MQX application like the driver example with KSDK ver 1.2.0.

It appears 1.2.0 KSKD MQX applications only allow NIO UART drivers but there isn’t any documentation or examples on how to use the NIO UART drivers in a NON-blocking environment.

Any help would be much appreciated. I’ve exhausted all trial and error methods I could think of to achieve non-blocking without modifying MQX in KSDK 1.2.0 and taking over interrupts. I don’t think that was the intent. What changed from KSDK 1.1.0 to 1.2.0 that does not allow the non-blocking API driver to function correctly?

Thanks,

0 Kudos
1,079 Views
DavidS
NXP Employee
NXP Employee

Hi Mark,

I will investigate this next week.

The NIO seems to work with printf() that will format the string and then write string to a buffer for the UART to transmit.  If the buffer gets full, then the NIO code will actually block to wait for the buffer to free up some space.

How much data are you trying to transmit?

The non-NIO driver accepts a pointer to your string data with size information and then will never block.  But you do have to be careful not to do another Sendata too soon.

Regards,

David

0 Kudos
1,079 Views
M_Grillo
Contributor III

Hi David,

I’m trying to receive without blocking but the non-Nio driver doesn’t work with KSDK-MQX applications in ver 1.2.0.

I’m trying to port my MQX 4.0.x projects over to KSDK w/MQX because I was under the impression that the full MQX version would not be supporting newer Kinetis devices along with KDS going forward but I just realized the latest release of the full MQX, version 4.2.0, supports all the new Kinetis devices along with KDS 3.0.0. Is the full version of MQX going to be supported with new devices and tool chains going forward?

It would definitely make it much simpler for me to port to MQX4.2.0 rather than KSDK. I’m assuming with MQX 4.2.0 UART, FLASH, I/O and etc drivers stayed the same except for improvements.

Thanks,

Mark

0 Kudos
1,079 Views
surrealist14
Contributor III

Hi Mark and David,

Good info and a good conversation, but should it be started in a new thread?  Doesn't seem to go with getchar() not returning EOF...

Just a thought!

Scott

0 Kudos
1,079 Views
M_Grillo
Contributor III

Thanks David!

Looking forward to it. :smileyhappy:

Mark

0 Kudos
1,079 Views
ivadorazinova
NXP Employee
NXP Employee

Hi Scott,

please, have you tried put timeout to the while ?

Kind Regards,

Iva

0 Kudos
1,079 Views
surrealist14
Contributor III

Hi Iva,

Thanks for your advice.  However, there really is no need to use a timeout.  Either there is a character ready, and the Rx Data Register will be full, or there isn't, and getchar() should return an EOF.

However, this clearly requires modifying UART_HAL_ReceiveDataPolling(), which in turn means that I would be modifying the KSDK code.  Perhaps it should return some new status code to indicate that there was no data available.  In turn, the provided _read() Receive() function would need to check the return to see that no data was available and then return a size to indicate "no data", perhaps EOF, which is (-1)..

All of this is doable, but I'm surprised that the KSDK code needs modification already, or that other users haven't run into this kind of problem already.  There may be some other way to approach it that doesn't require any modification to the KSDK, but at the moment I don't see it.

It may be that the best choice is simply not to use the fsl_debug_console as is, but rather modify it as I have describes to provide the behavior I need.

Going forward, I would like to implement interrupt-driven transmit and receive, avoiding the busy-wait check for data in the Rx Data Register altogether.  I would be grateful to the community for any example of connecting normal printf()/scanf()/getchar()/putchar() type functions to one of the UARTs in the K60.  Ultimately, I'd like to extend that concept to support more than one UART, perhaps by adding additional file descriptors instead of the pre-defined stdin, stdout, and stderr.  printf() is really just fprintf(stdin,..) under the hood, just like getchar() is equivalent to fgetchar(stdin).

Thank you for your idea, and kind regards!

Scott

0 Kudos