Cannot make software serial send more than one character

ChibiOS public support forum for topics related to the Atmel AVR family of micro-controllers.

Moderators: utzig, tfAteba

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Cannot make software serial send more than one character

Postby carldong » Wed Mar 22, 2017 9:53 pm

I tried to implement a software serial port on AVR, using a GPIO for TX and INT0 for Rx. For now, the driver can transmit characters -- but only one at a time. When I used `chprintf`, only the first character is printed. I debugged this for a few hours but cannot get why. I am not sure whether `sdRequestDataI` work as I thought, but I can't see any difference in its use on hardware serial ports. Here is the (possibly) responsible code for transmission(and receive):

Code: Select all

OSAL_IRQ_HANDLER(TIMER2_COMPA_vect) {
  static int8_t i;
  /* Data byte.*/
  static msg_t byte;
  uint8_t bit;

  OSAL_IRQ_PROLOGUE();
  switch (sds_state) {
  case IDLE:
    osalSysLockFromISR();
    byte = sdRequestDataI(&SDS);
    osalSysUnlockFromISR();
    if (byte >= Q_OK)
      sds_state = TRANSMIT_INIT;
    /* Do Nothing.*/
    break;
  case RECEIVE_INIT:
    i = 0;
    byte = 0;
    sds_state = RECEIVE;
    break; /* Break for the initial half period.*/
  case RECEIVE:
    if (i < sds_bits_per_char) {
      byte |= palReadPad(AVR_SDS_RX_PORT, AVR_SDS_RX_PIN) << i;
      ++i;
    } else {
      /* If last bit is STOP, then assume info is correct. Otherwise, treat as garbage*/
      if (palReadPad(AVR_SDS_RX_PORT, AVR_SDS_RX_PIN)) {
        osalSysLockFromISR();
        sdIncomingDataI(&SDS, byte);
        osalSysUnlockFromISR();
      }
      sds_state = IDLE;
      i = 0;
      byte = 0;
    }
    break;
  case TRANSMIT_INIT:
    /* Transmit must not be interrupted.*/
    usartS_disable_rx();
    sds_state = TRANSMIT;
    i = -1;
  /* No break here or timing will be wrong.*/
  case TRANSMIT:
    /* START.*/
    if (i == -1) {
      bit = 0;
    }
    /* STOP.*/
    else if (i == sds_bits_per_char) {
      bit = 1;
      sds_state = IDLE;
      /* Re-enable receive at the end of a transmit.*/
      usartS_enable_rx();
    }
    /* Data.*/
    else {
      bit = (byte & (1 << i)) != 0;
    }
    palWritePad(AVR_SDS_TX_PORT, AVR_SDS_TX_PIN, bit);
    ++i;
    break;
  }
  OSAL_IRQ_EPILOGUE();
}


I didn't include the INT0 interrupt because it is not used for transmission. This might look long, but enough to say that the RS232 protocol itself works because I can transmit one character. However, I don't really know why I can only get one character from the queue. `SDS` is the serial driver, which *should* be properly initialized with `sdObjectInit`. Without any other I/O available (most if not all are used for other stuff), I can't really see what's going on inside the program.

BTW, RX pin is PD2, and TX is PC0. I can post the full code if needed.

User avatar
tfAteba
Posts: 547
Joined: Fri Oct 16, 2015 11:03 pm
Location: Strasbourg, France
Has thanked: 91 times
Been thanked: 48 times

Re: Cannot make software serial send more than one character

Postby tfAteba » Thu Mar 23, 2017 12:56 am

Hi carldong,

Sorry for the delay, I'm a bit busy this time.

Very interesting initiative to implement a software serial.

For me, it will help to have the full code to try and see in my side what happen in order to help you.

I will not have time to try it since this week-end.

What is you board and the version used?
regards,

Theo.

utzig
Posts: 359
Joined: Sat Jan 07, 2012 6:22 pm
Location: Brazil
Has thanked: 1 time
Been thanked: 20 times
Contact:

Re: Cannot make software serial send more than one character

Postby utzig » Thu Mar 23, 2017 1:45 pm

carldong,

If you don't mind, please create a pastebin/gist of this (with syntax highlighting), even better with the whole file/code. Also, it might be a non-AVR specific thing that is going wrong there which would have a better chance of being found by posting in General.

Cheers,
Fabio Utzig

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Cannot make software serial send more than one character

Postby carldong » Thu Mar 23, 2017 10:08 pm

serial_lld.c: http://pastebin.com/xCU7sMm9
serial_lld.h: http://pastebin.com/tWu2TRn2

I am pretty sure it is not AVR specific.

However, previously I had it working on an Arduino using PD2/3. Later I moved to a custom board and used PD2/PC0 instead, and it didn't work. Sending characters one by one seems to work.

Another note, trying to send to &SD1 then &SDS without a thread sleep in between causes a constant flood of garbage data on both ports. For example, in the main thread if I do this:

Code: Select all

while (1) {
   chprintf((BaseSequentialStream*) &SD1, "USART1\r\n" );
   //chThdSleepSeconds(1); <- This line
   chprintf((BaseSequentialStream*) &SDS, "Software USART\r\n" );
   chThdSleepSeconds(1);
}


Commenting "this line" will cause characters 'S' and 'U' flooding both serial terminals. Uncommenting causes alternating "USART1\r\n" and "S" in their respective ports.

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Cannot make software serial send more than one character

Postby carldong » Fri Mar 24, 2017 4:43 am

tfAteba wrote:Hi carldong,
What is you board and the version used?


Board was both an Arduino UNO (which worked) and a custom board (which does not). The only part which I modified was the TX pin.

Also, UNO has 16M clock while custom has 7.3728M. However, since I can get one character out I assume this is not the problem (I adjusted timer settings, of course).

Version... Since I stripped away basically everything unneeded... I only remember it is 16.x.x. I probably have not modified anything else.

And I forgot to post the configuration:

Code: Select all

/**
 * @brief B4800 on 7372800Hz Clock
 */
const SerialConfig softserial_config = {
  UBRR(4800), /* No use, just a placeholder.*/
  USART_CHAR_SIZE_8,
  192,
  (1 << CS21) /* Divide 8.*/
};
/**
 * @brief B4800(approx) on 16000000Hz Clock
 */
const SerialConfig softserial_config = {
  UBRR(4800), /* No use, just a placeholder.*/
  USART_CHAR_SIZE_8,
  52,
  (1 << CS22) /* Divide 64.*/
};


Choose one according to your clock, if you need testing. If using other clocks, the last two numbers are just TIM2 configs.

User avatar
tfAteba
Posts: 547
Joined: Fri Oct 16, 2015 11:03 pm
Location: Strasbourg, France
Has thanked: 91 times
Been thanked: 48 times

Re: Cannot make software serial send more than one character

Postby tfAteba » Fri Mar 24, 2017 9:40 am

Hi Carldong,

carldong wrote:
However, previously I had it working on an Arduino using PD2/3. Later I moved to a custom board and used PD2/PC0 instead, and it didn't work.


    1 - Can you make a quick test with the Arduino Board and confirm that it is working fine when you use PD2/3 pins.
    2 - Can you use Arduino board and try to transmit by using PD2/PC0 pins. Just verify that these pins are not used for another thing.
    3 - If the above test are working, use your custom board to make the same test and see the result.

While waiting your feedback this weekend, I will make test of your software library.
regards,

Theo.

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Cannot make software serial send more than one character

Postby carldong » Tue Mar 28, 2017 10:14 pm

tfAteba wrote:Hi Carldong,

carldong wrote:
However, previously I had it working on an Arduino using PD2/3. Later I moved to a custom board and used PD2/PC0 instead, and it didn't work.


    1 - Can you make a quick test with the Arduino Board and confirm that it is working fine when you use PD2/3 pins.
    2 - Can you use Arduino board and try to transmit by using PD2/PC0 pins. Just verify that these pins are not used for another thing.
    3 - If the above test are working, use your custom board to make the same test and see the result.

While waiting your feedback this weekend, I will make test of your software library.


No, it does not work even when I changed it back to PD2/3. Not sure what causes it now.

The following causes "U" to flood the console:

Code: Select all

  while (true) {
    //debug("USART1\r\n");
    //chThdSleepSeconds(1);
    chprintf((BaseSequentialStream*) &SDS, "USARTS\r\n");
    chThdSleepSeconds(1);
  }

User avatar
tfAteba
Posts: 547
Joined: Fri Oct 16, 2015 11:03 pm
Location: Strasbourg, France
Has thanked: 91 times
Been thanked: 48 times

Re: Cannot make software serial send more than one character

Postby tfAteba » Tue Mar 28, 2017 10:45 pm

Ok,

So the first thing to do is to make it work with a board such as the Arduino UNO.

I will make some investigations an try to make it work. At first time just the TX part which use the GPIO pin.

If you finally manage it don't hesitate to share your results.

As soon as I will get a result, I will give a feedback.

Thanks for your pastebin code.
regards,

Theo.

utzig
Posts: 359
Joined: Sat Jan 07, 2012 6:22 pm
Location: Brazil
Has thanked: 1 time
Been thanked: 20 times
Contact:

Re: Cannot make software serial send more than one character

Postby utzig » Tue Mar 28, 2017 11:53 pm

carldong wrote:The following causes "U" to flood the console:

Code: Select all

  while (true) {
    //debug("USART1\r\n");
    //chThdSleepSeconds(1);
    chprintf((BaseSequentialStream*) &SDS, "USARTS\r\n");
    chThdSleepSeconds(1);
  }

Probably CPU resetting. Some non-handled interrupt maybe?

I will try to test it here some day this week.

carldong
Posts: 62
Joined: Wed Oct 15, 2014 6:08 pm
Has thanked: 1 time
Been thanked: 1 time

Re: Cannot make software serial send more than one character

Postby carldong » Wed Mar 29, 2017 12:52 am

I have no idea what happened. I moved the usartS_start_timer outof the #if #endif block in usartS_init, and now it (magically) sort of works. Although, there are problems:

Code: Select all

USARTS{h0D}
USARTS{h0D}
USARTS{h0D}
USARTS{h0D}
UUSARTS{h0D}
USARTS{h0D}
USARTS{h0D}
USARTS{h0D}
USARTS{h0D}
UUSARTS{h0D}
USARTS{h0D}
USARTS{h0D}
USARTS{h0D}
USARTS{h0D}
UUSARTS{h0D}


That {h0D} is just \r displayed in Digilent WaveForms, which is not the problem. As you see, periodically, 'U' gets sent twice. Not sure whether it is caused by overflows or such... I have a serial buffer size of 16.


Return to “AVR Support”

Who is online

Users browsing this forum: No registered users and 17 guests