Errore di lettura / scrittura I2C sotto carico di interrupt pesante


10

Nel mio sistema, sto usando I2C e realizzo sotto carico di interrupt pesante (da altre fonti), la comunicazione I2C si interrompe facilmente. Questo comportamento previsto è per I2C? Mi sarei aspettato nonostante il carico di interruzione, sarebbe comunque ok dato che I2C non è esattamente un'interfaccia time-critical, l'orologio è fornito di dati.

Aggiornare:

Il processore è STM32. Gli interrupt sono dovuti ad ADC, non riesco a disabilitare gli interrupt durante gli eventi di lettura, quindi devo trovare una soluzione in cui posso rendere più stabile la comunicazione i2c. L'STM32 è master e lo slave è un altro dispositivo (accelerometro).

Update2:

Quando collego un analizzatore logico all'orologio con un piccolo cavo volante, il problema scompare. È interessante notare che non vi è alcun carico di interruzione, lettura scrittura funziona bene, quando c'è un carico di interruzione, non lo fanno. Tuttavia, se collego la sonda all'orologio, la lettura e la scrittura funzionano anche sotto carico di interrupt. Penso che ci sia un problema di capacità da qualche parte.


1
La tua domanda è molto generica perché tutto dipende dal design del tuo sistema. Il modo in cui I2C gestisce dipende davvero dai dispositivi sul bus. Puoi ignorarli e venire a dopo? In un FPGA, potresti progettare la logica per occuparti di molto per te ed evitarlo. Ancora una volta, abbiamo bisogno di ulteriori informazioni sul microcontrollore e su quali altre cose hai. Di solito una buona soluzione qui è usare un RTOS e progettare correttamente le attività.
Gustavo Litovsky,

Due cose da cercare: abbassamento della tensione sui pullup o sulla potenza del master e slave i2c o problemi di emi o capacità. Per quanto riguarda il carico di interrupt, vuoi dire che il tuo master si sta arrestando per gestire un interrupt? Alcuni chip non consentono l'allungamento infinito del clock.
Passante,

@GustavoLitovsky hai ragione, ma l'80% dei cicli della CPU sta servendo l'interrupt ADC e non c'è abbastanza tempo per fare un ciclo di lettura durante la finestra non ISR. Quindi la lettura verrà interrotta, non importa quanto bene progetta il sistema operativo.
Ktc,

@Passerby potresti avere ragione. Il problema è scomparso quando ho collegato la sonda dell'analizzatore logico alla linea dell'orologio.
Ktc,

Qual è il tuo valore attuale per i pull-up. Hai provato a cambiarli con un valore diverso? (Prova 10k o 4k7 o 2k solo per una prima ipotesi)
Tom L.

Risposte:


9

Questo è un problema software, stai impiegando troppo tempo a riparare gli interrupt e la tua routine I2C non è in grado di gestirlo (quindi sono due cose che non sono giuste). Ho vissuto diverse situazioni simili.

Primo: devi fare il meno possibile negli interrupt, solo leggere e archiviare i dati, non fare alcuna elaborazione che potresti fare al di fuori dell'ISR, la matematica può richiedere MOLTO cicli di CPU e la CPU non può fare nient'altro mentre in quell'interruzione.

Secondo: indaga su DMA per automatizzare le cose, in modo che i tuoi interrupt diventino quasi un processo automatizzato in background.

Terzo: se I2C è importante, metti anche QUELLO in un interrupt, ma assicurati di stabilire le priorità!

Quarto: capire perché la routine I2C non riesce, I2C stesso può resistere a tempistiche, pause e attese molto intermittenti, quindi potrebbe essere necessario modificare la routine per consentire ciò.

Quinto: vedi se riesci a "concatenare" gli interrupt, potresti scoprire che puoi servire le letture dell'ADC in modo più efficiente o mettere l'ADC in una modalità diversa in cui funziona di più per te prima di interrompere (ad esempio, aspetta che tutte le letture siano disponibili, quindi leggi tutto in un colpo, anziché 8 interrupt separati per 8 letture di canali ADC separati).

Sesto: utilizzare un oscilloscopio o un analizzatore logico e aggiungere pin IO sulla scheda, per tracciare il tempo impiegato in ciascun bit di codice, per vedere se è possibile accelerarlo. (Impostare il pin alto quando si inserisce una funzione / ISR, impostarlo di nuovo in basso all'uscita).

Settimo: Decidi se hai davvero bisogno di leggere così tanto l'ADC, andare più piano peggiorerà le cose? È controintuitivo, ma a volte correre più lentamente in realtà dà risultati migliori, facendo il lavoro di mediare il segnale per te e ridurre picchi / transitori che potrebbero causare problemi o richiedere un'elaborazione aggiuntiva da rimuovere. Abbiamo migliorato una routine PID di controllo del motore semplicemente eseguendo 1/4 della velocità, liberando un carico di tempo della CPU nel processo.


Grazie per i suggerimenti Il problema in qualche modo punta all'hardware.
Ktc,

4

Uno slave del bus che è impegnato con altre cose ha la capacità di allungare il tempo per guadagnare tempo fino a quando non è in grado di continuare la sua comunicazione. Lo fa non inviando immediatamente l'impulso di clock ACK / NACK, mantenendo la comunicazione in uno stato intermedio fino a quando non è pronto a rispondere.

L'allungamento dell'orologio è il modo appropriato per affrontare questo tipo di situazione. Un dispositivo che non si allunga e fa altre cose cattive (blocco / riavvio del bus, NACK un indirizzo o comando valido, ecc.) Può essere problematico e pone un onere aggiuntivo sul master per mantenere le cose ordinate (deve ripetere i comandi , tenere traccia degli NACK, ecc.)


Hai ragione ma il problema è l'host. L'host è impegnato con altre cose, non con lo schiavo. Quindi non sono così sicuro di poter fare un allungamento dell'orologio.
Ktc,

Stai utilizzando l'hardware I2C integrato o bit-bang il protocollo dalle linee GPIO? Non esiste un intervallo di timeout I2C specifico definito nello standard, quindi gli slave devono attendere indefinitamente il completamento del pacchetto da parte del master.
Adam Lawrence,

Uso le API STM32 IC2. Vedi l'aggiornamento, sembra un problema di capacità.
Ktc,

1

A seconda delle capacità dell'STM32 (non ne ho mai usato uno), potresti provare uno dei seguenti approcci. Se puoi fornire maggiori dettagli su ciò che stai cercando di fare e avere un argomento convincente sul perché ogni interrupt è necessario nella forma in cui lo hai ora, allora si potrebbe pensare a una risposta più specifica. In particolare nel tuo caso, tuttavia, I2C è abbastanza lento da non essere un problema con routine di interruzione ben scritte.

  • Gli interrupt per qualsiasi cosa di solito possono essere disabilitati. Esistono al massimo uno o due Interrupt non mascherabili in qualsiasi controller usuale, uno dei quali viene ripristinato. Se non hai bisogno del controllo guidato da interruzioni di qualcosa (ADC o I2C, nel tuo caso), trasforma quel codice periferico in uno che non usa gli interrupt, quindi disabilita gli interrupt.

  • I gestori di interruzioni non dovrebbero essere lunghi. Cerca di fare il meno possibile dal vettore di interrupt stesso. L'approccio minimalista estremo agli interrupt è semplicemente impostare un flag all'interno della routine del gestore di interrupt e avere, diciamo, il ciclo principale che fa tutto il lavoro pesante da lì in poi. Ciò che richiede la tua specifica applicazione e architettura del firmware potrebbe non essere semplice come quello, ma vale davvero la pena impegnarsi per vedere quanto bisogna veramente fare all'interno degli interrupt.

  • Se hai un DMA periferico, usa quello invece di interrompere ad ogni byte. In genere, sarebbe più semplice inserire l'ADC su DMA rispetto a I2C, ma chip diversi hanno implementazioni diverse. Non sarei sorpreso se ci fosse un modo pulito di scatenare uno scambio I2C anche con il DMA. DMA consente di ridurre il numero di interruzioni e lascia libero il core del processore di dover gestire ogni singolo blocco di dati.

  • Prova a identificare le istanze specifiche in cui stai vedendo il danneggiamento dei dati e il meccanismo con cui si sta verificando il danneggiamento dei dati. Questo è molto più difficile da fare, ma con l'uso creativo di un moderno oscilloscopio / analizzatore logico potresti essere in grado di vedere alcuni dei problemi. In particolare, assicurati che il problema abbia a che fare con il tempismo e non con la memoria (che è una possibilità con una combinazione di codice terribile e un compilatore liberale)

MODIFICA: Alcune note specifiche relative a questa istanza del problema, dai tuoi commenti sulla domanda:

  • Avere l'80% di CPU utilizzato per leggere l'ADC di solito non è una cosa utile da fare. La raccolta di dati è inutile se non è possibile agire su di essi o addirittura salvarli.
  • Anche se in qualche modo stai raccogliendo (utilmente) un'enorme quantità di dati, gli interrupt ADC non dovrebbero essere così lunghi da sopprimere completamente la periferica I2C per un tempo abbastanza lungo da fargli perdere dati. I2C funziona al massimo a 100 / 400KHz. Avresti bisogno di un interrupt davvero lungo per interromperlo abbastanza a lungo da sembrare qualcosa di più grave del jitter di clock su I2C.

Grazie. Il nostro sistema richiede questo tipo di ISR ​​complesso e lungo, è una lunga storia. Hai ragione però, I2C deve sostenere anche sotto questo carico di interruzione e non può. Sospetto che il problema sia nell'hardware, vedi l'aggiornamento.
Ktc,

Per quanto vale, nella mia esperienza, la maggior parte dei casi d'uso che sembrano imporre un ISR follemente lungo sono in realtà quelli che meritano un RTOS. E sì, per la tua ultima modifica sembra un problema hardware. Prova a mettere un piccolo condensatore sulla linea in cui si trovava il tuo analizzatore logico e probabilmente starai bene. Perché ciò sia necessario, tuttavia, è in qualche modo più difficile rispondere. Verificherei i resistori pull-up I2C (potrebbe essere troppo basso per la capacità del bus) e controllerei i fogli dati di tutti i buffer / ripetitori I2C che potresti utilizzare.
Chintalagiri Shashank,

0

In un determinato sistema, potrebbe esserci del rumore che entra nell'orologio e nei bus dati. Il fatto che il tuo anlayer logico rimuova il problema lo dimostra. Per un'implementazione pratica e rapida, basta seguire l'indicazione data dalla tua osservazione. Su un bus i2c con implementazione a 400kbit / sec, basato su osservazioni simili, ho collegato 2M in parallelo con 12pf a terra da clock e punti dati e ho scoperto che il problema è stato risolto. Ciò rimuove / filtra il rumore al di fuori della banda di interesse richiesta per la specifica comunicazione i2c. Si prega di provare e consigliare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.