USART interrupt example doesn't work on LPC55S16-EVK board

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

USART interrupt example doesn't work on LPC55S16-EVK board

1,567 Views
IG
Contributor I

We are using LPC55S16-EVK board along with MCUXpresso IDE.

Imported provided SDK example: lpcxpresso55s16_usart_interrupt

As described in the project readme.txt file, checked that JP20, JP21 also JP22 are in place.

Connected serial terminal to the Com port detected by device manager on the PC with specified settings.

Run up the example using LinkServer debugger without any changes to the code.

I can see initial output on the terminal: "Usart functional API interrupt example.
Board receives characters then sends them out
Now please input:"

That means that TX from the board is working.

Trying to type in any characters doesn't work.

I was also trying to place breakpoints in the interrupt routing and in the main loop with no effect. Breakpoints are not reached.

Any clue on how to make provided example to work on the LPC55S16-EVK board would be appreciated.

Labels (1)
0 Kudos
14 Replies

1,448 Views
IG
Contributor I

Hi Miguel,

Thank you for your response.

It certainly makes sense to keep Interrupt handling routine as light as possible.

If you check provided code above, there are only few lines of code which are significant:

data = USART_ReadByte(BT_USART);
g_rxBuffer[rxIndex] = data;
rxIndex++;
rxIndex %= RX_BUFFER_SIZE;

The rest is just handling a scenario of more than one byte of data available when interrupt occurs (which we have seen).

Ideally we would like to have an interrupt on every byte received. Is it feasible? and how to do that?

0 Kudos

1,437 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @IG 

I suggest you could change the interrupt and when the handler occurs you only change the state of a flag and in the main routine/task read data until the RXFIFO is empty. For example:

void USART0_IRQHandler(void)

{

FIFO_FLAG = 1;

SDK_ISR_EXIT_BARRIER

}

 

if(FIFO_FLAG)

{

while(base_USART.FIFOSTAT & kUSART_RxFifoNotEmptyFlag)

{

data = USART_ReadByte(BT_USART);

                      g_rxBuffer[rxIndex] = data;

                      rxIndex++;

}

FIFO_FLAG = 0;

}

This is just the recieving routine, you could implement a routine to count for the amount of bytes you recieved the way is more efficient for you.

Let me know if this works.

Best Regards, Miguel.

0 Kudos

1,425 Views
IG
Contributor I

Hi Miguel,

Thank you for your response.

I got the idea, though I think that suggested solution might not work as in our application interrupt has highest priority compared to any other task. In case the source of interrupt hasn't been cleared inside the interrupt handling routine it would be calling interrupt handler again and again without any chance for any other task to process the flag.

I think we are making some progress as we found that using printf() method via SDK debug semihost console affects USART0 operation. And I mean using printf() not in the same task where USART operation is handled but in any other task, which has priority lower than USART handling one.

This still remains a question how printf() to semihost console can affect USART0 operation from a completely different task, but we proved that switching from semihost console to a UART console removes this effect. 

I would appreciate if you could provide more information on semihost console operation and how it can affect USART interrupt routine?

Thank you.

0 Kudos

1,386 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @IG 

This links have information about the semihost console.

https://community.nxp.com/t5/MCUXpresso-IDE-Knowledge-Base/MCUXpresso-IDE-and-Semihosting/ta-p/11164...

https://community.nxp.com/t5/LPCXpresso-IDE-FAQs/What-is-Semihosting/m-p/475390

 

I found that the semihost console could affect the performance of the system because it stops the processor, so this could be affecting the interrupts. Please read "Semihost Performance" from the "What is Semihosting?" link. If the UART console works fine I suggest you use it to solve this issue.

Best Regards, Miguel.

 

0 Kudos

1,381 Views
IG
Contributor I

Hi Miguel,

On another note, I've continued to read through the links provided and have seen another option of redirecting debugging via ITM:  How to use ITM Printf - NXP Community

The only issue with this method is that mentioned file attached to this page cannot be accessed.

Would you be able to find retarget_itm.c.zip  file and upload it for us?

 

Thank you.

Ilya

0 Kudos

1,342 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @IG 

Sorry, I didn't find the file. It look to be too old.

Miguel.

0 Kudos

1,531 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @IG 

I've been investigating your issue.

Could you provide me more information, You said the breakpoints are not reached, where does the code stop running? Which pin configuration you have beside the JP20, JP21 and JP22?, you tried validating the value of the array demoRingBuffer when you stop the program? Have you tried other USART examples?

I'll be investigating more about your problem.

Best Regards, Miguel.

0 Kudos

1,523 Views
IG
Contributor I

Hi Miguel,

Thank you for your response.

We tried LPC55S16-EVK board with default set of configuration switches. No other modifications.

I think it is mostly confusing as examples are configured to use USART0 but the actual messaging also appears on the debug COM port (whatever that is when connecting the USB cable from LPC55S16-EVK board). So, initially we were expecting to get input output via that debug COM port but that didn't work.

By connecting appropriate wires to the USART0 pin outs from the EVK board via additional TTL-USB adaptor I have seen it working using USART0. 

I think additional description would be appropriate for the examples.

 

Another issue that we were facing while using the examples, as far as I understand from the ringbuffer functionality description, as soon as it is setup, even without reading from ringbuffer, USART will keep receiving data and copying it into ring buffer.

I have defined big enough ring buffer of 32 bytes.

Sending 22bytes via serial port, I would like a capability to parse it byte by byte.

After receiving the first byte, starting the parser (with printf inside). Soon getting Receive error on USART. I've also noticed that if the length of incoming data is less than 16 bytes it works but if the length of incoming data is more than 16 bytes it throws a Receive error.

I was expecting the ringbuffer to continue working in the background based on interrupt to receive remaining 21 bytes from USART FIFO into the ringbuffer while my parsing is ongoing.

I would appreciate if you can help with this issue.

0 Kudos

1,494 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @IG 

 

Thanks for providing this information about the demo, I'll look into it.

I'm afraid you misunderstand the demoRingBuffer, it is not recieving data all the time, only reads when the interrupt of the RX occurs. Regarding your other issue, could you tell me which error are you getting? Just to verify, are you changing the value of the macro DEMO_RING_BUFFER_SIZE to 32 or you only change the size of the demoRingBuffer (uint8_t demoRingBuffer[32]) array? Since the demo use this macro to control the data count I think this could be causing the problem. I'll investigate further more what could be causing this.

Best regards, Miguel.

0 Kudos

1,481 Views
IG
Contributor I

Hi Miguel,

Thank you for your response.

Our aim to keep getting data bytes via USART along as they are coming as we do not know ahead the length of incoming messages.

Here is an extract of my code:

#define BT_USART USART0
#define USART_CLK_SRC kCLOCK_Flexcomm0
#define USART_CLK_FREQ CLOCK_GetFlexCommClkFreq(0U)
#define USART0_IRQHandler FLEXCOMM0_IRQHandler
#define RX_BUFFER_SIZE 64

static uint8_t g_rxBuffer[RX_BUFFER_SIZE];

static volatile size_t receivedBytes=0;
uint8_t receivedDataSize=0;

//Interrupt handing routine

void USART0_IRQHandler(void)
{
uint8_t data;
uint8_t receivedBytes;
uint8_t rxIndex=0;

receivedBytes=(BT_USART->FIFOSTAT>>16)&0x1F;
/* If new data arrived. */
if (kUSART_RxFifoNotEmptyFlag & USART_GetStatusFlags(BT_USART))
{
    for(uint8_t i=0; i<receivedBytes; ++i)
   {
        data = USART_ReadByte(BT_USART);
        g_rxBuffer[rxIndex] = data;
        rxIndex++;
        rxIndex %= RX_BUFFER_SIZE;
    }
    size_t bytesSent = xStreamBufferSendFromISR( BTStreamBuffer,
                                                                                 ( void * ) g_rxBuffer,
                                                                                 receivedBytes,
                                                                                 NULL );
  }
  else if (kUSART_RxError & USART_GetStatusFlags(USART0))
  {
       printf("Received ERROR\n");

 

       /* Clear rx error state. */
       BT_USART->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;
       /* clear rxFIFO */
       BT_USART->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;

   }
   SDK_ISR_EXIT_BARRIER;
}

void BT_USART_Init(StreamBufferHandle_t xStreamBuffer)
{
    PRINTF("BT_USART_Init entry\n");

    /* attach main clock divide to FLEXCOMM0 */
    CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0);

    BTStreamBuffer = xStreamBuffer;

    if(xTaskCreate(BT_USART_Task, "BT_USART_Task", configMINIMAL_STACK_SIZE + 100, NULL,                supervisor_task_PRIORITY, &g_BTUSARTTaskHandle) !=pdPASS)
    {
           PRINTF("BT_USART_Task creation failed!.\r\n");
           while (1)
           ;
      }
}

static void BT_USART_Task(void *pvParameters)
{
    uint32_t i;

    PRINTF("BT_USART_Task entry\n");

/*
* config.baudRate_Bps = 115200U;
* config.parityMode = kUSART_ParityDisabled;
* config.stopBitCount = kUSART_OneStopBit;
* config.loopback = false;
* config.enableTxFifo = false;
* config.enableRxFifo = false;
*/
    usart_config_t config;
    status_t status;

    USART_GetDefaultConfig(&config);
    config.baudRate_Bps = 115200U;
    config.enableTx = true;
    config.enableRx = true;

    size_t bytesSent=0;
    const TickType_t x100ms = pdMS_TO_TICKS( 100 );

    status = USART_Init(BT_USART, &config, USART_CLK_FREQ);
    if (kStatus_Success == status){
         PRINTF("USART0 init success\n");
    }
    else{
         PRINTF("USART0 init failed\n");
     }

     /* Enable RX interrupt. */
     USART_EnableInterrupts(USART0, kUSART_RxLevelInterruptEnable |                  kUSART_RxErrorInterruptEnable);
     EnableIRQ(FLEXCOMM0_IRQn);

while (1)
{

    /* Delay some time, simulate the app is processing other things */
    i = 0x10U;
    while (i--)
    {
         __NOP();
    }
  }

    vTaskSuspend(NULL);
}

The idea of this program: when USART0 interrupt occurred, check how many bytes were received, copy all received bytes from USART0 to local array and then send it to another task using FreeRTOS StreamBuffer which is basically copying data to another buffer.

Another task (called appInput) will receive the data and print them out to the console for verification.

Sending 18 bytes from my PC to the USART0 on LPC55S16EVK development board, I am getting the following results:
"appInput got 1 bytes
Received ERROR
appInput got 16 bytes"

First interrupt happens when 1 byte of data received and it is sent to the printing task ("appInput got 1 bytes"). Then another interrupt occurred and this time kUSART_RxError status was indicated, hence print output of "Received ERROR", followed by final 3rd interrupt where 16bytes of data received. In total 17 bytes received instead of 18.

I would appreciate if you could point me out into a right direction in order to resolve this issue and allow consistent USART operation.

Thank you.

0 Kudos

1,450 Views
Miguel04
NXP TechSupport
NXP TechSupport

Hi @IG 

 

The interrupt routine should not have many instructions. I understand that you are trying to read many data with the same interrupt, but I suggest that all the logic you want to do must be implemented inside the main functions/tasks and the receive handler only read data and increments another variable to count the data received. It is not ideal to have FOR cycles, PRINTF, or WHILE inside an interrupt, since these are blocking code it could affect the performance of for program. The most efficient way is separating the interrupt from the common routine of your code, as I mentioned before. Let me know if this works for you or you have any other question.

Best Regards, Miguel.

0 Kudos

1,420 Views
frank_m
Senior Contributor III

> It is not ideal to have FOR cycles, PRINTF, or WHILE inside an interrupt, since these are blocking code it could affect the performance of for program.

Quite a bit of an understatement.
For / while loops are not dangerous per se, the runtime effect can usually be assessed. They can become a problem, though.

Something like printf(), which almost always relies on other interrupts, should never be used in interrupt context.

0 Kudos

1,417 Views
IG
Contributor I

Hi Frank,

Thank you for your reply.

I completely agree with your comment, while in our sample Interrupt handling routing the printf() only called in case of RxError condition for debugging purposes. In normal operation it should never be used and it should not hit this specific RxError condition.

Meanwhile, we have discovered that using printf() method via SDK debug semihost console affects USART0 operation based on interrupt. And I mean using printf() not in the same task where USART operation is handled but in any other task, which has priority lower than USART handling one.

This still remains a question how printf() to semihost console can affect USART0 operation from a completely different task, but we proved that switching from semihost console to a UART console removes this effect. 

I would appreciate if you could provide more information on semihost console operation and how it can affect USART interrupt routine?

Thank you.

0 Kudos

1,413 Views
frank_m
Senior Contributor III

To be honest, I don't have any experience with M33 devices, just some M0/3/4/7.

Interrupt priorities might play a role. "Bursts" on more than one interface can cause missed characters if they overlap. Not sure how the semihosting is implemented, but obviously it is not unintrusive.

> And I mean using printf() not in the same task where USART operation is handled but in any other task,  ...

This sounds like you are using an OS (like e.g. FreeRTOS), which complicates things. Many RTOSes grab control over the interrupt handling, or significant parts of it.

In such cases, I used to resort to "older" techniques. You could store some relevant values in variables/arrays at realtime, and read them out later "offline". 

I currently debug a board with two proprietary MCUs with intertwined operation, which is effectively undebuggable in realtime.
Instead I use fast toggles on free or "slow" pins to output debug states - which requires a scope. The effect on runtime is minimal in this case.

 

0 Kudos