Electronics > Microcontrollers

STM32: I2C with HAL what am I doing wrong?

(1/3) > >>

Watth:
Hey everyone,
After a successful attempt with SPI, I am now having trouble with I2C.
Contect; I'm using a Nucleo-L412KB to try to command a MAX6956AAX LED driver. Using STM32CubeIDE.
The thing is that I can't get to send anything at all. Here's part of main.c (the full file is attached):

--- Code: ---/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */
uint8_t devAddW = 0b10000000; // device (MAX6956) address; W because end with bit 0 (write mode)
uint8_t data[8]; // data array
int8_t dataLength; // size that has to be transmitted
uint32_t tickMem; // last recorded tick
uint16_t delay = 200; // time delay (ms)

HAL_I2C_StateTypeDef stateI2C_1; // state of the I2C bus
HAL_I2C_StateTypeDef stateI2C_2; // state of the I2C bus too
HAL_StatusTypeDef retI2C; // value returned by I2C transmit
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_I2C1_Init(void);

int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
    // setting pins as LED drives
data[0] = 0x0A;
data[1] = 0x0;
data[3] = 0x0;
data[4] = 0x0;

dataLength = 4;

stateI2C_1 = HAL_I2C_GetState(&hi2c1);
retI2C = HAL_I2C_Master_Transmit(&hi2c1, devAddW, data, dataLength, 100);
stateI2C_2 = HAL_I2C_GetState(&hi2c1);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
while (1) {

data[0] = 0x07; // display test mode command address
data[1] = 0x00; // display test mode disabled (normal mode)
dataLength = 2;

stateI2C_1 = HAL_I2C_GetState(&hi2c1); // state before transmit
retI2C = HAL_I2C_Master_Transmit(&hi2c1, devAddW, data, dataLength, 100);
stateI2C_2 = HAL_I2C_GetState(&hi2c1); // state after transmit

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); // blink LED to show at least *something* is happening.
tickMem = HAL_GetTick();
while (HAL_GetTick() < tickMem + delay)
{
}

data[0] = 0x07; // display test mode command address
data[1] = 0xFF; // display test mode enabled : should light LEDs at half current

stateI2C_1 = HAL_I2C_GetState(&hi2c1); // state before transmit
retI2C = HAL_I2C_Master_Transmit(&hi2c1, devAddW, data, dataLength, 100);
stateI2C_2 = HAL_I2C_GetState(&hi2c1); // state after transmit

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); // blink LED to show at least *something* is happening.
tickMem = HAL_GetTick();
while (HAL_GetTick() < tickMem + delay)
{
}
}
}

--- End code ---
I also add the I2C init function so you may see if my config is wrong:

--- Code: ---static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00707CBB;
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();
}
}

--- End code ---
What happens is that HAL_I2C_Master_Transmit() returns HAL_ERROR (in the retI2C variable) from the first attempt (before the infinite loop).
Is it the 3d arg I give in HAL_I2C_Master_Transmit() that isn't good?

thm_w:

--- Quote ---Slave Address
The MAX6956 has a 7-bit-long slave address (Figure 6). The eighth bit following the 7-bit slave address is the R/W bit. It is low for a write command, high for a read command. The first 3 bits (MSBs) of the MAX6956 slave address are always 100. Slave address bits A3, A2, A1, and A0 are selected by address inputs, AD1 and AD0. These two input pins may be connected to GND, V+, SDA, or SCL. The MAX6956 has 16 possible slave addresses (Table 3) and therefore, a maximum of 16 MAX6956 devices may share the same interface.
--- End quote ---

https://datasheets.maximintegrated.com/en/ds/MAX6956.pdf


--- Quote --- * @param  DevAddress Target device address: The device 7 bits address value
 *         in datasheet must be shifted to the left before calling the interface
--- End quote ---

How do you have the address pins on the MAX6956 hooked up?

The third argument looks ok, data[] array.
But you are using int for dataLength, not uint, not sure if that matters:

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Robotec:
it may be included in some of your functions but in almost all CUBEMX predefined functions after init you have to call the correspondent start function.

First thing I would do is attach a oscilloscope or logic analyser and see what is happening there.

Watth:

--- Quote from: thm_w on January 26, 2022, 10:52:28 pm ---
--- Quote ---Slave Address
How do you have the address pins on the MAX6956 hooked up?

--- End quote ---
both to GND, therefore the adress (from A6 to A0] should be 1000000

--- Quote ---The third argument looks ok, data[] array.
But you are using int for dataLength, not uint, not sure if that matters:

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

--- End quote ---
Ah, thanks, I didn't catch that. Also I didn't pay attention and should have used a u_in16 (adress shifted to the right, as per UM1785). Size should be unint_16 too. Althjough, note that the compiler didn't note that as an error nor a warning.
So here's the new declaration block:

--- Code: ---uint16_t devAddW = 0b1000000000000000; // // device address W because (ends with bit 0 for write mode) shifted to right
uint8_t data[8]; // data array
uint16_t dataLength; // size that has to be transmitted
uint32_t tickMem; // last recorded tick
uint16_t delay = 200; // time delay (ms)

--- End code ---

--- End quote ---

Watth:

--- Quote from: Robotec on January 27, 2022, 08:06:02 am ---it may be included in some of your functions but in almost all CUBEMX predefined functions after init you have to call the correspondent start function.

--- End quote ---
I didn't find anything except init functions (that MX added automatically)

--- Quote ---First thing I would do is attach a oscilloscope or logic analyser and see what is happening there.

--- End quote ---
I did, and there's nothing there. Which isn't surprising as I I checked with the debug that the transmit functions always return errors :/

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version