So the setup I am using is a K22FN512 (Arm Cortex M4) along with a AGM01(9DOF sensor board, gyro/accel/mag). The board containing the sensors has an I2C interface to communicate with the two chips mounted on it. I have the breakout board Vdd and Vdio connected to the K22's 3.3v pin. The slave address and reset pins from the sensor board are connected to the K22 though GPIO.
Now I can not seem to get the slave to acknowledge anything at all. So far I have done the following:
- Measured Vdd and Vdio, both fine
- Measured SCL and SDA low/high voltages, both fine
- Slowed down clock from 90kHz to ~1.5kHz
- Switched the slave address from 0x20 to 0x21, still not acknowledging
- Moved logic probes over to test points soldered on sensor breakout board, signal still strong no signs of cable/capacitance problems
I'm at a loss on what to try next. Below is my code, logic analyzer output, and links to the documentation of the hardware. The code is not complete, I intend to also handle multi-bytes reads and other stuff but right now I can't even read the device id register.
Ref manual for K22:
Can't post more then two links since I'm under 10 rep (apparently the picture counts)
Gyroscope is the FXAS21002C
Breakout board is the BRKT-STBC-AGM01-QRC
Code:
/*
Sensor module header
*/
#ifndef SENSORS_H
#define SENSORS_H
#include <cmsis_os.h> // CMSIS RTOS header file
#include "MK22F51212.h" // CMSIS Peripheral Access Layer for MK22F51212
// I2C defs
#define I2C_READ_BIT 0x01
#define I2C_WRITE_BIT 0x00
#define I2C_READ_BUFF 6u
#define I2C_READ(add) ((uint8_t)((((uint8_t)add) << 1) | I2C_READ_BIT));
#define I2C_WRITE(add) ((uint8_t)((((uint8_t)add) << 1) | I2C_WRITE_BIT));
// Gyro address defs
#define GYRO_ADD 0x20
#define GYRO_STATUS 0x00
#define GYRO_X_MSB 0x01
#define GYRO_X_LSB 0x02
#define GYRO_Y_MSB 0x03
#define GYRO_Y_LSB 0x04
#define GYRO_Z_MSB 0x05
#define GYRO_Z_LSB 0x06
#define GYRO_DR_STATUS 0x07
#define GYRO_F_STATUS 0x08
#define GYRO_F_SETUP 0x09
#define GYRO_F_EVENT 0x0A
#define GYRO_INT_SRC_FLAG 0x0B
#define GYRO_WHO_AM_I 0x0C
#define GYRO_CTRL_REG0 0x0D
#define GYRO_RT_CFG 0x0E
#define GYRO_RT_SRC 0x0F
#define GYRO_RT_THS 0x10
#define GYRO_RT_COUNT 0x11
#define GYRO_TEMP 0x12
#define GYRO_CTRL_REG1 0x13
#define GYRO_CTRL_REG2 0x14
#define GYRO_CTRL_REG3 0x15
// RTX core
int Init_Thread_Sensors (void);
void Thread_Sensors (void const *argument);
// Sensor struct for sensors state
typedef struct {
int16_t gyro_x;
int16_t gyro_y;
int16_t gyro_z;
int16_t accel_x;
int16_t accel_y;
int16_t accel_z;
int16_t mag_x;
int16_t mag_y;
int16_t mag_z;
}sensor;
// Struct for I2C data
typedef struct {
uint8_t device;
uint8_t reg;
uint8_t bytes;
uint8_t data[I2C_READ_BUFF];
}i2c_transfer;
// Sensor model and mutex
extern sensor sensorData;
extern osMutexId sensor_mutex;
// Functions
void init_I2C(void);
void init_IMU(void);
void read_I2C(i2c_transfer*);
void write_I2C(i2c_transfer*);
#endif
.
/*----------------------------------------------------------------------------
* Sensor thread, I2C0 used
*---------------------------------------------------------------------------*/
#include "Sensors.h"
// RTX info
osThreadId tid_Thread_Sensors; // thread id
osThreadDef (Thread_Sensors, osPriorityNormal, 1, 0); // thread object
void init_I2C(void){
// Enable module clock
SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK;
// Config pin mux for I2C bus
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
PORTB_PCR0 = PORT_PCR_MUX(0x02) | PORT_PCR_ODE_MASK | PORT_PCR_PE_MASK |PORT_PCR_PS_MASK; // SCL
PORTB_PCR1 = PORT_PCR_MUX(0x02) | PORT_PCR_ODE_MASK | PORT_PCR_PE_MASK |PORT_PCR_PS_MASK; // SDA
// Config gpio
SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;
PORTC_PCR5 = PORT_PCR_MUX(0x01) | PORT_PCR_ODE_MASK; // RST
PORTC_PCR6 = PORT_PCR_MUX(0x01) | PORT_PCR_ODE_MASK; // SA
GPIOC_PDDR |= (1<<5) | (1<<6);
GPIOC_PSOR |= 1<<5;
GPIOC_PCOR |= 1<<6;
// Config I2C0
I2C0_F = I2C_F_MULT(0x02) | I2C_F_ICR(0x3F);
I2C0_C1 = I2C_C1_IICEN_MASK;
}
void init_IMU(void){
}
int Init_Thread_Sensors (void) {
init_I2C();
tid_Thread_Sensors = osThreadCreate (osThread(Thread_Sensors), NULL);
if(!tid_Thread_Sensors) return(-1);
return(0);
}
void Thread_Sensors (void const *argument) {
i2c_transfer packet;
while (1) {
packet.device = GYRO_ADD;
packet.reg = GYRO_WHO_AM_I;
read_I2C(&packet);
osThreadYield(); // suspend thread
}
}
void read_I2C(i2c_transfer* data){
// Wait for bus ready
while(I2C0_S & I2C_S_BUSY_MASK);
// Trigger Start signal
I2C0_C1 |= I2C_C1_TX_MASK | I2C_C1_MST_MASK;
// Send Write command
I2C0_D = I2C_WRITE(data->device);
// Wait for ACK
//while((I2C0_S & I2C_S_RXAK_MASK)==1){};
while((I2C0_S & I2C_S_IICIF_MASK)==0){};
I2C0_S |= I2C_S_IICIF_MASK;
// Write reg address
I2C0_D = data->reg;
// Wait for ACK
//while((I2C0_S & I2C_S_RXAK_MASK)==1){};
while((I2C0_S & I2C_S_IICIF_MASK)==0){};
I2C0_S |= I2C_S_IICIF_MASK;
// Repeat start to engage read
I2C0_C1 |= I2C_C1_RSTA_MASK;
// Send Read device command
I2C0_D = I2C_READ(data->device);
// Wait for ACK
//while((I2C0_S & I2C_S_RXAK_MASK)==1){};
while((I2C0_S & I2C_S_IICIF_MASK)==0){};
I2C0_S |= I2C_S_IICIF_MASK;
// Switch to RX mode
I2C0_C1 &= ~I2C_C1_TX_MASK;
I2C0_C1 |= I2C_C1_TXAK_MASK;
// Trigger Read and wait for Data
data->data[0] = I2C0_D;
//while((I2C0_S & I2C_S_TCF_MASK)==0){};
while((I2C0_S & I2C_S_IICIF_MASK)==0){};
I2C0_S |= I2C_S_IICIF_MASK;
// Store Sata
data->data[0] = I2C0_D;
// Trigger Stop
I2C0_C1 &= ~(I2C_C1_MST_MASK | I2C_C1_TX_MASK);
}
void write_I2C(i2c_transfer* data){
}
Solution found
Turns out I need to read the doc's closer, had the device in reset and didn't pull SPI_CS_B high like I was suppose to.