Skip to main content
Senior III
July 2, 2026
Question

I2C no clock

  • July 2, 2026
  • 2 replies
  • 125 views

NUCLEOWB55RG

 

I set I2C3 in MX. I have 2 x temp sensors & 2 x accelerometers in the bus.

/* Snippets of code to show how I2C3 is set up & used */

#include "main.h"

#include "adt7410.h"
#include "adxl345.h"

I2C_HandleTypeDef hi2c3;

ADT7410 temp_0;
ADT7410 temp_1;
ADXL345 acc_0;
ADXL345 acc_1;

static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);

int main(void)
{
HAL_Init();
MX_GPIO_Init();
MX_I2C3_Init();

/* ADT7410 set up */
/* temp_0 at 0x48
* temp_1 at 0x49 */
temp_0.adti2c = &hi2c3; // I2C Handler
ADT7410_Init(&temp_0, 0x48); // I2C address depends of A0 and A1 pins
ADT7410_Reset(&temp_0); // Optional
ADT7410_SetResolution(&temp_0, ADT7410_16BITS); // Put the device in 16 bits resolution
temp_1.adti2c = &hi2c3; // I2C Handler
ADT7410_Init(&temp_1, 0x49); // I2C address depends of A0 and A1 pins
ADT7410_Reset(&temp_1); // Optional
ADT7410_SetResolution(&temp_1, ADT7410_16BITS); // Put the device in 16 bits resolution

/* ADXL345 set up
* acc_0 at 0x1D, write 0x3A, read 0x3B
* acc_1 at 0x53, write 0xA6, read 0xA7
*/
acc_0.adxl345i2c = &hi2c3; // I2C handler - might have to change this
acc_1.adxl345i2c = &hi2c3; // ~CS needs to be tied to Vdd for I2C comms
ADXL345_Init(&acc_0, 0x1D, 0x3A, 0x3B); // ALT_ADDRESS tied to Vdd
ADXL345_Init(&acc_1, 0x53, 0xA6, 0xA7); // ALT_ADDRESS tied to GND

/* Init code for STM32_WPAN */
MX_APPE_Init();

while (1)
{
MX_APPE_Process();

}

}

static void MX_I2C3_Init(void)
{

/* USER CODE BEGIN I2C3_Init 0 */

/* USER CODE END I2C3_Init 0 */

/* USER CODE BEGIN I2C3_Init 1 */

/* USER CODE END I2C3_Init 1 */
hi2c3.Instance = I2C3;
hi2c3.Init.Timing = 0x0060112F;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}

/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}

/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C3_Init 2 */

/* USER CODE END I2C3_Init 2 */

}

The BLE part is transmitting the sensor values back every second but they are all 0. When I check I2C3_SCL with a scope its just flat, same with I2C3_SDA, nothing on the line at all.

I tried with I2C1 and I cant even connect to the board via BLE. I have swapped out 3 boards now, same result. Unhooked all the sensors, still nothing on SCL & SDA.

2 replies

Andrew Neil
Super User
July 2, 2026

Correct pullups ?

You haven’t shown your I2C routines - are they checking HAL return results ?

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Senior III
July 6, 2026

The GPIO’s were set to pullup in MX.

The sensors driver codes below, yes I’m using HAL,

 

ADXL345- accelerometer
 

#include "adxl345.h"


void ADXL345_Init(ADXL345 *ADXL345, uint8_t addr, uint8_t write, uint8_t read)
{
ADXL345->address = addr << 1;
ADXL345->write = write;
ADXL345->read = read;
ADXL345->range = TWO_G;
ADXL345->measure_mode = MEASURE;

ADXL345_SetRegisterValue(ADXL345, ADXL345_DATA_FORMAT, ADXL345->range);
ADXL345_SetRegisterValue(ADXL345, ADXL345_POWER_CTL, ADXL345->measure_mode);
}

void ADXL345_SetRegisterValue(ADXL345 *ADXL345, uint8_t regAddress, uint8_t regValue)
{
uint8_t data[2] = {0x00, 0x00};
data[0] = regAddress;
data[1] = regValue;

HAL_I2C_Master_Transmit(ADXL345->adxl345i2c, ADXL345->write, data, 2, ADXL345_TIMEOUT_I2C);
}

void ADXL345_Read_ID(ADXL345 *ADXL345, uint8_t *ID)
{
uint8_t addr = ADXL345_ID;

HAL_I2C_Mem_Read(ADXL345->adxl345i2c, ADXL345->read, addr, 1, ID, 1, ADXL345_TIMEOUT_I2C);
}

void ADXL345_ReadAcc(ADXL345 *ADXL345, acceleration_t *values)
{
uint8_t addr = ADXL345_DATAX0;
uint8_t raw[6] = {0x00, 0x00,0x00, 0x00,0x00, 0x00};

float scale_factor;

switch(ADXL345->range)
{
case TWO_G:
scale_factor = 0.003906; /* 1/256 */
break;

case FOUR_G:
scale_factor = 0.0078125; /* 1/128 */
break;

case EIGHT_G:
scale_factor = 0.01563; /* 1/64 */
break;

case SIXTEEN_G:
scale_factor = 0.03125; /* 1/32 */
break;
}

HAL_I2C_Master_Transmit(ADXL345->adxl345i2c, ADXL345->read, &addr, 1, ADXL345_TIMEOUT_I2C);
HAL_I2C_Master_Receive(ADXL345->adxl345i2c, ADXL345->read, raw, 6, ADXL345_TIMEOUT_I2C);

values->x_raw = ((raw[1] << 8) | raw[0]);
values->y_raw = ((raw[3] << 8) | raw[2]);
values->z_raw = ((raw[5] << 8) | raw[4]);

values->ax = ADXL345_axisValue(values->x_raw, scale_factor);
values->ay = ADXL345_axisValue(values->y_raw, scale_factor);
values->az = ADXL345_axisValue(values->z_raw, scale_factor);
}

float ADXL345_axisValue(uint16_t axis_raw, float scale_factor)
{
float val;
uint16_t inv;

if ((axis_raw & 0xF000) == 0xF000)
{
inv = (uint16_t)~axis_raw;
val = -1 * ((float) (inv + 1) ) * scale_factor;
}
else
{
val = (float) (axis_raw) * scale_factor;
}

return val;
}

 

 

ADT7410, temperature sensor driver curtesy of Axel Chabot,

 

#include "adt7410.h"


/**
* Init function
* @param ADT7410 struct pointer
* @param addr I2C address of the IC depend of the config a0, a1
*/
void ADT7410_Init(ADT7410 *ADT7410, uint8_t addr)
{
ADT7410->fault_queue = ADT7410_1_FAULT;
ADT7410->ct_polarity = ADT7410_CT_ACTIVE_LOW;
ADT7410->int_polarity = ADT7410_INT_ACTIVE_LOW;
ADT7410->int_ct_mode = ADT7410_INTERRUPT_MODE;
ADT7410->operation_mode = ADT7410_CONTINOUS_MODE;
ADT7410->resolution = ADT7410_13BITS;
ADT7410->address = (uint16_t) (addr << 1);
}

/**
* Reset function
* @param ADT7410 struct pointer
*/
void ADT7410_Reset(ADT7410 *ADT7410)
{
uint8_t addr = ADT7410_ADDR_RESET;
HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, &addr, 1, ADT7410_TIMEOUT_I2C);
HAL_Delay(1);
ADT7410->fault_queue = ADT7410_1_FAULT;
ADT7410->ct_polarity = ADT7410_CT_ACTIVE_LOW;
ADT7410->int_polarity = ADT7410_INT_ACTIVE_LOW;
ADT7410->int_ct_mode = ADT7410_INTERRUPT_MODE;
ADT7410->operation_mode = ADT7410_CONTINOUS_MODE;
ADT7410->resolution = ADT7410_13BITS;
}

/**
* Conversion state
* @param ADT7410 struct pointer
* @return true when temperature conversion is done, false otherwise
*/
uint8_t ADT7410_Ready(ADT7410 *ADT7410)
{
uint8_t rdy = 0;
rdy = (ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_STATUS) & 0x80);
return (!rdy);
}

/**
* Identification number of the IC
* @param ADT7410 struct pointer
* @return ID number
*/
uint8_t ADT7410_id(ADT7410 *ADT7410)
{
return ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_ID);
}

/**
* Get register value from an address
* @param ADT7410 struct pointer
* @param regAddress Register address
* @return Return the value asked
*/
uint8_t ADT7410_GetRegisterValue(ADT7410 *ADT7410, uint8_t regAddress)
{
uint8_t receivedData = 0x00;
HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, &regAddress, 1, ADT7410_TIMEOUT_I2C);
HAL_I2C_Master_Receive(ADT7410->adti2c, ADT7410->address, &receivedData, 1, ADT7410_TIMEOUT_I2C);
return receivedData;
}

/**
* Set register value from an address
* @param ADT7410 struct pointer
* @param regAddress Register address
* @param regValue Value to write into the register
*/
void ADT7410_SetRegisterValue(ADT7410 *ADT7410, uint8_t regAddress, uint8_t regValue)
{
uint8_t data[2] = { 0x00, 0x00 };
data[0] = regAddress;
data[1] = regValue;
HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, data, 2, ADT7410_TIMEOUT_I2C);
}

/**
* Change configuration of fault queue in case of noisy temperature environment.
* @param ADT7410 Struct pointer
* @param new New fault queue value
*/
void ADT7410_SetFaultQueue(ADT7410 *ADT7410, ADT7410_Fault_Queue new)
{
uint8_t reg;
reg = ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_CONF);
reg &= ~ADT7410_FAULT_QUEUE(0xFF);
reg |= ADT7410_FAULT_QUEUE((uint8_t ) new);
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_CONF, reg);
ADT7410->fault_queue = new;
}

/**
* Critical over temperature indicator polarity
* @param ADT7410 struct pointer
* @param new New polarity
*/
void ADT7410_SetCTPolarity(ADT7410 *ADT7410, ADT7410_CT_Polarity new)
{
uint8_t reg;
reg = ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_CONF);
reg &= ~ADT7410_CT_POLARITY(0xFF);
reg |= ADT7410_CT_POLARITY((uint8_t ) new);
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_CONF, reg);
ADT7410->ct_polarity = new;
}

/**
* Over temperature and under temperature Indicator polarity
* @param ADT7410 struct pointer
* @param new New polarity
*/
void ADT7410_SetINTPolarity(ADT7410 *ADT7410, ADT7410_INT_Polarity new)
{
uint8_t reg;
reg = ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_CONF);
reg &= ~ADT7410_INT_POLARITY(0xFF);
reg |= ADT7410_INT_POLARITY((uint8_t ) new);
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_CONF, reg);
ADT7410->int_polarity = new;
}

/**
* Set the functioning mode for CT and INT pins (comparator or interrupt)
* @param ADT7410 struct pointer
* @param new New mode
*/
void ADT7410_SetINTCTMode(ADT7410 *ADT7410, ADT7410_INT_CT_Mode new)
{
uint8_t reg;
reg = ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_CONF);
reg &= ~ADT7410_INT_CT_MODE(0xFF);
reg |= ADT7410_INT_CT_MODE((uint8_t ) new);
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_CONF, reg);
ADT7410->int_ct_mode = new;
}

/**
* Set Set the functioning mode for temperature conversion
* @param ADT7410 struct pointer
* @param new New mode
*/
void ADT7410_SetOperationMode(ADT7410 *ADT7410, ADT7410_Operation_Mode new)
{
uint8_t reg;
reg = ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_CONF);
reg &= ~ADT7410_OPERATION_MODE(0xFF);
reg |= ADT7410_OPERATION_MODE((uint8_t ) new);
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_CONF, reg);
ADT7410->operation_mode = new;
}

/**
* Switch between 13bits and 16bits resolution
* @param ADT7410 struct pointer
* @param new New resolution
*/
void ADT7410_SetResolution(ADT7410 *ADT7410, ADT7410_Resolution new)
{
uint8_t reg;
reg = ADT7410_GetRegisterValue(ADT7410, ADT7410_ADDR_CONF);
reg &= ~ADT7410_RESOLUTION(0xFF);
reg |= ADT7410_RESOLUTION((uint8_t ) new);
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_CONF, reg);
ADT7410->resolution = new;
}

/**
* Set the high temperature setpoint
* @param ADT7410 struct pointer
* @param newTemp New high temperature
*/
void ADT7410_SetTHigh(ADT7410 *ADT7410, uint16_t newTemp)
{
uint8_t data[3];
data[0] = ADT7410_ADDR_THIGH_MSB;
data[1] = newTemp >> 8;
data[2] = newTemp & 0xFF;
HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, data, 3, ADT7410_TIMEOUT_I2C);
}

/**
* Set the low temperature setpoint
* @param ADT7410 struct pointer
* @param newTemp New low temperature
*/
void ADT7410_SetTLow(ADT7410 *ADT7410, uint16_t newTemp)
{
uint8_t data[3];
data[0] = ADT7410_ADDR_TLOW_MSB;
data[1] = newTemp >> 8;
data[2] = newTemp & 0xFF;
HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, data, 3, ADT7410_TIMEOUT_I2C);
}

/**
* Set the critical temperature setpoint
* @param ADT7410 struct pointer
* @param newTemp New critical temperature
*/
void ADT7410_SetTCrit(ADT7410 *ADT7410, uint16_t newTemp)
{
uint8_t data[3];
data[0] = ADT7410_ADDR_TCRIT_MSB;
data[1] = newTemp >> 8;
data[2] = newTemp & 0xFF;
HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, data, 3, ADT7410_TIMEOUT_I2C);
}

/**
* Set the hysteresis temperature setpoint
* @param ADT7410 struct pointer
* @param newTemp New hysteresis temperature
*/
void ADT7410_SetTHyst(ADT7410 *ADT7410, uint8_t newTemp)
{
if (newTemp <= 15)
{
uint8_t hyst = newTemp & 0xF;
ADT7410_SetRegisterValue(ADT7410, ADT7410_ADDR_THYST, hyst);
}
}

/**
* Start single conversion of temperature
* @param ADT7410 struct pointer
* @return HAL_OK when everything good, HAL_TIMEOUT otherwise
*/
HAL_StatusTypeDef ADT7410_ReadTemp(ADT7410 *ADT7410)
{
ADT7410_SetOperationMode(ADT7410, ADT7410_ONE_SHOT_MODE);
uint32_t startTime = HAL_GetTick();

while (!ADT7410_Ready(ADT7410))
{
if (HAL_GetTick() - startTime> (uint32_t) 1.5 * ADT7410_SINGLE_CONV_TIME)
{
return HAL_TIMEOUT;
}
}

uint8_t addr = ADT7410_ADDR_TEMP_MSB;
uint8_t raw[2] = { 0x00, 0x00 };
uint16_t raw_read = 0x0000;

HAL_I2C_Master_Transmit(ADT7410->adti2c, ADT7410->address, &addr, 1, ADT7410_TIMEOUT_I2C);
HAL_I2C_Master_Receive(ADT7410->adti2c, ADT7410->address, raw, 2, ADT7410_TIMEOUT_I2C);

raw_read += (raw[0] << 8);
raw_read += (raw[1] << 0);

ADT7410->raw_data = raw_read;
ADT7410_RawToTemp(ADT7410);

return HAL_OK;
}

/**
* Convert raw temperature to decimal temperature
* @param ADT7410 struct pointer
*/
void ADT7410_RawToTemp(ADT7410 *ADT7410)
{
if (ADT7410->resolution == ADT7410_16BITS)
{
if ((ADT7410->raw_data & 0x8000) == 0x8000) {
ADT7410->deg_data = ((float) (ADT7410->raw_data - 65536)) / 128.0;
}
else
{
ADT7410->deg_data = ((float) (ADT7410->raw_data)) / 128.0;
}
}
else
{
if ((ADT7410->raw_data & 0x8000) == 0x8000)
{
ADT7410->deg_data = ((float) (ADT7410->raw_data - 8192)) / 16.0;
}
else
{
ADT7410->deg_data = ((float) (ADT7410->raw_data)) / 16.0;
}
}
}

 



 

Andrew Neil
Super User
July 6, 2026

The GPIO’s were set to pullup in MX

The internal pullups are likely too weak to be useful for I2C.

Check the waveforms on an oscilloscope …

See the diagram here: https://electronics.stackexchange.com/a/473799

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Andrew Neil
Super User
July 8, 2026

What’s that white wire doing?

Please show a schematic of the full setup.

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.