Part Number: MSPM0G3507
Hello,
I am working with the MSPM0G3507 and trying to drive the SPI in polling (blocking) mode as a master to communicate with an ICM-20948 IMU sensor. However, I am encountering some unexpected bugs during communication.
Here is a snippet of my SPI polling driver code:
HAL_Status DevHAL_SPI_TransmitReceive_4Wire(SPI_Regs *spi, uint8_t *Tx_Buffer, uint8_t *Rx_Buffer, uint32_t Size){
volatile uint32_t timeout = 0xFFFFFFU;
volatile uint8_t RxClean;
while (DL_SPI_isBusy(spi))if (--timeout == 0) return HAL_BUSY;
while (Size > 0){
while (!DL_SPI_isTXFIFOEmpty(spi)) if (--timeout == 0) return HAL_TIMEOUT;
uint8_t fill = (Size > 4) ? 4 : Size;
DL_SPI_fillTXFIFO8(spi, Tx_Buffer, fill);
for (uint8_t i = 0; i < fill; i += 1){
*Rx_Buffer = DL_SPI_receiveDataBlocking8(spi);
Rx_Buffer += 1;
}
Tx_Buffer += fill;
Size -= fill;
}
return HAL_OK;
}
HAL_Status DevHAL_SPI_Transmit_4Wire(SPI_Regs *spi, uint8_t *Tx_Buffer, uint32_t Size){
uint8_t fill = 0;
uint32_t timeout = 0xFFFFFFU;
volatile uint8_t RxClean;
while (DL_SPI_isBusy(spi))if (--timeout == 0) return HAL_BUSY;
while(Size > 0) {
while (!DL_SPI_isTXFIFOEmpty(spi)) if (--timeout == 0) return HAL_TIMEOUT;
Tx_Buffer += fill;
fill = (Size > 4) ? 4 : Size;
DL_SPI_fillTXFIFO8(spi, Tx_Buffer, fill);
Size -= fill;
}
while (DL_SPI_receiveDataCheck8(spi, &RxClean));
return HAL_OK;
}
When I simply use this function to read the sensor's "Who Am I" register, it works fine without any issues. The problem arises when I try to read a longer block of sensor data.
//Part of Code
static inline uint8_t SPI_Transmit(uint8_t *data, uint8_t size) {
return DevHAL_SPI_Transmit_4Wire(SPI0, data, size);
}
static inline uint8_t SPI_Receive(uint8_t *tx_data, uint8_t *rx_data, uint8_t size) {
return DevHAL_SPI_TransmitReceive_4Wire(SPI0, tx_data, rx_data, size);
}
#define ICM_CS_PULLUP __NOP();
#define ICM_CS_PULLDOWN __NOP();
//The code i use for reading WAI
uint8_t ICM_SPIEx_RdReg(uint8_t bank, uint8_t reg, uint8_t *value) {
switch (bank) {
case 0:
ICM_SPI_WriteReg(ICM_REG_BANK_SEL, ICM_BANK_SEL_USER_BANK_0);
break;
case 1:
ICM_SPI_WriteReg(ICM_REG_BANK_SEL, ICM_BANK_SEL_USER_BANK_1);
break;
case 2:
ICM_SPI_WriteReg(ICM_REG_BANK_SEL, ICM_BANK_SEL_USER_BANK_2);
break;
case 3:
ICM_SPI_WriteReg(ICM_REG_BANK_SEL, ICM_BANK_SEL_USER_BANK_3);
break;
default:
return 1;
}
return ICM_SPI_ReadReg(reg, value);
}
uint8_t ICM_SPI_WriteReg(uint8_t reg, uint8_t value) {
uint8_t status = 0;
uint8_t tx_buffer[2] = {reg, value};
ICM_CS_PULLDOWN;
status = SPI_Transmit(tx_buffer, 2);
ICM_CS_PULLUP;
return status;
}
uint8_t ICM_SPI_ReadReg(uint8_t reg, uint8_t *value) {
uint8_t status = 0;
uint8_t tx_buffer[2] = {reg | 0x80, 0x00};
uint8_t rx_buffer[2] = {0, 0};
ICM_CS_PULLDOWN;
status = SPI_Receive(tx_buffer, rx_buffer, 2);
ICM_CS_PULLUP;
*value = rx_buffer[1];
return status;
}
void ICM_DataBurstRead(int16_t *Accel, int16_t *Gyro, int16_t *Temp, int16_t *Mag) {
uint8_t status = HAL_OK;
uint8_t tx_buffer[15] = {0x00};
uint8_t rx_buffer[15] = {0xFF};
tx_buffer[0] = ICM_REG_ACCEL_XOUT_H | 0x80;
ICM_SPI_WriteReg(ICM_REG_BANK_SEL, ICM_BANK_SEL_USER_BANK_0);
ICM_CS_PULLDOWN;
status = SPI_Receive(tx_buffer,rx_buffer,15);
ICM_CS_PULLUP;
Accel[0] = (int16_t)((rx_buffer[1] << 8) | rx_buffer[2]);
Accel[1] = (int16_t)((rx_buffer[3] << 8) | rx_buffer[4]);
Accel[2] = (int16_t)((rx_buffer[5] << 8) | rx_buffer[6]);
Gyro[0] = (int16_t)((rx_buffer[7] << 8) | rx_buffer[8]);
Gyro[1] = (int16_t)((rx_buffer[9] << 8) | rx_buffer[10]);
Gyro[2] = (int16_t)((rx_buffer[11] << 8) | rx_buffer[12]);
*Temp = (int16_t)((rx_buffer[13] << 8) | rx_buffer[14]);
/*
if (Mag != NULL){
Mag[0] = (int16_t)(rx_buffer[16] << 8 | rx_buffer[15]);
Mag[1] = (int16_t)(rx_buffer[18] << 8 | rx_buffer[17]);
Mag[2] = (int16_t)(rx_buffer[20] << 8 | rx_buffer[19]);
}
*/
}
The data read by this code is very strange. I used the debugger and UART to capture some frames. After manual inspection and calculation, I found that some of the data is correct (representing valid Euler angles), but most of the time the data is disordered and cannot be interpreted (garbage values).
I then tried modifying the SPI driver code to:
HAL_Status DevHAL_SPI_TransmitReceive_4Wire(SPI_Regs *spi, uint8_t *Tx_Buffer, uint8_t *Rx_Buffer, uint32_t Size){
volatile uint32_t timeout = 0xFFFFFFU;
volatile uint8_t RxClean;
while (DL_SPI_isBusy(spi))if (--timeout == 0) return HAL_BUSY;
while (DL_SPI_receiveDataCheck8(spi, &RxClean));
while (Size > 0){
while (!DL_SPI_isTXFIFOEmpty(spi)) if (--timeout == 0) return HAL_TIMEOUT;
uint8_t fill = (Size > 4) ? 4 : Size;
DL_SPI_fillTXFIFO8(spi, Tx_Buffer, fill);
for (uint8_t i = 0; i < fill; i += 1){
*Rx_Buffer = DL_SPI_receiveDataBlocking8(spi);
Rx_Buffer += 1;
}
Tx_Buffer += fill;
Size -= fill;
}
return HAL_OK;
}
But a new problem appeared. The SPI communication is not blocked, but the read data is even worse: only the first 5 bytes are correct, and all subsequent bytes read back as 0. I haven't verified whether the first few values are actually valid.
I have previously verified the same ICM-20948 driver code and sensor on an STM32 platform, and everything worked perfectly. So the issue seems to be related to my SPI driver implementation on the MSPM0G3507.
Has anyone encountered similar issues or can provide guidance on what might be going wrong?
Thank you.