Serial Problem

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: RoccoMarco, lbednarz, tfAteba

redfox74
Posts: 21
Joined: Sat Feb 12, 2011 12:08 am

Serial Problem

Post by redfox74 »

Hi Giovanni,
i have an a questions . I write my first program using task using your fantastic os , but i have a doubt .
So The program is simple , this is the code :
#include "ch.h"
#include "hal.h"
#include "test.h"

/*
* Red LED blinker thread, times are in milliseconds.
*/
static WORKING_AREA(waThread1, 128);
static msg_t Thread1(void *arg) {

(void)arg;
while (TRUE) {
palClearPad(IOPORT2, 7);
//sdAsynchronousWrite(&SD1,"CIAO",4);
chThdSleepMilliseconds(500);
palSetPad(IOPORT2, 7);

chThdSleepMilliseconds(500);
}
}

// USART thread, processes GPS inputs
static WORKING_AREA(waThread2, 512);
static msg_t Thread2(void *arg) {

(void)arg;
char c;
while (TRUE)
{
c = chIOGet(&SD1);
switch(c)
{
case '1':
sdWrite(&SD1,"Recived 1\n\r",11);
break;
case '2':
sdWrite(&SD1,"Recived 2\n\r",11);
break;
case '3':
sdWrite(&SD1,"Recived 3\n\r",11);
break;
case '4':
sdWrite(&SD1,"Recived 4\n\r",11);
break;
case '5':
sdWrite(&SD1,"Recived 5\n\r",11);
break;
default:
sdWrite(&SD1,"NO AVAILABLE\n\r",15);
menu();
}

}
}

/*
* Application entry point.
*/

int menu(void)
{
sdWrite(&SD1,"MP32 Testing Program Choose your test\n\r",40);
sdWrite(&SD1,"1) Test Radio Input\n\r",21);
sdWrite(&SD1,"2) Test PWM Output \n\r",21);
sdWrite(&SD1,"3) Read Anag Input (ANX)\n\r",27);
sdWrite(&SD1,"4) Read Anag Input (SPI)\n\r",27);
sdWrite(&SD1,"5) Read Anag Input (I2c)\n\r",27);
sdWrite(&SD1,"6) Read Barometer (I2c)\n\r",27);
sdWrite(&SD1,"7) Read GPS (Ser2)\n\r",27);

}

int main(void) {


/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
*/
halInit();
chSysInit();

/*
* Activates the serial driver 2 using the driver default configuration.
*/
sdStart(&SD1, NULL);
/*
* Creates the blinker thread.
*/
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
/*
* Creates the Serial1 Recive Thread.
*/

chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);

menu();

/*
* Normal main() thread activity, in this demo it does nothing except
* sleeping in a loop and check the button state.
*/
while (TRUE) {

//chThdSleepMilliseconds(5000);
}
}

But when the thread2 call the menu some time i don't see some character in my terminal ...
Do you have some idea ? Problem with variable definition or passing ?
In the next day i start to write some Howto and tutorial on your hal for customers of MP32 . I hope that they decide to sue your OS on my board.
Onother request is but in your api there's a function that return the number of byte available in the buffer ? In the documentation i don't found it.
The last question is : I need to remap a external Xtal to different pin XTAL_REMAP , how is possible to do that in your OS ?
Regards
Roberto
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Serial Problem

Post by Giovanni »

Answered privately.

Giovanni
Cyrille
Posts: 26
Joined: Sun May 15, 2011 7:55 pm

Re: Serial Problem

Post by Cyrille »

Hi,

I work under ChibiOS with the STM32, and I have some difficulties with the serial driver.

A - What happen if the the Rx buffer overflow (buffer to small wrt incoming data)? How to prevent/handle Rx Buffer overflow ?

B - I would like to use the receiving Interrupt on serial port 4. Does anyone would have a sample code ?

Now, I use the code below which is not optimized.

while(TRUE)

{

size_t qSize = chQSizeI(&(&SD4)->iqueue); //Rx Buffer Size
size_t qSpace = chQSpaceI(&(&SD4)->iqueue); //Rx Buffer Space
ByteAvailable = qSize-qSpace; //Available bytes to be read
if(ByteAvailable>0)//Read ByteAvailable
{
sdRead(&SD4, (uint8_t*)&Rx, ByteAvailable);

...
}
chThdSleepMilliseconds(50); //Thread Sample time
}


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

Re: Serial Problem

Post by Giovanni »

Hi Cyrille,

About your questions, there are only several possible ways to make the buffer not overflow:
1) Read the data fast enough.
2) Implement a protocol that ensures that data is not sent until explicitly requested.
3) As a mitigation measure you may increase the buffer size in halconf.h.

About your code, if you need to just read the data present in the buffer, the easiest way is to use

sdReadTimeout(&SD4, buf, sizeof(buf), TIME_IMMEDIATE);

The above function returns just the data present in the buffer and does not block. Note that the serial driver generates an event when data is available in the buffer so you don't have to use the interrupt handler directly. You may do the following in your thread:

1) Register the thread on the SD4 event source (chIOGetEventSource(), chEvtRegister()).
2) Wait for the event (chEvtWaitOne()).
3) Read the flags associated to the event (chIOGetAndClearFlags()).
5) If an error flag is specified the process the error (the possible flags are specified in the serial driver documentation, see SD_PARITY_ERROR and following).
4) If a IO_INPUT_AVAILABLE flag is present then read all the data in the buffer (sdReadTimeout(...,, TIME_IMMEDIATE)).
5) Process the data.
6) Repeat from point 2.

The above solution allows to read and process data continuously.

Giovanni
Cyrille
Posts: 26
Joined: Sun May 15, 2011 7:55 pm

Re: Serial Problem

Post by Cyrille »

Hi Giovanni,
Thanks for your last reply.
I'm a beginner with ChibiOS.
So how to :
1) Register the thread on the SD4 event source (chIOGetEventSource(), chEvtRegister()).
I have tried the following code, but after the thread creation I don't know how to continue.
static Thread *ThreadGPS;
ThreadGPS = chThdCreateStatic(waThreadGPS, sizeof(waThreadGPS), NORMALPRIO, ThreadGPS, NULL);
EventListener s4EventListener;
chEvtRegister(??(ThreadGPS), &s4EventListener, 0);


2) Wait for the event (chEvtWaitOne()).

3) Read the flags associated to the event (chIOGetAndClearFlags()).

Do you have a sample code?

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

Re: Serial Problem

Post by Giovanni »

Hi Cyrille,

It is the thread that needs to wait for events that has to register using chEvtRegister().

Try the following (note not tested, I just wrote an example):

Code: Select all

msg_t my_thread(void *p) {
  EventListener s4EventListener;

  (void)p;
  chEvtRegister(chIOGetEventSource(&SD4), &s4EventListener, 1);
  while (TRUE) {
    ioflags_t flags;

    chEvtWaitOne(EVENT_MASK(1));
    flags = chIOGetAndClearFlags(&SD4);
    if (flags & IO_INPUT_AVAILABLE) {
      /* Data available read here.*/
    }
    if (flags & IO_OUTPUT_EMPTY) {
      /* Data sent, you may transmit from here.*/
    }
    if (flags & (SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR |
                 SD_NOISE_ERROR | SD_BREAK_DETECTED)) {
      /* Some receive error happened.*/
    }
  }
}


Giovanni
Cyrille
Posts: 26
Joined: Sun May 15, 2011 7:55 pm

Re: Serial Problem

Post by Cyrille »

Giovanni,

I have tested your code.A GPS is connected to SD4. I have added some "printf" on SD1 to see if the code works when data arrived on SD4, but nothing (even before the While(true) : the "tread init" is not sent!)
It is may be my thread creation int the main or ...?

Code: Select all

int main (void)
{
...
static Thread *ThreadGPS;
ThreadGPS = chThdCreateStatic(waThreadGPS, sizeof(waThreadGPS), NORMALPRIO, ThreadGPS, NULL);
...
}


static msg_t ThreadGPS(void *p) {
  EventListener s4EventListener;
  sdWrite(&SD1,"thread init\r\n",17);
  (void)p;
  chEvtRegister(chIOGetEventSource(&SD4), &s4EventListener, 1);
  while (TRUE) {
    ioflags_t flags;

    chEvtWaitOne(EVENT_MASK(1));
    flags = chIOGetAndClearFlags(&SD4);
    if (flags & IO_INPUT_AVAILABLE) {
      /* Data available read here.*/
       sdWrite(&SD1,"OK\r\n",16);
    }
    if (flags & IO_OUTPUT_EMPTY) {
      /* Data sent, you may transmit from here.*/

    }
    if (flags & (SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR |
                 SD_NOISE_ERROR | SD_BREAK_DETECTED)) {
      /* Some receive error happened.*/
       sdWrite(&SD1,"Error\r\n",16);
    }
  }
}


Thanks

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

Re: Serial Problem

Post by Giovanni »

You have both a variable and a function with the same name ThreadGPS.

Are you sure the thread really starts? try placing a breakpoint.

Giovanni
Dave_fr
Posts: 27
Joined: Thu Feb 17, 2011 11:26 pm

Re: Serial Problem

Post by Dave_fr »

Hi,

chEvtWaitOne(EVENT_MASK(1));


In what exact circumstances does this line unlock the thread (where can I find it in the documentation) ?

if (flags & IO_OUTPUT_EMPTY) {
/* Data sent, you may transmit from here.*/


Who do I make sure that "chEvtWaitOne(EVENT_MASK(1));" unlocks when I want to send data ?

Best regards,

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

Re: Serial Problem

Post by Giovanni »

It does not work that way, The transmission event is generated when the transmission buffer becomes empty (transition from non-empty to empty), you may transmit in any moment if there is space in the buffer.

Depending on the timeout parameter of sdWriteTimeout() the function blocks when there is no space (TIME_INFINITE) or returns immediately (TIME_IMMEDIATE).

Giovanni
Post Reply