Lendo dados de uma porta serial SerCx2-Managed
Um controlador serial (ou UART) normalmente inclui um FIFO de recebimento. Esse FIFO fornece buffer controlado por hardware de dados recebidos do dispositivo periférico que está conectado à porta serial. Para ler dados do FIFO de recebimento, o driver periférico deste dispositivo envia solicitações de leitura (IRP_MJ_READ) para a porta serial.
Se a porta serial continuar a receber dados mais rapidamente do que o driver periférico pode ler os dados, o FIFO de recebimento poderá estourar. Para evitar a perda de dados devido ao estouro, o driver periférico normalmente deve configurar a porta serial para usar o controle de fluxo de hardware. Com o controle de fluxo, o hardware do controlador serial sinaliza automaticamente o dispositivo periférico para parar de enviar dados quando o FIFO de recebimento está quase cheio. Como regra, as portas seriais gerenciadas pelo SerCx2 devem usar o controle de fluxo de hardware. Para obter mais informações, consulte Detalhes do controle de fluxo.
No entanto, o controle de fluxo não deve ser usado para impedir que o dispositivo periférico envie dados por muito tempo ou o dispositivo pode não continuar operando corretamente. Por exemplo, o dispositivo periférico pode ter um buffer de dados interno que pode estourar se o dispositivo for impedido por muito tempo de enviar dados desse buffer para a porta serial.
Nesta página
- Usando solicitações de leitura assíncronas
- Detalhes do tempo limite do intervalo
- Detalhes do controle de fluxo
Usando solicitações de leitura assíncronas
Para evitar a operação incorreta e a possível perda de dados, o driver periférico é responsável por ler os dados do FIFO de recebimento do controlador serial em tempo hábil. Normalmente, antes que os dados sejam recebidos, o driver periférico envia uma solicitação de leitura assíncrona para a porta serial em antecipação à chegada futura de dados do dispositivo periférico. Essa solicitação de leitura permanece pendente na fila de E/S do SerCx2 até que os dados estejam disponíveis para serem lidos do FIFO de recebimento.
Na maioria das plataformas de hardware, um driver periférico não precisa ter mais de uma solicitação de leitura pendente por vez. Em casos raros, um driver pode precisar ter mais de uma solicitação de leitura pendente se, depois que os dados forem recebidos, uma solicitação de leitura demorar tanto para ser processada antes que possa ser concluída que o backup de dados resultante faça com que o dispositivo periférico perca dados ou se comporte incorretamente.
Supondo que o driver periférico tenha apenas uma solicitação de leitura pendente por vez, o tamanho necessário do buffer de dados nessa solicitação depende em grande parte do comportamento conhecido do dispositivo periférico. Por exemplo, se o driver souber com antecedência quantos bytes de dados esperar do dispositivo, o driver definirá o tamanho do buffer na solicitação para esse número de bytes. A solicitação de leitura é concluída assim que o buffer é preenchido com os dados do FIFO de recebimento. Em resposta, o driver pode enviar de forma assíncrona uma nova solicitação de leitura para aguardar o próximo bloco de dados.
No entanto, o driver periférico pode não saber com antecedência quantos dados esperar do dispositivo periférico. Nesse caso, o driver define o buffer de dados na solicitação de leitura para um tamanho apropriado e, em seguida, depende de um tempo limite de intervalo para identificar o final dos dados do dispositivo periférico. Escolher um tamanho apropriado para o buffer de leitura pode exigir conhecimento detalhado sobre como o dispositivo periférico opera. Se o buffer de leitura for muito pequeno, o driver precisará enviar uma ou mais solicitações de leitura adicionais para concluir a leitura dos dados.
Detalhes do tempo limite do intervalo
Para definir os parâmetros de tempo limite para solicitações de leitura e gravação, um driver periférico pode enviar uma solicitação de IOCTL_SERIAL_SET_TIMEOUTS para a porta serial. Os tempos limite para leituras são controlados pelos valores de parâmetro ReadIntervalTimeout, ReadTotalTimeoutMultiplier e ReadTotalTimeoutConstant nesta solicitação. ReadIntervalTimeout especifica o intervalo de tempo máximo permitido entre dois bytes consecutivos em uma transação de recebimento. Se ReadTotalTimeoutMultiplier e ReadTotalTimeoutConstant forem zero e o FIFO de recebimento do controlador serial estiver vazio quando uma solicitação de leitura for enviada para a porta serial, essa solicitação não atingiu o tempo limite (e, portanto, permanecerá pendente na fila de E/S do SerCx2) até que a porta receba pelo menos um byte de novos dados. Para obter mais informações, consulte SERIAL_TIMEOUTS.
Uma porta serial em um circuito integrado do SoC (Sistema em um Chip) pode receber dados de um dispositivo periférico com taxas de pico de vários megabits por segundo ou mais. O desenvolvedor do driver periférico para este dispositivo pode ser tentado a definir o valor de tempo limite do intervalo (conforme especificado pelo parâmetro ReadIntervalTimeout ) como um milissegundo ou menos, mas é improvável que esse valor tenha o efeito desejado. Isso ocorre porque a precisão do temporizador usado para detectar tempos limite de intervalo é limitada pela granularidade do relógio do sistema.
Por exemplo, se o período do relógio do sistema for de 15 milissegundos e o driver definir o valor ReadIntervalTimeout como 1 milissegundo, um intervalo de bytes em qualquer lugar no intervalo de 0 a pouco mais de 15 milissegundos poderá disparar um tempo limite. Ocasionalmente, essa configuração pode causar um tempo limite no meio de uma transmissão de dados do dispositivo periférico. Para garantir que um tempo limite só possa ocorrer após a conclusão dessa transmissão, o driver pode definir ReadIntervalTimeout como um valor um pouco maior que 15 milissegundos. Por exemplo, se ReadIntervalTimeout for definido como 20 milissegundos, um intervalo de bytes a bytes de 30 milissegundos disparará de forma confiável um tempo limite e um intervalo de 15 milissegundos ou menos não disparará um tempo limite.
Para obter mais informações sobre como a precisão do temporizador depende do relógio do sistema, consulte Precisão do temporizador.
Detalhes do controle de fluxo
Como prática recomendada, os drivers periféricos que usam portas seriais gerenciadas pelo SerCx2 devem configurar essas portas para usar o controle de fluxo de hardware para impedir que o FIFO de recebimento transborde. Na ausência de uma solicitação de leitura pendente, o SerCx2 não fornece nenhum buffer de software de dados de recebimento que exceda a capacidade do FIFO de recebimento. Se esse FIFO tiver permissão para estourar, os dados serão perdidos.
Para habilitar o controle de fluxo de hardware, um driver periférico pode enviar uma solicitação IOCTL_SERIAL_SET_HANDFLOW para definir as configurações de handshake e controle de fluxo para a porta serial. Ou o driver pode enviar uma solicitação IOCTL_SERIAL_APPLY_DEFAULT_CONFIGURATION para configurar a porta serial para usar um conjunto de configurações de hardware padrão que incluem o controle de fluxo de hardware. A solicitação IOCTL_SERIAL_SET_HANDFLOW usa a estrutura SERIAL_HANDFLOW para descrever as configurações de controle de fluxo. Uma solicitação IOCTL_SERIAL_APPLY_DEFAULT_CONFIGURATION pode conter informações semelhantes em um formato de dados especificado pelo fornecedor.
Se o driver periférico usar uma solicitação IOCTL_SERIAL_SET_HANDFLOW para habilitar o controle de fluxo de hardware, o driver deverá definir os seguintes sinalizadores na estrutura SERIAL_HANDFLOW nesta solicitação:
- O sinalizador SERIAL_CTS_HANDSHAKE no membro ControlHandShake da estrutura. Esse sinalizador permite que a porta serial use o controle de fluxo para operações de recebimento.
- Os sinalizadores SERIAL_RTS_CONTROL e SERIAL_RTS_HANDSHAKE no membro FlowReplace . Esses sinalizadores permitem que a porta serial use o controle de fluxo para operações de transmissão.