3

I am wondering if it is possible to send 9 data bits framed with a start/stop bit at 1.25MBaud.

I am currently using PySerial to configure the UART pins on the pi. I've stumbled across a few problems.

Pyserial requires you to send in ascii to the port, which is 7 bits, however can be converted into a byte with a leading serial using bytes(data.encode("ascii")

Pyserial does not seem to like 1.25MBaud

Any advice to maximize speed and configurability of the UART pins would be appreciated!

2
  • 1
    This is the type of question where a little info of the project and what you are trying to accomplish would help us help you. Dec 3, 2014 at 11:54
  • 1
    I am trying to emulate a master in a master slave protocol, the physical layer is RS-485. Once I figure out how to output 9 data bits at a specified baud rate I can use the appropriate transceivers or create my own. The parity bit would have to be switched from mark to space within 1 bit time (800ns) Dec 8, 2014 at 9:44

2 Answers 2

3

The serial driver (see stty, man stty) only supports 5-8 data bits.

The nearest standard serial speed is 230400.

You can get 1.25 Mbps by using the init_uart_clock setting in /boot/config.txt (set it to 16 times the maximum value you want to use, i.e. init_uart_clock=20000000). stty will then let you select 1250000 bps.

I'm not aware of a practical solution for the 9 data bits. I've read of people trying to use the parity bit as an extra data bit.

12
  • Thank you so much! I will try this. I'd need to change the parity within 1 bit time Dec 8, 2014 at 9:54
  • I don't think that will be feasible. I see no way of achieving your stated aims with the Pi under Linux and frankly I can't see it being achieved in bare metal either. The 1.25MBs is the killer for me. Is there no way the speed requirement could be relaxed?
    – joan
    Dec 8, 2014 at 10:00
  • No! It's too test hardware which is at this speed! Dec 8, 2014 at 10:13
  • Is this two way communications are do you just need to send? How long are the messages (total number of bits) to be sent and can there be gaps between each message?
    – joan
    Dec 8, 2014 at 10:21
  • 600+ characters to be sent, 200+ characters to be received, characters are 9 data bits framed with start/stop bits. the response gap is very small but thats fine as I plan to emulate the master in a master/slave protocol. I've seen the raspberry pi buffer messages this size and output at a slower baud rate than i want! Dec 8, 2014 at 10:26
2

I have experimented and have a sort of solution to sending 9-bit data at 1.25 Mbps.

It involves modifications to my pigpio library.

I've added a gpioWaveAddSerialX() function which extends the gpioWaveAddSerial() function to allow for setting the number of data bits. This function constructs a waveform representing the serial data to be transmitted.

This also required an update to the internal waveBitDelay() function to allow for a variable number of data bits.

The other needed change was to change the base clock from 1 MHz to 1.25 MHz by changing clkDivI = 50 * micros to clkDivI = 40 * micros in the internal initClock() function.

The manifest constant PI_WAVE_MAX_BAUD in pigpio.h was changed to 1000000.

9-bit data 1.25 Mbps overview 9-bit data 1.25 Mbps detail

waveBitDelay

static void waveBitDelay(unsigned baud, unsigned bits, unsigned *bitDelay)
{
   unsigned fullBit, halfBit, s, e, d, m, i, err, t;

   /* scaled 100X */

   fullBit = 100000000 / baud;
   halfBit =  50000000 / baud;

   d = (fullBit/200)*200;

   s = 0;

   e = d;

   t = d/100;
   bitDelay[0] = t ? t : 1;

   err = d / 3;

   for (i=0; i<bits; i++)
   {
      s = e;

      m = halfBit + (i+1)*fullBit;

      e = s + d;

      if ((e-m) < err) e+=200;

      t = (e-s)/100;
      bitDelay[i+1] = t ? t : 1;
   }

   s = e;

   e = ((100*(bits+2)*1000000 / baud)+100)/200*200;

   t = (e-s)/100;
   bitDelay[bits+1] = t ? t : 1;
}

gpioWaveAddSerialX

int gpioWaveAddSerialX
   (unsigned gpio,
    unsigned bbBaud,
    unsigned bbBits,
    unsigned offset,
    unsigned numChar,
    char     *bstr)
{
   int i, b, p, lev, c, v;

   uint16_t *wstr = bstr;

   unsigned bitDelay[17];

   DBG(DBG_USER,
      "gpio=%d baud=%d bits=%d offset=%d numChar=%d str=[%s]",
      gpio, bbBaud, bbBits, offset, numChar, myBuf2Str(numChar,
      (char *)bstr));

   CHECK_INITED;

   if (gpio > PI_MAX_USER_GPIO)
      SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);

   if ((bbBaud < PI_WAVE_MIN_BAUD) || (bbBaud > PI_WAVE_MAX_BAUD))
      SOFT_ERROR(PI_BAD_WAVE_BAUD,
         "gpio %d, bad baud rate (%d)", gpio, bbBaud);

   if (numChar > PI_WAVE_MAX_CHARS)
      SOFT_ERROR(PI_TOO_MANY_CHARS, "too many chars (%d)", numChar);

   if (offset > PI_WAVE_MAX_MICROS)
      SOFT_ERROR(PI_BAD_SER_OFFSET, "offset too large (%d)", offset);

   if (bbBits > 8) numChar /= 2;

   if (!numChar) return 0;

   waveBitDelay(bbBaud, bbBits, bitDelay);

   for (i=0; i<=bbBits+1; i++) DBG(0, "bit%d delay=%d", i, bitDelay[0]);

   p = 0;

   wf[2][p].gpioOn  = (1<<gpio);
   wf[2][p].gpioOff = 0;
   wf[2][p].flags   = 0;

   if (offset > bitDelay[0]) wf[2][p].usDelay = offset;
   else                      wf[2][p].usDelay = bitDelay[0];

   for (i=0; i<numChar; i++)
   {
      p++;

      /* start bit */

      wf[2][p].gpioOn = 0;
      wf[2][p].gpioOff = (1<<gpio);
      wf[2][p].usDelay = bitDelay[0];
      wf[2][p].flags   = 0;

      lev = 0;

      if (bbBits < 9)
         c = bstr[i];
      else
         c = wstr[i];

      DBG(0, "i=%d c=%x", i , c);

      for (b=0; b<bbBits; b++)
      {
         if (c & (1<<b)) v=1; else v=0;

         if (v == lev) wf[2][p].usDelay += bitDelay[b+1];
         else
         {
            p++;

            lev = v;

            if (lev)
            {
               wf[2][p].gpioOn  = (1<<gpio);
               wf[2][p].gpioOff = 0;
               wf[2][p].flags   = 0;
            }
            else
            {
               wf[2][p].gpioOn  = 0;
               wf[2][p].gpioOff = (1<<gpio);
               wf[2][p].flags   = 0;
            }

            wf[2][p].usDelay = bitDelay[b+1];
         }
      }

      /* stop bit */

      if (lev) wf[2][p].usDelay += bitDelay[9];
      else
      {
         p++;

         wf[2][p].gpioOn  = (1<<gpio);
         wf[2][p].gpioOff = 0;
         wf[2][p].usDelay = bitDelay[9];
         wf[2][p].flags   = 0;
      }
   }

   p++;

   wf[2][p].gpioOn  = (1<<gpio);
   wf[2][p].gpioOff = 0;
   wf[2][p].usDelay = bitDelay[0];
   wf[2][p].flags   = 0;

   return rawWaveAddGeneric(p, wf[2]);
}

Test program.

#include <stdio.h>
#include <stdint.h>

#include <pigpio.h>

#define GPIO 14

int main(int argc, char *argv[])
{
   uint16_t buf[1024];
   int i, wid;

   if (gpioInitialise() < 0) return 1;

   gpioSetMode(GPIO, PI_OUTPUT);

   for (i=0; i<600; i++) buf[i] = i; 

   gpioWaveAddSerialX(GPIO, 1000000, 9, 2, 0, 1200, (char*)buf);

   wid = gpioWaveCreate();

   if (wid >= 0)
   {
      printf("ready recorder, then return\n");

      getchar();

      if (wid >= 0) gpioWaveTxSend(wid, 0);

      printf("stop recorder, then return\n");

      getchar();
   }
   else printf("error %d\n", wid);

   gpioTerminate();
}
20
  • This looks awesome! Where can I find a tutorial to set up the pi to use C? Dec 8, 2014 at 18:24
  • 1
    A C programming environment (gcc) will be included in most GNU/Linux distributions for the Pi. Certainly Raspbian does out of the box. What I've done may or may not work reliably for your hardware. There's only one way to find out.
    – joan
    Dec 8, 2014 at 18:32
  • For sure, giving this a try. I have a B+ Model. Dec 9, 2014 at 14:38
  • How did you call the functions in your library. For example how have you chosen which gpio to use? How did you set the speed? and how did you set the serial data to be sent? I'm so confused! Dec 12, 2014 at 12:46
  • I'm also not sure how to change the clock speeds :( Dec 12, 2014 at 12:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.