Optimize ADC temperature search
Use a binary search to find our target temperate in fewer comparisons. The search algorithm is ostensibly slower because it involves a division, but it's a div-by-two so should be optimized into a simple bit-shift. Fewer comparisons involves fewer pgm_read_words and should be faster overall, but the gain is arguably tiny. Note by Traumflug: According to @Wurstnase's performance measurements, gain is actually pretty huge. Temp conversions 0..1024 before this and the previous few commits: minimum: 1011.84 clock cycles. maximum: 1993.92 clock cycles. average: 1768.85 clock cycles. Now: minimum: 437.72 clock cycles. maximum: 494.76 clock cycles. average: 470.278 clock cycles. That's a speedup by factor 3.7 on average!
This commit is contained in:
parent
65857b17dc
commit
fbe1832467
52
temp.c
52
temp.c
|
|
@ -186,15 +186,24 @@ static uint16_t mcp3008_read(uint8_t channel) {
|
|||
*/
|
||||
#if defined TEMP_THERMISTOR || defined TEMP_MCP3008
|
||||
static uint16_t temp_table_lookup(uint16_t temp, uint8_t sensor) {
|
||||
uint8_t j;
|
||||
uint8_t lo, hi;
|
||||
uint8_t table_num = temp_sensors[sensor].additional;
|
||||
|
||||
for (j = 1; j < NUMTEMPS; j++) {
|
||||
if (pgm_read_word(&(temptable[table_num][j][0])) > temp) {
|
||||
// Binary search for table value bigger than our target.
|
||||
//
|
||||
// lo = index of highest entry less than target.
|
||||
// hi = index of lowest entry greater than or equal to target.
|
||||
for (lo = 0, hi = NUMTEMPS - 1; hi - lo > 1; ) {
|
||||
uint8_t j = lo + (hi - lo) / 2 ;
|
||||
if (pgm_read_word(&(temptable[table_num][j][0])) >= temp)
|
||||
hi = j ;
|
||||
else
|
||||
lo = j ;
|
||||
}
|
||||
|
||||
if (DEBUG_PID && (debug_flags & DEBUG_PID))
|
||||
sersendf_P(PSTR("pin:%d Raw ADC:%d table entry: %d"),
|
||||
temp_sensors[sensor].temp_pin, temp, j);
|
||||
temp_sensors[sensor].temp_pin, temp, hi);
|
||||
|
||||
if (sizeof(temptable[0][0]) == 2 * sizeof(uint16_t)) {
|
||||
/**
|
||||
|
|
@ -209,31 +218,31 @@ static uint16_t temp_table_lookup(uint16_t temp, uint8_t sensor) {
|
|||
// y = ((x - x₀)y₁ + (x₁-x)y₀) / (x₁ - x₀)
|
||||
// y = temp
|
||||
// x = ADC reading
|
||||
// x₀= temptable[j-1][0]
|
||||
// x₁= temptable[j][0]
|
||||
// y₀= temptable[j-1][1]
|
||||
// y₁= temptable[j][1]
|
||||
// x₀= temptable[lo][0]
|
||||
// x₁= temptable[hi][0]
|
||||
// y₀= temptable[lo][1]
|
||||
// y₁= temptable[hi][1]
|
||||
temp = (
|
||||
// ((x - x₀)y₁
|
||||
((uint32_t)temp - pgm_read_word(&(temptable[table_num][j-1][0]))) *
|
||||
pgm_read_word(&(temptable[table_num][j][1]))
|
||||
((uint32_t)temp - pgm_read_word(&(temptable[table_num][lo][0]))) *
|
||||
pgm_read_word(&(temptable[table_num][hi][1]))
|
||||
// +
|
||||
+
|
||||
// (x₁-x)y₀)
|
||||
(pgm_read_word(&(temptable[table_num][j][0])) - (uint32_t)temp) *
|
||||
pgm_read_word(&(temptable[table_num][j - 1][1])))
|
||||
(pgm_read_word(&(temptable[table_num][hi][0])) - (uint32_t)temp) *
|
||||
pgm_read_word(&(temptable[table_num][lo][1])))
|
||||
// /
|
||||
/
|
||||
// (x₁ - x₀)
|
||||
(pgm_read_word(&(temptable[table_num][j][0])) -
|
||||
pgm_read_word(&(temptable[table_num][j - 1][0])));
|
||||
(pgm_read_word(&(temptable[table_num][hi][0])) -
|
||||
pgm_read_word(&(temptable[table_num][lo][0])));
|
||||
} else
|
||||
if (sizeof(temptable[0][0]) == 3 * sizeof(uint16_t)) {
|
||||
// Linear interpolation using pre-computed slope.
|
||||
// y = y₁ - (x - x₁) * d₁
|
||||
#define X1 pgm_read_word(&(temptable[table_num][j][0]))
|
||||
#define Y1 pgm_read_word(&(temptable[table_num][j][1]))
|
||||
#define D1 pgm_read_word(&(temptable[table_num][j][2]))
|
||||
#define X1 pgm_read_word(&(temptable[table_num][hi][0]))
|
||||
#define Y1 pgm_read_word(&(temptable[table_num][hi][1]))
|
||||
#define D1 pgm_read_word(&(temptable[table_num][hi][2]))
|
||||
|
||||
temp = Y1 - ((((int32_t)temp - X1) * D1 + (1 << 7)) >> 8);
|
||||
}
|
||||
|
|
@ -241,18 +250,9 @@ static uint16_t temp_table_lookup(uint16_t temp, uint8_t sensor) {
|
|||
if (DEBUG_PID && (debug_flags & DEBUG_PID))
|
||||
sersendf_P(PSTR(" temp:%d.%d"), temp / 4, (temp % 4) * 25);
|
||||
|
||||
// Value found, no need to read the table further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_PID && (debug_flags & DEBUG_PID))
|
||||
sersendf_P(PSTR(" Sensor:%d\n"), sensor);
|
||||
|
||||
// Clamp for overflows.
|
||||
if (j == NUMTEMPS)
|
||||
temp = temptable[table_num][NUMTEMPS - 1][1];
|
||||
|
||||
return temp;
|
||||
}
|
||||
#endif /* TEMP_THERMISTOR || TEMP_MCP3008 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue