Search code examples
stm32i2cled

STM32L4 I2C LED Driver


I am trying to control LEDs using IS31FL3236A LED driver from LUMISSIL Microsystem which communicates with I2C.

LED driver datasheet

I use the HAL communication protocol of the STM32, I am able to turn on all the LEDs but I don't understand why I can't control the LEDs one by one or choose the intensity of the LEDs.

Here is my code.

IS31FL3236A.h to configure the address of all channels and the device address.

#define Single 0
#define RGB 1

#define Addr_GND    0x78 // P7 datasheet 0x78 = 1111000 en bit (addr 1)
#define PWM 0x04
#define All_EN  0x4A
#define IS3236_REG_PWM_OUT1     0x01 //LED PWM
#define IS3236_REG_PWM_OUT2     0x02
#define IS3236_REG_PWM_OUT3     0x03
#define IS3236_REG_PWM_OUT4     0x04
#define IS3236_REG_PWM_OUT5     0x05
#define IS3236_REG_PWM_OUT6     0x06
#define IS3236_REG_PWM_OUT7     0x07
#define IS3236_REG_PWM_OUT8     0x08
#define IS3236_REG_PWM_OUT9     0x09
#define IS3236_REG_PWM_OUT10    0x0A
#define IS3236_REG_PWM_OUT11    0x0B
#define IS3236_REG_PWM_OUT12    0x0C
#define IS3236_REG_PWM_OUT13    0x0D
#define IS3236_REG_PWM_OUT14    0x0E
#define IS3236_REG_PWM_OUT15    0x0F
#define IS3236_REG_PWM_OUT16    0x10
#define IS3236_REG_PWM_OUT17    0x11
#define IS3236_REG_PWM_OUT18    0x12
#define IS3236_REG_PWM_OUT19    0x13
#define IS3236_REG_PWM_OUT20    0x14
#define IS3236_REG_PWM_OUT21    0x15
#define IS3236_REG_PWM_OUT22    0x16
#define IS3236_REG_PWM_OUT23    0x17
#define IS3236_REG_PWM_OUT24    0x18
#define IS3236_REG_PWM_OUT25    0x19
#define IS3236_REG_PWM_OUT26    0x1A
#define IS3236_REG_PWM_OUT27    0x1B
#define IS3236_REG_PWM_OUT28    0x1C
#define IS3236_REG_PWM_OUT29    0x1D
#define IS3236_REG_PWM_OUT30    0x1E
#define IS3236_REG_PWM_OUT31    0x1F
#define IS3236_REG_PWM_OUT32    0x20
#define IS3236_REG_PWM_OUT33    0x21
#define IS3236_REG_PWM_OUT34    0x22
#define IS3236_REG_PWM_OUT35    0x23
#define IS3236_REG_PWM_OUT36    0x24

#define IS3236_REG_CTRL_OUT1    0x26 //LED ONOFF
#define IS3236_REG_CTRL_OUT2    0x27
#define IS3236_REG_CTRL_OUT3    0x28
#define IS3236_REG_CTRL_OUT4    0x29
#define IS3236_REG_CTRL_OUT5    0x2A
#define IS3236_REG_CTRL_OUT6    0x2B
#define IS3236_REG_CTRL_OUT7    0x2C
#define IS3236_REG_CTRL_OUT8    0x2D
#define IS3236_REG_CTRL_OUT9    0x2E
#define IS3236_REG_CTRL_OUT10   0x2F
#define IS3236_REG_CTRL_OUT11   0x30
#define IS3236_REG_CTRL_OUT12   0x31
#define IS3236_REG_CTRL_OUT13   0x32
#define IS3236_REG_CTRL_OUT14   0x33
#define IS3236_REG_CTRL_OUT15   0x34
#define IS3236_REG_CTRL_OUT16   0x35
#define IS3236_REG_CTRL_OUT17   0x36
#define IS3236_REG_CTRL_OUT18   0x37
#define IS3236_REG_CTRL_OUT19   0x38
#define IS3236_REG_CTRL_OUT20   0x39
#define IS3236_REG_CTRL_OUT21   0x3A
#define IS3236_REG_CTRL_OUT22   0x3B
#define IS3236_REG_CTRL_OUT23   0x3C
#define IS3236_REG_CTRL_OUT24   0x3D
#define IS3236_REG_CTRL_OUT25   0x3E
#define IS3236_REG_CTRL_OUT26   0x3F
#define IS3236_REG_CTRL_OUT27   0x40
#define IS3236_REG_CTRL_OUT28   0x41
#define IS3236_REG_CTRL_OUT29   0x42
#define IS3236_REG_CTRL_OUT30   0x43
#define IS3236_REG_CTRL_OUT31   0x44
#define IS3236_REG_CTRL_OUT32   0x45
#define IS3236_REG_CTRL_OUT33   0x46
#define IS3236_REG_CTRL_OUT34   0x47
#define IS3236_REG_CTRL_OUT35   0x48
#define IS3236_REG_CTRL_OUT36   0x49
#define Imax    0x11
#define update  0x25
#define freq    0x4B
#define mode    0x01

main.c to turn on all LEDs

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */
  //I2C_GPIO_Init();
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART2_UART_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */

  //I2C_GPIO_Init();
  IS31FL3236A_Init();
  static const uint16_t LED19 = 0x13;
  static const uint16_t LED19PWM = 0x38;
  static const uint16_t deviceAddr = 0x78;
  static const uint16_t Update = 0x25;
  static const uint16_t Freq = 0x4B;
  static const uint16_t intensityPWM = 0x02;
  static const uint16_t CurrentMax = 0x00;
  static const uint16_t Mode = 0x01;

  uint8_t pwm[bufSize];
  uint8_t current[bufSize];
  uint8_t mode1[bufSize];

  pwm[0] = 0x7B;
  current[0] = 0x00;
  mode1[0] = 0x01;


  uint8_t i=0;
  /*for(i=0;i<=0x49;i++){
      HAL_I2C_Mem_Write(&hi2c1, Addr_GND, i, I2C_MEMADD_SIZE_16BIT, (uint8_t*)PWM, 1, HAL_MAX_DELAY);
  }
  for(i=0;i<=0x24;i++){
          HAL_I2C_Mem_Write(&hi2c1, Addr_GND, i, sizeof(i), (uint8_t*)Imax, sizeof(Imax), 10);

      }*/
  HAL_I2C_Mem_Write(&hi2c1, deviceAddr, LED19PWM, I2C_MEMADD_SIZE_8BIT, pwm, bufSize, 10);
  HAL_I2C_Mem_Write(&hi2c1, deviceAddr, LED19, I2C_MEMADD_SIZE_8BIT, current, bufSize, 10);

  HAL_I2C_Mem_Write(&hi2c1, deviceAddr, Freq, I2C_MEMADD_SIZE_8BIT, current, bufSize, 10);
  HAL_I2C_Mem_Write(&hi2c1, deviceAddr, Mode, I2C_MEMADD_SIZE_8BIT, current, bufSize, 10);

  HAL_I2C_Mem_Write(&hi2c1, deviceAddr, Update, I2C_MEMADD_SIZE_8BIT, mode1, bufSize, 10);

  /* USER CODE END 2 */

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


      /*uint8_t i=0;
      for(i=0;i<=0x49;i++){
          HAL_I2C_Mem_Write(&hi2c1, Addr_GND, i, sizeof(i), (uint8_t*)PWM, sizeof(PWM), 10);
      }
      for(i=0;i<=0x24;i++){
              HAL_I2C_Mem_Write(&hi2c1, Addr_GND, i, sizeof(i), (uint8_t*)Imax, sizeof(Imax), 10);
          }

      HAL_I2C_Mem_Write(&hi2c1, Addr_GND, freq, sizeof(freq), (uint8_t*)Imax, sizeof(Imax), 10);
      HAL_I2C_Mem_Write(&hi2c1, Addr_GND, mode, sizeof(mode), (uint8_t*)Imax, sizeof(Imax), 10);
      HAL_I2C_Mem_Write(&hi2c1, Addr_GND, RESET, sizeof(RESET), (uint8_t*)mode, sizeof(mode), 10);
      HAL_I2C_Mem_Write(&hi2c1, Addr_GND, update, sizeof(update), (uint8_t*)mode, sizeof(mode), 10);*/

      //Swith();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

To select LED number 19 for example, I just removed the two for loops and added this but the LED does not light up.

      HAL_I2C_Mem_Write(&hi2c1, GND, IS3236_REG_PWM_OUT19, sizeof(IS3236_REG_PWM_OUT19), (uint8_t*)PWM, sizeof(PWM), 10);
      HAL_I2C_Mem_Write(&hi2c1, GND, IS3236_REG_CTRL_OUT19, sizeof(IS3236_REG_CTRL_OUT19), (uint8_t*)Imax, sizeof(Imax), 10);
      HAL_I2C_Mem_Write(&hi2c1, GND, update, sizeof(update), (uint8_t*)mode, sizeof(mode), 10);

I2C configuration

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x00702991;
  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 */

  /* USER CODE END I2C1_Init 2 */

}

stm32l4xx_hal_msp.c

/**
* @brief I2C MSP Initialization
* This function configures the hardware resources used in this example
* @param hi2c: I2C handle pointer
* @retval None
*/
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PA9     ------> I2C1_SCL
    PA10     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    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(GPIOA, &GPIO_InitStruct);

    /* Peripheral clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }

}

/**
* @brief I2C MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hi2c: I2C handle pointer
* @retval None
*/
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
{
  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */

  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();

    /**I2C1 GPIO Configuration
    PA9     ------> I2C1_SCL
    PA10     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_10);

  /* USER CODE BEGIN I2C1_MspDeInit 1 */

  /* USER CODE END I2C1_MspDeInit 1 */
  }

}

Solution

  • Here is what STM32 expects

    HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, 
                                        uint16_t DevAddress, 
                                        uint16_t MemAddress, 
                                        uint16_t MemAddSize, 
                                        uint8_t *pData, 
                                        uint16_t Size, 
                                        uint32_t Timeout);
    

    Here is what you give:

    HAL_I2C_Mem_Write(&hi2c1, GND, IS3236_REG_PWM_OUT19, sizeof(IS3236_REG_PWM_OUT19), (uint8_t*)PWM, sizeof(PWM), 10);
    HAL_I2C_Mem_Write(&hi2c1, GND, IS3236_REG_CTRL_OUT19, sizeof(IS3236_REG_CTRL_OUT19), (uint8_t*)Imax, sizeof(Imax), 10);
    HAL_I2C_Mem_Write(&hi2c1, GND, update, sizeof(update), (uint8_t*)mode, sizeof(mode), 10);
    
    1. Do not take a sizeof(#define)
      • Rebind register #defines into static const. Or #define the MemAddSize if desired
    2. Don't use a pointer to a #define
    3. Change your MemAddSize to either: I2C_MEMADD_SIZE_16BIT, I2C_MEMADD_SIZE_8BIT

    My blind guess as to why the system is able to turn the leds all on or off and at max brightness is due to address auto increment.

    Try using the I2C_MEM_WRITE() using magic numbers and local variables, buffers, and pointers. If this works then it is likely your usage of #defines within your driver file.

    Check the return type of HAL_StatusTypeDef between each call. Make sure that it is OK.

    Here are two example for stm32 i2c:

    1. Example using mem_write()
    2. Intro to stm32 i2c

    ------------ Reply 1 ------------

    Dont use I2C_MEMADD_SIZE_16BIT for the Size param. You need to specify the num of of the buffer you are pointing to. Go to your local source code and look at the instructions for how to use I2C_mem_write(). Based on the data sheet, I believe you should also be using I2C_MEMADD_SIZE_8BIT instead of 16.

    Suppose you have a buffer of size one. You want to only read one byte then.

    #define bufSize 1
    
    uint8_t myBuf[bufSize];
    myBuf[0] = someDataVal;
    
    HAL_I2C_Mem_Write(&hi2c1, deviceAddr, LED19, I2C_MEMADD_SIZE_8BIT, myBuf, bufSize , 10);
    

    ------------ Reply 2 ------------

    • Is bufSize defined? If so, what number is it?

    • You need to be assigning to the first index of each buf if you are only writing one byte from each buf. pwm[0], current[0] (not 1), mode1[0] (not 2).

      uint8_t pwm[bufSize];
      uint8_t current[bufSize];
      uint8_t mode1[bufSize];
      
      pwm[0] = 0x7B;
      current[1] = 0x00;
      mode1[2] = 0x01;
      

    ------------ Reply 3 ------------

    // First lets discuss device address
    // What is your AD pin connected to (PG 7)
    // Currently you have it configured to 0x78. Bit shift it for STM32 
    // 0x78 << 1
    
    uint8_t myBuf[1];
    
    // Turn on the device by writing to register 0. Shutdown register
    myBuf[0] = 0x01;
    HAL_I2C_Mem_Write(&hi2c1, ((uint16_t) 0x78) << 1, 0x00, I2C_MEMADD_SIZE_8BIT, myBuf, 1, 10;
    
    // Then lets assign the pwm to the first LED (OUT1). Register 1. Reuse prior buffer. 
    myBuf[0] = 0x80;
    // Lets toggle LED 19
    HAL_I2C_Mem_Write(&hi2c1, ((uint16_t) 0x78) << 1, 0x01, I2C_MEMADD_SIZE_8BIT, myBuf, 1, 10;
    
    // Enable OUT1 via Control register 26
    myBuf[0] = 0x01;    // This would have maximum current settings (Pg. 9)
    HAL_I2C_Mem_Write(&hi2c1, ((uint16_t) 0x78) << 1, 0x26, I2C_MEMADD_SIZE_8BIT, myBuf, 1, 10;
    
    // Tell system to update the registers. Register 25
    myBuf[0] = 0x00;
    HAL_I2C_Mem_Write(&hi2c1, ((uint16_t) 0x78) << 1, 0x25, I2C_MEMADD_SIZE_8BIT, myBuf, 1, 10;
    
    • I always would encourage you to look at the HAL_STATUS of each of these returns. Can you tell me if it is OK?