cancel
Showing results for 
Search instead for 
Did you mean: 

LSM6DS032 programming finite state machine

mpopko
Associate II

Hi all,

 

I'm trying to move Finite State Machine config from devkit using Unico GUI to final application. I've prepared movement wakeup example from FSM datasheet in Unico, which is working totally fine on devkit, it could even detect knocking in desk.

Zrzut ekranu 2024-02-05 113640.png

static const uint8_t lsm6dso32_prg_wakeup[] = {
    0x50, 0x40, 0x12, 0x20, 0x0C, 0x0D,
    0x00, 0x38, // threshold (1.00)
    0xAE, 0x23, // hyst (0.03)
    0x02, //mask A
    0x02, //temp mask A
    0x41,
    0x75,
    0x10,
    0x10,
    0x22,
    0x00
};

I've tried to replicate example from here: https://community.st.com/t5/mems-sensors/dear-st-community-i-am-currently-trying-to-setup-a-finite-state/td-p/77183

Overall, it doesn't seem to be working, code below gives me infinite interrupts on INT1. So far I discovered on devkit, it happens when fsm is correctly enabled but there is issue in fsm program. It also happens when I comment lsm6dso32_ln_pg_write.

ImuError imuInit(void)
{
	uint8_t id;
	HAL_StatusTypeDef err = HAL_OK;

	// Set the IMU's reset bit and wait for it to clear after a reset
	uint8_t resetValue = 1;
	lsm6dso32_reset_set(&lsm6Context, resetValue);
	do
	{
		lsm6dso32_reset_get(&lsm6Context, &resetValue);
	} while (resetValue);

	if (lsm6dso_device_id_get(&lsm6Context, &id) != HAL_OK)
	{
		return imuInitError;
	}

	if (id != LSM6DSO32_ID)
	{
		return imuUnknownID;
	}

	err = lsm6dso32_i3c_disable_set(&lsm6Context, LSM6DSO32_I3C_DISABLE);
	if (err != HAL_OK)
	{
		return imuInitError;
	}

	err = lsm6dso32_auto_increment_set(&lsm6Context, PROPERTY_ENABLE);
	if (err != HAL_OK)
	{
		return imuInitError;
	}

	err = lsm6dso32_block_data_update_set(&lsm6Context, PROPERTY_ENABLE);
	if (err != HAL_OK)
	{
		return imuInitError;
	}

	err = lsm6dso32_fifo_mode_set(&lsm6Context, LSM6DSO32_BYPASS_MODE);
	if (err != HAL_OK)
	{
		return imuInitError;
	}

	err = lsm6dso32_xl_full_scale_set(&lsm6Context, LSM6DSO32_8g);
	if (err != HAL_OK)
	{
		return imuInitError;
	}

	err = lsm6dso32_gy_full_scale_set(&lsm6Context, LSM6DSO32_1000dps);
	if (err != HAL_OK)
	{
		return imuInitError;
	}
	err = lsm6dso32_xl_data_rate_set(&lsm6Context,
			LSM6DSO32_XL_ODR_26Hz_LOW_PW);
	if (err != HAL_OK)
	{
		return imuError;
	}

	err = lsm6dso32_gy_data_rate_set(&lsm6Context,
			LSM6DSO32_GY_ODR_26Hz_LOW_PW);
	if (err != HAL_OK)
	{
		return imuError;
	}

	sGyroRange = gyro1000dps;

	volatile uint32_t ret = 0;
	lsm6dso32_pin_int1_route_t int1_route = { 0 };
	int1_route.fsm_int1_a.int1_fsm1 = 1;
	ret = lsm6dso32_pin_int1_route_set(&lsm6Context, &int1_route);
	ret = lsm6dso32_long_cnt_int_value_set(&lsm6Context, 0x0000U);
	ret = lsm6dso32_fsm_start_address_set(&lsm6Context, 0x0400U);
	ret = lsm6dso32_fsm_number_of_programs_set(&lsm6Context, 1);
	lsm6dso32_emb_fsm_enable_t fsm_enable = { 0 };
	fsm_enable.fsm_enable_a.fsm1_en = 1;
	ret = lsm6dso32_fsm_enable_set(&lsm6Context, &fsm_enable);
	ret = lsm6dso32_fsm_data_rate_set(&lsm6Context, LSM6DSO32_ODR_FSM_26Hz);
	ret = lsm6dso32_ln_pg_write(&lsm6Context, 0x0400, (uint8_t *)lsm6dso32_prg_wakeup, sizeof(lsm6dso32_prg_wakeup));
	ret = lsm6dso32_fsm_init_set(&lsm6Context, 1);
	ret = lsm6dso32_emb_fsm_en_set(&lsm6Context, 1);

	lsm6dso32_pin_int2_route_t int2_route = { 0 };
	int2_route.int2_ctrl.int2_drdy_g = 1;
	lsm6dso32_pin_int2_route_set(&lsm6Context, &int2_route);

	return imuOk;
}

On MCU side interrupt is setted correctly, I've successfully ran dedicated wkup function like below, however it's not enough senstive for my application.

lsm6dso32_pin_int1_route_t int1_route = { 0 };
int1_route.md1_cfg.int1_wu = 1;
lsm6dso32_pin_int1_route_set(&lsm6Context, &int1_route);
lsm6dso32_wkup_threshold_set(&lsm6Context, 0b00000001);
lsm6dso32_wkup_dur_set(&lsm6Context, 0b00000000);

 Instead of lsm6dso32_ln_pg_write, I've tried to save FSM program byte by byte.

	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x50);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x40);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x12);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x20);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x0C);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x0D);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x00); //thr
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x38); //thr
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0xAE); //hyst
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x23); //hyst
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x02);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x02);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x41);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x75);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x10);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x10);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x22);
	ret = lsm6dso32_ln_pg_write_byte(&lsm6Context, 0x0400, 0x00);

And it seems that it was programmed correctly, however it doesn't bring me any interrupts. When I try to break it, for example commenting last 2 bytes, I get the same infinite interrupts behavior as I mentioned in the beginning.

 

What other cause could there be for the fsm not working properly?

5 REPLIES 5
Federica Bossi
ST Employee

Hi @mpopko ,

We are doing some analysis to better understand which could be the problem. In the meantime can you confirm me that you haven't generated an .ucf file?

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
mpopko
Associate II

Hi @Federica Bossi 

I'm attaching both .fsm and .ucf files which are working fine on devkit. 

mpopko
Associate II

I just wanted to add I've tried different levels of treshold and hysteresis in that final application, there are no any signs of proper functioning.

Hi @Federica Bossi, have you managed to discover anything related?

@Federica Bossi 

I probably found issue in ST library (lsm6dso32_reg.c). Function:

int32_t lsm6dso32_ln_pg_write(stmdev_ctx_t *ctx, uint16_t address,
                              uint8_t *buf, uint8_t len)

Writes first byte in correct address, but next one finds page wrap (1666-1681 lines):

      lsb = (uint8_t)address & 0xFFU;
[...]
    for (i = 0; ((i < len) && (ret == 0)); i++)
    {
      ret = lsm6dso32_write_reg(ctx, LSM6DSO32_PAGE_VALUE, &buf[i], 1);

      /* Check if page wrap */
      if ((lsb == 0x00U) && (ret == 0))
      {
        lsb++;
        msb++;
        ret = lsm6dso32_read_reg(ctx, LSM6DSO32_PAGE_SEL,
                                 (uint8_t *)&page_sel, 1);

        if (ret == 0)
        {
          page_sel.page_sel = msb;
          page_sel.not_used_01 = 1;
          ret = lsm6dso32_write_reg(ctx, LSM6DSO32_PAGE_SEL,
                                    (uint8_t *)&page_sel, 1);
        }
      }
    }

Which results in writting next bytes to next page - so FSM can't find it as it looks at 0x0400 page. Implementation of page wrap is lsm6dso is a little different and it doesn't happen there:

    for (i = 0; ((i < len) && (ret == 0)); i++)
    {
      ret = lsm6dso_write_reg(ctx, LSM6DSO_PAGE_VALUE, &buf[i], 1);
      addr_pointed++;

      /* Check if page wrap */
      if (((addr_pointed % 0x0100U) == 0x00U) && (ret == 0))
      {
        ret = lsm6dso_read_reg(ctx, LSM6DSO_PAGE_SEL, (uint8_t *)&page_sel, 1);

        if (ret == 0)
        {
          page_sel.page_sel = ((uint8_t)(addr_pointed >> 8) & 0x0FU);
          page_sel.not_used_01 = 1;
          ret = lsm6dso_write_reg(ctx, LSM6DSO_PAGE_SEL,
                                  (uint8_t *)&page_sel, 1);
        }
      }
    }

Is this a bug and if not why has it been implemented in this way?