Post Go back to editing

The adxl367 uses fifo, non-interruptible mode, and is unable to obtain a specified number of data

Thread Summary

The user is experiencing unexpected FIFO behavior with the ADXL367 in stream mode, where 513 data entries are observed instead of the expected 192 (64 samples per axis). The final answer clarifies that the FIFO_SAMPLES register should be set to 64 to trigger the watermark after 192 samples, and suggests reading from the hold register down to FIFO[385] to get the latest 128 samples. The accompanying answers confirm that the FIFO will be full with 513 values if not managed correctly, and recommend checking the overrun bit to avoid losing data.
AI Generated Content
Category: Datasheet/Specs
Product Number: adxl367

I use the FIFO of ADXL367 and set it to stream mode, hoping to save 64 sets of X, Y, and Z-axis data with a sampling frequency of 400Hz. I poll the FIFO data every 1 second (without using interrupts), but I always find 513 data entries when reading the FIFO, which is inconsistent with the manual description. How should I configure it to achieve my desired functionality?

 

this is my code 

uint16_t adx1367_get_fifo_xyz(uint16_t *buff)
{
uint8_t data_buff[512 * 2] = {0};
uint16_t fifo_entries = 0;
uint8_t reg_val[2] = {0};

adxl367_get_register_value(&reg_val[0], ADXL367_REG_STATUS, 1);
if(reg_val[0] & 1 << 2){
adxl367_get_register_value(reg_val, ADXL367_REG_FIFO_ENTRIES_L, 2);
fifo_entries = ((reg_val[1] & 0x03) << 8) | reg_val[0];
if((0 == fifo_entries)){
return 0;
}

adxl367_get_register_value(data_buff, ADXL367_REG_I2C_FIFO_DATA, fifo_entries);
fifo_entries = (fifo_entries > SAMPLE_DEFAULT_AXI_HZ*6 ? SAMPLE_DEFAULT_AXI_HZ*6:fifo_entries);
for(int index = 0; index < fifo_entries; index++){
buff[index] = (data_buff[index * 2] << 6) + (data_buff[index*2 + 1] >> 2);
}
return fifo_entries;
}

return 0;
}

void adxl367_fifo_setup(void)
{
sample_mode_info_t *p_sample = NULL;
uint8_t reg_value = 0;

p_sample = sample_config_get();

// Set fifo stream mode
adxl367_get_register_value(&reg_value, ADXL367_REG_FIFO_CONTROL, 1);
reg_value &= ~(3);
reg_value |= ADXL367_STREAM_MODE;

// Set fifo sample x,y,z
reg_value &= ~(0x0F << 3);

// set fifo sample 64/1
reg_value &= ~(1 << 2);
adxl367_set_register_value(reg_value, ADXL367_REG_FIFO_CONTROL);


// set fifo sample 64/1
reg_value = 0;
adxl367_get_register_value(&reg_value, ADXL367_REG_FIFO_SAMPLES, 1);
reg_value = p_sample->sample_axi_hz;
adxl367_set_register_value(reg_value, ADXL367_REG_FIFO_SAMPLES);
}

Thread Notes

  • Hello  thanks for reaching us!

    What kind of configuration do you want to achieve? 



    Taking also into account the holding reg, you can read 513 values (sets of data of 2 bytes, FIFO watermark and FIFO ENTRIES only track the 512 inside the FIFO memory)

    In stream mode after 1 second, the FIFO will be full with data (mix of new and old data) if you do not follow the watermark bit you will lose the oldest data available, you can also check the overrun bit.

    On a first sight, the behavior of the part and your code are both consistent.

    Let me know how I can help you achieving a different functionality.

    have a nice week,

    Mario SM

  • Hello Mario SM,

    Hello, it's great that you can help me.

    My intended purpose is to read the latest 64*2 sets of three-axis data from the FIFO, as configured in my setup: I have configured the FIFO in stream mode, set the FIFO_SAMPLES register to 64, and set the ODR to 400Hz. Of course, I'm not using interrupts but polling once per second to read data.

    I believed that when reading from the FIFO via I2C, there should be 64*2 sets of three-axis data, with older data being discarded; however, in practice, I observe that the FIFO is always full (513 data points) when I read it, which is confusing to me. Could you help explain this?

    My requirement is to poll the FIFO once per second to read data, and I expect the FIFO to keep only the latest 64 sets of data in the FIFO.

    Here is my detailed code.

    #include <stdlib.h>
    #include "adxl367.h"
    #include "nrf_drv_twi.h"
    #include "sample_mode.h"
    #include "nrf_delay.h"
    
    static const nrf_drv_twi_t * p_twi;
    
    uint32_t adxl367_set_register_value(uint8_t register_value, uint8_t register_address)
    {
    	uint8_t buffer[2] = {0};
    	buffer[0] = register_address;
    	buffer[1] = register_value;
    
    	return nrf_drv_twi_tx(p_twi, I2C_AXI_ADDR, buffer, 2, false);
    }
    
    uint32_t adxl367_get_register_value(uint8_t* read_data, uint8_t register_address, uint8_t register_nb)
    {
    	int ret = 1;
    	uint8_t buffer[64] = {0};
    	
    	if (register_address > ADXL367_REG_STATUS_2)
    		return ret;
    	
    	ret = nrf_drv_twi_tx(p_twi, I2C_AXI_ADDR, &register_address, 1, false);
    	if (ret)
    		return ret;
    	
    	ret = nrf_drv_twi_rx(p_twi, I2C_AXI_ADDR, buffer, register_nb);
    	if (ret)
    		return ret;
    	
    	for(int index = 0; index < register_nb; index++)
    		read_data[index] = buffer[index];
    
    	return 0;
    }
    
    int adx1367_get_raw_xyz(uint16_t* x, uint16_t* y, uint16_t* z)
    {
    	uint8_t xyz_values[3] = {0};
    	uint8_t reg_data = 0;
    
    	adxl367_get_register_value(&reg_data, ADXL367_REG_STATUS, 1);
    	if(reg_data & 1){
    		adxl367_get_register_value(xyz_values, ADXL367_REG_XDATA, 3);	
    		*x = xyz_values[0] << 6;	
    		*y = xyz_values[1] << 6;	
    		*z = xyz_values[2] << 6;
    
    		if(*x & 0x2000){
    			*x |= 0xC000;
    		}
    
    		if(*y & 0x2000){
    			*y |= 0xC000;
    		}
    
    		if(*z & 0x2000){
    			*z |= 0xC000;
    		}
    	}
    	else{
    		*x = 0;
    		*y = 0;
    		*z = 0;
    	}
    	return 0;
    }
    
    uint16_t adx1367_get_fifo_xyz(uint16_t *buff)
    {
    	uint8_t data_buff[512 * 2] = {0};
    	uint16_t fifo_entries = 0;
    	uint8_t reg_val[2] = {0};
    
    	adxl367_get_register_value(&reg_val[0], ADXL367_REG_STATUS, 1);
    	if(reg_val[0] & 1 << 2){
    		adxl367_get_register_value(reg_val, ADXL367_REG_FIFO_ENTRIES_L, 2);
    		fifo_entries = ((reg_val[1] & 0x03) << 8) | reg_val[0];
    		if((0 == fifo_entries)){
    			return 0;
    		}
    		
    		adxl367_get_register_value(data_buff, ADXL367_REG_I2C_FIFO_DATA, fifo_entries);
    		fifo_entries = (fifo_entries > SAMPLE_DEFAULT_AXI_HZ*6 ? SAMPLE_DEFAULT_AXI_HZ*6:fifo_entries);
    		for(int index = 0; index < fifo_entries; index++){
    			buff[index] = (data_buff[index * 2] << 6) + (data_buff[index*2 + 1] >> 2);
    		}
    		return fifo_entries;
    	}
    	
    	return 0;
    }
    
    void adxl367_fifo_setup(void)
    {
    	sample_mode_info_t *p_sample = NULL;
    	uint8_t reg_value = 0;
    
    	p_sample = sample_config_get();
    	
    	// Set fifo stream mode
    	adxl367_get_register_value(&reg_value, ADXL367_REG_FIFO_CONTROL, 1);
    	reg_value &= ~(3);
    	reg_value |= ADXL367_STREAM_MODE;
    
    	// Set fifo sample x,y,z
    	reg_value &= ~(0x0F << 3);
    
    	// set fifo sample 64
    	reg_value &= ~(1 << 2);
    	adxl367_set_register_value(reg_value, ADXL367_REG_FIFO_CONTROL);
    
    
    	// set fifo sample 64
    	reg_value = 0;
    	adxl367_get_register_value(&reg_value, ADXL367_REG_FIFO_SAMPLES, 1);
    	reg_value = p_sample->sample_axi_hz;
    	adxl367_set_register_value(reg_value, ADXL367_REG_FIFO_SAMPLES);
    }
    
    int adxl367_start(void)
    {
    	int status = 0;
    	uint8_t reg_value = 0;
    
    	//adxl367_fifo_setup();
    	
    	// set measure mode
    	adxl367_get_register_value(&reg_value, ADXL367_REG_POWER_CTL, 1);
    	reg_value &= ~(3);
    	reg_value |= 2;
    	
    	status = adxl367_set_register_value(reg_value, ADXL367_REG_POWER_CTL);
    	if (status)
    		return -1;
    
    	nrf_delay_ms(100);
    	return 0;
    }
    
    int adxl367_stop(void)
    {
    	int status;
    	uint8_t reg_value = 0;
    	reg_value = 0;
    	adxl367_get_register_value(&reg_value, ADXL367_REG_POWER_CTL, 1);
    
    	// set standby mode
    	reg_value &= ~(3);
    	status = adxl367_set_register_value(reg_value, ADXL367_REG_POWER_CTL);
    	if (status)
    		return -1;
    
    	nrf_delay_ms(50);
    	return 0;
    }
    
    int ADXl367_Init(nrf_drv_twi_t *hi2c)
    {
    	int status;
    	uint8_t reg_value = 0;
    	
    	p_twi = NULL;
    	if(NULL == hi2c)
    		return -1;
    
    	p_twi = hi2c;
    	
    	/* Perform soft reset */
    	status = adxl367_set_register_value(ADXL367_RESET_KEY, ADXL367_REG_SOFT_RESET);
    	if (status)
    		return -1;
    
    	nrf_delay_ms(20);
    
    	// check device id
    	adxl367_get_register_value(&reg_value, ADXL367_REG_DEVID_AD, 1);
    	if (reg_value != ADXL367_DEVICE_AD)
    		return -1;
    
    	adxl367_get_register_value(&reg_value, ADXL367_REG_PARTID, 1);
    	if (reg_value != ADXL367_PART_ID)
    		return -1;
    	
    	// set device output speed 200Hz and range to 4G
    	reg_value = 0;
    	adxl367_get_register_value(&reg_value, ADXL367_REG_FILTER_CTL, 1);
    	reg_value &= ~(3 << 6);
    	reg_value |= (1 << 6);
    	reg_value &= ~7;
    	reg_value |= 4;
    	status = adxl367_set_register_value(reg_value, ADXL367_REG_FILTER_CTL);
    	if (status)
    		return -1;
    
    	return 0;
    }
    

  • Hello  I am glad to help :)

    I believed that when reading from the FIFO via I2C, there should be 64*2 sets of three-axis data, with older data being discarded; however, in practice, I observe that the FIFO is always full (513 data points) when I read it, which is confusing to me. Could you help explain this?

    This is how the stream mode is expected to work, use this application note as reference: AN-1025: Utilization of the First In, First Out (FIFO) Buffer in Analog Devices, Inc. Digital Accelerometers | Analog Devices

    To read the latest 128 samples (almost 42 samples per axis), then you should read from the hold register down to FIFO[385]. (FIFO[0] contains the oldest sample, and FIFO [511] the latest)

    I would also note that writing a 64 in FIFO_SAMPLES while recording 3 axis while lead you to fire the watermark after 192 samples. (64 per axis)



    hope this helps,

    Mario SM

  • Hello Mario SM 

    Hey, thanks a lot for the detailed explanation.

    I see where you're coming from, and I think there might have been a slight misunderstanding on my part. Let me try to clarify exactly what I'm trying to achieve.

    My goal is to set up a system where I poll the FIFO for data every 1 second. In a perfect world, when I read it, the FIFO would only ever contain the absolute latest 192 data points (that's 64 samples for each of the 3 axes).

    To be completely clear on my setup and thought process, I have configured the FIFO in 'stream mode'. I've set the FIFO_SAMPLES register to 64 and the ODR to 400Hz. My expectation was that after one second, there would be exactly 64*3 (192) three-axis samples waiting in the FIFO, and no more.

    My understanding was that the FIFO_SAMPLES register is precisely for limiting the number of samples stored, but it doesn't seem to be working as I expected. Just to be specific, I am not using watermark interrupts—though I've noticed that when an interrupt does fire, the buffer does happen to contain 192 points. What I want, however, is for the FIFO to constantly maintain those 192 most recent points at all times, ready for me to poll.

    I'm probably missing something fundamental, but I'd really appreciate an authoritative explanation of how to get this behavior.

  • Hello  excuse me seems like I am not getting notified for the updates on the asian MEMS forum.

    Hope you had a great weekend,

    I am afraid that there is no way to make the FIFO work in the way you need, it will always get completely filled.

    Interrupt + host logic is the only way to simulate fixed-sample capture, using the FIFO watermark/fifo_samples and disabling the FIFO after receiving the interruption. But this process would be non-autonomous since it must be completely driven by the host cpu.

    In any case I must insist that in stream mode you will always have available the latest 192 samples, the rest of older data that you can just ignore.

    hope this helps somehow,

    Mario SM