最近的一次项目中使用到了ADI的三轴加速度传感器ADXL362,出现了一些问题,这里做一下总结,问题包括这几点:
1. 从spi读取的数据一直为0
2. 随后读取芯片ID正常,但是读取加速度一直为0
3. 第一次读取加速值为0,第一次之后就正常了
以上的问题,都跟spi配置相关。
ADXL362是一款不错的三轴加速度传感器,他的特性包括:
* 1.8 µA @ 100 Hz ODR、2.0 V电源
* 3.0 µA @ 400 Hz ODR、2.0 V电源
* 270 nA运动唤醒模式
* 10 nA待机电流
* 分辨率 1mg/LSB
可谓是功耗非常低,ADLX362支持SPI的通信方式。本节内容讨论ADLX362 SPI的相关配置内容。
通过数据手册可以知道ADLX362 SPI遵循模式为* CPHA = CPOL = 0 *(不工作时,时钟状态是低电平;在上升沿即第一个时钟沿采样数据)

数据手册中还提到,SPI操作使用多字节结构,第一个字节是命令。
* 0x0A 写入寄存器
* 0x0B 读取寄存器
* 0x0D 读取FIFO
也就是说在配置寄存器时,要先发送0x0A,紧接着是地址,然后是所要写入的内容,这样设备才能够确认是要写入寄存器。
而要读出寄存器内容时,要先发送0x0B,然后是地址,这样才能读出寄存器内容(以往好多设备是以地址的最高位来判断读写的,通常最高位是1就是读;最高位是0,表示写,这里有点不同)
如果是从fifo中读取加速度的值,需要先发送0x0D,紧接着就是读取数据了。
本适合使用stm32 提供的HAL库,初始化函数为:
void spi1_init(void)
{
SpiHandle_1.Instance = SPI1;
SpiHandle_1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; //2.5MHZ
SpiHandle_1.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle_1.Init.CLKPhase = SPI_PHASE_1EDGE; //SPI_PHASE_1EDGE
SpiHandle_1.Init.CLKPolarity = SPI_POLARITY_LOW; //SPI_POLARITY_LOW
SpiHandle_1.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle_1.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle_1.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle_1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle_1.Init.CRCPolynomial = 7;
SpiHandle_1.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
SpiHandle_1.Init.NSS = SPI_NSS_SOFT;
SpiHandle_1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
//master mode
SpiHandle_1.Init.Mode = SPI_MODE_MASTER;
if(HAL_SPI_Init(&SpiHandle_1) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
}
以及包括
/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance == SPI1)
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO TX/RX clock */
SPI1_SCK_GPIO_CLK_ENABLE();
SPI1_MISO_GPIO_CLK_ENABLE();
SPI1_MOSI_GPIO_CLK_ENABLE();
/* Enable SPI clock */
SPI1_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* SPI SCK GPIO pin configuration */
GPIO_InitStruct.Pin = SPI1_SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN; //GPIO_PULLDOWN
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = SPI1_SCK_AF;
HAL_GPIO_Init(SPI1_SCK_GPIO_PORT, &GPIO_InitStruct);
/* SPI MISO GPIO pin configuration */
GPIO_InitStruct.Pin = SPI1_MISO_PIN;
GPIO_InitStruct.Alternate = SPI1_MISO_AF;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(SPI1_MISO_GPIO_PORT, &GPIO_InitStruct);
/* SPI MOSI GPIO pin configuration */
GPIO_InitStruct.Pin = SPI1_MOSI_PIN;
GPIO_InitStruct.Alternate = SPI1_MOSI_AF;
HAL_GPIO_Init(SPI1_MOSI_GPIO_PORT, &GPIO_InitStruct);
}
}
有两点需要注意的是:
1. 在spi1_init()中,正确配置SPI模式,比如SPI_PHASE_1EDGE,SPI_POLARITY_LOW,这都是adxl362所要求的(时钟低电平,第一个沿采样数据)。
2. 在HAL_SPI_MspInit()中,配置IO相关寄存器,SCK IO 要选择GPIO_PULLDOWN 模式,其他IO选择GPIO_PULLUP模式,否则会出现初次配置adxl寄存器的时候失败,接着读取寄存器正常的情况。
static void Sensor_IO_Write(uint8_t WriteAddr, uint8_t *pBuffer, uint16_t nBytesToWrite )
{
//HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,
// uint32_t Timeout)
uint8_t reg_cmd = 0;
reg_cmd = ADXL362_WRITE_REG;
adxl362_enable();
HAL_SPI_Transmit(&SpiHandle_1, ®_cmd, 1, 1000);
HAL_SPI_Transmit(&SpiHandle_1, &WriteAddr, 1, 1000);
HAL_SPI_Transmit(&SpiHandle_1, pBuffer, nBytesToWrite, 1000);
adxl362_disable();
}
static void Sensor_IO_Read(uint8_t ReadAddr, uint8_t *pBuffer, uint16_t nBytesToRead, uint8_t r_flag)
{
//HAL_SPI_Receive
uint8_t rd_addr = 0;
uint8_t reg_cmd = 0;
rd_addr = ReadAddr;
adxl362_enable();
if(r_flag == ADXL362_READ_REG){
reg_cmd = ADXL362_READ_REG;
HAL_SPI_Transmit(&SpiHandle_1, ®_cmd, 1, 1000);
HAL_SPI_Transmit(&SpiHandle_1, &rd_addr, 1, 1000);
}
if(r_flag == ADXL362_READ_FIFO){
reg_cmd = ADXL362_READ_FIFO;
HAL_SPI_Transmit(&SpiHandle_1, ®_cmd, 1, 1000);
}
HAL_SPI_Receive(&SpiHandle_1, pBuffer, nBytesToRead, 1000);
adxl362_disable();
}
跟使用手册中的操作顺序要一致。
adxl362别的操作就不多写了,按照数据手册配置寄存器,基本没什么问题了。