Decouple temperature ISR from ADC readings
Read from ADC as fast as possible using the ADC interrupt to get more accurate instantaneous readings. Decouple the temperature_isr from the adc reading interval, so that the two can run independently for future use.
This commit is contained in:
parent
e87188e7e3
commit
16b9acf8bc
@ -573,6 +573,7 @@ void dcode_9()
|
|||||||
for (uint8_t i = 0; i < ADC_CHAN_CNT; i++)
|
for (uint8_t i = 0; i < ADC_CHAN_CNT; i++)
|
||||||
printf_P(PSTR("\tADC%d=%4d\t(%S)\n"), i, dcode_9_ADC_val(i) >> 4, dcode_9_ADC_name(i));
|
printf_P(PSTR("\tADC%d=%4d\t(%S)\n"), i, dcode_9_ADC_val(i) >> 4, dcode_9_ADC_name(i));
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint8_t index = 0xff;
|
uint8_t index = 0xff;
|
||||||
@ -588,6 +589,7 @@ void dcode_9()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
//adc.c
|
|
||||||
|
|
||||||
#include "adc.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
#include "pins.h"
|
|
||||||
|
|
||||||
uint8_t adc_state;
|
|
||||||
uint8_t adc_count;
|
|
||||||
uint16_t adc_values[ADC_CHAN_CNT];
|
|
||||||
uint16_t adc_sim_mask;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef ADC_CALLBACK
|
|
||||||
extern void ADC_CALLBACK(void);
|
|
||||||
#endif //ADC_CALLBACK
|
|
||||||
|
|
||||||
|
|
||||||
void adc_init(void)
|
|
||||||
{
|
|
||||||
puts_P(PSTR("adc_init"));
|
|
||||||
adc_sim_mask = 0x00;
|
|
||||||
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
|
|
||||||
ADMUX |= (1 << REFS0);
|
|
||||||
ADCSRA |= (1 << ADEN);
|
|
||||||
// ADCSRA |= (1 << ADIF) | (1 << ADSC);
|
|
||||||
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff);
|
|
||||||
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8);
|
|
||||||
adc_reset();
|
|
||||||
// adc_sim_mask = 0b0101;
|
|
||||||
// adc_sim_mask = 0b100101;
|
|
||||||
// adc_values[0] = 1023 * 16;
|
|
||||||
// adc_values[2] = 1023 * 16;
|
|
||||||
// adc_values[5] = 1002 * 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adc_reset(void)
|
|
||||||
{
|
|
||||||
adc_state = 0;
|
|
||||||
adc_count = 0;
|
|
||||||
uint8_t i; for (i = 0; i < ADC_CHAN_CNT; i++)
|
|
||||||
if ((adc_sim_mask & (1 << i)) == 0)
|
|
||||||
adc_values[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adc_setmux(uint8_t ch)
|
|
||||||
{
|
|
||||||
ch &= 0x0f;
|
|
||||||
if (ch & 0x08) ADCSRB |= (1 << MUX5);
|
|
||||||
else ADCSRB &= ~(1 << MUX5);
|
|
||||||
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t adc_chan(uint8_t index)
|
|
||||||
{
|
|
||||||
uint8_t chan = 0;
|
|
||||||
uint16_t mask = 1;
|
|
||||||
while (mask)
|
|
||||||
{
|
|
||||||
if ((mask & ADC_CHAN_MSK) && (index-- == 0)) break;
|
|
||||||
mask <<= 1;
|
|
||||||
chan++;
|
|
||||||
}
|
|
||||||
return chan;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adc_cycle(void)
|
|
||||||
{
|
|
||||||
if (adc_state & 0x80)
|
|
||||||
{
|
|
||||||
uint8_t index = adc_state & 0x0f;
|
|
||||||
if ((adc_sim_mask & (1 << index)) == 0)
|
|
||||||
adc_values[index] += ADC;
|
|
||||||
if (++index >= ADC_CHAN_CNT)
|
|
||||||
{
|
|
||||||
index = 0;
|
|
||||||
adc_count++;
|
|
||||||
if (adc_count >= ADC_OVRSAMPL)
|
|
||||||
{
|
|
||||||
#ifdef ADC_CALLBACK
|
|
||||||
ADC_CALLBACK();
|
|
||||||
#endif //ADC_CALLBACK
|
|
||||||
adc_reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
adc_setmux(adc_chan(index));
|
|
||||||
adc_state = index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ADCSRA |= (1 << ADSC); //start conversion
|
|
||||||
adc_state |= 0x80;
|
|
||||||
}
|
|
||||||
}
|
|
81
Firmware/adc.cpp
Normal file
81
Firmware/adc.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "adc.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "pins.h"
|
||||||
|
|
||||||
|
static uint8_t adc_count; //used for oversampling
|
||||||
|
static uint8_t adc_channel_idx; //bitmask index
|
||||||
|
volatile uint8_t adc_channel; //regular index
|
||||||
|
volatile uint16_t adc_values[ADC_CHAN_CNT];
|
||||||
|
|
||||||
|
static void adc_reset();
|
||||||
|
static void adc_setmux(uint8_t ch);
|
||||||
|
|
||||||
|
void adc_init()
|
||||||
|
{
|
||||||
|
puts_P(PSTR("adc_init"));
|
||||||
|
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff); //disable digital inputs PORTF
|
||||||
|
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8); //disable digital inputs PORTK
|
||||||
|
ADMUX |= (1 << REFS0); //use AVCC as reference
|
||||||
|
|
||||||
|
//enable ADC, set prescaler/128, enable interrupt
|
||||||
|
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADIF) | (1 << ADIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adc_reset()
|
||||||
|
{
|
||||||
|
static const uint8_t first_channel_idx = 0;
|
||||||
|
static_assert((1 << first_channel_idx) & ADC_CHAN_MSK);
|
||||||
|
|
||||||
|
ADCSRA &= ~(1 << ADSC); //stop conversion just in case
|
||||||
|
adc_count = 0;
|
||||||
|
adc_channel = 0;
|
||||||
|
adc_channel_idx = first_channel_idx;
|
||||||
|
adc_setmux(adc_channel_idx);
|
||||||
|
memset((void*)adc_values, 0, sizeof(adc_values));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adc_setmux(uint8_t ch)
|
||||||
|
{
|
||||||
|
ch &= 0x0f;
|
||||||
|
if (ch & 0x08) ADCSRB |= (1 << MUX5);
|
||||||
|
else ADCSRB &= ~(1 << MUX5);
|
||||||
|
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
|
||||||
|
}
|
||||||
|
|
||||||
|
void adc_start_cycle() {
|
||||||
|
adc_reset();
|
||||||
|
ADCSRA |= (1 << ADSC); //start conversion
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ADC_CALLBACK
|
||||||
|
extern void ADC_CALLBACK();
|
||||||
|
#endif //ADC_CALLBACK
|
||||||
|
|
||||||
|
ISR(ADC_vect)
|
||||||
|
{
|
||||||
|
adc_values[adc_channel] += ADC;
|
||||||
|
if (++adc_count == ADC_OVRSAMPL)
|
||||||
|
{
|
||||||
|
// go to the next channel
|
||||||
|
if (++adc_channel == ADC_CHAN_CNT) {
|
||||||
|
#ifdef ADC_CALLBACK
|
||||||
|
ADC_CALLBACK();
|
||||||
|
#endif
|
||||||
|
return; // do not start the next measurement since there are no channels remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the next channel
|
||||||
|
while (++adc_channel_idx) {
|
||||||
|
if (ADC_CHAN_MSK & (1 << adc_channel_idx)) {
|
||||||
|
adc_setmux(adc_channel_idx);
|
||||||
|
adc_count = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ADCSRA |= (1 << ADSC); //start conversion
|
||||||
|
}
|
@ -1,15 +1,8 @@
|
|||||||
//adc.h
|
#pragma once
|
||||||
#ifndef _ADC_H
|
|
||||||
#define _ADC_H
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
extern "C" {
|
|
||||||
#endif //defined(__cplusplus)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
|
http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
|
||||||
*/
|
*/
|
||||||
@ -22,24 +15,9 @@ http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
|
|||||||
# error "ADC_CHAN_MSK oes not match ADC_CHAN_CNT"
|
# error "ADC_CHAN_MSK oes not match ADC_CHAN_CNT"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern uint8_t adc_state;
|
extern volatile uint8_t adc_channel;
|
||||||
extern uint8_t adc_count;
|
extern volatile uint16_t adc_values[ADC_CHAN_CNT];
|
||||||
extern uint16_t adc_values[ADC_CHAN_CNT];
|
|
||||||
extern uint16_t adc_sim_mask;
|
|
||||||
|
|
||||||
|
extern void adc_init();
|
||||||
extern void adc_init(void);
|
extern void adc_start_cycle(); //should be called from an atomic context only
|
||||||
|
static inline bool adc_cycle_done() { return adc_channel >= ADC_CHAN_CNT; }
|
||||||
extern void adc_reset(void);
|
|
||||||
|
|
||||||
extern void adc_setmux(uint8_t ch);
|
|
||||||
|
|
||||||
extern uint8_t adc_chan(uint8_t index);
|
|
||||||
|
|
||||||
extern void adc_cycle(void);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif //defined(__cplusplus)
|
|
||||||
#endif //_ADC_H
|
|
||||||
|
@ -97,6 +97,7 @@ unsigned char soft_pwm_bed;
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
//=============================private variables============================
|
//=============================private variables============================
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
#define TEMP_MEAS_RATE 250
|
||||||
static volatile bool temp_meas_ready = false;
|
static volatile bool temp_meas_ready = false;
|
||||||
|
|
||||||
#ifdef PIDTEMP
|
#ifdef PIDTEMP
|
||||||
@ -265,9 +266,6 @@ void __attribute__((noinline)) PID_autotune(float temp, int extruder, int ncycle
|
|||||||
target_temperature[extruder] = (int)temp; // to display the requested target extruder temperature properly on the main screen
|
target_temperature[extruder] = (int)temp; // to display the requested target extruder temperature properly on the main screen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
#ifdef WATCHDOG
|
#ifdef WATCHDOG
|
||||||
wdt_reset();
|
wdt_reset();
|
||||||
@ -451,9 +449,13 @@ void manage_heater()
|
|||||||
float pid_input;
|
float pid_input;
|
||||||
float pid_output;
|
float pid_output;
|
||||||
|
|
||||||
if(temp_meas_ready != true) //better readability
|
// run at TEMP_MEAS_RATE
|
||||||
return;
|
if(temp_meas_ready != true) return;
|
||||||
// more precisely - this condition partially stabilizes time interval for regulation values evaluation (@ ~ 230ms)
|
static unsigned long old_stamp = _millis();
|
||||||
|
unsigned long new_stamp = _millis();
|
||||||
|
unsigned long diff = new_stamp - old_stamp;
|
||||||
|
if(diff < TEMP_MEAS_RATE) return;
|
||||||
|
old_stamp = new_stamp;
|
||||||
|
|
||||||
// ADC values need to be converted before checking: converted values are later used in MINTEMP
|
// ADC values need to be converted before checking: converted values are later used in MINTEMP
|
||||||
updateTemperaturesFromRawValues();
|
updateTemperaturesFromRawValues();
|
||||||
@ -774,6 +776,11 @@ static float analog2tempAmbient(int raw)
|
|||||||
and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */
|
and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */
|
||||||
static void updateTemperaturesFromRawValues()
|
static void updateTemperaturesFromRawValues()
|
||||||
{
|
{
|
||||||
|
CRITICAL_SECTION_START;
|
||||||
|
adc_start_cycle();
|
||||||
|
temp_meas_ready = false;
|
||||||
|
CRITICAL_SECTION_END;
|
||||||
|
|
||||||
for(uint8_t e=0;e<EXTRUDERS;e++)
|
for(uint8_t e=0;e<EXTRUDERS;e++)
|
||||||
{
|
{
|
||||||
current_temperature[e] = analog2temp(current_temperature_raw[e], e);
|
current_temperature[e] = analog2temp(current_temperature_raw[e], e);
|
||||||
@ -793,10 +800,6 @@ static void updateTemperaturesFromRawValues()
|
|||||||
#else //DEBUG_HEATER_BED_SIM
|
#else //DEBUG_HEATER_BED_SIM
|
||||||
current_temperature_bed = analog2tempBed(current_temperature_bed_raw);
|
current_temperature_bed = analog2tempBed(current_temperature_bed_raw);
|
||||||
#endif //DEBUG_HEATER_BED_SIM
|
#endif //DEBUG_HEATER_BED_SIM
|
||||||
|
|
||||||
CRITICAL_SECTION_START;
|
|
||||||
temp_meas_ready = false;
|
|
||||||
CRITICAL_SECTION_END;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tp_init()
|
void tp_init()
|
||||||
@ -863,14 +866,16 @@ void tp_init()
|
|||||||
digitalWrite(MAX6675_SS,1);
|
digitalWrite(MAX6675_SS,1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// initialize the ADC and start a conversion
|
||||||
adc_init();
|
adc_init();
|
||||||
|
adc_start_cycle();
|
||||||
|
|
||||||
timer0_init(); //enables the heatbed timer.
|
timer0_init(); //enables the heatbed timer.
|
||||||
|
|
||||||
// timer2 already enabled earlier in the code
|
// timer2 already enabled earlier in the code
|
||||||
// now enable the COMPB temperature interrupt
|
// now enable the COMPB temperature interrupt
|
||||||
OCR2B = 128;
|
OCR2B = 128;
|
||||||
TIMSK2 |= (1<<OCIE2B);
|
ENABLE_TEMPERATURE_INTERRUPT();
|
||||||
|
|
||||||
timer4_init(); //for tone and Extruder fan PWM
|
timer4_init(); //for tone and Extruder fan PWM
|
||||||
|
|
||||||
@ -1374,10 +1379,6 @@ int read_max6675()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
|
|
||||||
void adc_ready(void) //callback from adc when sampling finished
|
void adc_ready(void) //callback from adc when sampling finished
|
||||||
{
|
{
|
||||||
current_temperature_raw[0] = adc_values[ADC_PIN_IDX(TEMP_0_PIN)]; //heater
|
current_temperature_raw[0] = adc_values[ADC_PIN_IDX(TEMP_0_PIN)]; //heater
|
||||||
@ -1400,11 +1401,8 @@ void adc_ready(void) //callback from adc when sampling finished
|
|||||||
temp_meas_ready = true;
|
temp_meas_ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
||||||
FORCE_INLINE static void temperature_isr()
|
FORCE_INLINE static void temperature_isr()
|
||||||
{
|
{
|
||||||
if (!temp_meas_ready) adc_cycle();
|
|
||||||
lcd_buttons_update();
|
lcd_buttons_update();
|
||||||
|
|
||||||
static uint8_t pwm_count = (1 << SOFT_PWM_SCALE);
|
static uint8_t pwm_count = (1 << SOFT_PWM_SCALE);
|
||||||
|
Loading…
Reference in New Issue
Block a user