1

对于我的爱好项目,我尝试制作一个与 MPU-6050 保持平衡的四轴飞行器。飞行控制器应该是FPGA Altera cyclone IV,因为它很有趣。我正在用 VHDL 对其进行编码。

无论如何,我被困在与 MPU-6050 的 I2C 通信上。作为基础,我使用了来自以下网址的 I2C 主 VHDL 代码:https ://www.digikey.com/eewiki/pages/viewpage.action?pageId=10125324 。

我尝试读取陀螺仪寄存器并在 8 个 LED 上打印出来,看看我是否有一些通信进来。

我尝试使用 1Hz 预分频器运行状态机中的所有 I2C 相位,并点亮一些 LED,以查看是否所有相位都已通过。情况就是这样。我已经为引脚分配了 2.5V 默认值,我使用 10k 上拉电阻。MPU6050 在 arduino 上运行完美。

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

     entity mpu6050_2 is
    port( clk_50 : in std_logic;
            areset : in std_logic;  
            i2c_SDA : INOUT  STD_LOGIC;
            i2c_SCL : INOUT  STD_LOGIC;
            leds : out std_LOGIC_VECTOR(7 downto 0)
     );
     end entity mpu6050_2;

     architecture struc of mpu6050_2 is

     component i2c_master is
     GENERIC(
     input_clk : INTEGER := 50_000_000; 
     bus_clk   : INTEGER := 400_000);   
     PORT(
      clk       : IN     STD_LOGIC;                   
      reset_n   : IN     STD_LOGIC;                   
      ena       : IN     STD_LOGIC;                   
      addr      : IN     STD_LOGIC_VECTOR(6 DOWNTO 0); 
      rw        : IN     STD_LOGIC;                    
      data_wr   : IN     STD_LOGIC_VECTOR(7 DOWNTO 0);  
      busy      : OUT    STD_LOGIC;     
      data_rd   : OUT    STD_LOGIC_VECTOR(7 DOWNTO 0);
      ack_error : BUFFER STD_LOGIC;  
      sda       : INOUT  STD_LOGIC;                    
      scl       : INOUT  STD_LOGIC);       
      end component ;

      type machine is (config1, config2, gyroH, gyroL);
      signal state  : machine:= config1; --current state

      signal SDA_int : std_LOGIC;
      signal SCL_int : std_LOGIC;
      signal i2c_ena : std_LOGIC;
      signal i2c_busy : std_LOGIC;
      signal busy_prev : std_LOGIC;
      signal i2c_rw : std_LOGIC;
      signal i2c_data_wr : STD_LOGIC_VECTOR(7 DOWNTO 0);
      signal gyro_data : std_LOGIC_VECTOR(15 downto 0);
      signal i2c_data_rd : std_LOGIC_VECTOR (7 downto 0);
      signal i2c_addr : STD_LOGIC_VECTOR(6 DOWNTO 0);


begin

process(areset, clk_50) 

    VARIABLE busy_cnt  : INTEGER := 0;  --keeps track of i2c busy signals during transaction

    begin

    if areset = '0' then
        busy_cnt := 0; 
        i2c_ena <= '0';
        state <= config1;

    elsif rising_edge(clk_50) then

        case state is

        when config1 =>
            busy_prev <= i2c_busy;
            if (busy_prev = '0' and i2c_busy = '1') then
                busy_cnt := busy_cnt + 1;
            end if;

                case busy_cnt is
                    when 0 =>
                        i2c_ena <= '1';
                        i2c_addr <= "1101000"; --MPU6050 adress
                        i2c_rw <= '0'; --write
                        i2c_data_wr <= x"6B"; -- hex6B powermanagement          
                    when 1 =>
                        i2c_rw <= '0'; --write
                        i2c_data_wr <= "00000000"; -- ON with internal clock
                    when 2 =>
                            i2c_ena <= '0';
                            if(i2c_busy = '0') then
                                busy_cnt := 0;
                                state <= config2;
                            end if;

                    when others => NULL;
                end case;       

        when config2 =>
            busy_prev <= i2c_busy;
            if (busy_prev = '0' and i2c_busy = '1') then
                busy_cnt := busy_cnt + 1;
            end if;

                case busy_cnt is
                    when 0 =>
                        i2c_ena <= '1';
                        i2c_addr <= "1101000"; --MPU6050 adress
                        i2c_rw <= '0'; --write
                        i2c_data_wr <= x"1B"; -- Gyro config            
                    when 1 =>
                        i2c_rw <= '0'; --write
                        i2c_data_wr <= "00000000"; -- 250 degree/sec, no self test
                    when 2 =>
                            i2c_ena <= '0';
                            if(i2c_busy = '0') then
                                busy_cnt := 0;
                                state <= gyroH;
                            end if;
                    when others => NULL;
                end case;               


        when gyroH =>
            busy_prev <= i2c_busy;
            if (busy_prev = '0' and i2c_busy = '1') then
                busy_cnt := busy_cnt + 1;
            end if;

                case busy_cnt is
                    when 0 =>
                        i2c_ena <= '1';
                        i2c_addr <= "1101000"; --MPU6050 adress
                        i2c_rw <= '0'; --write
                        i2c_data_wr <= x"43"; -- hex43 GYRO_OUT[15:8]           
                    when 1 =>
                        i2c_rw <= '1'; --read
                    when 2 =>
                            i2c_ena <= '0';
                        if(i2c_busy = '0') then
                            gyro_data(15 downto 8) <= i2c_data_rd;
                            busy_cnt := 0;
                            state <= gyroL;
                        end if;
                    when others => NULL;
                end case;

        when gyroL =>   
            busy_prev <= i2c_busy;
            if (busy_prev = '0' and i2c_busy = '1') then
                busy_cnt := busy_cnt + 1;
            end if;

                case busy_cnt is
                    when 0 =>
                        i2c_ena <= '1';
                        i2c_addr <= "1101000"; --MPU6050 adress
                        i2c_rw <= '0'; --write
                        i2c_data_wr <= x"44"; -- hex44 GYRO_OUT[7:0]            
                    when 1 =>
                        i2c_rw <= '1'; --read
                    when 2 =>
                            i2c_ena <= '0';
                        if(i2c_busy = '0') then
                            gyro_data(7 downto 0) <= i2c_data_rd;
                            busy_cnt := 0;
                            state <= gyroH; 
                        end if;

                    when others => NULL;
                end case;           

        end case;
    end if;

end process;

u0: i2c_master
port map(clk => clk_50, reset_n => areset, ena => i2c_ena, addr => i2c_addr, rw => i2c_rw, data_wr => i2c_data_wr, busy => i2c_busy, data_rd => i2c_data_rd
, sda => SDA_int, scl => SCL_int);

leds(7) <= gyro_data(0); --D4 
leds(6) <= gyro_data(1); -- D5 
leds(5) <= gyro_data(4); -- D6 
leds(4) <= gyro_data(7); -- D7 
leds(3) <= gyro_data(8);  -- D8 
leds(2) <= gyro_data(11); -- D9
leds(1) <= gyro_data(13); -- D10
leds(0) <= gyro_data(15); -- D11

i2c_SDA <= SDA_int;
i2c_SCL <= SCL_int;


end struc;

结果:即使我旋转 MPU6050,所有 LED 都不会改变状态。所以没有交流。谁能帮助我我做错了什么?

4

1 回答 1

1

首先:我在我的一个设计中使用了相同的组件并确认它有效。

我认为您一开始就使用了错误的 i2c 地址。

在数据表中,通常给出 i2c 地址,包括读/写位(对于 MPU-6050,这是0x68/011010000x69/01101001)。然而,所使用的 i2c 主组件希望通过将 ( &) i2c rw 位附加到给定地址(参见原始源中的第 124 行)来自行构建最终的 i2c 地址,因此您必须传递数据表中移位的地址一点。

尝试使用0x34/0110100i2c 地址进行读写。

我只是非常简要地查看了您的其余代码(因此可能还有其他罪魁祸首),但这应该足以让您继续前进。

于 2019-05-17T04:53:50.937 回答