cancel
Showing results for 
Search instead for 
Did you mean: 

Strange values when reading bytes from my I2C sensor [STM32L0]

MatheusMarkies
Associate

I have a system of sensors connected to an STM32 chip, all working via I2C and 3.3V.
I've created interface libraries for my sensors, specifically the temperature and accelerometer ones. However, when I read the values measured by the sensors, I came across a strange result.

Here's a printout of the serial communication:

Starting...
Scanning I2C bus:
Device found at 0x18
Device found at 0x1F
Device found at 0x50
Device found at 0x51
Device found at 0x7C
I2C scan completed.
Ready KX122
Ready MCP9808
Error in MAX17048 connection
Ready FRAM
Ready!
Next Memory Adds: 0
Starting Temperature Reading:
Temp:
Temp: 1077936128
Starting Battery Reading:
Failed to read voltage
Failed to read SOC
Bat: 0
RMS Accel: -1067319296, 0, 1081114624
Starting Vibration Reading:

 

As you can see, the acceleration and temperature values are all wrong. They should be double values.

Temp: 1077936128

RMS Accel: -1067319296, 0, 1081114626

The library codes, my main.c file and its header files are in Firmware Tools.rar.

8 REPLIES 8
Bob S
Principal

I'm not going to download archives and plow through them.  You can post relevant snippets of code here using the code tags ("</>").  I am presuming your are doing something like:

printf( "Temp: %f\n", temperature );

By default the built-in printf library does not support floating point.  There are compiler/linker flags to enable that.

Not sure there's a huge amount of interest for working over broken code. If you want people to browse I'd suppose GitHub would be better and platform agnostic. ie at least usable on a phone..

The thing with I2C is to use the register auto-increment to read a related block of registers. It also tends to be more atomic on the peripheral side, as it can see a large linear transaction, and knows when it ends, which might be particularly consequential when reading multi-byte values from a continuous device like a RTC, gyro or accelerometer.

Not all I2C device play well together, you might need to use multiple buses, and pay attention to the topology, pull-up values, and current sinking / low power operation of given slave devices.

Think also how you might attach a Logic Analyzer to monitor troublesome traffic, and generate GPIO triggering when range checking or error flagging senses an issue STM32 side.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

So, the problem is that these codes are in a private GitHub repository, and as I couldn't use the tags I preferred to put everything in a folder so that the question doesn't lack information. I apologize for that.
As for compatibility, I don't think that's the problem. I've tried removing the accelerometer and testing only temperature, and the other way around too.

I think there really is a problem with my libraries. This is the first time I've programmed a library for an i2c device from scratch.

So post the relevant sections of your library code here.  Perhaps the code that reads from the temperature sensor and manipulates the data to calculate the floating point value.  Include the temperature sensor mfg and part number for those so inclined to fetch the data sheet (for those like me whose IT departments restrict downloads).

For debugging purposes, have you looked at the raw data that you read from the sensor? Does it make sense?  Post that here as well.

I created a gits repository:  https://gist.github.com/a85b8288ed40ea9962f3d91e22202695.git

I should have done that from the start but I didn't pay attention.

Parts used:

  • STM32L053C8T6
  • MCP9808-E/MS (Temperature sensor)
  • KX122-1037 (Accelerometer)

By raw data you mean the reading that my library made?

In that case it would be: 1077936128 (Data taken from the print function I put in my Steup method)

 

HAL_StatusTypeDef MCP9808_ReadTemperature(I2C_HandleTypeDef *hi2c, double *temperature) {

uint8_t temp_data[2];

if (MCP9808_ReadRegister(hi2c, MCP9808_REG_TEMP, temp_data, 2) != HAL_OK) {

return HAL_ERROR;

}

 

uint16_t raw_temp = (temp_data[0] << 8) | temp_data[1];

raw_temp &= 0x0FFF; // Máscara para os 12 bits de dados

 

double temp = raw_temp & 0x0FFF;

temp /= 16.0;

 

if (raw_temp & 0x1000) {

temp -= 256.0;

}

 

*temperature = temp;

return HAL_OK;

}

 

static HAL_StatusTypeDef MCP9808_WriteRegister_16(I2C_HandleTypeDef *hi2c, uint8_t reg, uint16_t value) {

uint8_t data[3] = {reg, (value >> 8) & 0xFF, value & 0xFF};

return HAL_I2C_Master_Transmit(hi2c, MCP9808_I2C_ADDRESS << 1, data, 3, HAL_MAX_DELAY);

}

 

static HAL_StatusTypeDef MCP9808_WriteRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t *data, uint8_t len) {

uint8_t buffer[3];

buffer[0] = reg;

for (uint8_t i = 0; i < len; i++) {

buffer[i + 1] = data[i];

}

return HAL_I2C_Master_Transmit(hi2c, MCP9808_I2C_ADDRESS << 1, buffer, len + 1, HAL_MAX_DELAY);

}

 

static HAL_StatusTypeDef MCP9808_ReadRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t *data, uint8_t len) {

HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, MCP9808_I2C_ADDRESS << 1, &reg, 1, HAL_MAX_DELAY);

if (status == HAL_OK) {

status = HAL_I2C_Master_Receive(hi2c, MCP9808_I2C_ADDRESS << 1, data, len, HAL_MAX_DELAY);

}

return status;

}

 

static HAL_StatusTypeDef MCP9808_ReadRegister_16(I2C_HandleTypeDef *hi2c, uint8_t reg, uint16_t *value) {

uint8_t data[2];

HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hi2c, MCP9808_I2C_ADDRESS << 1, &reg, 1, HAL_MAX_DELAY);

if (status == HAL_OK) {

status = HAL_I2C_Master_Receive(hi2c, MCP9808_I2C_ADDRESS << 1, data, 2, HAL_MAX_DELAY);

if (status == HAL_OK) {

*value = (data[0] << 8) | data[1];

}

}

return status;

}

You're printing the ADDRESS of a pointer

HAL_StatusTypeDef MCP9808_ReadTemperature_LowPower(double *temperature) {
	HAL_StatusTypeDef status;

	status = MCP9808_Wake(&hi2c1);
	if (status != HAL_OK) {
		return status;
	}

	HAL_Delay(50);

	status = MCP9808_ReadTemperature(&hi2c1, temperature);

    char buffer[256];
    snprintf(buffer, sizeof(buffer),
             "Temp: %d\r\n", temperature);
	DEBUG_PRINT(buffer);

	if (status != HAL_OK) {
		return status;
	}

1077936128 -> 0x40400000

snprintf(buffer, sizeof(buffer), "Temp: %lf\r\n", *temperature); // print as double, if library permits

You can paste code via the </> icon

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you! I was actually printing the address!
I'm having a weird problem besides that, my program only runs when I upload code from CubeIDE, when I supply voltage to the system it doesn't start. Only via CubeIDE.
Why is that?

If @Tesla DeLorean answered your question, please mark it as the answer.

For the startup issue - please start a new thread.  Nobody who isn't already looking at this thread will see that.  Plus - there are several (many) other threads on this forum addressing that question.  I don't know if any are L0xx specific.  Usually the answer has to do with vector table location (at least in F4/L4/G4/F7 CPUs).