2016-01-13 09:53 AM
So, I'm trying to take the plunge into HAL with my STM32F407VG to be more ''future-proof'' but HAL seems to fight me at every avenue. Today's headache: I2C. Something that is usually pretty trivial to do has turned into just frustration. I have dumbed this down to a newly created project in STM32CubeMX with I2C1 being used.
I'm trying to write to device 0x94, address 0x2, value 0x1. So I try to use the following:
1.
uint8_t data[2] = { 2, 1 };
2.
HAL_I2C_Master_Transmit(&hi2c1, 0x94, &data[0], 2, 100);
Here are the cube's generated files for I2C:
/* I2C1 init function */
void
MX_I2C1_Init(
void
)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
HAL_I2C_Init(&hi2c1);
}
and low level initialization:
void
HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
if
(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB8 ------> I2C1_SCL
PB9 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__I2C1_CLK_ENABLE();
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
Here is the code from my std periph lib program using direct register changing:
// Configure I2C SCL and SDA pins.
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
// Configure I2C.
uint32_t pclk1 = 42000000;
I2C1 ->CR2 = pclk1 / 1000000;
// Configure frequency and disable interrupts and DMA.
I2C1 ->OAR1 = I2C_OAR1_ADDMODE | 0x33;
// Configure I2C speed in standard mode.
const
uint32_t i2c_speed = 100000;
int
ccrspeed = pclk1 / (i2c_speed * 2);
if
(ccrspeed < 4) {
ccrspeed = 4;
}
I2C1 ->CCR = ccrspeed;
I2C1 ->TRISE = pclk1 / 1000000 + 1;
I2C1 ->CR1 = I2C_CR1_ACK | I2C_CR1_PE;
// Enable and configure the I2C peripheral.
And here is the write function for the same command:
while
(I2C1 ->SR2 & I2C_SR2_BUSY );
I2C1 ->CR1 |= I2C_CR1_START;
// Start the transfer sequence.
while
(!(I2C1 ->SR1 & I2C_SR1_SB ));
// Wait for start bit.
I2C1 ->DR = 0x94;
while
(!(I2C1 ->SR1 & I2C_SR1_ADDR ));
// Wait for master transmitter mode.
I2C1 ->SR2;
I2C1 ->DR = 0x02;
// Transmit the address to write to.
while
(!(I2C1 ->SR1 & I2C_SR1_TXE ));
// Wait for byte to move to shift register.
I2C1 ->DR = 0x01;
// Transmit the value.
while
(!(I2C1 ->SR1 & I2C_SR1_BTF ));
// Wait for all bytes to finish.
I2C1 ->CR1 |= I2C_CR1_STOP;
// End the transfer sequence.
The std periph works great everytime. The HAL library fails with the same error after the device address is sent HAL_I2C_ERROR_AF everytime. Can someone tell me what I'm doing wrong here?
I have put the same device on the logic analyzer and I get 0x94+NAK on the HAL and 0x94+ACK, 0x2, 0x1 on the Std Periph.
Thanks for any help!
#i2c #stm32f407vg #fixed
2016-01-13 04:40 PM
I posted the HAL code with 400kHz as the speed but that was just from me trying something. I have tried in both 100kHz and 400kHz modes. On the logic analyzer both waveforms are identical up to the NAK on the HAL side and measure at 100kHz.
2016-01-13 06:03 PM
(No Text)... Post from my phone. Apparently, it doesn't work well.
2016-01-14 08:24 AM
Does anyone have any ideas? Surely, someone has used i2C with HAL?
2016-01-15 08:28 AM
Hi vance.jeremy,
If you increase the timeout value (Ex: use 10000 instead of 100), do you get the same error?-Mayla-To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2016-01-15 03:59 PM
Mayla,
Thanks for getting back to me on this. I tried changing the timeout to 10000 and I still get the same error for each and every try. No ACK from the CS43L22. I have also tried this on the F407 Discovery board and am getting the exact same results.2016-01-18 09:32 AM
Argh, found the issue. I had a bug in the initialization of the CS43L22 DAC. The reset line was being kept low for an active low reset line. Problem fixed and I2C on HAL is working.
2016-01-19 11:39 PM
Great to know that you fixed your issue. Thanks for update.
-Mayla-To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.