5

I want to use the latest HAL library instead of Standard Peripheral Library.

And i want to readout the BMA250E G-sensor's chip_id, but it doesn't work.

Value of aRxBuffer always keep at 0x00. But it should be 0xf9!

What's wrong in my code?

‪#‎include‬ "stm32f4xx_hal.h" 

#define I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define I2Cx_SDA_PIN GPIO_PIN_9
#define I2Cx_SDA_GPIO_PORT GPIOB
#define I2Cx_SDA_AF GPIO_AF4_I2C1

#define I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define I2Cx_SCL_PIN GPIO_PIN_6
#define I2Cx_SCL_GPIO_PORT GPIOB
#define I2Cx_SCL_AF GPIO_AF4_I2C1

#define I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
#define I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
#define I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() 
‪#‎define‬ I2C_ADDRESS 0x18 

static void SystemClock_Config(void); 

uint8_t aTxBuffer[2],aRxBuffer; 

int main()
{ 
    HAL_Init(); 
    SystemClock_Config(); 
    I2C_HandleTypeDef I2cHandle;

    I2cHandle.Instance = I2C1;
    I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    I2cHandle.Init.ClockSpeed = 400000;
    I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; 
    I2cHandle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
    I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; 
    I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    I2cHandle.Init.OwnAddress1 = 0; 
    I2cHandle.Init.OwnAddress2 = 0; 

    HAL_I2C_Init(&I2cHandle); 

    aTxBuffer[0]=0x00;
    HAL_I2C_Master_Transmit(&I2cHandle, I2C_ADDRESS,aTxBuffer, 1, 10000);  
    HAL_I2C_Master_Receive(&I2cHandle,I2C_ADDRESS|0x01 ,&aRxBuffer, 1, 10000);  
    HAL_Delay(1000);
} 
static void SystemClock_Config(void) 
{ 
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_OscInitTypeDef RCC_OscInitStruct;

    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; 
    RCC_OscInitStruct.HSEState = RCC_HSE_ON; 
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8; 
    RCC_OscInitStruct.PLL.PLLN = 360;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; 
    RCC_OscInitStruct.PLL.PLLQ = 7; 
    HAL_RCC_OscConfig(&RCC_OscInitStruct); 
    RCC_ClkInitStruct.ClockType = 
        (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 
         RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; 
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;         
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; 
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5); 
}

void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) 
{
    GPIO_InitTypeDef GPIO_InitStruct; 

    I2Cx_SCL_GPIO_CLK_ENABLE(); 
    I2Cx_SDA_GPIO_CLK_ENABLE(); 

    GPIO_InitStruct.Pin = I2Cx_SCL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Alternate = I2Cx_SCL_AF; 
    HAL_GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = I2Cx_SDA_PIN; 
    GPIO_InitStruct.Alternate = I2Cx_SDA_AF; 
    HAL_GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct);
} 

void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c) 
{  
    I2Cx_FORCE_RESET(); 
    I2Cx_RELEASE_RESET();  
    HAL_GPIO_DeInit(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN);
    HAL_GPIO_DeInit(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN); 
}
imbearr
  • 999
  • 7
  • 22
elecbuggy
  • 63
  • 1
  • 1
  • 5
  • First: fromat your code - it is unreadable now. Second: if you use HAL - you must check returned HAL status value always. – imbearr Jul 07 '16 at 04:36
  • So have you tried my second advice? What value returned when you call `HAL_I2C_Init`, `HAL_I2C_Master_Transmit`, `HAL_I2C_Master_Receive` functions, are it everytime equal `HAL_OK`? – imbearr Jul 07 '16 at 07:14
  • thank you very much – elecbuggy Jul 08 '16 at 16:43

1 Answers1

18

First, I would advise you to use STMCube. It will set up the clock and the I2C bus for you.

It is very good practice to check what the HAL functions return. If you don't have HAL_OK, something went wrong.

Try at 100KHz first, and then increase to 400KHz.

The I2C address of the device is 0x18 (if SDO is grounded, which I assume it is). But in the HAL driver, you have to define:

#‎define‬ I2C_ADDRESS (0x18<<1)

What you want to do is to read a register, so don't use HAL_I2C_Master_Receive or HAL_I2C_Master_Transmit, but HAL_I2C_Mem_Read or HAL_I2C_Mem_Write, like this:

#define REG_CHIP_ID 0x00
HAL_I2C_Mem_Read(&I2cHandle, I2C_ADDRESS, REG_CHIP_ID, I2C_MEMADD_SIZE_8BIT, &aRxBuffer, 1, 10000);

Also, note that the HAL takes care of the R/W bit of the address, so you don't need to do:

I2C_ADDRESS|0x01
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Guillaume Michel
  • 1,189
  • 8
  • 14
  • 1
    What's the difference between **HAL_I2C_Master_Receive/HAL_I2C_Master_Transmit** and **HAL_I2C_Mem_Read/HAL_I2C_Mem_Write**? – Alaa M. Jun 29 '17 at 08:00
  • 2
    `HAL_I2C_Master_Receive` performs a I2C read operation of N bytes (start, I2C address + Read, N bytes, stop). `HAL_I2C_Master_Transmit` performs a I2C write operation of N bytes (start, I2C address + Write, N bytes, stop). – Guillaume Michel Jun 29 '17 at 09:33
  • 6
    `HAL_I2C_Mem_Read` performs a I2C write operation to select the memory address to read and then reads N bytes (start, I2C address + Write, Memory address, repeated start, I2C address + Read, N bytes, stop) `HAL_I2C_Mem_Write` performs a I2C write operation to select the memory address to read and then writes N bytes (start, I2C address + Write, Memory address, repeated start, I2C address + Write, N bytes, stop) – Guillaume Michel Jun 29 '17 at 09:33
  • 1
    `HAL_I2C_Mem_Read` saved the day. `HAL_I2C_Master_Receive` was definitely the reason for failure. I wish I understood the nuance between them better. – tarabyte Oct 19 '18 at 01:12