MITM sur le bus I2C

9

J'ai essayé de concevoir un module qui me permettra de modifier les réponses esclaves sélectionnées sur un bus I2C. Voici la configuration de bus d'origine (les tractions et les connexions d'alimentation ne sont pas affichées pour plus de clarté:

entrez la description de l'image ici Il n'y a que 2 appareils sur ce bus et ce n'est qu'à 100 kHz. Un contrôleur MCU (maître I2C) et le lecteur de carte RFID (esclave I2C) NXP PN512. Je ne peux pas modifier le micrologiciel du contrôleur ni changer les transactions du bus I2C. La bonne partie est que le contrôleur envoie seulement 2 types de transactions:

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

Ce que je veux faire, c'est remplacer les octets de données sélectionnés lors de la lecture du registre maître par mes propres octets. Je peux envoyer les numéros de registre que le MCU veut lire sur mon PC via UART (921.6kbaud). Je peux les traiter en C / C ++ ou Python là-bas. Lorsque je reçois le numéro de registre dont la valeur doit être remplacée, je peux renvoyer un faux octet à mon appareil et il se chargera de le renvoyer au contrôleur en remplaçant la réponse de la carte d'origine.

Au début, j'ai divisé le bus I2C en deux bus: entrez la description de l'image ici

J'ai essayé Arduino Nano et plus tard un CPLD en utilisant l'étirement de l'horloge. Le matériel ATmega328 I2C faisant face au contrôleur MCU n'a pas pu suivre car parfois la séquence de démarrage a été générée plus tôt que 5us après le cycle d'arrêt précédent. Donc, de temps en temps, l'AVR effectuait une transaction de lecture. Le CPLD pouvait gérer la vitesse d'arrêt / démarrage, il s'est avéré que l'étirement du bus était désactivé dans le MCU.

J'ai eu l'idée que je pouvais "prédire" la lecture du registre maître en détectant une écriture sur un seul octet car je suis sûr qu'elle est suivie d'une lecture. Il semble que j'ai eu assez de temps pendant l'écriture d'adresse du cycle de lecture suivant pour introduire l'octet de l'esclave. Cela n'a pas vraiment fonctionné. Les transactions de bus semblaient bien au début (environ les 5 premières secondes) mais ensuite le contrôleur cessait toutes les communications sur le bus comme s'il détectait qu'il ne parlait pas directement pour lire la balise.

Le lecteur de carte peut également générer des interruptions vers le maître. Les IRQ sont basés sur un temporisateur ou un événement. J'ai attribué le problème au retard que j'introduisais par nature dans le bus. Je me suis peut-être trompé, mais j'ai trouvé une autre conception «zéro retard». entrez la description de l'image ici

L'idée est que je ne peux que couper la ligne SDA et laisser la ligne SCL connectée entre le maître et l'esclave. De cette façon, je peux toujours remplacer les octets sur la ligne de données dans les deux sens. La conception s'est avérée plus compliquée car je dois contrôler la direction de la ligne SDA en fonction du cycle du bus. Voici le code VHDL qui gère les transactions de bus et envoie des octets hexadécimaux via UART à l'ordinateur. La réception d'octets de l'ordinateur n'est pas encore implémentée:

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;

Vous trouverez ci-dessous les transitions de bus capturées avec le CPLD contrôlant la ligne SDA.

S'inscrire écrire:

entrez la description de l'image ici

S'inscrire lire:

entrez la description de l'image ici

Vous pouvez voir quelques problèmes lorsque la direction du bus change. Cela est dû aux différences de synchronisation entre le CPLD changeant la direction du bus et le lecteur de carte générant un ACK. Le niveau ACK semble stable sur le front montant du SCL. Autant que je sache, c'est tout ce dont vous avez besoin.

Avec cette chose en place, le contrôleur se comporte de la même manière qu'avec les bus divisés suspendant toute activité de bus en quelques secondes. Je teste également ce w Arduino qui se moque de ce MCU et génère du trafic de bus pour moi et il semble que l'Arduino se fige également de temps en temps. Donc je suppose que je peux avoir une sorte de problème avec la machine d'état VHDL où, dans certaines conditions, je suis coincé dans un état sans issue. Des idées?

Alexxx
la source
Votre question n'est pas très claire, en tout cas pour moi. Vous dites d'abord There's only 2 devices on this bus running at 100kHzet ensuite The hardware I2C was a slave and a bit banged I2C was a master on the card reader bus at 1Mbps. Pourquoi y a-t-il deux bus? Pourquoi le besoin du bus à grande vitesse? Fournissez un croquis de votre conception initiale et essayez de clarifier votre question.
SoreDakeNoKoto
Ouais désolé. Le bus d'origine n'a que le contrôleur (maître i2c) et le lecteur de carte / tag RFID (esclave i2c). Par conséquent, je n'ai pas vraiment à me soucier de l'adressage I2C car il est point à point (chaque paquet envoyé par le maître est pour cet esclave). Ma première approche a été de diviser le bus en 2 bus et d'agir comme esclave i2c du côté contrôleur et maître du côté lecteur RFID.
Alexxx
Le lecteur RIFD est capable de vitesses plus rapides (1 MHz ou même plus rapide), j'ai donc pensé que je pourrais l'utiliser pendant que je ne maintiens pas le bus (étirement du bus) du côté du contrôleur trop longtemps pendant que je lis les données du lecteur RFID S'inscrire. De plus, sans que le bus ne s'étire lorsque je détecte une écriture d'un seul octet, je n'ai que peu de temps pendant le cycle de lecture suivant pour lire l'octet du lecteur RIFD et le renvoyer au contrôleur.
Alexxx
Par étirement du bus, j'entends l'étirement de l'horloge I2C où l'esclave maintient la ligne SCL basse pour faire savoir au maître qu'il n'est pas encore prêt pour les données. Lorsque l'esclave est prêt, il libère la ligne SCL et le maître continue de lire les bits envoyés par l'esclave.
Alexxx
1
Il est préférable de modifier votre question à la place. Vous n'avez toujours pas expliqué pourquoi 2 bus sont nécessaires. Si tout ce dont vous avez besoin est de lire les données du lecteur de carte utilisant I2C, alors pourquoi ne pas simplement les connecter sur le même bus et faire lire votre MCU? L'étirement de l'horloge n'a de sens que du côté de l'esclave, généralement lorsqu'il est lent à répondre à un maître. Vous ne pouvez rien y faire si l'esclave n'est pas prêt. 100 à 400 kHz est généralement suffisant pour la plupart des applications; la seule raison pour laquelle vous pouvez souhaiter des vitesses plus rapides si vous devez effectuer une opération sensible au temps sur les données que vous avez lues ou similaires.
SoreDakeNoKoto

Réponses:

6

Je pense que tenter des hacks cutsey comme vous l'avez été pose des problèmes, avec exactement le type de symptômes que vous rencontrez. Vous essayez essentiellement de tricher et espérez ne pas vous faire prendre.

La seule chose que vous n'avez pas essayé, selon votre description, est une émulation complète de ce lecteur de carte. Vous n'avez pas vraiment expliqué ce qu'il fait exactement et à quel point c'est compliqué, mais à en juger par ce que le maître envoie, ce n'est pas si compliqué.

Utilisez un microcontrôleur avec une capacité esclave IIC matérielle. C'est connecté au maître. Le firmware émule le lecteur de carte. Étant donné que la seule chose que le maître lit jamais est une séquence de registres, l'autre partie du micrologiciel communique complètement de manière asynchrone avec le lecteur de carte pour en obtenir des informations et les contrôler. Cela signifie également que les lignes de réinitialisation et d'IRQ sont également séparées.

Si c'est bien fait, cela doit fonctionner, car il n'y a pas de tricherie. Le lecteur de carte voit un contrôleur lui envoyer des commandes et lire exactement comment il était destiné à être utilisé. Cela comprend la réponse aux événements IRQ.

Le maître pense qu'il parle directement à un vrai lecteur de carte parce que vous émulez toutes ses opérations comme la vraie chose, y compris le comportement de réinitialisation et d'IRQ.

Cela peut sembler plus de travail que certains brouillages rapides et sales d'un octet différent sur le piratage du bus, mais comme vous l'avez constaté, ce n'est pas si rapide et peut toujours avoir des problèmes de synchronisation. Avec une émulation complète, toutes les contraintes de synchronisation sont levées. Si votre émulation n'a pas encore rattrapé quelque chose que le lecteur de cartes a fait, alors elle agit pour le maître comme si elle ne s'était pas encore produite. Vous prétendez que rien de nouveau ne s'est produit jusqu'à ce que votre émulation soit prête à répondre à l'événement sous tous ses aspects.

Cela signifie que vous avez vraiment deux parties asynchrones du firmware: l'émulation IIC du lecteur présenté au maître et un pilote de lecteur de carte complet qui vous permet de garder tout son état en direct dans votre mémoire interne.

Puisque vous ne trichez pas, cela doit fonctionner s'il est bien fait. Le seul problème au niveau du système est qu'il y aura un certain retard dans la vue principale et les actions du lecteur de cartes par rapport au système existant. Cela ne sonne pas comme un gros problème pour un "lecteur de carte", et compte tenu de ce retard serait probablement de 10 secondes de millisecondes au pire. Cela ne devrait certainement pas être perceptible à l'échelle du temps humain.

Notez que la communication entre votre émulateur et le lecteur de carte n'est pas limitée aux 100 kbits / s actuellement utilisés. Vous devez l'exécuter aussi vite que le lecteur de carte et votre matériel le permettent. Après tout, sur ce lien, vous serez le maître, vous possédez donc l'horloge. Encore une fois, avec une architecture de micrologiciel appropriée et des tâches asynchrones, cela ne devrait pas avoir d'importance. En fait, votre pilote communiquera probablement plus souvent et obtiendra plus de données du lecteur de cartes que le maître n'en obtient de votre émulateur.

Olin Lathrop
la source
Merci d'avoir répondu. J'avais exactement quelques-uns à l'esprit lorsque j'ai déclaré pour la première fois que je regardais cela. J'ai rapidement abandonné l'idée car cela semble assez compliqué. Si le MCU écrivait et lisait seulement les registres, ce serait facile mais le lecteur communique avec une RFID qui a son propre protocole (commandes et réponses multi-octets). En plus de cela, le MCU met en place quelques drapeaux pour l'IRQ dans le lecteur et relit les statues. Il semblait donc qu'il serait beaucoup plus facile de ne cibler que quelques octets et de laisser le reste au lecteur.
Alexxx
De plus, si je divise le bus entier en 2 bus, je peux en effet parler au lecteur de carte à des vitesses plus rapides. Cependant, avec la dernière conception où j'ai coupé la ligne SDA uniquement, je dois m'en tenir au timing fourni par le MCU sur la ligne SCL qui est de 100KHz.
Alexxx
0

Je dirais que vous êtes sur la bonne voie avec un Arduino Nano comme MITM, bien que je pense que ce serait mieux avec deux.

entrez la description de l'image ici

Le NXP-PN512 fonctionnera à une vitesse d'horloge de 3,4 MHz, je suggère donc que vous puissiez utiliser quelque chose de l'ordre de 1,5 à 2 MHz pour le MCU de droite qui parle au Reader.
Étant donné que le MCU de gauche est réglé sur 100 kHz, une fois que vous avez reconnu tous les octets de transaction (adresse / registre-WR), vous pouvez le copier sur un bus parallèle 8 bits (ou même plus large) entre les MCU et envoyer les commandes au lecteur dans moins d'une heure d'horloge sur le canal I2C à vitesse lente. La réception égale d'un octet du lecteur est réalisée en moins d'une heure d'horloge sur le bus lent, ce qui donne le temps nécessaire pour configurer l'octet de réponse.

Je suppose ici que vous devrez peut-être traduire plusieurs octets en tant qu'identifiant NFC et pas seulement une conversion d'octet par octet (ce qui nécessite moins de temps).

Le problème majeur que je verrais alors est que si vous avez besoin de sérialiser plusieurs octets vers / depuis le PC pour mapper vos modifications, le timing devient encore plus critique. S'il y avait un moyen de construire votre algorithme / table de changement de mappage dans le MCU de gauche, cela semblerait une meilleure approche, bien que la résolution d'un mappage d'identifiants multi-bye soit toujours le plus grand défi.

Si je me trompe et que vous avez juste besoin de mapper, disons un seul octet d'identification de carte, cela pourrait fonctionner.

Lors de vos premiers tests avec l'Arduino, avez-vous vérifié que toutes les interruptions étaient désactivées (au moins seulement TWI utilisé)? Si vous ne l'avez pas fait, cela pourrait avoir gâché votre timing.

Jack Creasey
la source
1
Je ne vois pas pourquoi deux micros séparés sont nécessaires. Beaucoup de micros peuvent gérer deux bus IIC simultanément. Vous n'avez vraiment besoin que de matériel pour être l'esclave, bien que l'utilisation du matériel puisse être pratique même lorsque vous êtes le maître. La communication entre deux micros semble inutilement complexe et lente, par rapport à deux tâches exécutées dans le même micro. Je ne vois pas le problème que deux micros résolvent.
Olin Lathrop du
@Olin Lathrop. Il simplifie le développement logiciel. rend le débogage beaucoup plus simple, etc. Je n'ai absolument aucun problème à utiliser plusieurs MCU où le coût est principalement inférieur à celui des puces logiques à fonction unique et la fonctionnalité est plus facile à définir et à développer. Dans ce cas, il n'y a qu'un seul vecteur d'interruption TWI dans l'ATMega328, donc prendre en charge deux canaux I2C est plus difficile. ..Mais c'est certainement un choix personnel.
Jack Creasey
Dans ce cas, plusieurs processeurs ajoutent de la complexité et introduisent un besoin de communication supplémentaire. Vous n'avez pas besoin d'utiliser d'interruptions ou de matériel du tout pour IIC lorsque vous êtes le maître du bus. Cependant, il existe de nombreux processeurs qui peuvent gérer deux bus IIC indépendamment dans le matériel. Si l'ATMega ne le peut pas et que vous souhaitez utiliser deux IIC matériels, n'utilisez pas d'ATMega.
Olin Lathrop du
@Olin Lathrop. Disons que l'on n'est pas d'accord. Le dénigrement de bits IMO au-dessus d'une centaine de kHz n'est pas un démarreur. Le problème pour l'OP est que le coût de sérialisation des données à envoyer à un PC pour faire l'algorithme de mappage est lourd de problèmes de synchronisation.
Jack Creasey
Merci pour la réponse et les commentaires. ATMega328 / Arduino ne peut pas être utilisé du côté MCU en raison du timing du MCU I2C. Ce MCU est capable de générer une séquence de démarrage plus rapide que 4.7us après un arrêt précédent. Regardez le tableau 32-10 dans les fiches techniques ATMega328 (paramètre tBUF). Ce qui se passait, c'est que Arduino était en train de NACK toutes les lectures i2c qui ont suivi une écriture i2c. C'est apparemment un problème connu. J'ai trouvé des informations à ce sujet quelque part en ligne après avoir tiré tous mes cheveux dessus. C'est pourquoi je suis passé au CPLD.
Alexxx