MITM trên xe buýt I2C


9

Tôi đã cố gắng thiết kế một mô-đun cho phép tôi sửa đổi các phản hồi nô lệ được chọn trên xe buýt I2C. Đây là cấu hình bus gốc (kết nối pull-up và power không được hiển thị cho rõ ràng:

nhập mô tả hình ảnh ở đây Chỉ có 2 thiết bị trên xe buýt này và nó chỉ có 100kHz. Bộ điều khiển MCU (I2C master) và đầu đọc thẻ RFID (nô lệ I2C) NXP PN512. Tôi không thể sửa đổi phần sụn của bộ điều khiển hoặc thay đổi các giao dịch bus I2C. Phần tốt là Bộ điều khiển chỉ gửi 2 loại giao dịch:

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

Những gì tôi muốn làm là thay thế các byte dữ liệu được chọn trong quá trình đăng ký Master được đọc bằng các byte của riêng tôi. Tôi có thể gửi số đăng ký mà MCU muốn đọc cho PC của tôi qua UART (921.6kbaud). Tôi có thể xử lý chúng trong C / C ++ hoặc Python ở đó. Khi tôi nhận được số đăng ký có giá trị cần thay thế, tôi có thể gửi lại byte giả cho thiết bị của mình và sẽ gửi lại cho bộ điều khiển thay thế phản hồi thẻ gốc.

Lúc đầu, tôi chia xe buýt I2C thành hai xe buýt: nhập mô tả hình ảnh ở đây

Tôi đã thử Arduino Nano và sau đó là CPLD bằng cách kéo dài đồng hồ. Phần cứng I2C của ATmega328 đối mặt với bộ điều khiển MCU không thể theo kịp vì đôi khi trình tự bắt đầu được tạo ra sớm hơn 5us sau chu kỳ dừng trước đó. Vì vậy, cứ thỉnh thoảng thì AVR lại là một giao dịch đọc. CPLD có thể xử lý tốc độ dừng / khởi động, hóa ra việc kéo dài xe buýt đã bị vô hiệu hóa trong MCU.

Tôi đã nảy ra một ý tưởng rằng tôi có thể "dự đoán" thanh ghi chính được đọc bằng cách phát hiện một byte ghi đơn vì tôi chắc chắn rằng nó được theo sau bởi một lần đọc. Có vẻ như tôi đã có đủ thời gian trong quá trình ghi địa chỉ chu trình đọc sau đây để mang byte từ nô lệ. Điều đó đã không hoàn toàn làm việc. Các giao dịch xe buýt ban đầu có vẻ ổn (khoảng 5 giây đầu tiên) nhưng sau đó bộ điều khiển đã ngừng tất cả các thông tin liên lạc trên xe buýt như thể nó phát hiện ra rằng nó không trực tiếp nói chuyện với thẻ đọc.

Đầu đọc thẻ cũng có thể tạo ra các ngắt cho chủ. IRQ là một bộ đếm thời gian hoặc sự kiện dựa trên. Tôi gán cho vấn đề về sự chậm trễ mà tôi đã giới thiệu trên xe buýt. Tôi có thể đã sai nhưng tôi đã đưa ra một thiết kế "không trễ" khác. nhập mô tả hình ảnh ở đây

Ý tưởng là tôi chỉ có thể phá vỡ dòng SDA và để dòng SCL được kết nối giữa chủ và nô lệ. Bằng cách này, tôi vẫn có thể thay thế các byte trên dòng dữ liệu theo một trong hai hướng. Thiết kế tỏ ra phức tạp hơn khi tôi phải điều khiển hướng đường SDA dựa trên chu kỳ xe buýt. Dưới đây là mã VHDL xử lý các giao dịch xe buýt và gửi các byte hex qua UART đến máy tính. Nhận byte từ máy tính chưa được thực hiện:

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;

Dưới đây là các chuyển đổi xe buýt được chụp bằng CPLD kiểm soát đường SDA.

Đăng ký viết:

nhập mô tả hình ảnh ở đây

Đăng ký đọc:

nhập mô tả hình ảnh ở đây

Bạn có thể thấy một vài trục trặc khi hướng xe buýt thay đổi. Điều đó gây ra bởi sự khác biệt về thời gian giữa CPLD thay đổi hướng xe buýt và đầu đọc thẻ tạo ra ACK. Mức ACK dường như ổn định trên cạnh tăng của SCL. Theo như tôi biết đó là tất cả những gì bạn cần.

Với điều này, bộ điều khiển hoạt động theo cách tương tự như với các xe buýt phân chia đình chỉ bất kỳ hoạt động xe buýt nào trong vòng vài giây. Tôi cũng kiểm tra rằng Arduino chế tạo MCU đó và tạo ra lưu lượng xe buýt cho tôi và có vẻ như Arduino cũng đóng băng mọi lúc mọi nơi. Vì vậy, tôi đoán rằng tôi có thể có một số loại vấn đề với máy trạng thái VHDL trong đó trong một số điều kiện tôi bị kẹt trong một trạng thái không có lối thoát. Có ý kiến ​​gì không?


Dù sao, câu hỏi của bạn không rõ ràng lắm. Đầu tiên bạn nói There's only 2 devices on this bus running at 100kHzvà sau đó The hardware I2C was a slave and a bit banged I2C was a master on the card reader bus at 1Mbps. Tại sao có hai xe buýt? Tại sao cần xe buýt tốc độ cao? Cung cấp một bản phác thảo thiết kế ban đầu của bạn và cố gắng làm rõ câu hỏi của bạn.
TisteAndii

Ừ, xin lỗi. Bus gốc chỉ có bộ điều khiển (i2c master) và đầu đọc thẻ / thẻ RFID (nô lệ i2c). Do đó, tôi không thực sự phải lo lắng về việc đánh địa chỉ I2C vì nó là điểm tới điểm (mọi gói được gửi bởi chủ đều dành cho một nô lệ này). Cách tiếp cận đầu tiên của tôi là chia xe buýt thành 2 xe buýt và hoạt động như một nô lệ i2c ở phía bộ điều khiển và một bậc thầy ở phía đầu đọc RFID.
Alexxx

Đầu đọc RIFD có khả năng tốc độ nhanh hơn (1 MHz hoặc thậm chí nhanh hơn) vì vậy tôi nghĩ tôi có thể sử dụng nó để tôi không giữ xe buýt (kéo dài xe buýt) ở phía bộ điều khiển quá lâu trong khi tôi đọc dữ liệu từ đầu đọc RFID Đăng ký. Ngoài ra, không có bus kéo dài khi tôi phát hiện một byte ghi đơn, tôi chỉ có ít thời gian trong chu kỳ đọc tiếp theo để đọc byte từ đầu đọc RIFD và gửi lại cho bộ điều khiển.
Alexxx

Bằng cách kéo xe buýt, ý tôi là đồng hồ I2C kéo dài trong đó nô lệ giữ dòng SCL ở mức thấp để cho chủ nhân biết rằng nó chưa sẵn sàng với dữ liệu. Khi nô lệ sẵn sàng, nó giải phóng dòng SCL và chủ tiếp tục đọc các bit được gửi bởi nô lệ.
Alexxx

1
Thay vào đó là tốt nhất nếu bạn chỉnh sửa câu hỏi của bạn. Bạn vẫn chưa giải thích được tại sao cần 2 xe buýt. Nếu tất cả những gì bạn cần là đọc dữ liệu từ đầu đọc thẻ sử dụng I2C thì tại sao không kết nối chúng trên cùng một xe buýt và MCU của bạn đọc từ đó? Đồng hồ kéo dài chỉ có ý nghĩa về phía nô lệ, thường là khi nó chậm phản ứng với chủ. Không có gì bạn có thể làm về nó nếu nô lệ chưa sẵn sàng. 100-400kHz thường là đủ cho hầu hết các ứng dụng; lý do duy nhất bạn có thể muốn tốc độ nhanh hơn nếu bạn phải thực hiện một số thao tác nhạy cảm với thời gian trên dữ liệu bạn đã đọc hoặc tương tự.
TisteAndii

Câu trả lời:


6

Tôi nghĩ rằng việc cố gắng hack cutsey như bạn đã được yêu cầu rắc rối, với chính xác các loại triệu chứng bạn đang gặp phải. Về cơ bản, bạn đang cố gắng gian lận và hy vọng bạn không bị bắt.

Một điều bạn chưa từng thử, theo mô tả của bạn, là sự mô phỏng đầy đủ về thứ đầu đọc thẻ này. Bạn chưa thực sự giải thích chính xác những gì nó làm và mức độ phức tạp của nó, nhưng đánh giá từ những gì chủ nhân đang gửi nó không quá phức tạp.

Sử dụng một vi điều khiển với khả năng nô lệ IIC phần cứng. Đó là kết nối với chủ. Phần sụn mô phỏng đầu đọc thẻ. Vì thứ duy nhất mà chủ nhân từng đọc là một chuỗi các thanh ghi, phần khác của phần sụn giao tiếp hoàn toàn không đồng bộ với đầu đọc thẻ để lấy thông tin từ nó và để điều khiển nó. Điều này cũng có nghĩa là các dòng thiết lập lại và IRQ cũng tách biệt.

Nếu được thực hiện đúng, điều này phải làm việc, vì không có gian lận đang diễn ra. Đầu đọc thẻ nhìn thấy một bộ điều khiển gửi lệnh cho nó và thực hiện đọc chính xác cách nó được sử dụng. Điều này bao gồm trả lời các sự kiện IRQ.

Bậc thầy nghĩ rằng nó đang nói chuyện trực tiếp với một đầu đọc thẻ thực bởi vì bạn mô phỏng tất cả các hoạt động của nó giống như thật, bao gồm cả thiết lập lại và hành vi IRQ.

Điều này nghe có vẻ như công việc nhiều hơn một số cách nhanh chóng và bẩn gây nhiễu một byte khác nhau trên vụ hack xe buýt, nhưng như bạn thấy điều đó không nhanh chóng và có thể luôn gặp một số vấn đề về thời gian. Với một mô phỏng đầy đủ, tất cả các hạn chế thời gian được dỡ bỏ. Nếu phần mô phỏng của bạn chưa bắt kịp với thứ gì đó mà đầu đọc thẻ đã thực hiện, thì nó sẽ hoạt động với chủ như chưa xảy ra. Về cơ bản, bạn giả vờ không có gì mới xảy ra cho đến khi thi đua của bạn sẵn sàng đáp ứng sự kiện về mọi mặt.

Điều này có nghĩa là bạn thực sự có hai phần không đồng bộ của chương trình cơ sở: Trình mô phỏng IIC của trình đọc được trình bày cho chủ và trình điều khiển đầu đọc thẻ đầy đủ cho phép bạn giữ tất cả trạng thái của nó sống trong bộ nhớ trong của bạn.

Vì bạn không gian lận, điều này phải hoạt động nếu được thực hiện đúng. Vấn đề duy nhất ở cấp hệ thống là sẽ có một số độ trễ trong việc nhìn thấy chính và gây ra các hành động đọc thẻ so với hệ thống hiện có. Điều này không có vẻ là một vấn đề lớn đối với một "đầu đọc thẻ" và xem xét sự chậm trễ này có thể sẽ là 10 giây trong một giây tồi tệ nhất. Nó chắc chắn không nên được chú ý trên thang thời gian của con người.

Lưu ý rằng giao tiếp giữa trình giả lập của bạn và đầu đọc thẻ không bị giới hạn ở 100 kbits / s hiện đang được sử dụng. Bạn nên chạy nó nhanh như đầu đọc thẻ và phần cứng của bạn cho phép. Rốt cuộc, trên liên kết đó, bạn sẽ là chủ nhân, vì vậy bạn sở hữu đồng hồ. Một lần nữa, với kiến ​​trúc phần sụn phù hợp và các tác vụ không đồng bộ, điều này không thành vấn đề. Trên thực tế, trình điều khiển của bạn có thể sẽ liên lạc thường xuyên hơn và nhận được nhiều dữ liệu từ đầu đọc thẻ hơn so với trình điều khiển chính từ trình giả lập của bạn.


Cảm ơn câu trả lời. Tôi chính xác có một số trong tâm trí khi tôi lần đầu tiên nhìn vào đó. Tôi nhanh chóng từ bỏ ý tưởng vì điều đó dường như khá phức tạp. Nếu MCU chỉ viết và đọc các thanh ghi thì sẽ dễ dàng nhưng đầu đọc giao tiếp với một RFID có giao thức riêng (các lệnh và phản hồi nhiều byte). Trên hết, MCU đang thiết lập một vài lá cờ cho IRQ trong đầu đọc và đọc lại các bức tượng. Do đó, có vẻ như sẽ dễ dàng hơn nhiều khi chỉ nhắm mục tiêu một vài byte và để phần còn lại cho người đọc.
Alexxx

Ngoài ra, nếu tôi chia toàn bộ xe buýt thành 2 xe buýt, tôi thực sự có thể nói chuyện với đầu đọc thẻ với tốc độ nhanh hơn. Tuy nhiên, với thiết kế mới nhất mà tôi cắt đường SDA, tôi chỉ phải tuân theo thời gian do MCU cung cấp trên đường SCL là 100KHz.
Alexxx

0

Tôi muốn đề nghị bạn đi đúng hướng với Arduino Nano là MITM, mặc dù tôi nghĩ rằng nó sẽ tốt nhất với hai.

nhập mô tả hình ảnh ở đây

NXP-PN512 sẽ chạy ở tốc độ xung nhịp 3,4 Mhz, vì vậy tôi khuyên bạn nên sử dụng thứ gì đó ở mức 1,5 - 2 MHz cho MCU bên tay phải nói chuyện với Reader.
Vì MCU bên tay trái được đặt ở 100 kHz, khi bạn đã nhận ra bất kỳ byte giao dịch nào (địa chỉ / thanh ghi-WR), bạn có thể sao chép nó qua một bus song song 8 bit (hoặc thậm chí rộng hơn) giữa MCU và gửi lệnh đến đầu đọc ít hơn một giờ đồng hồ trên kênh I2C tốc độ chậm. Việc nhận một byte bằng nhau từ đầu đọc đạt được trong thời gian ngắn hơn một giờ trên xe buýt chậm để có đủ thời gian để thiết lập byte trả lời.

Tôi giả sử ở đây rằng bạn thực sự có thể cần dịch nhiều byte dưới dạng ID NFC chứ không chỉ là một byte theo chuyển đổi byte (đòi hỏi ít thời gian hơn).

Vấn đề chính mà tôi thấy sau đó là nếu bạn cần tuần tự hóa nhiều byte đến / từ PC để ánh xạ các thay đổi của mình, thời gian càng trở nên quan trọng hơn. Nếu có một cách để xây dựng thuật toán / bảng thay đổi ánh xạ của bạn vào MCU bên tay trái có vẻ là một cách tiếp cận tốt hơn, mặc dù việc giải quyết ánh xạ định danh nhiều người vẫn là thách thức lớn nhất.

Nếu tôi sai và bạn chỉ cần ánh xạ một byte định danh thẻ duy nhất, thì điều này có thể hoạt động.

Trong thử nghiệm đầu tiên với Arduino, bạn có đảm bảo rằng tất cả các ngắt đã bị tắt (ít nhất là chỉ sử dụng TWI)? Nếu bạn không thì điều này có thể đã gây rối với thời gian của bạn.


1
Tôi không thấy lý do tại sao hai micros riêng biệt là cần thiết. Rất nhiều micros có thể xử lý hai bus IIC cùng một lúc. Bạn thực sự chỉ cần phần cứng để làm nô lệ, mặc dù sử dụng phần cứng có thể thuận tiện ngay cả khi là chủ. Giao tiếp giữa hai micros có vẻ phức tạp và chậm một cách không cần thiết, so với hai tác vụ chạy trong cùng một micro. Tôi không thấy vấn đề mà hai micros giải quyết.
Olin Lathrop

@Olin Máy tiện. Nó đơn giản hóa việc phát triển phần mềm. làm cho việc gỡ lỗi đơn giản hơn nhiều, v.v ... Giống như tại sao ô tô có 100 bộ vi xử lý trong đó thay vì một (đơn giản hơn như bạn có thể đề xuất) bộ xử lý đa xử lý lớn. Tôi hoàn toàn không gặp vấn đề gì khi sử dụng nhiều MCU trong đó chi phí chủ yếu thấp hơn so với các chip logic chức năng đơn và chức năng dễ xác định và phát triển hơn. Trong trường hợp này, chỉ có một vectơ ngắt TWI trong ATMega328, vì vậy để hỗ trợ hai kênh I2C thì khó hơn. .. Nhưng đó chắc chắn là một lựa chọn cá nhân.
Jack Creasey

Trong trường hợp này, nhiều bộ xử lý thêm phức tạp và đưa ra nhu cầu giao tiếp thêm. Bạn không cần phải sử dụng ngắt hoặc phần cứng cho IIC khi bạn là chủ xe buýt. Tuy nhiên, có rất nhiều bộ xử lý có thể xử lý hai bus IIC độc lập trong phần cứng. Nếu ATMega không thể và bạn muốn sử dụng hai IIC phần cứng, thì đừng sử dụng ATMega.
Olin Lathrop

@Olin Máy tiện. Hãy đồng ý không đồng ý. Bit IMO bashing trên một trăm kHz là không bắt đầu. Vấn đề của OP là chi phí xê-ri hóa dữ liệu để gửi đến PC để thực hiện thuật toán ánh xạ có nhiều vấn đề về thời gian.
Jack Creasey

Cảm ơn câu trả lời và ý kiến. ATMega328 / Arduino không thể được sử dụng ở phía MCU do thời gian MCU I2C. MCU này có khả năng tạo ra chuỗi bắt đầu nhanh hơn 4,7us sau lần dừng trước. Nhìn vào bảng 32-10 trong bảng dữ liệu ATMega328 (tham số tBUF). Điều đang xảy ra là Arduino đã NACK tất cả các lần đọc i2c sau khi viết i2c. Đó rõ ràng là một vấn đề được biết đến. Tôi tìm thấy thông tin về điều đó ở đâu đó trên mạng sau khi tôi nhổ hết tóc. Đây là lý do tại sao tôi chuyển sang CPLD.
Alexxx
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.