No se obtiene el acuse de recibo del esclavo I2C MPU 9250 utilizando STM32F401RE

0

Estoy utilizando una placa de desarrollo STM32F401RE para comunicarme a través de I2C a un sensor de placa de ruptura basado en MPU9250. Hasta ahora he establecido la condición de inicio y he enviado la dirección del esclavo / bit de escritura al dispositivo, pero no recibo ningún reconocimiento. He intentado reducir la frecuencia de SCL a 50 KHz y acelerar el tiempo de subida, pero todavía nada. La dirección de esclavo que estoy enviando al dispositivo es 0x68. Soy relativamente nuevo en la programación básica, por lo que cualquier consejo sería muy apreciado.

Código del encabezado I2C:

void I2c_Init(uint8_t slaveAddr) {

  I2C1->CR1 &= ~I2C_CR1_PE;
  RCC->AHB1ENR |= (1ul << 1); //enable gpio clock
  RCC->APB1ENR |= (1ul << 21);// enable i2c clock

  GPIOB->MODER &= ~(3ul << 16);
  GPIOB->MODER |= (2ul << 16); //set pb8 to af mode 
  GPIOB->MODER &= ~(3ul << 18);
  GPIOB->MODER |= (2ul << 18); //set pb9 to af mode 

  GPIOB->AFR[1] &= ~(0xF << 0); //pin 8 i2c af 
  GPIOB->AFR[1] |= (4ul << 0);

  GPIOB->AFR[1] &= ~(0xF << 4); //pin 9 i2c af 
  GPIOB->AFR[1] |= (4ul << 4);

  GPIOB->OTYPER |= (1ul << 8); //set pb8 to open drain 
  GPIOB->OTYPER |= (1ul << 9); //set pb9 to open drain 

  GPIOB->OSPEEDR &= ~(3ul << 16);
  GPIOB->OSPEEDR |= (2ul << 16); //set pb8 to fast mode 
  GPIOB->OSPEEDR &= ~(3ul << 18);
  GPIOB->OSPEEDR |= (2ul << 18); //set pb9 to fast mode 

  GPIOB->PUPDR &= ~(3ul << 16);
  GPIOB->PUPDR &= ~(3ul << 18);

  I2C1->CR2 &= ~(0x3F << 0); //reset freqyency bits
  I2C1->CR2 = I2C_CR2_FREQ_3; //set register bits to 0x00000008 8MHz
  I2C1->CCR &= ~(1ul << 15); //set bit 15 to 0 sm mode
  I2C1->CCR &= ~(0xFFF << 0); //clear bits 0-11 for scl
  I2C1->CCR |= (0x28 << 0); // setup scl clock as 100Khz by 5000ns / PCLK 125 = 40 (0x28) /////////////50hz 20000ns/125 = 160 = 0xA0
  I2C1->TRISE &= ~(0x3F << 0); //clear bits 0 -5;
  I2C1->TRISE |=  (0x03 << 0); // set rise time to 1000/PCLK = 0x08 + 1 ////////for 300ns//////  300/125 = 0x02 + 1
  I2C1->OAR1 = (1ul << 14);
  //I2C1->OAR2 &= (1ul << 0);
  I2C1->CR1 |= I2C_CR1_PE | I2C_CR1_ACK;// | I2C_CR1_POS;

}


int write_i2c(uint8_t slaveAddr, uint8_t dat) {


  I2C1->CR1 |= I2C_CR1_START; //start bit init
  while (!(I2C1->SR1 & I2C_SR1_SB)); //wait for start confirm
  I2C1->DR = slaveAddr & ~(1ul << 7);// ~I2C_OAR1_ADD0; // send slave address and write bit
  while (!(I2C1->SR1 & I2C_SR1_ADDR))  // wait for address confirm
      if(I2C1->SR1 & I2C_SR1_AF)
          return -1; //if ack fail return 
      if(!(I2C1->SR1 & I2C_SR1_AF))  return 2;

  I2C1->SR1; //sr read
  I2C1->SR2; //sr2 read
  I2C1->DR &= ~(0xFF << 0); //clear data reg
  I2C1->DR |= (dat << 0); // send data
  while (!(I2C1->SR1 & (I2C_SR1_BTF | I2C_SR1_AF ))); //wait for data confirm

  I2C1->CR1 |= I2C_CR1_STOP; //stop bit
  return 0;
}

Salida de alcance:

Configuración:

    
pregunta Oliver Stone

2 respuestas

0

Estás utilizando una dirección incorrecta. La dirección de siete bits de su esclavo es 1101000 (suponiendo que AD0 = 0). Eso significa que el byte de dirección de 8 bits para una escritura sería 11010000, o 0xD0.

También estoy de acuerdo con la sugerencia de Marko Buršič de limpiar los bordes ascendentes reduciendo la resistencia de levantamiento.

    
respondido por el Annie
0

Antes de buscar problemas de código, debe tener un bus que funcione correctamente. Algunos dispositivos se han basado en pull ups, pero 10k es más bien una alta resistencia.

También debe habilitar las extensiones de MCU o agregar otros 10k en paralelo.

EDITAR:

Ahora veamos lo que obtienes del alcance: 0110 1000, que es 0x68 hex, ¿verdad? Pero debería tener una dirección de 7 bits + R / W bit = 11010000 De alguna manera, no se desplaza correctamente a la izquierda en su programa.

    
respondido por el Marko Buršič

Lea otras preguntas en las etiquetas