Интересный баг в STM32F103
Feb. 12th, 2021 01:00 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Сижу, разбираюсь, как с датчиком температуры-влажности SI7005 работать на STM32F103. Намучился уже с его кривым I2C (почему-то периодически возникают глюки на пустом месте, а первая попытка запуска I2C вообще не срабатывает, натыкаясь в момент посылки адреса слейва на NACK — а между прочим, некоторые в этом месте не делают проверку таймаута!).
Все более-менее заработало, но вот захотел я средствами МК вычислить точку росы. А там нужен логарифм. Я его, естественно, давай кусочно-линейной интерполяцией вычислять. Правда, оказалось, что точность для формулы нужна приличная (не хуже 0.01, чтобы результат отличался от формулы не больше, чем на ±0.1℃). И вот получилось, что, в отличие от STM32F0xx, здесь проще флоатами воспользоваться.
Однако…
Вообще ненормальная штука: если к элементу массива по вычисленному индексу (например, K[idx]), происходит зависание. А вот если этот же индекс вписать как константу (K[27]) — вопросов ноль!
Если вместо idx во float l ... подставить 27, все работает!
Вынес константы за пределы функции, и внезапно все заработало! Ух, шайтан, однако!!! Что это было???
Ссылка на код на гитхабе.
Нужно теперь подумать, как победить проблему с I2C (первое обращение абсолютно всегда заканчивается с ошибкой) и как избавиться от флоатов (чтобы на STM32F0x2 тоже это работало). Возможно, опять надо будет сделать целочисленную арифметику, заменив коэффициент на числитель/знаменатель. Или все-таки оставить флоаты.
Все более-менее заработало, но вот захотел я средствами МК вычислить точку росы. А там нужен логарифм. Я его, естественно, давай кусочно-линейной интерполяцией вычислять. Правда, оказалось, что точность для формулы нужна приличная (не хуже 0.01, чтобы результат отличался от формулы не больше, чем на ±0.1℃). И вот получилось, что, в отличие от STM32F0xx, здесь проще флоатами воспользоваться.
Однако…
Вообще ненормальная штука: если к элементу массива по вычисленному индексу (например, K[idx]), происходит зависание. А вот если этот же индекс вписать как константу (K[27]) — вопросов ноль!
float ln(uint16_t RH){
#define NKNOTS (32)
const uint16_t X[NKNOTS] = {1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 19, 22, 29, 37, 47, 59, 72, 87, 104,
123, 145, 171, 200, 232, 267, 348, 443, 555, 684, 832};
const float Y[NKNOTS] = {-6.90776, -6.21461, -5.80914, -5.52146, -5.29832, -5.116, -4.96185, -4.82831,
-4.60517, -4.42285, -4.2687, -4.13517, -3.96332, -3.81671, -3.54046, -3.29684,
-3.05761, -2.83022, -2.63109, -2.44185, -2.26336, -2.09557, -1.93102, -1.76609,
-1.60944, -1.46102, -1.32051, -1.05555, -0.814186, -0.588787, -0.379797, -0.183923};
const float K[NKNOTS] = {0.693147, 0.405465, 0.287682, 0.223144, 0.182322, 0.154151, 0.133531, 0.111572,
0.0911608, 0.0770753, 0.0667657, 0.0572834, 0.0488678, 0.0394648, 0.0304528,
0.023923, 0.0189492, 0.0153176, 0.0126161, 0.010499, 0.00883123, 0.00747952,
0.00634345, 0.00540186, 0.00463813, 0.00401461, 0.00327103, 0.00254071,
0.00201249, 0.00162008, 0.00132348, 0.00109478};
// find interval
int idx = (NKNOTS)/2, left = 0, right = NKNOTS-1; // left, right, middle
while(idx > left && idx < right){
uint16_t midval = X[idx];
if(RH < midval){
if(idx == 0) break;
if(RH > X[idx-1]){ // found
--idx;
break;
}
right = idx - 1;
idx = (left + right)/2;
}else{
if(RH < X[idx+1]) break; // found
left = idx + 1;
idx = (left + right)/2;
}
}
if(idx < 0) idx = 0;
else if(idx > NKNOTS-1) idx = NKNOTS - 1;
USB_send("idx="); USB_send(u2str(idx)); USB_send("\n");
float l = Y[idx] + K[idx]*(RH - X[idx]);
#undef NKNOTS
return l;
}
Если вместо idx во float l ... подставить 27, все работает!
Вынес константы за пределы функции, и внезапно все заработало! Ух, шайтан, однако!!! Что это было???
Ссылка на код на гитхабе.
Нужно теперь подумать, как победить проблему с I2C (первое обращение абсолютно всегда заканчивается с ошибкой) и как избавиться от флоатов (чтобы на STM32F0x2 тоже это работало). Возможно, опять надо будет сделать целочисленную арифметику, заменив коэффициент на числитель/знаменатель. Или все-таки оставить флоаты.