Falha na leitura / gravação I2C sob carga pesada de interrupção

10

No meu sistema, estou usando o I2C e percebo que, sob uma carga pesada de interrupção (de outras fontes), a comunicação do I2C é facilmente interrompida. Esse comportamento é esperado para o I2C? Eu esperava que, apesar da interrupção do carregamento, ainda estaria tudo bem, já que o I2C não é exatamente uma interface de tempo crítico, o relógio é fornecido com dados.

Atualizar:

O processador é STM32. As interrupções são devidas ao ADC, não posso desativar as interrupções durante os eventos de leitura, portanto, preciso encontrar uma solução para tornar a comunicação i2c mais estável. O STM32 é mestre e o escravo é outro dispositivo (acelerômetro).

Update2:

Quando conecto um analisador lógico ao relógio com um pequeno cabo voador, o problema desaparece. Curiosamente, não há carga de interrupção, a leitura e gravação funciona bem; quando há carga de interrupção, elas não funcionam. No entanto, se eu anexar a sonda ao relógio, a leitura e gravação também funcionará sob carga de interrupção. Eu acho que há um problema de capacitância em algum lugar.

Ktc
fonte
11
Sua pergunta é muito genérica, porque tudo depende do design do seu sistema. O modo como o I2C lida realmente depende dos dispositivos no barramento. Você pode ignorá-los e vir para o mais tarde? Em um FPGA, você pode projetar uma lógica para cuidar muito de você e evitar isso. Novamente, precisamos de mais informações sobre o microcontrolador e quais outras coisas você possui. Geralmente, uma boa solução aqui é usar um RTOS e projetar adequadamente as tarefas.
Gustavo Litovsky
Duas coisas a procurar: a tensão afunda nos pullups ou na energia do seu mestre e escravo i2c, ou problemas de emi ou capacitância. Quanto ao carregamento de interrupção, você quer dizer que seu mestre está parando para lidar com uma interrupção? Alguns chips não permitem o alongamento infinito do relógio.
21813 Passerby
@GustavoLitovsky, você está certo, mas 80% dos ciclos da CPU estão atendendo à interrupção do ADC e não há tempo suficiente para fazer um ciclo de leitura durante a janela não ISR. Portanto, a leitura será interrompida, não importa quão bem eu projete o sistema OS.
Ktc
@ Passerby você pode estar certo. O problema desapareceu quando conectei a sonda do analisador lógico à linha do relógio.
#
Qual é o seu valor atual para as flexões. Você já tentou alterá-los para um valor diferente? (Experimente 10k ou 4k7 ou 2k apenas por um primeiro palpite)
Tom L.

Respostas:

9

Este é um problema de software, você está gastando muito tempo atendendo a interrupções e sua rotina I2C não é capaz de lidar com isso (portanto, são duas coisas que não estão certas). Eu já passei por várias situações semelhantes.

Primeiro: você precisa fazer o mínimo possível nas interrupções, apenas ler e armazenar os dados, não realizar nenhum processamento que possa ser feito fora do ISR, a matemática pode demorar MUITOS ciclos de CPU e a CPU não pode fazer mais nada enquanto estiver nessa interrupção.

Segundo: Investigue o DMA para automatizar as coisas, para que suas interrupções se tornem quase um processo automatizado em segundo plano.

Terceiro: Se o I2C for importante, interrompa ISSO também, mas certifique-se de definir as prioridades!

Quarto: Descubra por que sua rotina I2C está falhando, o próprio I2C pode suportar tempos muito intermitentes, pausas e esperas etc., para que sua rotina precise ser modificada para permitir isso.

Quinto: veja se você pode "encadear" interrupções, pode achar que pode atender as leituras do ADC com mais eficiência ou colocar o ADC em um modo diferente, onde ele trabalha mais para você antes de interromper (por exemplo, espere que todas as leituras estejam disponíveis, depois leia tudo em uma ocorrência, em vez de 8 interrupções separadas para 8 leituras de canal ADC separadas).

Sexto: use um osciloscópio ou analisador lógico e pino de E / S sobressalentes na placa, para rastrear quanto tempo você gasta em cada parte do código, para ver se você pode acelerá-lo. (Coloque o pino alto quando inserir uma função / ISR, coloque-o novamente na saída).

Sétimo: decida se você realmente precisa ler muito o ADC, será que vai ficar mais lento piorando as coisas? É contra-intuitivo, mas às vezes correr mais devagar na verdade fornece resultados melhores, fazendo o trabalho de calcular o sinal para você e reduzindo picos / transientes que podem causar problemas ou exigir processamento extra para serem removidos. Melhoramos uma rotina PID de controle do motor, executando-a 1/4 da velocidade, liberando uma carga de tempo da CPU no processo.

John U
fonte
Obrigado por sugestões. O problema de alguma forma aponta para o hardware.
Ktc
4

Um escravo de ônibus que está ocupado com outras coisas tem a capacidade de esticar o relógio para ganhar tempo até conseguir continuar sua comunicação. Isso é feito não enviando imediatamente o pulso do relógio ACK / NACK, mantendo a comunicação em um estado intermediário até que esteja pronta para atender.

O alongamento do relógio é a maneira apropriada de lidar com esse tipo de situação. Um dispositivo que não estica e faz outras coisas ruins (parada / reinicialização do barramento, NACKs um endereço ou comando válido etc.) pode ser problemático e sobrecarrega o mestre para manter as coisas separadas (ele precisa repetir comandos , acompanhe os NACKs etc.)

Adam Lawrence
fonte
Você está certo, mas o problema é o host. O host está ocupado com outras coisas, não escravo. Portanto, não tenho tanta certeza de que posso fazer um alongamento do relógio.
Ktc
Você está usando hardware I2C a bordo ou substituindo o protocolo pelas linhas GPIO? Não há um intervalo de tempo limite I2C específico definido no padrão; portanto, os escravos devem esperar indefinidamente pelo mestre para concluir um pacote.
Adam Lawrence
Eu uso as APIs do STM32 IC2. Por favor, veja a atualização, parece um problema de capacitância.
Ktc 22/02
1

Dependendo dos recursos do STM32 (nunca usei um), você pode tentar uma das seguintes abordagens. Se você pode fornecer mais detalhes sobre o que está tentando fazer e ter um argumento convincente sobre por que cada interrupção é necessária na forma que você a possui agora, uma resposta mais específica pode ser pensada. No entanto, especificamente no seu caso, o I2C é lento o suficiente para que isso não seja um problema com rotinas de interrupção bem escritas.

  • Interrupções para qualquer coisa geralmente podem ser desativadas. Existem no máximo uma ou duas interrupções não mascaráveis ​​em qualquer controlador usual, uma das quais é redefinida. Se você não precisar de controle acionado por interrupção de algo (ADC ou I2C, no seu caso), transforme esse código periférico em um que não use interrupções e desative as interrupções.

  • Manipuladores de interrupção não devem ser longos. Tente fazer o mínimo possível do próprio vetor de interrupção. A abordagem minimalista extrema às interrupções é simplesmente definir um sinalizador dentro da rotina do manipulador de interrupções e, digamos, o loop principal faça todo o trabalho pesado a partir de então. O que sua arquitetura específica de aplicativo e firmware requer pode não ser tão simples quanto isso, mas realmente vale a pena fazer um esforço para ver o quanto realmente deve ser feito dentro das interrupções.

  • Se você tiver DMA periférico, use-o em vez de interromper a cada byte. Normalmente, seria mais fácil colocar o ADC no DMA do que no I2C, mas chips diferentes têm implementações diferentes. Eu não ficaria surpreso se houvesse uma maneira limpa de obter uma troca I2C para o DMA também. O DMA permite reduzir o número de interrupções e deixa o núcleo do processador livre de ter que lidar com todos os blocos de dados.

  • Tente identificar as instâncias específicas em que você está vendo corrupção de dados e o mecanismo pelo qual a corrupção de dados está acontecendo. Isso é muito mais difícil, mas com o uso criativo de um osciloscópio / analisador lógico moderno, você poderá ver alguns dos problemas. Especificamente, verifique se o problema está relacionado ao tempo e não à memória (que é uma possibilidade com uma combinação de código terrível e um compilador liberal)

Edição: Algumas notas específicas sobre esta instância do problema, a partir de seus comentários sobre a pergunta:

  • Ter 80% da CPU usado para ler o ADC geralmente não vale a pena. A coleta de dados é inútil se você não puder agir com base neles ou mesmo salvá-los.
  • Mesmo que você esteja de alguma forma reunindo (de maneira útil) uma enorme quantidade de dados, as interrupções do ADC não devem demorar tanto para suprimir completamente o periférico I2C por um tempo suficiente para fazê-lo perder dados. O I2C é executado a, no máximo, 100 / 400KHz. Você precisaria de uma interrupção muito, muito longa para interromper o tempo suficiente para parecer algo mais sério do que o jitter do relógio no I2C.
Chintalagiri Shashank
fonte
Obrigado. Nosso sistema requer esse tipo de ISR complexo e longo, é uma longa história. Você está certo, porém, o I2C deve sustentar mesmo com essa carga de interrupção e não pode. Suspeito que o problema esteja no hardware, consulte a atualização.
Ktc
Pelo que vale a pena, na minha experiência, a maioria dos casos de uso que parecem exigir um ISR insanamente longo são realmente aqueles que merecem um RTOS. E sim, na sua edição mais recente, parece um problema de hardware. Tente colocar um pequeno capacitor na linha onde estava o analisador lógico e você provavelmente ficará bem. Por que isso é necessário, porém, é um pouco mais difícil de responder. Eu verificaria os resistores pull-up I2C (pode ser muito baixo para a capacitância do seu barramento) e as folhas de dados de quaisquer buffers / repetidores I2C que você possa estar usando.
Chintalagiri Shashank 22/02
0

Em um determinado sistema, pode haver ruído entrando no relógio e nos barramentos de dados. O fato de o seu anlayser lógico remover o problema mostra isso. Para uma implementação prática e rápida, basta seguir a sugestão dada por sua observação. Em um barramento i2c com implementação de 400kbits / s, com base em observação semelhante, conectei 2M em paralelo com 12pf ao terra dos pontos de relógio e de dados e descobri que o problema estava resolvido. Isso remove / filtra o ruído fora da faixa de interesse necessária para a comunicação i2c específica. Por favor, tente e aconselhe.

user41360
fonte