Чтение чипа C i2c MCP9800 внезапно начинает давать сбой

У меня есть код:

#define AMB_LSB 0.0625

void Ambient::read()
{
uint32_t raw;
float filtered;

uint8_t bytes = 2;
uint8_t buf[bytes];

if(i2c_smbus_read_i2c_block_data(i2c_bus_address, A_TEMP_REG, bytes, buf) < 0)
printf("AMB Block Read Failed\n");

uint32_t va = buf[0];
uint32_t vb = buf[1];

uint32_t result = ((va<<8)+vb);

// 12-bit code
raw = result >> 4;

filtered = filter.execfilter( raw );
temperature = filtered * AMB_LSB;  << CALCULATION

printf("AMB buffers %d %d -> result %d -> raw %d -> filtered %d -> amb C %f\n",va, vb, result, raw, filtered, temperature);
}

Это код для чтения информации с MCP9800 через i2c. Извините за включение, но, возможно, это как-то связано с этим.

Функция работает хорошо около дюжины циклов, пока внезапно не начнет иметь неправильные значения. Но с некоторыми странными отклонениями.

1. Если РАСЧЕТ следующий

temperature = filtered * AMB_LSB;

Я получаю этот вывод:

temperature = ((float) filtered * (float) AMB_LSB);

ЗА РАБОТОЙ

AMB buffers 28 240 -> result 7408 -> raw 463 -> filtered 463 -> amb C 28.937500
AMB buffers 28 240 -> result 7408 -> raw 463 -> filtered 463 -> amb C 28.937500
AMB buffers 28 240 -> result 7408 -> raw 463 -> filtered 1024 -> amb C 64.000000

провал

AMB buffers 29 0 -> result 7424 -> raw 464 -> filtered -**2147483648** -> amb C -134217728.000000
AMB buffers 29 0 -> result 7424 -> raw 464 -> filtered **2147483647** -> amb C 134217728.000000
AMB buffers 29 0 -> result 7424 -> raw 464 -> filtered -**2147483648** -> amb C -134217728.000000

Поэтому, как только он начинает давать сбой, я вижу, что вывод отфильтрованного значения неверен.

2. Если РАСЧЕТ:

temperature = raw * AMB_LSB;

Так что отфильтрованный вообще не используется, вывод такой:

ЗА РАБОТОЙ

AMB buffers 29 48 -> result 7472 -> raw 467 -> filtered 0 -> amb C 29.187500
AMB buffers 29 48 -> result 7472 -> raw 467 -> filtered 2147483647 -> amb C 29.187500
AMB buffers 29 64 -> result 7488 -> raw 468 -> filtered 468 -> amb C 29.250000

провал

AMB buffers **255 130** -> result **65410** -> raw **4088** -> filtered 2147483647 -> amb C 255.500000
AMB buffers **255 130** -> result **65410** -> raw **4088** -> filtered -2147483648 -> amb C 255.500000
AMB buffers **255 130** -> result **65410** -> raw **4088** -> filtered 2147483647 -> amb C 255.500000

Смотрите отмеченные звездочкой цифры для вывода, который является неправильным. По какой-то причине, когда вы не используете отфильтрованные значения, остальные цифры тоже начинают становиться неправильными! Всю дорогу до байтов я снял чип i2c.

Итак, сначала я вижу, что, возможно, фильтр не работает правильно. Но его удаление также делает неправильное необработанное значение необработанным. Все, что execFilter () делает, это некоторое усреднение, чтобы предотвратить большие случайные изменения.

Кроме того, я также создал скрипт через CLI, который использовал i2cget, и он был очень постоянным в своих возвращаемых значениях. Там не было сбоев или неожиданных значений.

Почему это происходит?

2

Решение

Похоже, аппаратная проблема. Многие из ваших значений 0x7FFFFFFF, например линия SDA управляется нагрузочным резистором. Это произошло бы, если бы шум на линии SDA вызвал ложное условие остановки I2C — устройство немедленно включило бы его выход, и вы получили бы только высокие биты для остальной части передачи.

На линиях SCL и SDA предлагаются фильтры низких частот RC для замедления фронтов и блокировки высокочастотного шума, что помогает предотвратить такие ошибки связи.

2

Другие решения

Проверьте возвращаемое значение из i2c_smbus_read_i2c_block_data() звоните, а не только будь то отрицательный или нет.

Бьюсь об заклад, он возвращает 0 или 1, когда вы получаете неудачные переводы. Помните, что фактическая функция зависит от адаптера; Я бы никогда не предположил, что он полностью преуспеет, если не вернет ошибку, поскольку задокументировано, что вместо этого возвращается число байтов.

0

Это привело к повреждению памяти из другого класса в моем приложении.

ВОТ

0