SerialDriver strange loopback

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

enrico.dallavia
Posts: 105
Joined: Thu Mar 12, 2015 10:15 am
Has thanked: 2 times

Re: SerialDriver strange loopback

Post by enrico.dallavia »

I modified the code to read the data I got from the loopback

Code: Select all

chMtxLock(&mtxRs485);
 palSetPad(GPIOC, GPIOC_RS485_DE);//enable write
 
  chprintf((BaseSequentialStream*)&SD2,"%s","ABCDEF\n\r"); // write
   
  eventflags_t flags;

   do{
        chEvtWaitOneTimeout(EVENT_MASK(1), MS2ST(10));
      
      flags = chEvtGetAndClearFlags(&Writer);
      
       if (flags & [b]CHN_TRANSMISSION_END[/b]) {
          chMtxLock(&mtx);
         chprintf((BaseSequentialStream *)&SD1,"transmission end\r\n");
         chMtxUnlock(&mtx);
          break;
       }
   }while(1);

//read data from loopback
   msg_t charbuf;
   do
   {
      charbuf = chnGetTimeout(&SD2, TIME_IMMEDIATE);
      if ( charbuf != Q_TIMEOUT )
      {
         chMtxLock(&mtx);
         chprintf((BaseSequentialStream *)&SD1,"%c ",(char)charbuf);
         chMtxUnlock(&mtx);
      }
   }while (charbuf != Q_TIMEOUT);

   chMtxLock(&mtx);
   chprintf((BaseSequentialStream *)&SD1,"\r\n");
   chMtxUnlock(&mtx);

   palClearPad(GPIOC, GPIOC_RS485_DE);     /* switch to read mode  */

  chMtxUnlock(&mtxRs485);



In my reader thread I have

Code: Select all

while(1){
           
    chMtxLock(&mtxRs485);

    palClearPad(GPIOC, GPIOC_RS485_DE);     /* switch to reader mode*/

    eventflags_t flags;

    chEvtWaitOneTimeout(EVENT_MASK(1), MS2ST(10));
   
    flags = chEvtGetAndClearFlags(&Listener);
   
    if (flags & CHN_INPUT_AVAILABLE) {

       chMtxLock(&mtx);
      chprintf((BaseSequentialStream *)&SD1,"Got data to be read\r\n");
      chMtxUnlock(&mtx);

        msg_t charbuf;
         do
         {
            charbuf = chnGetTimeout(&SD2, TIME_IMMEDIATE);
            if ( charbuf != Q_TIMEOUT )
            {
            chMtxLock(&mtx);
            chprintf((BaseSequentialStream *)&SD1,"%c ",(char)charbuf);
            chMtxUnlock(&mtx);
            }
         }
         while (charbuf != Q_TIMEOUT);
         chMtxLock(&mtx);
       chprintf((BaseSequentialStream *)&SD1,"\r\n");
    chMtxUnlock(&mtx);
chMtxUnlock(&mtxRs485);


but after every write, I have one read of 0 data so the thread is very time consuming. Is it possible to have it waiting for the real data to be read? I mean, in the writer thread I'm sure to read every char from the loopback, so why I've got a CHN_INPUT_AVAILABLE flags active?

Thanks
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: SerialDriver strange loopback

Post by Giovanni »

The wait is performed in chEvtWait(), you should never poll.

Giovanni
enrico.dallavia
Posts: 105
Joined: Thu Mar 12, 2015 10:15 am
Has thanked: 2 times

Re: SerialDriver strange loopback

Post by enrico.dallavia »

but i don't want to block the writer thread while waiting for asynchronous command, since the data I wrote must be around 10-20 every second. Should I switch to 1 thread only, where the reading is performed just before the writing? but I need a timeout not to block the writing. So if I receive something I can manage them before the writing.
On the other side (pc gui application) I will send a command only after receiving a data packet.
steved
Posts: 834
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 12 times
Been thanked: 138 times

Re: SerialDriver strange loopback

Post by steved »

enrico.dallavia wrote:Should I switch to 1 thread only, where the reading is performed just before the writing? but I need a timeout not to block the writing. So if I receive something I can manage them before the writing.

I think so - you have half-duplex operation, so you don't need to support simultaneous reading and writing.

Look at using the UART driver (instead of the serial driver); that allows character by character receive through callbacks, so its easy to implement a timeout in case data goes missing (normally, I would expect that you can tell 'end of message' from the data you receive).
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: SerialDriver strange loopback

Post by Giovanni »

It depends on the protocol you are trying to implement, I imagine there is one end starting with a transmission and the other answering. RS485 is half duplex so your protocol dictates when receive and when transmit.

Design the state machine of the protocol (on both sides), in general is a bad idea trying to write code without a idea of what you want to do.

Giovanni
enrico.dallavia
Posts: 105
Joined: Thu Mar 12, 2015 10:15 am
Has thanked: 2 times

Re: SerialDriver strange loopback

Post by enrico.dallavia »

the board is meant to implement an anemometer, so it reads data from 2 different encoder and compute the speed (rpm) and the direction of the wind. it sends the data with nmea standard packet trough 485. usually it will not receive anything from the user. the only time when i have to manage something as an input is when the user has to change some parameters in the firmware, such us number of samples for the average or calibrate the device. so i thought that using 1 thread for write and another for read, who will be usually on polling the input would be a not so bad idea. but i hit the unforeseen problem that the chip for 485 has a loopback. i don't know why but yesterday evening i saw it working with 2 thread (no loopback after rise and clear the pad and reading the data testing chn_input's flag), but today it was not. how having a callback with uart will help me? because i can set a time limit from the first time i got a data as an input while keep receiving the msg and somehow stop the thread for the periodic transmission. but the loopback will be a pain in the ass, since i will have the callback giving me an unwanted input. using my previous code, is there a way after reading the loopback to have the chn_input flag active only when real data is incoming? I don't understand why I have it active on my reader tread, maybe because it is triggered by the data of the loopback? but i should have already cleared it when i checked for transmission complete in the writing thread.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: SerialDriver strange loopback

Post by Giovanni »

No, loopback is like normal data, the difference is that you are transmitting in that moment.

You can use the loopback as a verification of the transmitted data: you expect it and compare it with the transmitted data. You have to remove it from the RX queue anyway.

About the UART driver.

The uart driver is unbuffered and operates in an asynchronous way, for transmitting you would do:

1) Set a timeout virtual timer.
2) Activate transmitter signal.
3) Start receiving N bytes.
4) Start sending N bytes.
5) Wait for the RX callback or the timeout callback.

On the callback of the received N bytes you stop the timeout timer and stop the transmitter signal. The loopback data has been consumed and also gives you confirmation of correct transmission (no collision on RS485 bus).

It is more complex to use because you have to synchronize the driver callbacks with your thread.

Giovanni
enrico.dallavia
Posts: 105
Joined: Thu Mar 12, 2015 10:15 am
Has thanked: 2 times

Re: SerialDriver strange loopback

Post by enrico.dallavia »

Hello, finally I manage somehow to have a working application with both send and receive (as suggested, I put together receive and send in one thread)

The code fragment is as follow

Code: Select all

int iBytesRead = 0;

         do
         {
            charbuf = chnGetTimeout(&SD2, MS2ST(10));
            if ( charbuf != Q_TIMEOUT )
            {
      acBuffer[iBytesRead] = (char)charbuf;
      iBytesRead+=1;
            }
         }while (charbuf != Q_TIMEOUT);

         if(iBytesRead > 0){
        acBuffer[iBytesRead] = 0;
        chMtxLock(&mtx);
   chprintf((BaseSequentialStream *)&SD1,"Read %s\n\r",acBuffer);
   chMtxUnlock(&mtx);
    }

  palSetPad(GPIOC, GPIOC_RS485_DE);       /*enable write  */
 

 #ifndef TEST
  chprintf((BaseSequentialStream*)&SD2,"%s",acTxBuf); // write read data
 #else
  chprintf((BaseSequentialStream*)&SD2,"%s","ABCDEF\n\r"); // write dummy data for test only
 #endif

  do{
     chEvtWaitOneTimeout(EVENT_MASK(1), MS2ST(1));
      
   flags = chEvtGetAndClearFlags(&Writer);
      
       if (flags & CHN_TRANSMISSION_END) {
          //chMtxLock(&mtx);
         //chprintf((BaseSequentialStream *)&SD1,"transmission end\r\n");
         //chMtxUnlock(&mtx);
          break;
         }
    }while(1);

      do
      {
         charbuf = chnGetTimeout(&SD2, MS2ST(1));
         if ( charbuf != Q_TIMEOUT )
         {
            //chMtxLock(&mtx);
            //chprintf((BaseSequentialStream *)&SD1,"%c ",(char)charbuf);
            //chMtxUnlock(&mtx);
         }
      }while (charbuf != Q_TIMEOUT);

   palClearPad(GPIOC, GPIOC_RS485_DE);     /* enable read */


it is not elegant, but it works (at least)

Thanks you all for the suggestion
enrico.dallavia
Posts: 105
Joined: Thu Mar 12, 2015 10:15 am
Has thanked: 2 times

Re: SerialDriver strange loopback

Post by enrico.dallavia »

Good evening,
now I have another issue, the data I sent from SD2 with

Code: Select all

chprintf((BaseSequentialStream*)&SD2,"%s",acTxBuf); 

are sometimes corrupted, the serial port is configured with a speed of 115200 bps.
The string I'm sending is something like $SMHU,00.00,0200,*03 the header $SMHU is fixed and the lenght is fixed.
But often on pc side, I got something like:
$HU,00.00,0193,*0a

$S00.00,0193,*0a

$U,00.00,0200,*03

$S,*0a

seems the OS eat some character in the middle.

Inside halconf.h I change the value of buffer to

Code: Select all

#define SERIAL_BUFFERS_SIZE         128


is this value for both receiver and transmitter buffer?

Am i using a wrong function to write the data? maybe I have to write 1 char at time and check (how?) when it is really sent, or check if I have enough space in the transmission buffer (how?)
Or are there other issues I've not considered?

Thanks
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: SerialDriver strange loopback

Post by Giovanni »

The OS does not eat characters as far I know, it could be noise on the line, lack of terminations or other HW-related issues. Take a logic analyzer and look at the output if you have doubts.

Giovanni
Post Reply