MQX with UART... How to receive?

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

MQX with UART... How to receive?

Jump to solution
3,119 Views
holyhope
Contributor III

Hi, I'm stuck on the UART - RX ....

I'm using FRDM-K64 demo board and MQX 4.1.1

From user config I'm set a new (ttyb) UART, the UART1.

I correctly send data from K64 to my PC via serial port, but I have problem with receive routine...

I can read the receive buffer with this function (from rs485 example NOT for frdm-k64 but for one TWR)

fread(data_buffer, 1, 18, ttybSci1_dev);

where ttybSci1_dev is name of my port. The problem is that I can read but MQX do not tell me when a packet (or a byte) arrive, like linux with the signal


i suppose RX interrupt are managed by MQX and redefined tham I bypass MQX routine that acquire the byte


there is, something similar SIGNAL in linux, that I can use? Something that alert me when a byte arrive?


Example:


/* For write I use: */

char data_bufferTR[] = "\nTaskRead";

write(ttybSci1_dev, data_bufferTR, strlen(data_bufferTR));

fflush(ttybSci1_dev);

/* For read I use */

void   *semReceivedData;

if (_sem_open("SemaphoreForDataRX", &semReceivedData) != MQX_OK) {

   printf("\nOpening semReceivedData semaphore failed.");

   _task_block();

}

if (_sem_wait(semReceivedData, 0) != MQX_OK) {

         printf("\nWwaiting for semReceivedDatasemaphore failed");

         _task_block();

}                 

fread(data_buffer, 1, NumberByteReceived, ttybSci1_dev)



So I need how to give the semaphore semReceivedData when MQX receive a packet (or a byte and I  will join all in a packet)

Many thanks,

Massimiliano

Tags (4)
1 Solution
694 Views
RadekS
NXP Employee
NXP Employee

Thank you for additional information.

If you use serial driver in interrupt mode (ittyb), you shouldn’t have problem with losing some characters. Interrupt driver use buffer for received characters and fread() reads from this buffer.

Size for this buffer could be changed in user_config.h by macro BSPCFG_SCI1_QUEUE_SIZE. For example:

#define BSPCFG_SCI1_QUEUE_SIZE             256

Default value is 64 (defined in [your board].h file).

So, you can use fread() per one byte.

For timeout:

I would like to propose for example install your own interrupt routine by _int_install_isr(vector, isr_ptr, isr_data); function. This function returns pointer to the old interrupt routine (in case of success).

So, you can have interrupt routine where you just clear PIT timer and call default interrupt routine. In PIT interrupt you will handle semaphores (in case of timeout).

If you want something simple:

Do

{

bytesRead = fread(inBuffer,1,1,fd);

                _time_get_elapsed_ticks(&lastByteTime);

                memcpy(&inPacket[inPacketSize], inBuffer, bytesReaded);

                inPacketSize += bytesReaded;

                _time_get_elapsed_ticks(&now);

} while (_time_diff_milliseconds(&now, &lastByteTime, &overflow) <250);

View solution in original post

0 Kudos
4 Replies
694 Views
RadekS
NXP Employee
NXP Employee

In fact, you can configure serial port for blocking or non-blocking access (strictly not recommended).

Default configuration is blocking access.

So, if you call fread(data_buffer, 1, 18, ttybSci1_dev); it will stay at this instruction until you receive 18 characters.

If you use ttyb (pooling mode) function will block also other tasks with lower priority - It waits in read loop.

I would like to recommend configure UART1 as ittyb (interrupt mode). In this case, function fread will stay and wait for receive 18 characters. However other tasks could run while you wait for characters. Semaphores are already included in serial driver.

Note: please make sore, that you don't use ttyb and ittyb drivers simultaneously.


Have a great day,
RadekS

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

694 Views
holyhope
Contributor III

Hi, many thanks for your answer.

It is useful but it is not what I want, I explain: I need to receive something BUT I NOT KNOW HOW IT WILL BE LONG!!!

So there are two way for identify a packet:

1) with a timeout, started on first char and resetted on every char: when, for example, 250 msec pass from last char, so the packet it is finisched!

2) with a stop char, like a CR or LF (carrige return, Line Feed): when I receive one of this char, so the packet is finisched!

I need to use fread when the packet arrive and I do not know how it will long so i can't use fread(data_buffer, 1, 18, ttybSci1_dev) with 18 char, or any other number, because I must read only at the end of the packet received and I need that:


One Signal (like linux, or any other similar thing) tell me WHEN the packet is received (or one byte: so I can elaborate single byte and join into a packet) and HOW it is long!

With interrupt I try in this way:

typedef struct my_isr_uart_struct

{

  void                     *OLD_ISR_DATA;

  void      (_CODE_PTR_ OLD_ISR)(void *);

  _mqx_uint                   TICK_COUNT;

} MY_ISR_UART_STRUCT, * MY_ISR_UART_STRUCT_PTR;

void uart_isr_redef( void * );

LWSEM_STRUCT    lwsemUartRX;

   MY_ISR_UART_STRUCT_PTR  isr_uart_ptr;

   if(! _int_install_isr(INT_UART1_RX_TX, uart_isr_redef, isr_uart_ptr))

   {

       printf("Install interrupt handler to interrupt vector table of MQX kernel failed.\n");

       _task_block();

   }

/*ISR*-----------------------------------------------------------

*

* ISR Name : UART_isr

* Comments :

*END*-----------------------------------------------------------*/

void uart_isr_redef (void *user_isr_ptr )

{

  MY_ISR_UART_STRUCT_PTR  isr_ptr;

   _lwsem_post(&lwsemUartRX);

   isr_ptr = (MY_ISR_UART_STRUCT_PTR)user_isr_ptr;

   isr_ptr->TICK_COUNT++;

   /* Chain to the previous notifier */

   (*isr_ptr->OLD_ISR)(isr_ptr->OLD_ISR_DATA);

}

/* EOF */

but not work!!!

So I suppose two things:

1) Interrupt, and overwrite them, do not work or it is not the correct way... (I'm using an advanced operative system I don't wanto to use interrupt in this low level mode!!! but if it is the only way I can use them )

2) use a fread(data_buffer, 1, 1, ttybSci1_dev)  where I read ever 1 byte i can lost some char and it is not the right way.

So what I can do?

Many thanks

Massimiliano

0 Kudos
695 Views
RadekS
NXP Employee
NXP Employee

Thank you for additional information.

If you use serial driver in interrupt mode (ittyb), you shouldn’t have problem with losing some characters. Interrupt driver use buffer for received characters and fread() reads from this buffer.

Size for this buffer could be changed in user_config.h by macro BSPCFG_SCI1_QUEUE_SIZE. For example:

#define BSPCFG_SCI1_QUEUE_SIZE             256

Default value is 64 (defined in [your board].h file).

So, you can use fread() per one byte.

For timeout:

I would like to propose for example install your own interrupt routine by _int_install_isr(vector, isr_ptr, isr_data); function. This function returns pointer to the old interrupt routine (in case of success).

So, you can have interrupt routine where you just clear PIT timer and call default interrupt routine. In PIT interrupt you will handle semaphores (in case of timeout).

If you want something simple:

Do

{

bytesRead = fread(inBuffer,1,1,fd);

                _time_get_elapsed_ticks(&lastByteTime);

                memcpy(&inPacket[inPacketSize], inBuffer, bytesReaded);

                inPacketSize += bytesReaded;

                _time_get_elapsed_ticks(&now);

} while (_time_diff_milliseconds(&now, &lastByteTime, &overflow) <250);

0 Kudos
694 Views
holyhope
Contributor III

Hi, many thanks for your answer.

I choice the first street so I use fread with one char every time.

I NOT try (for now) to overwrite interrupt.

Now my code is working, I'm setting up a timer (for timeout) after that I will modify this post and add the code.


I have a question about your "simple" code :


Do

{

bytesRead = fread(inBuffer,1,1,fd);

                _time_get_elapsed_ticks(&lastByteTime);

                memcpy(&inPacket[inPacketSize], inBuffer, bytesReaded);

                inPacketSize += bytesReaded;

                _time_get_elapsed_ticks(&now);

} while (_time_diff_milliseconds(&now, &lastByteTime, &overflow) <250);


You, before all, try to read something with "fread" after that you store a timestamp, copy in memory the byte and store another timestamp, right?

but you in while (_time_diff_milliseconds(&now, &lastByteTime, &overflow) <250); are using the total time used from CPU to store data, NOT the time between two byte, isn't it? I'm sorry maybe I'm wrong but I understand in this way....

And another question: I suppose to move the instruction in this way:


while (1)

   Do

   {                _time_get_elapsed_ticks(&lastByteTime);

   bytesRead = fread(inBuffer,1,1,fd);

                   memcpy(&inPacket[inPacketSize], inBuffer, bytesReaded);

                   inPacketSize += bytesReaded;

                   _time_get_elapsed_ticks(&now);

   } while (_time_diff_milliseconds(&now, &lastByteTime, &overflow) <250);

   lwsempost(&lwUartSem)

}


So in this way I have the time between two byte BUT fread(inBuffer,1,1,fd); is a blocking function so on the last byte, my do while cycle will stuck on last byte and never reach the other instruction (like the:  memcpy inPacketSize and the major important time_get_elapsed_ticks that store the time elapsed for the exit-check-Do/while-cycle) and never the  instruction } while (_time_diff_milliseconds... that check if the time are elapsed... or not?

(I add another cycle only for post the LW-sempahore)


THE FIRST VERSION of my code, that not use timeout is that:

This version stop rx when a CR/LF occours (ascii char 0x0D)

It is only a demo version:

-> second packet will overwrite and lenght wil not reset

-> improvement #1 : best way is to use Queue but now I do not know how to do them in MQX (I never tryied... Now I will try do do them!!!)

-> improvement #2 : use timer to set a timeout  instead "stop char" 0x0D and store the packet in a MQX-Queue (improvement #1)

This is the code (please do not smile on my name of ittyb...) for any critical / suggestion / advice feel free to write them and I will answer: Maybe there is a better way and I will learn a new method (very probably that my code need changes...)

main.c:

#include <mqx.h>

#include <bsp.h>

#include <sem.h>

#include "main.h"

#if ! BSPCFG_ENABLE_IO_SUBSYSTEM

#error This application requires BSPCFG_ENABLE_IO_SUBSYSTEM defined non-zero in user_config.h. Please recompile BSP with this option.

#endif

#ifndef BSP_DEFAULT_IO_CHANNEL_DEFINED

#error This application requires BSP_DEFAULT_IO_CHANNEL to be not NULL. Please set corresponding BSPCFG_ENABLE_TTYx to non-zero in user_config.h and recompile BSP with this option.

#endif

#define MaxSci1_CHANNEL "ittyb:"

LWSEM_STRUCT    lwsemUartRX;

typedef struct rx_str_template

{

  char data_buf_RX[256];

  _mqx_uint nCharRx;

  _mqx_uint ConteggioInternoCharRicevuti;

} RX_STR, * RX_STR_PTR;

RX_STR rx_str;

void main_task (uint32_t initial_data){

   _task_id   task_id;

   uint32_t result;

   result = _lwsem_create(&lwsemUartRX, 0);

   if (result != MQX_OK) {

       printf("\nCreating lwsemUartRX failed: 0x%X", result);

       _task_block();

   }

   task_id = _task_create(0,READ_TASK, 0);

   printf("\nread_task created, id 0x%lX", task_id);

   while(1)

   {

    _lwsem_wait(&lwsemUartRX);

    printf("\nData:\n ");

    int i =0;

    for(i=0;i<rx_str.nCharRx;i++){

    printf("%c",rx_str.data_buf_RX[i]);

    }

    printf("\n");

   }

   _task_block();

}

void read_task(uint32_t initial_data){

  MQX_FILE_PTR MaxSci1_dev = NULL;

  bool disable_rx = FALSE;

  rx_str.nCharRx = 0;

  MaxSci1_dev =  fopen( MaxSci1_CHANNEL, NULL );

  if (MaxSci1_dev == NULL) {printf("\nError opening Sci1");}

  else{printf("\nSci1 opned!");}

   while (TRUE) {

    fread(&(rx_str.data_buf_RX[rx_str.nCharRx]), 1, 1, MaxSci1_dev);

    if(rx_str.data_buf_RX[rx_str.nCharRx] == 0x0D){

    _lwsem_post(&lwsemUartRX);

    }

    rx_str.nCharRx++;

   }

}


I suppose that is not much inherent in this topic, so I open a new thred for speach about it, here:


what is the best way for Timeout on UART RX with MQX?


Many thanks

Massimiliano


0 Kudos