MITM di I2C Bus

9

Saya telah mencoba mendesain modul yang akan memungkinkan saya untuk memodifikasi respons budak yang dipilih pada bus I2C. Berikut ini konfigurasi bus asli (pull-up dan koneksi daya tidak diperlihatkan dengan jelas:

masukkan deskripsi gambar di sini Hanya ada 2 perangkat di bus ini dan hanya 100kHz. MCU pengontrol (master I2C) dan pembaca kartu RFID (budak I2C) NXP PN512. Saya tidak dapat memodifikasi firmware pengontrol atau mengubah transaksi bus I2C. Bagian baiknya adalah Controller hanya mengirim 2 jenis transaksi:

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

Apa yang ingin saya lakukan adalah mengganti byte data yang dipilih selama register Master dibaca dengan byte saya sendiri. Saya dapat mengirim nomor register yang ingin dibaca oleh MCU ke PC saya melalui UART (921.6kbaud). Saya dapat memprosesnya dalam C / C ++ atau Python di sana. Ketika saya menerima nomor register yang nilainya perlu diganti, saya dapat mengirim byte palsu kembali ke perangkat saya dan akan mengirimkannya kembali ke controller menggantikan respons kartu asli.

Pada awalnya saya membagi bus I2C menjadi dua bus: masukkan deskripsi gambar di sini

Saya mencoba Arduino Nano dan kemudian CPLD menggunakan peregangan jam. Perangkat keras ATmega328 I2C yang menghadap ke pengontrol MCU tidak dapat mengikuti karena kadang-kadang urutan mulai dihasilkan lebih cepat dari 5us setelah siklus berhenti sebelumnya. Jadi, kadang-kadang AVR adalah NAK'ing transaksi baca. CPLD bisa menangani kecepatan stop / start ternyata peregangan bus dinonaktifkan di MCU.

Saya datang dengan ide bahwa saya dapat "memprediksi" register Master membaca dengan mendeteksi satu byte tulis karena saya yakin itu diikuti oleh membaca. Tampaknya saya punya cukup waktu selama menulis alamat siklus baca berikut untuk membawa byte dari slave. Itu tidak berhasil. Transaksi bus tampaknya baik-baik saja pada awalnya (sekitar 5 detik pertama) tetapi kemudian controller menghentikan semua komunikasi di bus seolah-olah mendeteksi bahwa itu tidak langsung berbicara dengan tag membaca.

Pembaca kartu juga dapat menghasilkan interupsi ke master. IRQ berbasis waktu atau peristiwa. Saya menghubungkan masalah ini dengan keterlambatan yang saya perkenalkan di bus. Saya mungkin salah tetapi saya datang dengan desain "zero-delay" yang lain. masukkan deskripsi gambar di sini

Idenya adalah bahwa saya hanya dapat mematahkan garis SDA dan membiarkan garis SCL terhubung antara master dan slave. Dengan cara ini saya masih bisa mengganti byte pada jalur data di kedua arah. Desainnya terbukti lebih rumit karena saya harus mengendalikan arah jalur SDA berdasarkan siklus bus. Berikut adalah kode VHDL yang menangani transaksi bus dan mengirim hex byte melalui UART ke komputer. Menerima byte dari komputer belum diterapkan:

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 bawah ini adalah transit bus yang ditangkap dengan CPLD yang mengendalikan jalur SDA.

Daftar tulis:

masukkan deskripsi gambar di sini

Daftar baca:

masukkan deskripsi gambar di sini

Anda dapat melihat beberapa gangguan saat perubahan arah bus. Itu disebabkan oleh perbedaan waktu antara CPLD yang mengubah arah bus dan pembaca kartu yang menghasilkan ACK. Level ACK tampaknya stabil di sisi kenaikan SCL. Sejauh yang saya tahu hanya itu yang Anda butuhkan.

Dengan hal ini pada tempatnya, pengontrol berperilaku sama seperti dengan bus-bus yang membekukan aktivitas bus dalam beberapa detik. Saya juga menguji Arduino yang mengejek MCU itu dan menghasilkan lalu lintas bus untuk saya dan sepertinya Arduino juga membeku setiap saat. Jadi saya kira saya mungkin memiliki semacam masalah dengan mesin negara VHDL di mana dalam beberapa kondisi saya terjebak dalam satu negara tanpa jalan keluar. Ada ide?

Alexxx
sumber
Pertanyaan Anda tidak terlalu jelas, bagi saya. Pertama yang Anda katakan There's only 2 devices on this bus running at 100kHzdan kemudian The hardware I2C was a slave and a bit banged I2C was a master on the card reader bus at 1Mbps. Kenapa ada dua bus? Mengapa perlu bus kecepatan tinggi? Berikan sketsa desain awal Anda dan coba klarifikasi pertanyaan Anda.
SoreDakeNoKoto
Ya maaf Bus asli hanya memiliki pengontrol (master i2c) dan pembaca kartu / tag RFID (i2c slave). Oleh karena itu saya tidak perlu khawatir tentang pengalamatan I2C karena itu point-to-point (setiap paket yang dikirim oleh master adalah untuk slave yang satu ini). Pendekatan pertama saya adalah membagi bus menjadi 2 bus dan bertindak sebagai budak i2c di sisi pengontrol dan master di sisi pembaca RFID.
Alexxx
Pembaca RIFD mampu kecepatan lebih cepat (1MHz atau bahkan lebih cepat) jadi saya pikir saya dapat menggunakannya karena saya tidak memegang bus (peregangan bus) pada sisi pengontrol terlalu lama saat saya membaca data dari pembaca RFID daftar. Juga, tanpa peregangan bus ketika saya mendeteksi satu byte tulis saya hanya punya sedikit waktu selama siklus baca berikutnya untuk membaca byte dari pembaca RIFD dan mengirimkannya kembali ke controller.
Alexxx
Dengan bus streching yang saya maksud adalah jam I2C yang membentang di mana budak memegang garis SCL rendah untuk membiarkan master tahu bahwa itu belum siap dengan data. Ketika slave siap, ia melepaskan garis SCL dan master terus membaca bit yang dikirim oleh slave.
Alexxx
1
Lebih baik jika Anda mengedit pertanyaan Anda sebagai gantinya. Anda masih belum menjelaskan mengapa 2 bus diperlukan. Jika yang Anda butuhkan adalah membaca data dari pembaca kartu yang menggunakan I2C lalu mengapa tidak menghubungkannya di bus yang sama dan minta MCU Anda membacanya? Peregangan jam hanya masuk akal di sisi budak, biasanya ketika lambat untuk merespons master. Tidak ada yang bisa Anda lakukan jika budak belum siap. 100-400kHz biasanya cukup untuk sebagian besar aplikasi; satu-satunya alasan Anda mungkin menginginkan kecepatan lebih tinggi jika Anda harus melakukan operasi yang sensitif terhadap waktu pada data yang telah Anda baca atau yang serupa.
SoreDakeNoKoto

Jawaban:

6

Saya pikir mencoba hacks cutsey seperti Anda telah meminta masalah, dengan persis gejala yang Anda hadapi. Anda pada dasarnya mencoba menipu dan berharap Anda tidak ketahuan.

Satu hal yang belum Anda coba, menurut uraian Anda, adalah emulasi penuh dari pembaca kartu ini. Anda belum benar-benar menjelaskan apa sebenarnya yang dilakukan dan seberapa rumitnya, tetapi menilai dari apa yang dikirim oleh tuannya tidaklah begitu rumit.

Gunakan mikrokontroler dengan kemampuan budak IIC perangkat keras. Itu terhubung ke master. Firmware mengemulasi pembaca kartu. Karena satu-satunya hal yang pernah dibaca oleh master adalah urutan register, bagian lain dari firmware berkomunikasi sepenuhnya secara tidak sinkron dengan pembaca kartu untuk mendapatkan informasi darinya dan untuk mengendalikannya. Ini juga berarti bahwa garis reset dan IRQ terpisah juga.

Jika dilakukan dengan benar, ini harus berhasil, karena tidak ada kecurangan yang terjadi. Pembaca kartu melihat controller mengirimnya perintah dan melakukan membaca persis bagaimana itu dimaksudkan untuk digunakan. Ini termasuk menanggapi acara IRQ.

Master berpikir itu berbicara langsung ke pembaca kartu nyata karena Anda meniru semua operasinya persis seperti yang asli, termasuk pengaturan ulang dan perilaku IRQ.

Ini mungkin terdengar seperti lebih banyak pekerjaan daripada beberapa jam yang cepat dan kotor memasukkan byte yang berbeda ke peretasan bus, tetapi ketika Anda menemukan itu tidak begitu cepat, dan mungkin selalu memiliki beberapa masalah waktu. Dengan emulasi penuh, semua batasan waktu diangkat. Jika emulasi Anda belum menangkap sesuatu yang telah dilakukan pembaca kartu, maka itu bertindak untuk master seperti itu belum terjadi. Anda pada dasarnya berpura-pura tidak ada yang baru terjadi sampai emulasi Anda siap merespons acara dalam semua aspek.

Ini berarti Anda benar-benar memiliki dua bagian asinkron dari firmware: Emulasi IIC dari pembaca yang disajikan kepada master, dan driver pembaca kartu lengkap yang memungkinkan Anda untuk mempertahankan semua statusnya dalam memori internal Anda.

Karena Anda tidak curang, ini harus berhasil jika dilakukan dengan benar. Satu-satunya masalah tingkat sistem adalah bahwa akan ada beberapa keterlambatan dalam melihat master dan menyebabkan tindakan pembaca kartu daripada sistem yang ada. Ini kedengarannya bukan masalah besar bagi "pembaca kartu", dan mengingat keterlambatan ini kemungkinan akan 10 milidetik paling buruk. Itu tentu tidak boleh terlihat pada skala waktu manusia.

Perhatikan bahwa komunikasi antara emulator dan pembaca kartu Anda tidak terbatas pada 100 kbits / detik yang saat ini digunakan. Anda harus menjalankannya secepat pembaca kartu dan perangkat keras Anda memungkinkan. Lagi pula, pada tautan itu Anda akan menjadi master, sehingga Anda memiliki jam. Sekali lagi, dengan arsitektur firmware yang tepat dan tugas yang tidak sinkron, ini seharusnya tidak menjadi masalah. Bahkan, driver Anda mungkin akan berkomunikasi lebih sering dan mendapatkan lebih banyak data dari pembaca kartu daripada master dapatkan dari emulator Anda.

Olin Lathrop
sumber
Terima kasih atas jawabannya. Saya benar-benar memiliki beberapa dalam pikiran ketika saya pertama kali menyatakan melihat itu. Saya cepat-cepat meninggalkan ide itu karena tampaknya cukup rumit. Jika MCU hanya menulis dan membaca register itu akan mudah tetapi pembaca berkomunikasi dengan RFID yang memiliki protokol sendiri (perintah dan tanggapan multi-byte). Selain itu MCU sedang menyiapkan beberapa bendera untuk IRQ di pembaca dan membaca kembali patung-patung. Oleh karena itu sepertinya akan jauh lebih mudah untuk hanya menargetkan beberapa byte dan menyerahkan sisanya kepada pembaca.
Alexxx
Juga, jika saya membagi seluruh bus menjadi 2 bus saya memang dapat berbicara dengan pembaca kartu dengan kecepatan lebih cepat. Namun dengan desain terbaru di mana saya memotong garis SDA hanya saya harus tetap pada waktu yang disediakan oleh MCU pada jalur SCL yang 100KHz.
Alexxx
0

Saya sarankan Anda berada di jalur yang benar dengan Arduino Nano sebagai MITM, meskipun saya pikir akan lebih baik dengan dua.

masukkan deskripsi gambar di sini

NXP-PN512 akan berjalan pada kecepatan clock 3,4 Mhz, jadi saya sarankan Anda dapat menggunakan sesuatu dengan urutan 1,5 - 2 MHz untuk MCU tangan kanan berbicara dengan Reader.
Karena tangan kiri MCU diatur pada 100 kHz, setelah Anda mengenali byte transaksi (address / register-WR) Anda dapat menyalinnya melalui bus paralel 8bit (atau bahkan lebih lebar) antara MCU dan mengirim perintah ke pembaca di kurang dari satu jam pada saluran I2C kecepatan lambat. Sama menerima byte dari pembaca dicapai dalam waktu kurang dari satu jam di bus lambat memberikan waktu yang cukup untuk mengatur byte balasan.

Saya berasumsi di sini bahwa Anda mungkin benar-benar perlu menerjemahkan beberapa byte sebagai ID NFC dan bukan hanya konversi byte demi byte tunggal (yang membutuhkan lebih sedikit waktu).

Masalah utama yang saya lihat kemudian adalah bahwa jika Anda perlu membuat serial beberapa byte ke / dari PC untuk memetakan perubahan Anda, pengaturan waktu menjadi lebih penting. Jika ada cara untuk membangun algoritme / tabel perubahan pemetaan Anda ke MCU kiri yang tampaknya merupakan pendekatan yang lebih baik, meskipun menyelesaikan pemetaan multi-bye identifier masih merupakan tantangan terbesar.

Jika saya salah dan Anda hanya perlu memetakan mengatakan satu byte kartu pengenal, maka ini mungkin berhasil.

Dalam pengujian awal Anda dengan Arduino, apakah Anda memastikan bahwa semua interupsi dimatikan (setidaknya hanya TWI yang digunakan)? Jika Anda tidak melakukannya, ini mungkin mengacaukan waktu Anda.

Jack Creasey
sumber
1
Saya tidak melihat mengapa dua micros terpisah diperlukan. Banyak micros dapat menangani dua bus IIC secara bersamaan. Anda benar-benar hanya membutuhkan perangkat keras untuk menjadi budak, meskipun menggunakan perangkat keras bisa nyaman bahkan ketika menjadi master. Berkomunikasi antara dua mikron tampaknya tidak perlu rumit dan lambat, dibandingkan dengan dua tugas yang berjalan di mikro yang sama. Saya gagal melihat masalah yang dipecahkan dua mikron.
Olin Lathrop
@Olin Lathrop. Ini menyederhanakan pengembangan perangkat lunak. membuat debugging jauh lebih sederhana dll. Ini seperti mengapa mobil memiliki 100-an mikroprosesor di dalamnya daripada satu (lebih sederhana seperti yang Anda sarankan) prosesor multiproses yang besar. Saya sama sekali tidak punya masalah menggunakan beberapa MCU di mana biayanya sebagian besar di bawah chip logika fungsi tunggal dan fungsinya lebih mudah untuk didefinisikan dan dikembangkan. Dalam hal ini hanya ada satu interrupt vector TWI di ATMega328 sehingga untuk mendukung dua saluran I2C lebih sulit. ..Tapi itu tentu pilihan pribadi.
Jack Creasey
Dalam hal ini, banyak prosesor menambah kerumitan dan memperkenalkan kebutuhan akan komunikasi ekstra. Anda tidak perlu menggunakan interupsi, atau perangkat keras sama sekali, untuk IIC saat menjadi master bus. Namun, ada banyak prosesor yang dapat menangani dua bus IIC secara independen dalam perangkat keras. Jika ATMega tidak bisa, dan Anda ingin menggunakan dua perangkat keras IIC, maka jangan gunakan ATMega.
Olin Lathrop
@Olin Lathrop. Mari kita sepakat untuk tidak setuju. IMO bit bashing di atas seratus kHz adalah non-starter. Masalah untuk OP adalah bahwa biaya serialisasi data untuk dikirim ke PC untuk melakukan algoritma pemetaan penuh dengan masalah waktu.
Jack Creasey
Terima kasih atas jawaban dan komentarnya. ATMega328 / Arduino tidak dapat digunakan di sisi MCU karena waktu MCU I2C. MCU ini mampu menghasilkan urutan mulai lebih cepat dari 4,7 kita setelah berhenti sebelumnya. Lihat tabel 32-10 di lembar data ATMega328 (parameter tBUF). Apa yang terjadi adalah bahwa Arduino KEMBALI semua i2c membaca yang mengikuti tulisan i2c. Ini tampaknya masalah yang diketahui. Saya menemukan info tentang itu di suatu tempat online setelah saya menarik semua rambut saya di atas ini. Inilah sebabnya saya beralih ke CPLD.
Alexxx