diff --git a/configtool/thermistortablefile.py b/configtool/thermistortablefile.py index 27f2348b2..9f8e0c294 100644 --- a/configtool/thermistortablefile.py +++ b/configtool/thermistortablefile.py @@ -54,6 +54,7 @@ def generateTempTables(sensors, settings): ofp.output("#define NUMTABLES %d" % len(tl)) ofp.output("#define NUMTEMPS %d" % N) + ofp.output("#define TEMPTABLE_FORMAT 1") ofp.output(""); for i in range(len(tl)): @@ -65,7 +66,7 @@ def generateTempTables(sensors, settings): ofp.close(); return True - ofp.output("const uint16_t PROGMEM temptable[NUMTABLES][NUMTEMPS][2] = {") + ofp.output("const uint16_t PROGMEM temptable[NUMTABLES][NUMTEMPS][3] = {") tcount = 0 for tn in tl: @@ -102,8 +103,9 @@ def BetaTable(ofp, params, names, settings, finalTable): samples = optimizeTempTable(thrm, N, hiadc) + prev = samples[0] for i in samples: - t = int(thrm.temp(i)) + t = thrm.temp(i) if t is None: ofp.output("// ERROR CALCULATING THERMISTOR VALUES AT ADC %d" % i) continue @@ -117,10 +119,12 @@ def BetaTable(ofp, params, names, settings, finalTable): c = " " else: c = "," - ostr = (" {%4s, %5s}%s // %4d C, %6.0f ohms, %0.3f V," - " %0.2f mW") % (i, t * 4, c, t, int(round(r)), - vTherm, ptherm * 1000) + delta = (t-thrm.temp(prev))/(prev-i) if i!=prev else 0 + ostr = (" {%4s, %5s, %5s}%s // %4d C, %6.0f ohms, %0.3f V," + " %0.2f mW, m=%0.4f") % (i, int(t * 4), int(delta*4*256), c, + int(t), int(round(r)), vTherm, ptherm * 1000, delta) ofp.output(ostr) + prev = i if finalTable: ofp.output(" }") @@ -145,8 +149,9 @@ def SteinhartHartTable(ofp, params, names, settings, finalTable): samples = optimizeTempTable(thrm, N, hiadc) + prev = samples[0] for i in samples: - t = int(thrm.temp(i)) + t = thrm.temp(i) if t is None: ofp.output("// ERROR CALCULATING THERMISTOR VALUES AT ADC %d" % i) continue @@ -157,8 +162,10 @@ def SteinhartHartTable(ofp, params, names, settings, finalTable): c = " " else: c = "," - ofp.output(" {%4d, %5d}%s // %4d C, %6d ohms" % - (i, t * 4, c, t, int(round(r)))) + delta = (t-thrm.temp(prev))/(prev-i) if i!=prev else 0 + ofp.output(" {%4d, %5d, %5d}%s // %4d C, %6d ohms, m=%0.4f" % + (i, int(t * 4), int(delta*4*256), c, int(t), int(round(r))), delta) + prev = i if finalTable: ofp.output(" }") diff --git a/simulator.h b/simulator.h index 1491a518d..6392706ed 100644 --- a/simulator.h +++ b/simulator.h @@ -142,6 +142,7 @@ void sim_error(const char msg[]); void sim_assert(bool cond, const char msg[]); void sim_gcode_ch(char ch); void sim_gcode(const char msg[]); +void sim_report_temptables(int sensor) ; /** * Initialize simulator timer and set time scale. diff --git a/simulator/analog_sim.c b/simulator/analog_sim.c index 7cef91133..eea4d8428 100644 --- a/simulator/analog_sim.c +++ b/simulator/analog_sim.c @@ -1,15 +1,41 @@ +#include "temp.h" #include "analog.h" #include "simulator.h" +#include static bool analog_initialised = false; void analog_init(void) { - sim_info("analog_init: not implemented in simulator"); analog_initialised = true; } +static uint16_t analog_read_value = 0; uint16_t analog_read(uint8_t channel) { sim_assert(analog_initialised, "analog_init() was not called before analog_read()"); sim_assert(sim_interrupts, "interrupts disabled"); - return 0; + return analog_read_value; +} + +void sim_report_temptables(int sensor) { + int i ; + temp_sensor_t s, first = sensor, last = sensor+1 ; + + // sensor is a specific sensor or -1 for "all sensors" + if (sensor == -1) { + first = 0; + last = NUM_TEMP_SENSORS; + } + + sei(); + analog_init(); + printf("; Temperature sensor test %d\n", sensor); + for (s = first; s < last; s++ ) { + printf("; Sensor %d\n", s); + for (i = 0 ; i < 1024 ; i++ ) { + analog_read_value = i ; + temp_sensor_tick() ; + uint16_t temp = temp_get(s); + printf("%d %.2f\n", i, ((float)temp)/4 ) ; + } + } } diff --git a/simulator/simulator.c b/simulator/simulator.c index 96ee137ef..b157b47bd 100644 --- a/simulator/simulator.c +++ b/simulator/simulator.c @@ -45,7 +45,7 @@ int verbose = 1; ///< 0=quiet, 1=normal, 2=noisy, 3=debug, etc. int trace_gcode = 0; ///< show gcode on the console int trace_pos = 0; ///< show print head position on the console -const char * shortopts = "qgpvt:o::"; +const char * shortopts = "qgpvt:o::T::"; struct option opts[] = { { "quiet", no_argument, &verbose , 0 }, { "verbose", no_argument, NULL, 'v' }, @@ -53,6 +53,7 @@ struct option opts[] = { { "pos", no_argument, NULL, 'p' }, { "time-scale", required_argument, NULL, 't' }, { "tracefile", optional_argument, NULL, 'o' }, + { "report-temptable", optional_argument, NULL, 'T' }, { 0, 0, 0, 0 } }; @@ -65,6 +66,7 @@ static void usage(const char *name) { printf(" -p || --pos show head position on console\n"); printf(" -t || --time-scale=n set time-scale; 0=warp-speed, 1=real-time, 2=half-time, etc.\n"); printf(" -o || --tracefile[=filename] write simulator pin trace to 'outfile' (default filename=datalog.out)\n"); + printf(" -T || --report-temptable=n Report calculated temperatures for all ADC values and exit\n"); printf("\n"); exit(1); } @@ -96,6 +98,9 @@ void sim_start(int argc, char** argv) { case 'o': recorder_init(optarg ? optarg : "datalog.out"); break; + case 'T': + sim_report_temptables(optarg ? atoi(optarg) : -1); + exit(0); default: exit(1); } diff --git a/temp.c b/temp.c index e0162cf5b..f43c55cb4 100644 --- a/temp.c +++ b/temp.c @@ -186,53 +186,64 @@ 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) { - - 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); - - // Wikipedia's example linear interpolation formula. - // 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] - temp = ( - // ((x - x₀)y₁ - ((uint32_t)temp - pgm_read_word(&(temptable[table_num][j-1][0]))) * - pgm_read_word(&(temptable[table_num][j][1])) - // + - + - // (x₁-x)y₀) - (pgm_read_word(&(temptable[table_num][j][0])) - (uint32_t)temp) * - pgm_read_word(&(temptable[table_num][j - 1][1]))) - // / - / - // (x₁ - x₀) - (pgm_read_word(&(temptable[table_num][j][0])) - - pgm_read_word(&(temptable[table_num][j - 1][0]))); - - 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; - } + // Binary search for table value bigger than our 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 ; } + // lo = index of highest entry less than target + // hi = index of lowest entry greater than or equal to target if (DEBUG_PID && (debug_flags & DEBUG_PID)) - sersendf_P(PSTR(" Sensor:%d\n"), sensor); + sersendf_P(PSTR("pin:%d Raw ADC:%d table entry: %d"), + temp_sensors[sensor].temp_pin, temp, hi); + + #if (TEMPTABLE_FORMAT == 0) + // Wikipedia's example linear interpolation formula. + // y = ((x - x₀)y₁ + (x₁-x)y₀) / (x₁ - x₀) + // y = temp + // x = ADC reading + // 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][lo][0]))) * + pgm_read_word(&(temptable[table_num][hi][1])) + // + + + + // (x₁-x)y₀) + (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][hi][0])) - + pgm_read_word(&(temptable[table_num][lo][0]))); + #elif (TEMPTABLE_FORMAT == 1) + // Linear interpolation using pre-computed slope + // y = y₁ - (x-x₁)*d₁ + #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); + #else + #error "temptable format unrecognized" + #endif + + if (DEBUG_PID && (debug_flags & DEBUG_PID)) + sersendf_P(PSTR(" temp:%d.%d"), temp / 4, (temp % 4) * 25); - // Clamp for overflows. - if (j == NUMTEMPS) - temp = temptable[table_num][NUMTEMPS - 1][1]; + if (DEBUG_PID && (debug_flags & DEBUG_PID)) + sersendf_P(PSTR(" Sensor:%d\n"), sensor); return temp; }