2021-11-09 12:48 AM
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
2021-11-09 01:14 AM
//--------------- 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 */
}
}
2021-11-09 06:16 AM
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.
2021-11-11 11:41 PM
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
2021-12-02 11:52 PM