MITM sul bus I2C


9

Ho cercato di progettare un modulo che mi consentirà di modificare le risposte slave selezionate su un bus I2C. Ecco la configurazione originale del bus (i pull-up e le connessioni di alimentazione non sono mostrati per chiarezza:

inserisci qui la descrizione dell'immagine Ci sono solo 2 dispositivi su questo bus ed è solo 100kHz. Un controller MCU (master I2C) e un lettore di schede RFID (slave I2C) NXP PN512. Non riesco a modificare il firmware del controller o le transazioni del bus I2C. La parte buona è che il controller invia solo 2 tipi di transazioni:

Master (Write Register) - <s><address+W><register number><data><p> Master (Read Register) - <s><address+W><register number><p><s><address+R><data><p>

Quello che voglio fare è sostituire i byte di dati selezionati durante la lettura del registro Master con i miei byte. Posso inviare i numeri di registro che l'MCU vuole leggere sul mio PC tramite UART (921.6kbaud). Posso elaborarli in C / C ++ o Python lì. Quando ricevo il numero di registro il cui valore deve essere sostituito, posso inviare un byte falso al mio dispositivo e mi occuperò di rispedirlo al controller sostituendo la risposta della carta originale.

Inizialmente ho diviso il bus I2C in due bus: inserisci qui la descrizione dell'immagine

Ho provato Arduino Nano e successivamente un CPLD usando il clock stretching. L'I2C hardware ATmega328 di fronte al controller MCU non riusciva a tenere il passo poiché a volte la sequenza di avvio veniva generata prima di 5us dopo il precedente ciclo di arresto. Quindi ogni tanto l'AVR stava effettuando una transazione di lettura. Il CPLD era in grado di gestire la velocità di arresto / avvio, risultando che l'allungamento del bus era disabilitato nell'MCU.

Mi è venuta l'idea di poter "prevedere" la lettura del registro principale rilevando una scrittura a byte singolo poiché sono sicuro che sia seguita da una lettura. Sembra che durante il seguente ciclo di lettura dell'indirizzo abbia avuto abbastanza tempo per portare il byte dallo slave. Non ha funzionato del tutto. Le transazioni del bus sembravano andate bene all'inizio (circa i primi 5 secondi) ma poi il controller stava interrompendo tutte le comunicazioni sul bus come se rilevasse che non sta parlando direttamente con il tag read.

Il lettore di schede può anche generare interruzioni per il master. Gli IRQ sono basati su timer o eventi. Ho attribuito il problema al ritardo che stavo introducendo intrinsecamente sul bus. Potrei essermi sbagliato, ma mi è venuta in mente un'altra idea di "ritardo zero". inserisci qui la descrizione dell'immagine

L'idea è che posso solo interrompere la linea SDA e lasciare la linea SCL collegata tra il master e lo slave. In questo modo posso ancora sostituire i byte sulla linea dati in entrambe le direzioni. Il design si è rivelato più complicato in quanto devo controllare la direzione della linea SDA in base al ciclo del bus. Ecco il codice VHDL che gestisce le transazioni del bus e invia al computer byte esadecimali su UART. La ricezione di byte dal computer non è ancora implementata:

library ieee; 
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all; 

entity I2C_Sniffer is 
port ( 
 clk : in std_logic;

 scl_master : in std_logic; 
 sda_master : inout std_logic;
 sda_slave  : inout std_logic;

 tx : out std_logic

); 
end entity I2C_Sniffer; 

architecture arch of I2C_Sniffer is
 signal clkDiv: std_logic_vector(7 downto 0) := (others => '0');

 type I2C_STATE is (I2C_IDLE, I2C_MASTER_WRITE, I2C_SLAVE_ACK, I2C_MASTER_READ, I2C_MASTER_ACK);
 signal i2cState: I2C_STATE := I2C_IDLE;

 type I2C_BUS_DIR is (MASTER_TO_SLAVE, SLAVE_TO_MASTER);
 signal i2cBusDir: I2C_BUS_DIR := MASTER_TO_SLAVE;

 signal i2cRxData: std_logic_vector(7 downto 0);
 signal i2cCntr: integer range 0 to 8 := 0;

 signal i2cAddr: std_logic := '1';
 signal i2cCmd: std_logic := '0';

 signal scl_d: std_logic := '1';
 signal scl: std_logic := '1';
 signal sda_d: std_logic := '1';
 signal sda: std_logic := '1';

 --Strobes for SCL edges and Start/Stop bits
 signal start_strobe : std_logic := '0';
 signal stop_strobe : std_logic := '0';
 signal scl_rising_strobe : std_logic := '0';
 signal scl_falling_strobe : std_logic := '0';

 type UART_STATE is (UART_IDLE, UART_START, UART_DATA, UART_STOP);
 signal uartState: UART_STATE := UART_IDLE;

 signal uartTxRdy: std_logic := '0';
 signal uartTxData: std_logic_vector(7 downto 0);
 signal uartCntr: integer range 0 to 8 := 0;

begin

 CLK_DIV: process (clk)
 begin
   if rising_edge(clk) then
     clkDiv <= std_logic_vector(unsigned(clkDiv) + 1);
   end if;
 end process;

I2C_STROBES: process (clk)
begin
  if rising_edge(clk) then
    --Pipelined SDA and SCL signals

    scl_d <= scl_master;
    scl <= scl_d;

    scl_rising_strobe <= '0';
    if scl = '0' and scl_d = '1' then
      scl_rising_strobe <= '1';
    end if;

    scl_falling_strobe <= '0';
    if scl = '1' and scl_d = '0' then
      scl_falling_strobe <= '1';
    end if;

    if i2cBusDir = MASTER_TO_SLAVE then
      sda_d <= sda_master;
      sda <= sda_d;
    else
      sda_d <= sda_slave;
      sda <= sda_d;
    end if;

    start_strobe <= '0';
    if sda_d = '0' and sda = '1' and scl = '1' and scl_d = '1' then
      start_strobe <= '1';
    end if;

    stop_strobe <= '0';
    if sda_d = '1' and sda = '0' and scl = '1' and scl_d = '1' then
      stop_strobe <= '1';
    end if;
  end if;
end process;

BUS_DIR: process(sda_master, sda_slave, i2cBusDir)
begin 
  if i2cBusDir = MASTER_TO_SLAVE then
    sda_slave <= sda_master;
    sda_master <= 'Z';
  else
    sda_master <= sda_slave;
    sda_slave <= 'Z';
  end if;
end process;

I2C: process(clk)
begin
    if rising_edge(clk) then
        uartTxRdy <= '0';

        case i2cState is
            when I2C_IDLE =>
                i2cBusDir <= MASTER_TO_SLAVE;

                if start_strobe = '1' then
                    i2cAddr <= '1';
                    i2cCntr <= 0;
                    i2cState <= I2C_MASTER_WRITE;
                end if;

            -- Master Write (Address/Data)
            when I2C_MASTER_WRITE =>
                i2cBusDir <= MASTER_TO_SLAVE;

                if stop_strobe = '1' then
                    i2cState <= I2C_IDLE;
                        uartTxData <= "00001010";
                        uartTxRdy <= '1';
                end if;

                if scl_rising_strobe = '1' then
                    if i2cCntr <= 7 then
                        i2cRxData(7 - i2cCntr) <= sda;
                        i2cCntr <= i2cCntr + 1;
                    end if;
                end if;

                if i2cCntr = 4 then
                    case i2cRxData(7 downto 4) is
                        when "0000" => uartTxData <= "00110000"; --0
                        when "0001" => uartTxData <= "00110001"; --1
                        when "0010" => uartTxData <= "00110010"; --2
                        when "0011" => uartTxData <= "00110011"; --3
                        when "0100" => uartTxData <= "00110100"; --4
                        when "0101" => uartTxData <= "00110101"; --5
                        when "0110" => uartTxData <= "00110110"; --6
                        when "0111" => uartTxData <= "00110111"; --7
                        when "1000" => uartTxData <= "00111000"; --8
                        when "1001" => uartTxData <= "00111001"; --9
                        when "1010" => uartTxData <= "01000001"; --A
                        when "1011" => uartTxData <= "01000010"; --B
                        when "1100" => uartTxData <= "01000011"; --C
                        when "1101" => uartTxData <= "01000100"; --D
                        when "1110" => uartTxData <= "01000101"; --E
                        when "1111" => uartTxData <= "01000110"; --F
                        when others => uartTxData <= "00111111"; --?
                    end case;
                    uartTxRdy <= '1';
                end if;

                if i2cCntr = 8 then
                    case i2cRxData(3 downto 0) is
                        when "0000" => uartTxData <= "00110000"; --0
                        when "0001" => uartTxData <= "00110001"; --1
                        when "0010" => uartTxData <= "00110010"; --2
                        when "0011" => uartTxData <= "00110011"; --3
                        when "0100" => uartTxData <= "00110100"; --4
                        when "0101" => uartTxData <= "00110101"; --5
                        when "0110" => uartTxData <= "00110110"; --6
                        when "0111" => uartTxData <= "00110111"; --7
                        when "1000" => uartTxData <= "00111000"; --8
                        when "1001" => uartTxData <= "00111001"; --9
                        when "1010" => uartTxData <= "01000001"; --A
                        when "1011" => uartTxData <= "01000010"; --B
                        when "1100" => uartTxData <= "01000011"; --C
                        when "1101" => uartTxData <= "01000100"; --D
                        when "1110" => uartTxData <= "01000101"; --E
                        when "1111" => uartTxData <= "01000110"; --F
                        when others => uartTxData <= "00111111"; --?
                    end case;
                    uartTxRdy <= '1';
                end if;

                if i2cCntr = 8 then
                    if scl_falling_strobe = '1' then
                        i2cState <= I2C_SLAVE_ACK;

                        if i2cAddr = '1' then
                            i2cCmd <= i2cRxData(0);
                            i2cAddr <= '0';
                        end if;
                    end if;
                end if;

            when I2C_SLAVE_ACK =>
                i2cBusDir <= SLAVE_TO_MASTER;

                if scl_falling_strobe = '1' then
                    i2cCntr <= 0;

                    if i2cCmd = '0' then
                        i2cState <= I2C_MASTER_WRITE;
                    else
                        i2cState <= I2C_MASTER_READ;
                    end if;
                end if;

            when I2C_MASTER_READ =>
                i2cBusDir <= SLAVE_TO_MASTER;

                if stop_strobe = '1' then
                    i2cState <= I2C_IDLE;
                        uartTxData <= "00001010";
                        uartTxRdy <= '1';
                end if;

                if scl_rising_strobe = '1' then
                    if i2cCntr <= 7 then
                        i2cRxData(7 - i2cCntr) <= sda;
                        i2cCntr <= i2cCntr + 1;
                    end if;
                end if;

                if i2cCntr = 4 then
                    case i2cRxData(7 downto 4) is
                        when "0000" => uartTxData <= "00110000"; --0
                        when "0001" => uartTxData <= "00110001"; --1
                        when "0010" => uartTxData <= "00110010"; --2
                        when "0011" => uartTxData <= "00110011"; --3
                        when "0100" => uartTxData <= "00110100"; --4
                        when "0101" => uartTxData <= "00110101"; --5
                        when "0110" => uartTxData <= "00110110"; --6
                        when "0111" => uartTxData <= "00110111"; --7
                        when "1000" => uartTxData <= "00111000"; --8
                        when "1001" => uartTxData <= "00111001"; --9
                        when "1010" => uartTxData <= "01000001"; --A
                        when "1011" => uartTxData <= "01000010"; --B
                        when "1100" => uartTxData <= "01000011"; --C
                        when "1101" => uartTxData <= "01000100"; --D
                        when "1110" => uartTxData <= "01000101"; --E
                        when "1111" => uartTxData <= "01000110"; --F
                        when others => uartTxData <= "00111111"; --?
                    end case;
                    uartTxRdy <= '1';
                end if;

                if i2cCntr = 8 then
                    case i2cRxData(3 downto 0) is
                        when "0000" => uartTxData <= "00110000"; --0
                        when "0001" => uartTxData <= "00110001"; --1
                        when "0010" => uartTxData <= "00110010"; --2
                        when "0011" => uartTxData <= "00110011"; --3
                        when "0100" => uartTxData <= "00110100"; --4
                        when "0101" => uartTxData <= "00110101"; --5
                        when "0110" => uartTxData <= "00110110"; --6
                        when "0111" => uartTxData <= "00110111"; --7
                        when "1000" => uartTxData <= "00111000"; --8
                        when "1001" => uartTxData <= "00111001"; --9
                        when "1010" => uartTxData <= "01000001"; --A
                        when "1011" => uartTxData <= "01000010"; --B
                        when "1100" => uartTxData <= "01000011"; --C
                        when "1101" => uartTxData <= "01000100"; --D
                        when "1110" => uartTxData <= "01000101"; --E
                        when "1111" => uartTxData <= "01000110"; --F
                        when others => uartTxData <= "00111111"; --?
                    end case;
                    uartTxRdy <= '1';
                end if;

                if i2cCntr = 8 and scl_falling_strobe = '1' then
                    i2cState <= I2C_MASTER_ACK;
                end if;

            when I2C_MASTER_ACK =>
                i2cBusDir <= MASTER_TO_SLAVE;
                if scl_falling_strobe = '1' then
                    i2cCntr <= 0;
                end if;

                if stop_strobe = '1' then
                    i2cState <= I2C_IDLE;
                    uartTxData <= "00001010"; -- \n
                    uartTxRdy <= '1';
                end if;
        end case;
    end if;
end process;


UART: process (clk, clkDiv(1), uartTxRdy)
begin
    if rising_edge(clk) then
        case uartState is
            when UART_IDLE =>
                if uartTxRdy = '1' then
                    uartState <= UART_START;
                end if;

            when UART_START =>
                if clkDiv(1 downto 0) = "00" then
                    tx <= '0';
                    uartState <= UART_DATA;
                    uartCntr <= 0;
                end if;

            when UART_DATA =>
                if clkDiv(1 downto 0) = "00" then
                    if uartCntr <= 7 then
                        uartCntr <= uartCntr + 1;
                        tx <= uartTxData(uartCntr);
                    else
                        tx <= '1';
                        uartState <= UART_STOP;
                    end if;
                end if;

            when UART_STOP =>
                if clkDiv(1 downto 0) = "00" then
                    tx <= '1';
                    uartState <= UART_IDLE;
                end if;
        end case;
    end if;
  end process;
end architecture arch;

Di seguito sono riportate le transizioni del bus acquisite con il CPLD che controlla la linea SDA.

Registrati scrivi:

inserisci qui la descrizione dell'immagine

Registrati leggi:

inserisci qui la descrizione dell'immagine

Puoi vedere alcuni difetti quando cambia la direzione del bus. Ciò è causato dalle differenze di temporizzazione tra il CPLD che modifica la direzione del bus e il lettore di schede che genera un ACK. Il livello ACK sembra essere stabile sul fronte di salita dell'SCL. Per quanto ne so, è tutto ciò di cui hai bisogno.

Con questa soluzione, il controller si comporta allo stesso modo dei bus divisi che sospendono qualsiasi attività del bus in pochi secondi. Ho anche testato quel w Arduino che prende in giro quel MCU e genera traffico di autobus per me e sembra che Arduino si blocchi anche di tanto in tanto. Quindi immagino di avere qualche tipo di problema con la macchina a stati VHDL in cui in alcune condizioni rimango bloccato in uno stato senza via d'uscita. Qualche idea?


La tua domanda non è molto chiara, per me comunque. Prima dici There's only 2 devices on this bus running at 100kHze poi The hardware I2C was a slave and a bit banged I2C was a master on the card reader bus at 1Mbps. Perché ci sono due autobus? Perché la necessità del bus ad alta velocità? Fornisci uno schizzo del tuo progetto iniziale e prova a chiarire la tua domanda.
SoreDakeNoKoto,

Si scusa. Il bus originale ha solo il controller (master i2c) e il lettore di schede / tag RFID (slave i2c). Quindi non devo preoccuparmi davvero dell'indirizzamento I2C in quanto punto-punto (ogni pacchetto inviato dal master è per questo slave). Il mio primo approccio è stato quello di dividere il bus in 2 bus e agire come slave i2c sul lato controller e come master sul lato lettore RFID.
Alexxx,

Il lettore RIFD è in grado di velocità più elevate (1MHz o anche più veloce), quindi ho pensato che potrei usarlo così non tengo il bus (bus stretching) sul lato controller per troppo tempo mentre leggo i dati dal lettore RFID Registrati. Inoltre, senza l'allungamento del bus quando rilevo una scrittura a byte singolo, ho solo poco tempo durante il ciclo di lettura successivo per leggere il byte dal lettore RIFD e inviarlo al controller.
Alexxx,

Per bus streching intendo l'orologio I2C che si estende dove lo slave mantiene bassa la linea SCL per far sapere al master che non è ancora pronto per i dati. Quando lo slave è pronto, rilascia la linea SCL e il master continua a leggere i bit inviati dallo slave.
Alexxx,

1
È preferibile invece modificare la domanda. Non hai ancora spiegato perché sono necessari 2 autobus. Se tutto ciò che serve è leggere i dati dal lettore di schede che utilizza I2C, perché non collegarli semplicemente sullo stesso bus e far leggere l'MCU da esso? L'allungamento dell'orologio ha senso solo dalla parte dello schiavo, di solito quando è lento a rispondere a un maestro. Non c'è niente che tu possa fare al riguardo se lo schiavo non è pronto. 100-400kHz è generalmente sufficiente per la maggior parte delle applicazioni; l'unico motivo per cui potresti desiderare velocità più elevate se devi eseguire un'operazione con tempo sensibile sui dati che hai letto o simili.
SoreDakeNoKoto,

Risposte:


6

Penso che tentare hack cutsey come te sia stato chiedere guai, con esattamente il tipo di sintomi che stai riscontrando. In pratica stai cercando di imbrogliare e spero di non essere scoperto.

L'unica cosa che non hai provato, secondo la tua descrizione, è un'emulazione completa di questo lettore di schede. Non hai davvero spiegato cosa fa esattamente e quanto sia complicato, ma a giudicare da ciò che il master sta inviando non è così complicato.

Utilizzare un microcontrollore con funzionalità slave IIC hardware. Questo è collegato al master. Il firmware emula il lettore di schede. Poiché l'unica cosa che il master ha mai letto è una sequenza di registri, l'altra parte del firmware comunica in modo completamente asincrono con il lettore di schede per ottenere informazioni da esso e controllarle. Questo significa anche che anche le linee di reset e IRQ sono separate.

Se fatto bene, questo deve funzionare, poiché non ci sono imbrogli. Il lettore di schede vede un controller che invia i suoi comandi e fa legge esattamente come doveva essere usato. Ciò include la risposta agli eventi IRQ.

Il master pensa che stia parlando direttamente con un vero lettore di schede perché emuli tutte le sue operazioni proprio come le cose reali, inclusi il comportamento di reset e IRQ.

Questo potrebbe sembrare più lavoro di qualche jam veloce e sporco che blocca un byte diverso sull'hack del bus, ma come hai scoperto non è così veloce e potrebbe sempre avere dei problemi di temporizzazione. Con un'emulazione completa, tutti i vincoli di temporizzazione vengono eliminati. Se la tua emulazione non ha ancora raggiunto qualcosa che il lettore di carte ha fatto, allora agisce come se non fosse ancora successo. Praticamente fai finta che non sia successo nulla di nuovo fino a quando la tua emulazione non è pronta a rispondere all'evento in tutti gli aspetti.

Ciò significa che hai davvero due parti asincrone del firmware: l'emulazione IIC del lettore presentata al master e un driver del lettore di schede completo che ti consente di mantenere vivo tutto il suo stato nella memoria interna.

Dal momento che non stai imbrogliando, questo deve funzionare se fatto bene. L'unico problema a livello di sistema è che ci sarà un certo ritardo nel vedere e causare azioni del lettore di carte rispetto al sistema esistente. Questo non suona come un grosso problema per un "lettore di schede", e considerando questo ritardo sarebbe probabilmente 10s di millisecondi nel peggiore dei casi. Certamente non dovrebbe essere evidente su una scala temporale umana.

Si noti che la comunicazione tra l'emulatore e il lettore di schede non è limitata ai 100 kbit / s attualmente utilizzati. Dovresti farlo veloce come il lettore di schede e l'hardware lo consentono. Dopotutto, su quel link sarai il padrone, quindi possiedi l'orologio. Ancora una volta, con una corretta architettura del firmware e attività asincrone, questo non dovrebbe avere importanza. In effetti, il tuo driver probabilmente comunicherà più spesso e otterrà più dati dal lettore di schede di quanto il master ottenga dall'emulatore.


Grazie per la risposta. Avevo esattamente in mente alcuni quando ho dichiarato per la prima volta di guardarlo. Ho rapidamente abbandonato l'idea in quanto sembra essere abbastanza complicato. Se l'MCU stesse solo scrivendo e leggendo i registri sarebbe facile ma il lettore comunica con un RFID che ha il suo protocollo (comandi e risposte multi-byte). Inoltre, l'MCU sta installando alcune bandiere per l'IRQ nel lettore e sta leggendo le statue. Pertanto sembrava che sarebbe stato molto più semplice indirizzare solo pochi byte e lasciare il resto al lettore.
Alexxx,

Inoltre, se divido l'intero bus in 2 bus, posso effettivamente parlare con il lettore di schede a velocità più elevate. Tuttavia, con l'ultimo design in cui ho tagliato solo la linea SDA, devo attenermi ai tempi previsti dall'MCU sulla linea SCL che è 100KHz.
Alexxx,

0

Suggerirei di essere sulla buona strada con un Arduino Nano come MITM, anche se penso che sarebbe meglio con due.

inserisci qui la descrizione dell'immagine

L'NXP-PN512 funzionerà a una velocità di clock di 3,4 Mhz, quindi suggerirei che potresti usare qualcosa dell'ordine di 1,5 - 2 MHz per la MCU della mano destra che parla con il Reader.
Poiché l'MCU di sinistra è impostato su 100 kHz, dopo aver riconosciuto tutti i byte di transazione (indirizzo / registro-WR) è possibile copiarlo su un bus parallelo a 8 bit (o anche più ampio) tra gli MCU e inviare i comandi al lettore in meno di un tempo di clock sul canale I2C a bassa velocità. Allo stesso modo la ricezione di un byte dal lettore si ottiene in meno di un tempo di clock sul bus lento dando il tempo adeguato per impostare il byte di risposta.

Sto assumendo qui che potrebbe essere necessario tradurre più byte come un ID NFC e non solo un singolo byte per conversione di byte (che richiede meno tempo).

Il problema principale che vedrei allora è che se è necessario serializzare più byte sul / dal PC per mappare le modifiche, i tempi diventano ancora più critici. Se esistesse un modo per integrare l'algoritmo / la tabella di modifica della mappatura nell'MCU di sinistra, ciò sembrerebbe un approccio migliore, sebbene risolvere una mappatura di identificatori multi-byte sia ancora la sfida maggiore.

Se sbaglio e devi solo mappare dire un singolo byte identificativo della carta, allora potrebbe funzionare.

Nei primi test con Arduino, ti sei assicurato che tutti gli interrupt fossero disattivati ​​(almeno in uso TWI)? In caso contrario, ciò potrebbe aver incasinato i tuoi tempi.


1
Non vedo perché sono necessari due micro separati. Numerosi micro possono gestire contemporaneamente due bus IIC. Hai solo bisogno di hardware per essere lo schiavo, anche se l'uso dell'hardware può essere conveniente anche quando sei il padrone. La comunicazione tra due micro sembra inutilmente complessa e lenta, rispetto a due attività in esecuzione nella stessa micro. Non riesco a vedere il problema risolto da due micro.
Olin Lathrop il

@Olin Lathrop. Semplifica lo sviluppo del software. rende il debug molto più semplice, ecc. ecc. È come il motivo per cui le auto hanno 100 microprocessori al loro interno piuttosto che un grande processore multiprocesso (come potresti suggerire). Non ho assolutamente problemi a utilizzare MCU multipli in cui il costo è principalmente inferiore a quello dei chip logici a funzione singola e la funzionalità è più facile da definire e sviluppare. In questo caso c'è un solo vettore di interruzione TWI in ATMega328, quindi è più difficile supportare due canali di I2C. ..Ma è certamente una scelta personale.
Jack Creasey,

In questo caso, più processori aggiungono complessità e introducono la necessità di una comunicazione aggiuntiva. Non è necessario utilizzare gli interrupt o l'hardware per IIC quando si è il padrone del bus. Tuttavia, ci sono molti processori in grado di gestire due bus IIC in modo indipendente nell'hardware. Se l'ATMega non è possibile e si desidera utilizzare due IIC hardware, non utilizzare un ATMega.
Olin Lathrop il

@Olin Lathrop. Accettiamo di non essere d'accordo. Il bit IMO al di sopra di cento kHz è un non-avviatore. Il problema per l'OP è che il costo di serializzare i dati da inviare a un PC per eseguire l'algoritmo di mappatura è carico di problemi di temporizzazione.
Jack Creasey,

Grazie per la risposta e i commenti. ATMega328 / Arduino non può essere utilizzato sul lato MCU a causa del timing I2C dell'MCU. Questo MCU è in grado di generare una sequenza di avvio più veloce di 4.7us dopo un arresto precedente. Guarda la tabella 32-10 nei fogli dati ATMega328 (parametro tBUF). Quello che stava succedendo era che Arduino stava NACKing tutte le letture i2c che seguivano una scrittura i2c. Apparentemente è un problema noto. Ho trovato informazioni su questo da qualche parte online dopo che mi sono passato tutti i capelli sopra. Questo è il motivo per cui sono passato al CPLD.
Alexxx,
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.