2024-09-03 01:56 AM - edited 2024-09-03 03:52 AM
Hi guys,
I am currently trying to read the value of the WhoAmI register using SPI communication with the ICM42688P, but it returns 0xf3 when it should return 0x47.
Is there something wrong with my program or configuration?
Please tell me about it.
.hpp
#pragma once
#include "arm_math.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_gpio.h"
#include "spi.h"
class IMUICM42688P {
public:
IMUICM42688P(SPI_HandleTypeDef &hspi, GPIO_TypeDef *cs_x, uint16_t cs_pin);
void init();
uint8_t getWhoAmI();
float32_t getAccelX();
float32_t getAccelY();
float32_t getAccelZ();
private:
uint8_t read(const uint8_t address);
void write(const uint8_t address, const uint8_t data);
void setConfigs();
void setAccelConfig();
void setPowerManage();
SPI_HandleTypeDef &_hspi;
GPIO_TypeDef *cs_x_;
const uint16_t cs_pin_;
float32_t accel_range_; // default: 2.0f
float32_t imu_range_;
};
.cpp
#include "halplus/layer_driver/circuit/icm42688p.hpp"
IMUICM42688P::IMUICM42688P(SPI_HandleTypeDef &hspi, GPIO_TypeDef *cs_x, uint16_t cs_pin): _hspi(hspi), cs_x_(cs_x), cs_pin_(cs_pin){}
void IMUICM42688P::init(){
HAL_SPI_Init(&_hspi);
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_SET);
setConfigs();
}
uint8_t IMUICM42688P::getWhoAmI(){
const uint8_t address = 0x75; //< Input who_am_i: 0x75, return: 0x47
return read(address);
}
float32_t IMUICM42688P::getAccelX(){
const int16_t raw_accel_x = static_cast<int16_t>(((read(0x1F) << | read(0x20)));
return (accel_range_ * static_cast<float32_t>(raw_accel_x) / static_cast<float32_t>(INT16_MAX));
}
float32_t IMUICM42688P::getAccelY(){
const int16_t raw_accel_y = static_cast<int16_t>((read(0x21) << | read(0x22));
return (accel_range_ * static_cast<float32_t>(raw_accel_y) / static_cast<float32_t>(INT16_MAX));
}
float32_t IMUICM42688P::getAccelZ(){
const int16_t raw_accel_z = static_cast<int16_t>((read(0x23) << | read(0x24));
return (accel_range_ * static_cast<float32_t>(raw_accel_z) / static_cast<float32_t>(INT16_MAX));
}
uint8_t IMUICM42688P::read(const uint8_t address){
constexpr uint16_t size = 2;
const uint8_t read_mode = 0b10000000; //< (read:1, write:0)
const uint8_t tx_data[size] = {static_cast<uint8_t>(read_mode | address), 0x00};
uint8_t rx_data[size] = {0x00, 0x00};
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_RESET); // CS pin: LOW
HAL_SPI_TransmitReceive(&_hspi, (uint8_t*)tx_data, (uint8_t*)rx_data, size, 100);
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_SET);
return rx_data[1];
}
void IMUICM42688P::write(const uint8_t address, const uint8_t data){
constexpr uint16_t size = 2;
const uint8_t tx_data[size] = {address, data};
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_RESET); // CS pin: LOW
HAL_SPI_Transmit(&_hspi, (uint8_t*)tx_data, size, 100);
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_SET); // CS pin: HIGH
}
void IMUICM42688P::setConfigs(){
HAL_Delay(10);
setPowerManage();
HAL_Delay(10);
setAccelConfig();
HAL_Delay(10);
}
void IMUICM42688P::setAccelConfig(){
constexpr uint8_t accel_conf_addr = 0x50;
constexpr uint8_t accel_conf_data = 0b01100110; // range:2[g], rate:1k[Hz]
write(accel_conf_addr, accel_conf_data);
}
void IMUICM42688P::setPowerManage(){
constexpr uint8_t accel_conf_addr = 0x4E;
constexpr uint8_t accel_conf_data = 0b00011111; // range:2[g], rate:1k[Hz]
write(accel_conf_addr, accel_conf_data);
}
Microcontroller STM32F407vgt6,cubeide
Best regards.
2024-09-03 05:08 AM
Show the wiring diagram.
Make sure you have a common ground.
Show CLK vs MOSI
Get the clock rate to 1 MHz rather than 10 MHz
2024-09-03 05:21 AM
Orange is SCLK and blue is MOSI.
Best regards.
2024-09-03 06:08 AM
This doesn't seem to be correct - there are no pulses on SCK (nor MISO/MOSI).
Double-check the wiring.
JW
2024-09-03 06:08 AM
Not going to catch a 10 MHz signal with a 27 kHz sampling rate.
Code seems fine.
2024-09-03 06:42 AM
How much is optimal in this case?
Best regards.
2024-09-03 06:52 AM
Your scaling and what you're capturing is unhelpful. You need to capture the interaction of the data/clocks at the point where you're interacting with the WHOAMI register.
Do you work with someone who has more experience debugging digital circuits and signals?
Perhaps start by drawing a schematic of exactly what you've wired to what.
The make/model of boards the TDK IC is mounted on would also be good contextual information in your presentation of the problem.
2024-09-03 07:44 AM
Since this module is used for wiring, we assume that the wiring is correct.
Can you tell me what other possibilities there are?
Best regards.
2024-09-03 08:54 AM - edited 2024-09-03 08:55 AM
Show waveforms on the bus taken by oscilloscope, this time set with proper sampling rate (i.e. at least 4x the SPI baudrate, but more is preferrable).
JW
2024-09-03 01:24 PM
Looks to be stock imagery, some chance you can share YOUR wiring implementation?
https://strawberry-linux.com/catalog/items?code=42688
>>Can you tell me what other possibilities there are?
There are a lot of opportunities to fail, far fewer to do things correctly and succeed.
VDD + VDDIO to 3.3V
GND to GND
-CS to GPIO
SCLK to SPIx_SCLK
SDO to SPIx_MISO
SDI to SPIx_MOSI
I'd probably avoid HAL_SPI_Transmit() and use HAL_SPI_TransmitReceive() into a scratch buffer, the former is apt to complete early and the CS go high prior to completion.
The signals you want to look at are where it's physically interacting with the part, you'll see the data bits going out, the clocks, and the data bits coming back.
Large traces with nothing happening on them isn't helpful. Are the GPIO pins correctly configured? Can you capture the actual interaction and response? Can you find a Logic Analyzer?
2024-09-03 06:14 PM
Thank you for your response.
Changed program to use HAL_SPI_TransmitReceive().
#include "halplus/layer_driver/circuit/icm42688p.hpp"
#define WHO_AM_I 0x75
#define PWR_MGMT_0 0x4E
#define DEVICE_CONFIG 0x11
#define DRIVE_CONFIG 0x13
#define GYRO_CONFIG 0x4F
ICM42688P::ICM42688P(SPI_HandleTypeDef &hspi, GPIO_TypeDef *cs_x, uint16_t cs_pin): hspi_(hspi), cs_x_(cs_x), cs_pin_(cs_pin){}
uint8_t ICM42688P::read_byte(uint8_t reg) {
uint8_t rx_data[2];
uint8_t tx_data[2];
tx_data[0] = reg | 0x80;
tx_data[1] = 0x00; // dummy
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi_, tx_data, rx_data, 2, 1);
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_SET);
return rx_data[1];
}//rx:receive,tx:transmit
void ICM42688P::write_byte( uint8_t reg, uint8_t val) {
uint8_t rx_data[2];
uint8_t tx_data[2];
tx_data[0] = reg & 0x7F;
tx_data[1] = val; // write data
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi_, tx_data, rx_data, 2, 1);
HAL_GPIO_WritePin(cs_x_, cs_pin_, GPIO_PIN_SET);
}
void ICM42688P::setup() {
uint8_t who_am_i;
HAL_Delay(50); // wait start up
who_am_i = read_byte(WHO_AM_I); // 1. read who am i
printf( "who : 0x%x\n",who_am_i); // 2. check who am i value
// error check
if ( who_am_i != 0x47){
while(1){
printf( "gyro_error\r");
}
}
HAL_Delay(50); // wait
write_byte(DEVICE_CONFIG, 0x00);
HAL_Delay(50);
write_byte(PWR_MGMT_0, 0x1F); // set pwr_might
HAL_Delay(50);
write_byte(DRIVE_CONFIG, 0x03); // set config
HAL_Delay(50);
write_byte(GYRO_CONFIG, 0x06); // set gyro config 32kHz 2000dps
HAL_Delay(50);
}
.hpp
#pragma once
#include <stdio.h>
#include <stdint.h>
#include "spi.h"
#include "stm32f4xx.h"
#include "stm32f4xx_hal_spi.h"
//#include "arm_math.h"
class ICM42688P {
public:
ICM42688P(SPI_HandleTypeDef &hspi, GPIO_TypeDef *cs_x, uint16_t cs_pin);
uint8_t read_byte(uint8_t reg);
void write_byte(uint8_t reg, uint8_t val);
void setup();
private:
SPI_HandleTypeDef &hspi_;
GPIO_TypeDef *cs_x_;
uint16_t cs_pin_;
};
The change to this program returned the value of the WhoAmI() register as 0x0.
Wiring is done referring to this image.
Sorry, I have been disconnecting the module and looking at the signal.
Should I just put the module back on and check the SDI and SDO signals?
Sorry for repeating myself, but thank you in advance.