Intervalo entre dois caracteres que escrevem mensagem sobre RS485

0

Estou usando um controlador embarcado ATMEL (at91sam9x25e) e sua porta serial para enviar / receber via RS485 Modbus RTU. A comunicação normal funciona bem, mas às vezes - ao escrever - alguns pacotes são divididos com um atraso de cerca de 3,5 ms entre dois caracteres dentro de uma mensagem e, portanto, são detectados como nova mensagem.

Configurações:

  • Mono 3.2.8
  • Modbus RTU 19,2 kBaud
  • RS485
  • Auto-RTS

Estou enviando o pacote inteiro de uma só vez:

try  
{
  Thread.Sleep(_timePreSend);
  _serialPort.Write(buffer, offset, count);
} catch(Exception err)
{
   log.Error(err.Message);
} finally
{
   Thread.Sleep(2);
}

Eu usei os 2 ms antes, quando eu estava habilitando / desabilitando o RTS manualmente, para que ele transmitisse os últimos bits do buffer (UART ou FIFO).

Captura do osciloscópio:

120318000100020032000403200000001C000500000000000000003D <- gap -> B6

Saída do stty:

stty -F /dev/ttyS4 -a
speed 19200 baud; rows 0; columns 0; line = 0;    
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl    -ixon  -ixoff
-iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
 echoctl echoke

Qual poderia ser o motivo para essa lacuna? O que posso fazer para evitar isso?

    
por user3447279 18.05.2016 / 11:17

2 respostas

1

É difícil dizer exatamente o que causa isso. Infelizmente, as portas seriais do Linux não oferecem garantias de tempo, e os protocolos UART normais não devem ter requisitos de tempo apertados como este. Se o seu protocolo exigir esse tipo de garantia de tempo, você terá que acessar seus drivers de kernel e talvez escrever seu próprio driver que garanta a entrega atômica de todos os bytes sem intervalos, provavelmente usando interrupções para garantir que o buffer UART seja sempre recarregado em tempo hábil. Você não pode obter esse tipo de garantia do userspace sem a ajuda do kernel.

Dito isto, você pode tentar descobrir o que causa sua divisão e, talvez, trabalhar em torno dela e determinar empiricamente que ela é confiável o suficiente na prática para trabalhar com seus propósitos. O atraso é sempre antes do último byte? Em caso afirmativo, parece que algo na pilha está armazenando um caractere em buffer por algum motivo, talvez para otimizar o throughput fornecendo vários bytes para o hardware de uma só vez e apenas fornecendo o byte solitário após um pequeno tempo limite. Você deve primeiro certificar-se de que seu aplicativo de espaço do usuário está se comportando corretamente: verifique as chamadas do sistema executando-as em strace e verifique se o pacote está gravado no kernel em uma única chamada de sistema write . Se estiver, é hora de ler a fonte do kernel para o seu driver UART e ver se há algum buffer estranho envolvido.

Outra possibilidade é que o driver do kernel simplesmente lide com os dados em um encadeamento do kernel (ou diretamente em seu contexto de processo), e as lacunas que você está vendo são outro processo sendo agendado. Se assim for, a única maneira de contornar isso é modificar o driver do kernel ou escrever o seu próprio, para que ele manipule a transmissão de forma estrita em tempo real, sem permitir que outros processos tenham prioridade (por exemplo, fazendo tudo em contexto de interrupção).

    
por 18.05.2016 / 12:36
0

Eu finalmente descobri qual era o problema desse comportamento. Eu usei alguns ocupados esperando no meu loop de comunicação, o que levou a carga de CPU pesada. Eu li, então, que usando comandos SerialPort como BytesToRead e Read não são ideais de todo: Se você precisar usar o .NET System.IO.Port.Serialport

Por isso, tentei usar funções assíncronas de ByteStream ReadAsync e WriteAsync , conforme descrito em minha nova pergunta Forma correta de usar timeouts com porta serial e ReadAsync e eu tenho muito menos uso de cpu e sem falhas nenhuma.

    
por 20.06.2016 / 16:28