2019-09-25 01:10 PM
I am using an ST Micro MCU via SPI to the LIS3DSH to read x,y,z data(using CubeMX HAL). I can read in single byte mode fine but the multi byte access bit in Control register 6 has no effect. I have tried Control register 6 : ADD_INC disabled or enabled with no difference in behavior. If I request a read starting from a known non-zero address, that same data is just repeated for the number of bytes requested.
LIS3DSH initialization:
transmitData[0] = LIS3DSH_WRITE | LIS3DSH_CTRL_REG6;
transmitData[1] = LIS3DSH_CTRL_REG6_BOOT | LIS3DSH_CTRL_REG6_ADD_INC;
SPISend( transmitData, receiveData, 2);
transmitData[0] = LIS3DSH_WRITE | LIS3DSH_CTRL_REG4;
transmitData[1] = (LIS3DSH_CTRL_REG4_ODR100 << LIS3DSH_CTRL_REG4_ODR_SHIFT)
| LIS3DSH_CTRL_REG4_BDU
| LIS3DSH_CTRL_REG4_Z_EN
| LIS3DSH_CTRL_REG4_Y_EN
| LIS3DSH_CTRL_REG4_X_EN;
SPISend( transmitData, receiveData, 2);
transmitData[0] = LIS3DSH_WRITE | LIS3DSH_CTRL_REG5;
transmitData[1] = (LIS3DSH_CTRL_REG5_BW_800HZ << LIS3DSH_CTRL_REG5_BW_SHIFT)
| (LIS3DSH_CTRL_REG5_FSCALE_2G << LIS3DSH_CTRL_REG5_FSCALE_SHIFT)
| (LIS3DSH_CTRL_REG5_ST_OFF << LIS3DSH_CTRL_REG5_ST_SHIFT)
| LIS3DSH_CTRL_REG5_SIM_4WIRE;
SPISend( transmitData, receiveData, 2);
where:
void SPISend(uint8_t* transmit, uint8_t* receive, uint16_t length) {
HAL_StatusTypeDef status;
HAL_GPIO_WritePin( Accel_SPI_NSS_GPIO_Port, Accel_SPI_NSS_Pin, GPIO_PIN_RESET);
status = HAL_SPI_TransmitReceive( &hspi2, transmit, receive, length, 100);
HAL_GPIO_WritePin( Accel_SPI_NSS_GPIO_Port, Accel_SPI_NSS_Pin, GPIO_PIN_SET);
if (status != HAL_OK) {
Error_Handler();
}
}
My single byte reads:
transmitData[1] = (uint8_t) DUMMY;
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_X_L);
SPISend( transmitData, receiveData, 2);
xl = receiveData[1];
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_X_H);
SPISend( transmitData, receiveData, 2);
xh = receiveData[1];
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_Y_L);
SPISend( transmitData, receiveData, 2);
yl = receiveData[1];
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_Y_H);
SPISend( transmitData, receiveData, 2);
yh = receiveData[1];
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_Z_L);
SPISend( transmitData, receiveData, 2);
zl = receiveData[1];
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_Z_H);
SPISend( transmitData, receiveData, 4);
zh = receiveData[1];
x = (xh << 8) | xl;
y = (yh << 8) | yl;
z = (zh << 8) | zl;
My multi byte read:
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_X_L);
SPISend( transmitData, receiveData, 7);
x = (int16_t) (receiveData[2] << 8) | (int16_t) receiveData[1];
y = (int16_t) (receiveData[4] << 8) | (int16_t) receiveData[3];
z = (int16_t) (receiveData[6] << 8) | (int16_t) receiveData[5];
Since the part supports multi byte reads, it seems that I must be missing something in the part initialization?
My HAL spi initialization is the same on both mcu spi channels and my other spi device (not LIS3DSH) supports multi byte transfers without an issue.
static void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
/* SPI2 parameter configuration*/
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 7;
hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
Any help appreciated.
Thanks,
-Phil
2019-09-25 11:54 PM
HI Phil, according to the ds, the SPI Write command is performed with 16 clock pulses. A multiple byte write command is performed by adding blocks of 8 clock pulses to the previous one. Please consider also that the ADD_INC bit of the CTRL_REG6 (25h) is by default "1", meaning you don't have to change its value for the SPI address increment. How are you setting this bit? Regards
2019-09-26 10:31 AM
Hi Eleon,
The ST Micro HAL method HAL_SPI_TransmitReceive() uses the parameter hspi2.Init.DataSize = SPI_DATASIZE_8BIT; to determine word size. So for single byte transfer(2 words) I send 16 clocks. In my multi byte example above, I send 7*8= 56 clocks.
The bit is set in the initialization code repeated here:
transmitData[0] = LIS3DSH_WRITE | LIS3DSH_CTRL_REG6;
transmitData[1] = LIS3DSH_CTRL_REG6_BOOT | LIS3DSH_CTRL_REG6_ADD_INC;
SPISend( transmitData, receiveData, 2);
where:
#define LIS3DSH_CTRL_REG6 0x25U
#define LIS3DSH_CTRL_REG6_BOOT 0x80U
#define LIS3DSH_CTRL_REG6_FIFO_EN 0x40U
#define LIS3DSH_CTRL_REG6_WTM_EN 0x20U
#define LIS3DSH_CTRL_REG6_ADD_INC 0x10U
I have also tried without the boot bit enabled and also with setting ctrl reg 6 explictly to zero. This has no effect on multi byte transfer response.
for example:
With initialization as above and then later reading a non zero accel register:
transmitData[0] = (uint8_t) (LIS3DSH_READ | LIS3DSH_Z_H);
SPISend( transmitData, receiveData, 4);
Results in:
So the value in LIS3DSH_Z_H is repeated 3 times as (0xc0) rather than stepping forward from address OUT_Z_H (0x2D) to reading FIFO_CTRL(0x2E), FIFO_SRC(0x2F) etc.
It seems that maybe an additional bit needs to be set somewhere?
Thanks,
-Phil