锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

加速度传感器(STK8321)的初始化

时间:2022-12-03 20:30:00 二向高g值加速度传感器采用3轴加速度传感器

阅读STK8321的数据手册,我们知道STK8321是一颗具有 ±2g/±4g/±8g支持三轴线加速度传感器i2c和spi接口通信具有极低的电流消耗(微安级)和32级深度FIFO,各种电子设备应用广泛。
我在这里将其应用于智能手镯,主控MCU采用NRF52832,通过SPI读取3轴加速度数据,进行常规步行统计、方向识别等。根据使用场景的要求,需要对其进行检查STK8321设置在低功耗模式下,等时采样FIFO通过中断信号通知主芯片NRF52832读取FIFO缓存。

软件流程如下:
一、初始化相关GPIO管脚
2,初始化MCU的SPI接口及中断配置
三、传感器检测
四、传感器配置
5,NRF52832中断读取FIFO
6,NRF52832数据处理
七、异常检测处理

详细代码:
1,GPIO相关,包含SPI的SCK, MISO,MOSI,CS,在电源控制管脚初始化之前,将所有管脚设置为输出低电平并延迟一段时间,以释放芯片和管脚上的残余电量。

    /** * Init SPI Pin of Platform */  /** * SPI MOSI */  nrf_gpio_cfg(             BMA_SPI_MOSI_PIN,             NRF_GPIO_PIN_DIR_OUTPUT,             NRF_GPIO_PIN_INPUT_DISCONNECT,             NRF_GPIO_PIN_PULLUP,             NRF_GPIO_PIN_S0S1,             NRF_GPIO_PIN_NOSENSE);       nrf_gpio_pin_clear(STK_SPI_MOSI_PIN);   /** * SPI SCL */  nrf_gpio_cfg(             BMA_SPI_SCL_PIN,             NRF_GPIO_PIN_DIR_OUTPUT,             NRF_GPIO_PIN_INPUT_DISCONNECT,             NRF_GPIO_PIN_PULLUP,             NRF_GPIO_PIN_S0S1,             NRF_GPIO_PIN_NOSENSE);       nrf_gpio_pin_clear(STK_SPI_SCL_PIN);    /** * SPI MISO */      nrf_gpio_cfg(             BMA_SPI_MISO_PIN,             NRF_GPIO_PIN_DIR_OUTPUT,             NRF_GPIO_PIN_INPUT_DISCONNECT,             NRF_GPIO_PIN_PULLUP,             NRF_GPIO_PIN_S0S1,             NRF_GPIO_PIN_NOSENSE);   nrf_gpio_pin_clear(STK_SPI_MISO_PIN);        /** SPI CS */  nrf_gpio_cfg_output(STK_SPI_CS_PIN);  nrf_gpio_pin_clear(STK_SPI_CS_PIN);     /** POWER PIN */  nrf_gpio_cfg_output(STK_POWER_PIN);  cil_power_down();    nrf_delay_ms(50); 

2,初始化SPI,及MCU中断配置,SPI采用硬件SPI,上升沿触发是中断触发的类型。

 nrf_gpio_cfg_output(BMA_POWER_PIN);  cil_power_down();    nrf_deay_ms(50);
	
	cil_power_on();
	nrf_delay_ms(5);	
	
	nrf_gpio_pin_set(BMA_SPI_MOSI_PIN);
	nrf_gpio_pin_set(BMA_SPI_SCL_PIN);
	nrf_gpio_pin_set(BMA_SPI_CS_PIN);
	
	/** * SPI MISO */	
    nrf_gpio_cfg(
            BMA_SPI_MISO_PIN,
            NRF_GPIO_PIN_DIR_INPUT,
            NRF_GPIO_PIN_INPUT_CONNECT,
            NRF_GPIO_PIN_PULLUP,
            NRF_GPIO_PIN_S0S1,
            NRF_GPIO_PIN_NOSENSE);

    /** * Init INT of Platform */ 
	nrf_gpio_pin_pull_t config = NRF_GPIO_PIN_PULLDOWN;
    nrf_gpio_cfg_input(STK_INT2_PIN, config);
	
	// GPIOTE0 chanenl 0 as event
	// for GPIO pin STK_INT2_PIN (23)
	// Rasing trigger interrupt
    NRF_GPIOTE->CONFIG[0] = 1 << 0
                     |(STK_INT2_PIN << 8)
                     |(1 << 16);
	// Enable interrupt
	NRF_GPIOTE->INTENSET = 0x1;
	  
	// Set interrupt priority
    NVIC_SetPriority(GPIOTE_IRQn, 1);
    NVIC_ClearPendingIRQ(GPIOTE_IRQn);
    NVIC_EnableIRQ(GPIOTE_IRQn);
    
    /** * Init SPI of Platform */
	spi_configure(NRF_SPI0, STK_SPI_SCL_PIN, STK_SPI_MOSI_PIN, STK_SPI_MISO_PIN);

SPI分为两层,下层对接NRF52832硬件SPI接口,上层对接STK8321的调用:

static signed char STK_SPI_bus_write(unsigned char dev_addr,
	unsigned char reg_addr, unsigned char *reg_data, unsigned char cnt)
{ 
       
	int iError = 0;
	unsigned int i = 0;

	CS_STK_ENABLE();
	NRF_SPI0->ENABLE = 1; 
    
	//When 0, the data SDI is written into the chip
	spi_transfer( NRF_SPI0, (reg_addr)|0x00 ); 
	for( i = 0; i < cnt; i++ )
	{ 
       
		spi_transfer( NRF_SPI0, reg_data[i]);
	}
    
    NRF_SPI0->ENABLE = 0;
	CS_STK_DISABLE();
	return (signed char)iError;
}

static signed char STK_SPI_bus_read(unsigned char dev_addr, 
	unsigned char reg_addr, unsigned char *reg_data, unsigned char cnt)
{ 
       
	int iError = 0;
	unsigned int i = 0;
	CS_STK_ENABLE();
	 
    NRF_SPI0->ENABLE = 1; 
    
	//When 1, the data SDO from the chip is read.
	spi_transfer( NRF_SPI0, (reg_addr)|0x80); 
	for ( i = 0; i < cnt; i++ )
	{ 
       
		reg_data[i] = spi_transfer( NRF_SPI0, 0xff) & 0xFF;
	}

	NRF_SPI0->ENABLE = 0;	
	CS_STK_DISABLE();
	return (signed char)iError;
}

void stk8321_spi_write_reg(unsigned char reg_addr, unsigned char reg_data)
{ 
       
	STK_SPI_bus_write(STK832x_slave_addr, reg_addr, &reg_data, 1);
}

void stk8321_spi_read_reg(unsigned char reg_addr, unsigned char* reg_data,unsigned char len)
{ 
       	
	STK_SPI_bus_read(STK832x_slave_addr, reg_addr, reg_data, len);
}

3,传感器检测,主要是通过读取芯片ID,来判断SPI通讯是否成功。

uint8_t get_chip_id_stk8321(void)
{ 
       
	uint8_t chip_id = 0;
	
	stk8321_spi_read_reg(0x00, &chip_id,1);    
    
    return chip_id;
}

STK8321的寄存器0x00为只读类型,它的值就是芯片ID,根据手册,它的值为0x23,只要读取到的值一致,说明SPI通讯没问题了。
4,传感器配置,最重要、最繁琐的步骤,需要仔细的阅读芯片手册。

int stk8321_init( void )
{ 
       
    unsigned char  cnt = 0;
    unsigned char BackRead = 0;
	
	stk8321_error_cnt = 0;
			
	stk8321_spi_write_reg(0x14,0xB6); // soft reset
	nrf_delay_ms(10);
	
	cnt = 0;
    do{ 
       
        stk8321_spi_write_reg(0x00,0x23);  
		stk8321_spi_read_reg (0x00, &BackRead,1);
	}while( BackRead != 0x23 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;

	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x0F,0x03); // set Range +/= 2G
		stk8321_spi_read_reg (0x0F, &BackRead,1);
	}while( BackRead != 0x03 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
         
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x20,0x04); // push-pull, active high
		stk8321_spi_read_reg (0x20, &BackRead,1);
	}while( BackRead != 0x04 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x27,0x00);
		stk8321_spi_read_reg (0x27, &BackRead,1);
	}while( BackRead != 0x00 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x28,0x14);
		stk8321_spi_read_reg (0x28, &BackRead,1);
	}while( BackRead != 0x14 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x16,0x07);
		stk8321_spi_read_reg (0x16, &BackRead,1);
	}while( BackRead != 0x07 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;

	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x2A,0x04);
		stk8321_spi_read_reg (0x2A, &BackRead,1);
	}while( BackRead != 0x04 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
      
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x19,0x04);
		stk8321_spi_read_reg (0x19, &BackRead,1);    
	}while( BackRead != 0x04 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;

	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x17,0x40); // enable fifo watermark interrupt
		stk8321_spi_read_reg (0x17, &BackRead,1);
	}while( BackRead != 0x40 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x1A,0x40); // fifo interrupt mapping to INT2
		stk8321_spi_read_reg (0x1A, &BackRead,1);
	}while( BackRead != 0x40 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x3D,FIFO_DEPTH); // FIFO watermark level, max. is 16
		stk8321_spi_read_reg (0x3D, &BackRead,1);
	}while( BackRead != FIFO_DEPTH && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
	
	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x3E,0xC0); // FIFO mode selection, set FIFO buffer in stream mode
		stk8321_spi_read_reg (0x3E, &BackRead,1);
	}while( BackRead != 0xC0 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;

	cnt = 0;
    do{ 
       
		stk8321_spi_write_reg(0x11,0x76); // set low-power mode ODR~34Hz (sleep dur=25ms), equidistant sampling mode for fifo
		stk8321_spi_read_reg (0x11, &BackRead,1);
	}while( BackRead != 0x76 && (++cnt<32));
    if( cnt >= 32 )
      stk8321_error_cnt++;
	
    return ( stk8321_error_cnt != 0 )?(-1):(0);    
}

每个寄存器的配置,都采用写入-读取-验证的方式,以确保写入成功,写入失败后,可以继续尝试32次,增加一定的容错处理。

5,当以上步骤完成时,STK8321就可以进入正常工作, 它会每隔25ms采集一个XYZ数据,存放在FIFO寄存器中,当采集满16组数据后,STK8321会在中断引脚上输出一个高电平信号,MCU捕捉到这信号之后即可读取FIFO数据:

int stk8321_read_accel_xyz_fifo(struct stk8321_accel_data_fifo * fifo_buffer, int length)
{ 
       
	int com_rslt = 0;
    
	stk8321_spi_read_reg( 0x3F, gsensor_buff, FIFO_DEPTH*6);
	
	for ( int j = 0; j < FIFO_DEPTH; j++ )
	{ 
       
		fifo_buffer[j].x = (gsensor_buff[(j*6)+1] *16) + (gsensor_buff[j*6]/16);
		fifo_buffer[j].y = (gsensor_buff[(j*6)+3] *16) + (gsensor_buff[(j*6)+2]/16);
		fifo_buffer[j].z = (gsensor_buff[(j*6)+5] *16) + (gsensor_buff[(j*6)+4]/16);
		
		if(fifo_buffer[j].x>2047)
			fifo_buffer[j].x = fifo_buffer[j].x-4096;
		if(fifo_buffer[j].y>2047)
			fifo_buffer[j].y = fifo_buffer[j].y-4096;
		if(fifo_buffer[j].z>2047)
			fifo_buffer[j].z = fifo_buffer[j].z-4096;
        fifo_buffer[j].x /= 1; fifo_buffer[j].y /= 1; fifo_buffer[j].z /= 1;
	}
	
	return com_rslt;
}

6,至此,程序已经拿到三轴原始数据,可以将该原始数据传入具体的算法去处理。

7,实际使用中,STK8321有可能会出现故障,例如中断的频率变快、或中断信号消失,我们需要一个机制检测这种情况,作出相应的处理。 我这里采用的是监控中断周期的方法,即程序记录一段时间内的中断个数,正常来说,中断个数应该保持一个固定的数,一旦超出了范围,即认为发生了错误,可以对传感器进行重新复位初始化,使之恢复正常。代码片段:

	/** Read the 3-accel data from fifo buffer */
	stk8321_read_accel_xyz_fifo((struct stk8321_accel_data_fifo *)fifo_buf, FIFO_DEPTH*6 );
	/** * Less than 8*50=400ms indicate a error ocurr, we * need to re-configure the gsensor. */
	d4time = osal_systemClock - stepInterruptTime ;
	
	stepInterruptTime = osal_systemClock;
	
    if ( (d4time < (8-1)) || (d4time > 10) ) /* 8*system tick(50ms) = 400ms */
	{ 
       
		osal_set_event( task_id, TASK_STEP_BMA_RE_INIT_EVT );
		return ( events ^ STEP_TASK_DECT_EVT );
	}

频率过慢过快,或者5秒内没有任何中断信号产生,程序需要对STK8321重新初始化。

	/*************************************************************************** * * * To reiniatize the gsensor stk8321(or bma250e) if it not interruption * * out of 5s * * * ***************************************************************************/	
	if ( events & TASK_STEP_STK8321_RE_INIT_EVT )
	{ 
       		
		osal_start_timerEx( task_id, TASK_STEP_STK8321_RE_INIT_EVT , 5000);	
		 
		stk8321_init();
		
		return ( events ^ TASK_STEP_BMA_RE_INIT_EVT ); 
	}

上面的仅仅介绍了数据采集流程,具体参数如何配置,需要根据自己的业务需求配合datasheet才行。

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章