08-03-2020 11:39 AM
Hi,
i am trying to read quaternion's out of the BHI160b, that's why i purchased the BHI160b shuttle Board from Bosch. I want to connect it with my NUCLEO-F411RE from STM. So i implemented the library into my STM project. The next step was to figure out how to use the HAL_I2C functions to communicate with the sensor. I changed the read/write operations in the driver's file bhy_support.c like this:
uint8_t GTXBuffer[256];
int8_t SensorAPI_I2Cx_Read(uint8_t slave_address7, uint8_t subaddress, uint8_t *pBuffer, uint16_t ReadNumbr)
{
uint16_t DevAddress = slave_address7 << 1;
// send register address
HAL_I2C_Master_Transmit(&I2C_HANDLE, DevAddress, &subaddress, 1, BUS_TIMEOUT);
HAL_I2C_Master_Receive(&I2C_HANDLE, DevAddress, pBuffer, ReadNumbr, BUS_TIMEOUT);
return 0;
}
int8_t SensorAPI_I2Cx_Write(uint8_t slave_address7, uint8_t subaddress, uint8_t *pBuffer, uint16_t WriteNumbr)
{
uint16_t DevAddress = slave_address7 << 1;
GTXBuffer[0] = subaddress;
memcpy(>XBuffer[1], pBuffer, WriteNumbr);
// send register address
HAL_I2C_Master_Transmit(&I2C_HANDLE, DevAddress, GTXBuffer, WriteNumbr+1, BUS_TIMEOUT);
return 0;
}
I connected the Shuttle Board to my NUCLEO board like this:
___J1___|___NUCLEO___
1/2 | 3.3V
3 | GND
17 | PB7 -> I2C1_SCL
18 | PB6 -> I2C1_SDA
21 | PB5 -> DI/BHI160_INT
In my main loop i startet to initialize BHI160 Sensor with the function bhy_initialize_support();:
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
bhy_initialize_support();
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
int8_t ret;
/* BHY Variable*/
uint8_t *fifoptr = NULL;
uint8_t bytes_left_in_fifo = 0;
uint16_t bytes_remaining = 0;
uint16_t bytes_read = 0;
bhy_data_generic_t fifo_packet;
bhy_data_type_t packet_type;
BHY_RETURN_FUNCTION_TYPE result;
/* the remapping matrix for BHA or BHI here should be configured according to its placement on customer's PCB. */
/* for details, please check 'Application Notes Axes remapping of BHA250(B)/BHI160(B)' document. */
int8_t bhy_mapping_matrix_config[3*3] = {0,1,0,-1,0,0,0,0,1};
/* the remapping matrix for Magnetometer should be configured according to its placement on customer's PCB. */
/* for details, please check 'Application Notes Axes remapping of BHA250(B)/BHI160(B)' document. */
int8_t mag_mapping_matrix_config[3*3] = {0,1,0,1,0,0,0,0,-1};
/* the sic matrix should be calculated for customer platform by logging uncalibrated magnetometer data. */
/* the sic matrix here is only an example array (identity matrix). Customer should generate their own matrix. */
/* This affects magnetometer fusion performance. */
float sic_array[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
/* To get the customized version number in firmware, it is necessary to read Parameter Page 2, index 125 */
/* to get this information. This feature is only supported for customized firmware. To get this customized */
/* firmware, you need to contact your local FAE of Bosch Sensortec. */
//struct cus_version_t bhy_cus_version;
while (HAL_GPIO_ReadPin(BHI160_INT_GPIO_Port, BHI160_INT_Pin) == GPIO_PIN_RESET);
/* init the bhy chip */
if(bhy_driver_init(&bhy1_fw))
{
//DEBUG("Fail to init bhy\n");
}
/* wait for the bhy trigger the interrupt pin go down and up again */
//while (HAL_GPIO_ReadPin(BHI160_INT_GPIO_Port, BHI160_INT_Pin) == GPIO_PIN_SET);
HAL_Delay(100);
while (HAL_GPIO_ReadPin(BHI160_INT_GPIO_Port, BHI160_INT_Pin) == GPIO_PIN_RESET);
/* To get the customized version number in firmware, it is necessary to read Parameter Page 2, index 125 */
/* to get this information. This feature is only supported for customized firmware. To get this customized */
/* firmware, you need to contact your local FAE of Bosch Sensortec. */
//bhy_read_parameter_page(BHY_PAGE_2, PAGE2_CUS_FIRMWARE_VERSION, (uint8_t*)&bhy_cus_version, sizeof(struct cus_version_t));
//DEBUG("cus version base:%d major:%d minor:%d\n", bhy_cus_version.base, bhy_cus_version.major, bhy_cus_version.minor);
/* the remapping matrix for BHI and Magmetometer should be configured here to make sure rotation vector is */
/* calculated in a correct coordinates system. */
bhy_mapping_matrix_set(PHYSICAL_SENSOR_INDEX_ACC, bhy_mapping_matrix_config);
bhy_mapping_matrix_set(PHYSICAL_SENSOR_INDEX_MAG, mag_mapping_matrix_config);
bhy_mapping_matrix_set(PHYSICAL_SENSOR_INDEX_GYRO, bhy_mapping_matrix_config);
/* This sic matrix setting affects magnetometer fusion performance. */
bhy_set_sic_matrix(sic_array);
/* install the callback function for parse fifo data */
if(bhy_install_sensor_callback(VS_TYPE_ROTATION_VECTOR, VS_WAKEUP, sensors_callback_rotation_vector))
{
//DEBUG("Fail to install sensor callback\n");
}
/* enables the virtual sensor */
if(bhy_enable_virtual_sensor(VS_TYPE_ROTATION_VECTOR, VS_WAKEUP, ROTATION_VECTOR_SAMPLE_RATE, 0, VS_FLUSH_NONE, 0, 0))
{
//DEBUG("Fail to enable sensor id=%d\n", VS_TYPE_ROTATION_VECTOR);
}
/* continuously read and parse the fifo */
while (1)
{
/* wait until the interrupt fires */
/* unless we already know there are bytes remaining in the fifo */
while (!HAL_GPIO_ReadPin(BHI160_INT_GPIO_Port, BHI160_INT_Pin) && !bytes_remaining)
{
}
bhy_read_fifo(fifo + bytes_left_in_fifo, FIFO_SIZE - bytes_left_in_fifo, &bytes_read, &bytes_remaining);
bytes_read += bytes_left_in_fifo;
fifoptr = fifo;
packet_type = BHY_DATA_TYPE_PADDING;
do
{
/* this function will call callbacks that are registered */
result = bhy_parse_next_fifo_packet(&fifoptr, &bytes_read, &fifo_packet, &packet_type);
/* prints all the debug packets */
if (packet_type == BHY_DATA_TYPE_DEBUG)
{
bhy_print_debug_packet(&fifo_packet.data_debug, bhy_printf);
}
/* the logic here is that if doing a partial parsing of the fifo, then we should not parse */
/* the last 18 bytes (max length of a packet) so that we don't try to parse an incomplete */
/* packet */
} while ((result == BHY_SUCCESS) && (bytes_read > (bytes_remaining ? MAX_PACKET_LENGTH : 0)));
bytes_left_in_fifo = 0;
if (bytes_remaining)
{
/* shifts the remaining bytes to the beginning of the buffer */
while (bytes_left_in_fifo < bytes_read)
{
fifo[bytes_left_in_fifo++] = *(fifoptr++);
}
}
}
/* USER CODE BEGIN 3 */
}
}
When my programm jumps into the function it checks the product_id of the sensor and returns * return BHY_SUCCESS;* which means that the I2C connection is working!
Bosch also provides some example code for different sensor readings here. Because i want my rotation data in quaternion's i looked at the rotation_vector_example.c example. There are two functions static void sensors_callback_rotation_vector() and void demo_sensor(), but i cant get this code to work. I put the demo_sensor() in to my main loop and have the Sensor_callback_rotation_vector() in my main.c file. Maybe there is an other way to use this driver? In the documentation they say that the driver helps you in 3 phases to read out data: initialization, configuration and data readout. But i cant figure out how to actually do it!
Solved! Go to Solution.
08-24-2020 06:18 PM
You are currently use HAL_I2C_Master_Transmit + HAL_I2C_Master_Receive to implement I2C read.
Can you try to use the following function?
08-26-2020 04:29 PM
I debugged the program and found some issues i want to share, hopefully they help us to find a solution. It still seems like that the bhy_driver_init(&bhy1_fw) is working fine. After that i have this code where i can also find an error return from the Sensor.
bhy_mapping_matrix_set(PHYSICAL_SENSOR_INDEX_ACC, bhy_mapping_matrix_config);
bhy_mapping_matrix_set(PHYSICAL_SENSOR_INDEX_MAG, mag_mapping_matrix_config);
bhy_mapping_matrix_set(PHYSICAL_SENSOR_INDEX_GYRO, bhy_mapping_matrix_config);
After the Matrix was set up, it tries to write the parameter page to the Sensor with the function bhy_write_parameter_page(). Within this function it selects the parameter and reads the acknowledgments.
BHY_RETURN_FUNCTION_TYPE bhy_write_parameter_page(uint8_t page, uint8_t parameter, uint8_t *data, uint8_t length)
{
/* variable used for return the status of communication result */
BHY_RETURN_FUNCTION_TYPE com_rslt = BHY_COMM_RES;
uint8_t v_parameter_ack = BHY_INIT_VALUE;
uint8_t v_parameter_ack_check = BHY_INIT_VALUE;
/* write values to the load address*/
if (length > MAX_WRITE_BYTES)
{
length = MAX_WRITE_BYTES;
}
else if (length == 0)
{
return BHY_SUCCESS;
}
com_rslt = bhy_write_reg(BHY_I2C_REG_PARAMETER_WRITE_BUFFER_ZERO, data, length);
/* select the page*/
if (page > MAX_PAGE_NUM)
{
page = MAX_PAGE_NUM;
}
else if (page == 0)
{
return BHY_SUCCESS;
}
page = ((length & 0x07) << 4) | page;
com_rslt += bhy_write_reg(BHY_I2C_REG_PARAMETER_PAGE_SELECT__REG, &page, 1);
/* select the parameter*/
parameter |= 0x80;
com_rslt += bhy_set_parameter_request(parameter);
for (v_parameter_ack_check = BHY_INIT_VALUE;
v_parameter_ack_check < BHY_PARAMETER_ACK_LENGTH;
v_parameter_ack_check++)
{
/* read the acknowledgment*/
com_rslt += bhy_get_parameter_acknowledge(&v_parameter_ack);
if (v_parameter_ack == parameter)
{
com_rslt += BHY_SUCCESS;
break;
}
else if (v_parameter_ack == BHY_PARAMETER_ACK_CHECK)
{
bhy_delay_msec(BHY_PARAMETER_ACK_DELAY);
com_rslt += BHY_ERROR;
}
else
{
/* device not ready yet */
bhy_delay_msec(1);
}
}
return com_rslt;
}
But when it reads the acknowledgments it alwas ends up in an error executing this line com_rslt += BHY_ERROR; . This is the same for all three matrix mapping functions.
I am facing the same problem with the function bhy_enable_virtual_sensor(). It uses the function bhy_write_parameter_bytes(); which trys to write the parameter bytes to the sensor and check the acknowledgments afterwards. So this Function causes the error which returns -18 for the function bhy_enable_virtual_sensor().
I guess my write/read operation is still not working properly. i tried to implement the read function with the function HAL_I2C_Mem_Read() like this.
int8_t sensor_i2c_read(uint8_t slave_address7, uint8_t subaddress, uint8_t *pBuffer, uint16_t ReadNumbr)
{
uint16_t DevAddress = slave_address7 << 1;
HAL_StatusTypeDef status = HAL_OK;
status = HAL_I2C_Mem_Read(&hi2c1, DevAddress, (uint16_t)subaddress, I2C_MEMADD_SIZE_8BIT, pBuffer, ReadNumbr, HAL_MAX_DELAY);
if(status != HAL_OK)
{
HAL_Delay(1);
}
return 0;
}
With my logic analyzer i created a capture file of my i2c transactions, hopefully you can see anything in there.
08-26-2020 08:04 PM
Hello...Which microcontroller you should buy very much depends on what you are trying to do with it.Do you actually need a 180MHz M4 with LCD and SDRAM controller?If you don't need a lot of processing power your may also want to consider the less complex Cortex M0+ products. (eg. STM32L0, ATSAMD21, LPC8xx etc)
ST, Atmel and NXP all have cheap and readily available eval boards and software tools available.
08-26-2020 11:54 PM
When reading your log, i found one thing, each write function, you write one more byte as expect.
For example, for the bhy reset function, we need to write 0x01 to register 0x9B. But actually in your log, you write 01, 00 to the sensor.
Here it will not impact the result since reset will take effect from the first byte written into sensor.
But when we call write parameter page, the parameter page only accept 8 bytes, and you are trying to write 9 bytes.
Can you try to look into this first?
08-27-2020 06:13 AM
Pls try this. It works well on my side.
int8_t sensor_i2c_write(uint8_t addr, uint8_t reg, uint8_t *p_buf, uint16_t size)
{
if(HAL_I2C_Mem_Write(&hi2c1,(uint16_t)addr*2,(uint16_t)reg, I2C_MEMADD_SIZE_8BIT, p_buf, size,50))
return BHY_ERROR;
else
return BHY_SUCCESS;
}
int8_t sensor_i2c_read(uint8_t addr, uint8_t reg, uint8_t *p_buf, uint16_t size)
{
if(HAL_I2C_Mem_Read(&hi2c1,(uint16_t)addr*2,(uint16_t)reg, I2C_MEMADD_SIZE_8BIT, p_buf, size,50))
return BHY_ERROR;
else
return BHY_SUCCESS;
}