Exemplo de biblioteca PiGPIO para bater um UART em bits

11

A biblioteca do PiGPIO http://abyz.me.uk/rpi/pigpio/index.html menciona que um de seus recursos é "links seriais de software usando qualquer usuário gpio".

Entendo que isso significa que você pode usá-lo para gerar um software UART em qualquer 2 pinos GPIO gratuitos.

Na página de exemplos dos projetos, não há exemplos para esse recurso e não encontrei nenhum no Google.

Alguém já fez isso? Se sim, por favor me aponte para o exemplo.

Caso contrário, existem bibliotecas alternativas para a troca de bits de um UART?

Obrigado,

PhilBot
fonte
Veja também: raspberrypi.stackexchange.com/questions/3475/… e raspberrypi.stackexchange.com/questions/24019/… O último é respondido por @joan apontando para pigpio, para que ele possa oferecer mais informações.
Ghanima
Passei alguns dias testando a série do software pigpio enviando do Pi para um laptop e fazendo com que o laptop ecoasse de volta para o Pi. Eu pretendia escrever, mas os eventos ultrapassaram esse exercício. Vou ver o que posso encontrar.
Joan

Respostas:

13

Aqui está um Python que eu usei para testar a confiabilidade do serial de software. O lado da entrada é bastante trivial. Você acabou de fazer as chamadas abertas seriais de bit bang apropriadas em Python ou C. O lado de saída está mais envolvido, pois você precisa usar formas de onda para construir o fluxo de bits.

O código aqui está usando dados de 7 bits em vez de 8 bits. O teste foi escrito na mesma época em que eu adicionava suporte para diferentes bits por byte.

O código grava blocos de dados binários em um gpio conectado a um laptop (via dongle serial). O laptop faz eco dos dados seriais recebidos para sua linha serial de saída. O Pi lê os dados seriais em outro gpio.

O código verifica discrepâncias entre os dados enviados e recebidos. Presume-se que o laptop esteja livre de erros; portanto, presume-se que qualquer erro esteja ocorrendo.

Olhar para os logs com menos de 19,2kbps foi sólido. Qualquer coisa até 115,2kbps era razoável (mas exigiria soma de verificação) e 230,4kbps forneciam uma taxa de erro de 13% em bytes.

#!/usr/bin/env python

# bb_serial.py
# 2014-12-23
# Public Domain

# bit bang transmit and receive of serial data
#
# tested by connecting the arbitrary RX/TX gpios to a USB
# serial dongle plugged in to a Linux box.
#
# on the Linux box set the baud and data bits (cs5-cs8)
#
# stty -F /dev/ttyUSB0 19200 cs8
# cat </dev/ttyUSB0 >/dev/ttyUSB0
#
# so the Linux box echoes back data received from the Pi.
#
# laptop timings deviations
#
# baud  exp us   act us
#   50   20000    13310 * 75
#   75   13333    13310
#  110    9091    13310 * 75
#  134    7462     6792 * 150
#  150    6667     6792
#  200    5000     6792 * 150
#  300    3333     3362
#

import sys
import time
import difflib

import pigpio

RX=19
TX=26

MSGLEN=256

if len(sys.argv) > 1:
   baud = int(sys.argv[1])
else:
   baud = 115200

if len(sys.argv) > 2:
   bits = int(sys.argv[2])
else:
   bits = 8

if len(sys.argv) > 3:
   runtime = int(sys.argv[3])
else:
   runtime = 300

ten_char_time = 100.0 / float(baud)

if ten_char_time < 0.1:
   ten_char_time = 0.1

MASK=(1<<bits)-1

# initialise test data

msg = [0] * (MSGLEN+256)

for i in range(len(msg)):
   msg[i] = i & MASK

first = 0

pi = pigpio.pi()

pi.set_mode(TX, pigpio.OUTPUT)

# fatal exceptions off (so that closing an unopened gpio doesn't error)

pigpio.exceptions = False

pi.bb_serial_read_close(RX)

# fatal exceptions on

pigpio.exceptions = True

# create a waveform representing the serial data

pi.wave_clear()

TEXT=msg[first:first+MSGLEN]
pi.wave_add_serial(TX, baud, TEXT)
wid=pi.wave_create()

# open a gpio to bit bang read the echoed data

pi.bb_serial_read_open(RX, baud, bits)

# zero error counts

bad_char = 0
total_char = 0

# run for fixed time

start=time.time()

while (time.time()-start) < runtime:

   pi.wave_send_once(wid)   # transmit serial data
   pi.wave_delete(wid)

   TXTEXT = TEXT

   first += 1
   if first >= MSGLEN:
      first = 0

   TEXT=msg[first:first+MSGLEN]
   pi.wave_add_serial(TX, baud, TEXT,bb_bits=7)

   while pi.wave_tx_busy(): # wait until all data sent
      pass

   wid=pi.wave_create()

   count = 1
   text=""
   lt = 0
   total_char += MSGLEN

   while count: # read echoed serial data
      (count, data) = pi.bb_serial_read(RX)
      if count:
         text += data
         lt += count
      time.sleep(ten_char_time) # enough time to ensure more data

   if text != TXTEXT: # Do sent and received match?
      if lt == MSGLEN: # No, is message correct length?
         for i in range(MSGLEN): # If so compare byte by byte.
            if text[i] != TXTEXT[i]:
               # print("{:2X} {:2X}".format(text[i], TXTEXT[i]))
               bad_char += 1
      else: # Wrong message length, find matching blocks.
         ok = 0
         s=difflib.SequenceMatcher(None, TXTEXT, text)
         for frag in  s.get_matching_blocks():
            ok += frag[2] # More matching bytes found.
            # print(frag)
         # print(text, MSGLEN, ok)
         if ok < MSGLEN: # Sanity check.
            bad_char += (MSGLEN - ok)
         else:
            print("*** ERRONEOUS good={} LEN={} ***".format(ok, MSGLEN))

print("secs={} baud={} bits={} bad={:.3f}%".
   format(runtime, baud, bits, float(bad_char)*100.0/float(total_char)))

print("total={} badchar={}".format(total_char, bad_char))

# free resources

pi.wave_delete(wid)

pi.bb_serial_read_close(RX)

pi.stop()

Histórico

harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 230400; done
secs=300 baud=230400 bad=12.610%
total=249344 badchar=31443
secs=300 baud=230400 bad=12.580%
total=247296 badchar=31111
secs=300 baud=230400 bad=12.669%
total=246528 badchar=31232
secs=300 baud=230400 bad=12.274%
total=249600 badchar=30635
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 115200; done
secs=300 baud=115200 bad=0.378%
total=246784 badchar=934
secs=300 baud=115200 bad=0.152%
total=241408 badchar=368
secs=300 baud=115200 bad=0.189%
total=249088 badchar=472
secs=300 baud=115200 bad=0.347%
total=242688 badchar=843
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 57600; done
secs=300 baud=57600 bad=0.080%
total=220416 badchar=177
secs=300 baud=57600 bad=0.066%
total=219392 badchar=145
secs=300 baud=57600 bad=0.099%
total=219904 badchar=218
secs=300 baud=57600 bad=0.084%
total=219136 badchar=184
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 38400; done
secs=300 baud=38400 bad=0.019%
total=206336 badchar=39
secs=300 baud=38400 bad=0.021%
total=206848 badchar=43
secs=300 baud=38400 bad=0.015%
total=206592 badchar=30
secs=300 baud=38400 bad=0.030%
total=206592 badchar=61
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
secs=300 baud=19200 bad=0.000%
total=174336 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 75; done
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
joan
fonte
Qual dongle serial você usou? Os mais velhos às vezes pode ser bastante confiável ...
not2qubit
Usei um módulo de saída PL2303HX USB para RS232 TTL 5V 3.3V para os testes. £ 1,53 do eBay.
Joan
Você pode testar facilmente a confiabilidade do dongle; conectar seu próprio Tx a Rx e execute novamente o teste
earcam
0

Quando você conecta o Tx diretamente ao Rx para testar qualquer coisa que possa adicionar erro como dongles, ele mostra o quão bom a biblioteca realmente executa.

Use o GPIO 23 como Tx e o GPIO 24 como Rx ou outro GPIO gratuito no Raspberry Pi 3b +. Parece bom na mesma ordem que o UART a bordo e está praticamente ao lado dele, apenas 3 pinos à direita, com um pino GND à direita de Rx.

Resultados:

Until 19200bps no errors.
- 38400 and 57600 bps less 1% error sometimes
- 115200bps was 10-20% error or so
- 230400bps over 80% error or so

Se você pode viver com 19200 ou menos sem precisar usar hashes de soma de verificação nem conversores SPI / I2C para UART - tudo bem.

donghelan
fonte