2025-02-04 06:05 AM
I'm trying to use the I2C line of an STM32G071G8U6TR to talk with an external device. I've used the STMCube to configure the pins to be I2C with pull ups and high speed which created this Init
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
//hi2c1.Init.Timing = I2C_SPEEDCLOCK;
//hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_10BIT;
//hi2c1.Init.OwnAddress2 = 0xff;
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00503D58;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
if(HAL_I2C_Init(&hi2c1) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* USER CODE END I2C1_Init 2 */
}
However when I try and use this code to send commands to the device the status return is always returned as HAL_I2C_STATE_RESET, I've used a scope to check both the I2C lines and they are both high when this code is called.
void connect_vane()
{
//status = HAL_I2C_Master_Transmit_IT(&I2cHandle, MOTOR_ADDRESS_WRITE, (uint8_t*)aTxBuffer, TXBUFFERSIZE);
//if (HAL_OK == status)
//{
//bytes_written = bytes_to_write;
//connect_vane();
//message_buf[0] = 0x66; //Address 66
/*message_buf[0] = 0x3C; // '<'
message_buf[1] = 0x30; // '0'
message_buf[2] = 0x31; // '1'
message_buf[3] = 0x3E; // '>'
message_buf[4] = 0x0D; // '/r'*/
//HAL_I2C_Master_Transmit(&hi2c1, MOTOR_ADDRESS_WRITE, message_buf, 5, 1000);
aTxBuffer[0] = 0x66;
aTxBuffer[1] = 0x3C; // '<'
aTxBuffer[2] = 0x30; // '0'
aTxBuffer[3] = 0x31; // '1'
aTxBuffer[4] = 0x3E; // '>'
aTxBuffer[5] = 0x0D; // '/r'
do
{
if(HAL_I2C_Master_Transmit(&I2cHandle, MOTOR_ADDRESS_WRITE, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 1000)!= HAL_OK)
{
/* Error_Handler() function is called when error occurs. */
Error_Handler();
}
/*##-3- Wait for the end of the transfer #################################*/
/* Before starting a new communication transfer, you need to check the current
state of the peripheral; if it�s busy you need to wait for the end of current
transfer before starting a new one.
For simplicity reasons, this example is just waiting till the end of the
transfer, but application may perform other tasks while transfer operation
is ongoing. */
while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
{
}
/* When Acknowledge failure occurs (Slave don't acknowledge it's address)
Master restarts communication */
}
while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
HAL_Delay(50);
do
{
if(HAL_I2C_Master_Receive(&I2cHandle, (uint16_t)MOTOR_ADDRESS_WRITE, (uint8_t *)aRxBuffer, RXBUFFERSIZE, 1000) != HAL_OK)
{
/* Error_Handler() function is called when error occurs. */
Error_Handler();
}
/*##-5- Wait for the end of the transfer #################################*/
/* Before starting a new communication transfer, you need to check the current
state of the peripheral; if it�s busy you need to wait for the end of current
transfer before starting a new one.
For simplicity reasons, this example is just waiting till the end of the
transfer, but application may perform other tasks while transfer operation
is ongoing. */
while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
{
}
/* When Acknowledge failure occurs (Slave don't acknowledge it's address)
Master restarts communication */
}
while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF);
}
2025-02-04 10:30 PM
Are you using internal or external pull-up resistors?
What I2C device? What slave address is MOTOR_ADDRESS_WRITE defined as?
Do you see data activity?
2025-02-04 10:35 PM
> I've used the STMCube to configure the pins to be I2C with pull ups ...
That will not work.
The internal pull-ups are an order of magnitude too weak. You need about 1k ... 5k externally.
2025-02-05 01:04 AM
I'm currently only using the STM32's internal pull up resistors.
The device is a New Scale M3-LS-U2-8.
MOTOR_ADDRESS_WRITE is defined as 66.
With the code above it gets to:
if(HAL_I2C_Master_Transmit(&I2cHandle, MOTOR_ADDRESS_WRITE, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 1000)!= HAL_OK)
and returns busy. When I have added in a check status line above and debugged in the status is reading as "HAL_I2C_STATE_RESET"
2025-02-05 01:22 AM
@GTann.1 wrote:I'm currently only using the STM32's internal pull up resistors."
As @Ozone said, they are almost certainly too weak.
@GTann.1 wrote:The device is a New Scale M3-LS-U2-8.
So one of these: https://www.newscaletech.com/micro-motion-modules/m3-ls-linear-smart-stages/ ?
https://www.newscaletech.com/wp-content/uploads/M3-LS-U2-datasheet.pdf
Always best to give a link - so that people know exactly what you're referring to.
2025-02-05 01:27 AM - edited 2025-02-05 01:31 AM
@GTann.1 wrote:I'm currently only using the STM32's internal pull up resistors.
The device is a New Scale M3-LS-U2-8.
MOTOR_ADDRESS_WRITE is defined as 66.
With the code above it gets to:
if(HAL_I2C_Master_Transmit(&I2cHandle, MOTOR_ADDRESS_WRITE, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 1000)!= HAL_OK)and returns busy. When I have added in a check status line above and debugged in the status is reading as "HAL_I2C_STATE_RESET"
Do you mean 0x66 or decimal 66?
To me it sounds like the slave address is decimal 66 which is hex 0x42.
If it is, then you have to shift the 7-bit address to the left by 1 prior to calling the function.
HAL_I2C_Master_Transmit(&I2cHandle, MOTOR_ADDRESS_WRITE << 1, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 1000)
Which is explained in the HAL_I2C_Master_Transmit driver
/**
* @brief Transmits in master mode an amount of data in blocking mode.
* @PAram hi2c Pointer to a I2C_HandleTypeDef structure that contains
* the configuration information for the specified I2C.
* @PAram DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
* @PAram pData Pointer to data buffer
* @PAram Size Amount of data to be sent
* @PAram Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData,
uint16_t Size, uint32_t Timeout)
{
uint32_t tickstart;
uint32_t xfermode;
Also, you MUST use external pull-ups on the SDA and SCL lines, around 4.7K Ohms.
2025-02-05 01:40 AM
Sorry, I will remember in future to include a link.
That is the correct device.
2025-02-05 01:48 AM
The defined address is 0x66, the actual device address is 0x33 so 0x66 is used as a shifted version of the address.
2025-02-05 02:16 AM
Sometimes the vendor provides "clues" in the documentation what he means with I2C address.
But those are defined as 7-bit in the standard, and are extended to 8-bit in practice with the R/W bit.
The trouble is now, does the spec talk about an actual 7-bit value (like e.g. with SMBus), or do they mean "extended to 8-bit with the R/W-bit masked out". I came across both.
Occasionally, only trial and error helps ...
2025-02-05 02:43 AM
Indeed, there is industry-wide confusion & inconsistency with I2C addresses.
Only last week:
This is just one reason why it's vital to use an oscilloscope or analyser to see what's actually happening on the wires!