Sou membro de uma equipe de pesquisa que trabalha em um projeto que envolve um ASIC transmissor de RF e seu receptor sem fio, que deve enviar dados para um PC.
O receptor emite um sinal serial rápido , contínuo, assíncrono e não padrão (ou seja, não SPI, I2C, UART, etc.), portanto, meu trabalho é escrever um software de microcontrolador para fazer a interface do receptor com o computador. Atualmente, minha abordagem é usar interrupções acionadas por borda para colocar os dados em um buffer circular e fazer todo o processo de decodificação bit a bit no loop principal. O microcontrolador deve enviar esses dados simultaneamente usando USB (porta de comunicação virtual) para o computador.
Aqui está um problema que estou tendo e estou antecipando:
Não consigo processar os dados em buffer com rapidez suficiente, mesmo com o meu poderoso processador ARM Cortex M3 de 72 MHz. A taxa de bits é de 400 Kbps (2,5 us / bit). Para referência que deixa apenas 180 ciclos por bit (incluindo a decodificação E o ISR, que possui ~ 30 ciclos de sobrecarga!). O MCU também precisa lidar com muitas outras tarefas pesquisadas no loop principal.
O driver da porta virtual USB também é baseado em interrupção. Isso me deixa quase certo de que o driver acabará interrompendo o processador por tanto tempo que ele perde a janela de 2,5 microssegundos (180 ciclos) na qual um bit pode ser transmitido. Não tenho certeza de como normalmente são interrompidos conflitos / raças como essa.
Portanto, a pergunta é simples: o que alguém pode fazer para resolver esses problemas ou essa não é a abordagem correta? Também estou disposto a considerar abordagens menos centradas em software. Por exemplo, usando um chip USB dedicado com algum tipo de máquina de estado de hardware para a decodificação, mas esse é um território desconhecido.
Respostas:
Outra resposta: Pare de usar interrupções.
As pessoas saltam para usar interrupções com muita facilidade. Pessoalmente, raramente os uso porque eles realmente perdem muito tempo, como você está descobrindo.
Muitas vezes, é possível escrever um loop principal que controla tudo tão rapidamente, que a latência está dentro das especificações e muito pouco tempo é desperdiçado.
Pode haver algumas coisas no loop que acontecem com mais frequência do que outras. Talvez os bits recebidos, por exemplo, nesse caso, incluam mais desses testes, para que mais do processador seja dedicado a essa tarefa.
Pode haver alguns eventos para os quais a latência dessa abordagem é muito alta. Por exemplo, você pode precisar de um evento com tempo muito preciso. Nesse caso, tenha esse evento em interrupção e tudo o mais no loop.
fonte
Você poderia usar um FPGA em vez de um microcontrolador para decodificar e armazenar em buffer o fluxo de dados sem fio. Em seguida, use o processador ARM para liberar os buffers dos FPGAs (por exemplo, usando uma interface SPI) e enviar o conteúdo pela porta USB Comm. É um trabalho, mas um FPGA deve ser capaz de acompanhar com facilidade, desde que você consiga atendê-lo com frequência suficiente para garantir que seus buffers de hardware não excedam (ou se você pode lidar com dados descartados em um nível mais alto do protocolo )
fonte
Fácil: use um microcontrolador PSoC5 .
Você tem toda a facilidade de uso de um microcontrolador, além de conter um CPLD, para poder escrever seus próprios periféricos de hardware no Verilog. Basta escrever seu decodificador de dados seriais no verilog e usar o DMA para transmiti-lo para a porta USB.
Enquanto isso, o poderoso núcleo ARM de 32 bits pode estar girando suas instruções Thumb.
fonte
Eu acho que você tem uma escolha clássica de engenharia a fazer: rápido, barato, funciona: escolha duas.
A solução do @ vicatcu é certamente boa, mas se você não pode ou não adiciona mais hardware (e isso inclui um processador mais rápido), é necessário fazer uma escolha. Se esse link serial for o mais importante, você deve permanecer no ISR até que todos os bits tenham sido coletados. Na verdade, 180 instruções por bit não são nada ruins, mas não tente fazer tudo. Quando você detectar o início de uma transferência, gire até que a transferência seja concluída. Coloque o resultado em um FIFO e retome o processamento normal.
Você não diz quanto tempo cada transmissão tem, mas se elas são curtas e estouradas, essa seria uma solução viável. Estou disposto a apostar que sua implementação de porta COM virtual também possui algum buffer de hardware, portanto, um serviço de interrupção "lento", pois não deve apresentar muitos problemas. Quanto ao restante do que o MCU precisa fazer ... você precisa tomar algumas decisões de design.
fonte
Antes de tudo, eu já gosto de algumas respostas aqui, e algumas foram aprovadas.
Mas apenas para lançar outra solução possível: dadas as restrições do seu projeto, seria ruim adicionar um segundo microcontrolador (isso envolveria outra execução da placa)? Talvez um simples microcontrolador de 8 bits que se conecte ao seu Cortex-M3 por um periférico rápido como o SPI. O controlador de 8 bits de sua escolha pesquisaria bits e bytes de formato, como na resposta selecionada, mas quando tiver um byte, poderá despejá-lo no registro de dados SPI para transferência.
O lado do córtex-M3 simplesmente interromperia os dados SPI recebidos. Isso reduz a interrupção acionada por borda externa anterior de 400 KHz para 50 KHz.
As duas razões pelas quais estou sugerindo isso são porque alguns dos outros métodos (PSoC ou FPGA adicionado) são um pouco caros (embora isso provavelmente não importe para um projeto acadêmico de baixo volume) e porque podem permitir que você preserve alguns dos a estrutura do seu código atual.
Fora isso, acho que a ideia do PSoC é incrível com o seu próprio periférico personalizado transferindo DMA para USB.
fonte
Se o seu formato de dados for semelhante ao de um UART, mas a uma taxa de transmissão imprevisível, mas consistente, minha tendência seria usar um CPLD para converter todas as palavras dos dados recebidos no formato SPI ou no padrão assíncrono. Acho que não há necessidade de avançar até o âmbito das CPLDs. Na verdade, mesmo a lógica discreta pode quase ser viável. Se você pudesse gerar um relógio com um smidgin mais que 5x a sua taxa de dados desejada, poderia usar um contador de divisão por cinco e divisão por 16 com alguns portões. Organize o contador de divisão por cinco, para que seja mantido em redefinição sempre que a entrada estiver ociosa e o contador de divisão por 16 estiver em zero. Caso contrário, gere um pulso de clock SPI e bata no contador de divisão por 16 sempre que o contador de divisão por cinco atingir 2.
Dado o relógio 5x, era possível gerar o relógio SPI usando um 16V8 (o menor e mais barato dispositivo lógico programável atualmente disponível). Um segundo 16V8 ou 22V10 poderia ser usado como um divisor de taxa fracionária para gerar o relógio 5x, ou alguém poderia usar um chip um pouco maior (CPLD) e fazer tudo em um.
Editar / Adendo
Após algumas considerações adicionais, se alguém usar um CPLD, poderá adicionar facilmente alguns aprimoramentos adicionais ao circuito. Por exemplo, pode-se facilmente adicionar lógica para que o circuito seja travado até receber pelo menos 1,5 bits de bit de parada, seguidos por 3,5 bits de bit de início; se receber um bit de início muito curto, deve voltar a procurar o bit de parada. Além disso, se alguém estiver usando SPI, poderá usar o sinal / CS para garantir que o dispositivo receptor veja os dados corretamente enquadrados. Se o dispositivo que recebe os dados SPI pode lidar com quadros de 10 bits, pode-se enviar esses quadros diretamente. Caso contrário, cada quadro de dez bits poderá ser enviado como um quadro de 8 bits com o conjunto LSB (7 bits de dados) e um quadro com todos os dados limpos do LSB (3 bits de dados); o relógio SPI seria acelerado durante os bits de parada, para que todos os dados fossem enviados.
Alguns microcontroladores possuem módulos de geração PWM bastante versáteis, que incluem coisas como a capacidade de ser redefinido por um sinal externo e sincronizam seu tempo com a liberação desse sinal. Se o seu microcontrolador puder fazer isso, dependendo de seus recursos exatos, isso poderá simplificar consideravelmente o CPLD ou o circuito de geração de tempo.
Outra abordagem na qual o Rocketmagnet abordou um pouco, seria ter um micro pequeno cujo único objetivo é decodificar os dados seriais e convertê-los em um formato utilizável pelo micro principal. Sua taxa de dados de 400KHz é bastante rápida para decodificação de software, mas algo como um PIC poderia lidar com isso se não precisasse fazer mais nada ao mesmo tempo. Dependendo de quais dispositivos você está familiarizado, isso pode ser mais fácil ou mais difícil do que usar um CPLD.
fonte