cancel
Showing results for 
Search instead for 
Did you mean: 

I2C register configuration problem

freya17365
Associate II

Hi to all,

I'm trying to write my own I2C class, but SDA seems not willing to collaborate.

Here is pins configuration:

#define I2C1_SCL   8      // PB8

#define I2C1_SDA   9      // PB9

MYI2C::MYI2C()

{

   if(!(RCC->AHBENR & RCC_AHBENR_GPIOBEN)) RCC->AHBENR |= RCC_AHBENR_GPIOBEN;      // Enable GPIOB clock

   GPIOB->MODER &= ~(0x03<<(2*I2C1_SCL) | 0x03<<(2*I2C1_SDA));   //Alternate function

   GPIOB->MODER |= 0x02<<(2*I2C1_SCL) | 0x02<<(2*I2C1_SDA);

   GPIOB->OTYPER &= ~(0x01<<I2C1_SCL | 0x01<<I2C1_SDA);   // Push-Pull (PP) or Open Drain (OD)

   GPIOB->OTYPER |= 0x01<<I2C1_SCL | 0x01<<I2C1_SDA;

   GPIOB->OSPEEDR &= ~(0x03<<(2*I2C1_SCL) | 0x03<<(2*I2C1_SDA));   //Pin speed

   GPIOB->OSPEEDR |= 0x03<<(2*I2C1_SCL) | 0x03<<(2*I2C1_SDA);

   GPIOB->PUPDR &= ~(0x03<<(2*I2C1_SCL) | 0x03<<(2*I2C1_SDA));   // 0x00 = Open Drain; 0x01 = OD+PU; 0x02 = OD+PD

   GPIOB->PUPDR |= 0x00<<(2*I2C1_SCL) | 0x00<<(2*I2C1_SDA);

   GPIOB->AFR[1] &= ~(0x0F<<(4*(I2C1_SCL-8)) | 0x0F<<(4*(I2C1_SDA-8)));   //Alternate function 1 (I2C)

   GPIOB->AFR[1] |= 0x01<<(4*(I2C1_SCL-8)) | 0x01<<(4*(I2C1_SDA-8));

   if(!(RCC->APB1ENR & RCC_APB1ENR_I2C1EN)) RCC->APB1ENR|= RCC_APB1ENR_I2C1EN;      // Enable I2C clock

   I2C1->CR1 &= ~I2C_CR1_PE;                     // Disable I2C

   I2C1->CR1 &= ~(I2C_CR1_ANFOFF | I2C_CR1_DNF);      // Enable analog filter | Disable digital filter

   I2C2->TIMINGR = 0x20303E5D;   //0x00B01A4B;         // Timing register value is computed with the AN4235 xls file, fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns

   I2C1->CR1 |=   I2C_CR1_NOSTRETCH;   // Disable clock stretching   

   I2C1->CR1 |= I2C_CR1_PE;   // Enable I2C

}

Here is the draft of transmission routine:

void MYI2C::MasterTransmit(uint8_t addr, uint8_t reg, uint8_t *buf, uint32_t nbyte)

{

//   uint8_t i;

   uint32_t j;

   I2C2->CR1 &= ~I2C_CR1_PE;   // Disable I2C

   I2C2->TIMINGR = 0x20303E5D;   // 0x00B01A4B;   // Timing register value is computed with the AN4235 xls file, fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns

   I2C2->CR2 = 0x00000000;   // Reset CR2 register

   I2C2->CR2 = I2C_CR2_AUTOEND | I2C_CR2_NACK | 1 << 16 | addr;   // Auto end | one byte to write | slave address

   I2C2->CR1 |= I2C_CR1_PE;   // Enable I2C

   if((I2C2->ISR & I2C_ISR_TXE) == I2C_ISR_TXE)

   {

      myusart1.PrintString((uint8_t *) "Send reginster", '\n', 0);

      I2C2->TXDR = AHT21_GETSTATUS;   // Command to send

      I2C1->CR2 |= I2C_CR2_START; // Send start condition

   }

   return;

}

and in annex is what the scope sees.

I copied the value of timing register both from user manual example and from CubeMX configuration, but always the result remains the same

Probably I missed something along the way, but I am not able to understand what.

Please, can anyone help me?

Thank you

Freya

4 REPLIES 4
Yevgeni Tunik
Senior
  1. Your chosen baudrate 400000 bps is too high for your SCL pull-up resistor. SCL high level must reach 3.3 V.
  2. You can compare your initialization code versus the following code. This code is tested with Temperature Sensors TMP100 and microcontroller stm32f427zitx. Details of I2C interrupt are omitted here.

//--------------- I2C 1 -----------------------------------------

// Connector-connected (not implemented yet) temperature sensors  

#define SCL_I2C1_Pin GPIO_PIN_6

#define SCL_I2C1_GPIO_Port GPIOB

#define SDA_I2C1_Pin GPIO_PIN_7

#define SDA_I2C1_GPIO_Port GPIOB

//--------------- I2C 2 -----------------------------------------

//--------------- 3 board temperature sensors ------------------

#define SCL_I2C2_Pin GPIO_PIN_1

#define SCL_I2C2_GPIO_Port GPIOF

#define SDA_I2C2_Pin GPIO_PIN_0

#define SDA_I2C2_GPIO_Port GPIOF

void MX_I2C2_Init(void)

{

 hi2c2.Instance = I2C2;

 hi2c2.Init.ClockSpeed = 400000;

 hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;

 hi2c2.Init.OwnAddress1 = 0;

 hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

 hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

 hi2c2.Init.OwnAddress2 = 0;

 hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;

 hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

 if (HAL_I2C_Init(&hi2c2) != HAL_OK)

 {

  Error_Handler();

 }

 /** Configure Analogue filter

 */

 if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)

 {

  Error_Handler();

 }

 /** Configure Digital filter

 */

 if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)

 {

  Error_Handler();

 }

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if(i2cHandle->Instance==I2C1)

 {

 /* USER CODE BEGIN I2C1_MspInit 0 */

 /* USER CODE END I2C1_MspInit 0 */

  __HAL_RCC_GPIOB_CLK_ENABLE();

  /**I2C1 GPIO Configuration

  PB6   ------> I2C1_SCL

  PB7   ------> I2C1_SDA

  */

  GPIO_InitStruct.Pin = SCL_I2C1_Pin|SDA_I2C1_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

  GPIO_InitStruct.Pull = GPIO_PULLUP;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* I2C1 clock enable */

  __HAL_RCC_I2C1_CLK_ENABLE();

 /* USER CODE BEGIN I2C1_MspInit 1 */

 /* USER CODE END I2C1_MspInit 1 */

 }

 else if(i2cHandle->Instance==I2C2)

 {

 /* USER CODE BEGIN I2C2_MspInit 0 */

 /* USER CODE END I2C2_MspInit 0 */

  __HAL_RCC_GPIOF_CLK_ENABLE();

  /**I2C2 GPIO Configuration

  PF0   ------> I2C2_SDA

  PF1   ------> I2C2_SCL

  */

  GPIO_InitStruct.Pin = SDA_I2C2_Pin|SCL_I2C2_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

  GPIO_InitStruct.Pull = GPIO_PULLUP;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;

  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* I2C2 clock enable */

  __HAL_RCC_I2C2_CLK_ENABLE();

  /* I2C2 interrupt Init */

  HAL_NVIC_SetPriority(I2C2_EV_IRQn, 8, 0);

  HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);

 /* USER CODE BEGIN I2C2_MspInit 1 */

 /* USER CODE END I2C2_MspInit 1 */

 }

}

Addition to my "chosen baudrate" item:

For baudrate 400000 bps, SCL must be approximately (see exact numbers in datasheet of your slave device) 1.25 us at high level, and 1.25 us at low level.

For baudrate 100000 bps, SCL must be approximately 5 us at high level, and 5 us at low level.

Also, provide delays between CS change and SCL change according to datasheet of your slave device.

freya17365
Associate II

Hi to all,

I made some changes, but little changed.

Now I2C clock is HSI, slope are very narrow and pull up resistors are 1K instead of 10K. It's alittle better, but SDA continue to stay low regardless data sent.

Furthermore, I see only 9 clock pulses instead of 18 (9 for slave address and 9 for one byte to send). Do I forgot something?

I wrote my code by analyzing HAL code, but something should be gone wrong.

Now I'll reduce pull up to 560 ohm, but I don't think it could work on SDA laziness.

Any suggestions?

Thank you

Freya

freya17365
Associate II

Dear all,

at last I solved my problem.

In annex I enclose my working class. Of course it is strongly hardware dependent and is really basic, but if anyone can find it useful, she can use it

Bye

Freya