diff --git a/arduino_168_328p.h b/arduino_168_328p.h index 9bc289b..ed970fe 100644 --- a/arduino_168_328p.h +++ b/arduino_168_328p.h @@ -126,6 +126,16 @@ pins #define AIO5_WPORT PORTC #define AIO5_DDR DDRC +#define AIO6_PIN PINC6 +#define AIO6_RPORT PINC +#define AIO6_WPORT PORTC +#define AIO6_DDR DDRC + +#define AIO7_PIN PINC7 +#define AIO7_RPORT PINC +#define AIO7_WPORT PORTC +#define AIO7_DDR DDRC + #define PB0_PIN PINB0 #define PB0_RPORT PINB #define PB0_WPORT PORTB diff --git a/clock.c b/clock.c index 6d035d2..4c8ce34 100644 --- a/clock.c +++ b/clock.c @@ -31,6 +31,9 @@ void clock_250ms() { /* if (temp_get_target()) temp_print();*/ } + #ifdef TEMP_INTERCOM + start_send(); + #endif } void clock_10ms() { diff --git a/extruder/analog.c b/extruder/analog.c index c6d7c5e..ddced7b 100644 --- a/extruder/analog.c +++ b/extruder/analog.c @@ -1,48 +1,21 @@ #include "analog.h" +#include "temp.h" #include -#ifndef ANALOG_MASK - #warning ANALOG_MASK not defined - analog subsystem disabled - #define ANALOG_MASK 0 -#endif +/* OR-combined mask of all channels */ +#undef DEFINE_TEMP_SENSOR +#define DEFINE_TEMP_SENSOR(name, type, pin) | (((type == TT_THERMISTOR) || (type == TT_AD595)) ? 1 << (pin) : 0) +static const uint8_t analog_mask = 0 +#include "config.h" +; +#undef DEFINE_TEMP_SENSOR -uint8_t adc_running_mask, adc_counter; - -#if ANALOG_MASK & 1 - #define ANALOG_START 0 - #define ANALOG_START_MASK 1 -#elif ANALOG_MASK & 2 - #define ANALOG_START 1 - #define ANALOG_START_MASK 2 -#elif ANALOG_MASK & 4 - #define ANALOG_START 2 - #define ANALOG_START_MASK 4 -#elif ANALOG_MASK & 8 - #define ANALOG_START 3 - #define ANALOG_START_MASK 8 -#elif ANALOG_MASK & 16 - #define ANALOG_START 4 - #define ANALOG_START_MASK 16 -#elif ANALOG_MASK & 32 - #define ANALOG_START 5 - #define ANALOG_START_MASK 32 -#elif ANALOG_MASK & 64 - #define ANALOG_START 6 - #define ANALOG_START_MASK 64 -#elif ANALOG_MASK & 128 - #define ANALOG_START 7 - #define ANALOG_START_MASK 128 -#else - // ANALOG_MASK == 0 - #define ANALOG_START 0 - #define ANALOG_START_MASK 1 -#endif - -volatile uint16_t adc_result[8] __attribute__ ((__section__ (".bss"))); +static uint8_t adc_counter; +static volatile uint16_t adc_result[8] __attribute__ ((__section__ (".bss"))); void analog_init() { - #if ANALOG_MASK > 0 + if (analog_mask > 0) { #ifdef PRR PRR &= ~MASK(PRADC); #elif defined PRR0 @@ -55,36 +28,32 @@ void analog_init() { ADCSRA = MASK(ADEN) | MASK(ADPS2) | MASK(ADPS1) | MASK(ADPS0); adc_counter = 0; - adc_running_mask = 1; - - AIO0_DDR &= ANALOG_MASK; - DIDR0 = ANALOG_MASK & 0x3F; + AIO0_DDR &= ~analog_mask; + DIDR0 = analog_mask & 0x3F; // now we start the first conversion and leave the rest to the interrupt ADCSRA |= MASK(ADIE) | MASK(ADSC); - #endif /* ANALOG_MASK > 0 */ + } /* analog_mask > 0 */ } ISR(ADC_vect, ISR_NOBLOCK) { // emulate free-running mode but be more deterministic about exactly which result we have, since this project has long-running interrupts - adc_result[ADMUX & 0x0F] = ADC; - // find next channel - do { - adc_counter++; - adc_running_mask <<= 1; - if (adc_counter == 8) { - adc_counter = ANALOG_START; - adc_running_mask = ANALOG_START_MASK; - } - } while ((adc_running_mask & ANALOG_MASK) == 0); + if (analog_mask > 0) { + adc_result[ADMUX & 0x0F] = ADC; + // find next channel + do { + adc_counter++; + adc_counter &= 0x07; + } while ((analog_mask & (1 << adc_counter)) == 0); - // start next conversion - ADMUX = (adc_counter) | REFERENCE; - ADCSRA |= MASK(ADSC); + // start next conversion + ADMUX = (adc_counter) | REFERENCE; + ADCSRA |= MASK(ADSC); + } } uint16_t analog_read(uint8_t channel) { - #if ANALOG_MASK > 0 + if (analog_mask > 0) { uint16_t r; uint8_t sreg; @@ -100,7 +69,7 @@ uint16_t analog_read(uint8_t channel) { SREG = sreg; return r; - #else + } else { return 0; - #endif + } } diff --git a/extruder/arduino_168_328p.h b/extruder/arduino_168_328p.h index 9bc289b..ed970fe 100644 --- a/extruder/arduino_168_328p.h +++ b/extruder/arduino_168_328p.h @@ -126,6 +126,16 @@ pins #define AIO5_WPORT PORTC #define AIO5_DDR DDRC +#define AIO6_PIN PINC6 +#define AIO6_RPORT PINC +#define AIO6_WPORT PORTC +#define AIO6_DDR DDRC + +#define AIO7_PIN PINC7 +#define AIO7_RPORT PINC +#define AIO7_WPORT PORTC +#define AIO7_DDR DDRC + #define PB0_PIN PINB0 #define PB0_RPORT PINB #define PB0_WPORT PORTB diff --git a/extruder/config.h.dist b/extruder/config.h.dist index cd6d41a..d1851e1 100644 --- a/extruder/config.h.dist +++ b/extruder/config.h.dist @@ -3,6 +3,9 @@ #include "arduino.h" +// controller index- bus is multidrop after all +#define THIS_CONTROLLER_NUM 0 + //RS485 Interface pins #define RX_ENABLE_PIN DIO4 #define TX_ENABLE_PIN AIO2 @@ -30,43 +33,33 @@ #define TEMP_PIN AIO3 #define TEMP_PIN_CHANNEL 3 +//Read analog voltage from thermistor +#define TEMP_BED_PIN AIO6 +#define TEMP_BED_PIN_CHANNEL 6 + + #define REFERENCE REFERENCE_AVCC -#define ANALOG_MASK (MASK(TRIM_POT_CHANNEL) | MASK(TEMP_PIN_CHANNEL)) +#define ANALOG_MASK (MASK(TRIM_POT_CHANNEL) | MASK(TEMP_PIN_CHANNEL) | MASK(TEMP_BED_PIN_CHANNEL)) #define TEMP_THERMISTOR +#define HEATER_PIN DIO11 +#define BED_PIN AIO1 +#define FAN_PIN DIO12 + // extruder settings #define TEMP_HYSTERESIS 20 #define TEMP_RESIDENCY_TIME 60 -#define NUM_TEMP_SENSORS 1 -#ifdef TEMP_C -/***************************************************************************\ -* * -* Fill in the following struct according to your hardware * -* * -* If your temperature sensor has no associated heater, enter '255' as the * -* heater index. * -* * -* for GEN3 set temp_type to TT_INTERCOM, temp_pin to 0 and heater index to * -* 255 * -* * -\***************************************************************************/ +#ifdef DEFINE_TEMP_SENSOR +DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, TEMP_PIN_CHANNEL) +DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, TEMP_BED_PIN_CHANNEL) +#endif -struct { - uint8_t temp_type; - uint8_t temp_pin; - - uint8_t heater_index; -} temp_sensors[NUM_TEMP_SENSORS] = -{ - { - TT_THERMISTOR, - PINC3, - 0 - } -}; +#ifdef DEFINE_HEATER +DEFINE_HEATER(extruder, PORTD, HEATER_PIN, OCR0A) +DEFINE_HEATER(bed, PORTD, BED_PIN, OCR0B) #endif // list of PWM-able pins and corresponding timers @@ -74,56 +67,13 @@ struct { // OC0A DIO6 // OC0B DIO5 // OC1A DIO9 -// OC1B DIO10 +// OC1B DIO10 // OC2A DIO11 // OC2B DIO3 #define TH_COUNT 8 #define PID_SCALE 1024L -#define NUM_HEATERS 2 -#ifdef HEATER_C -/***************************************************************************\ -* * -* Fill in the following struct according to your hardware * -* * -* For the atmega168/328, timer/pin mappings are as follows * -* * -* OCR0A - PD6 * -* OCR0B - PD5 * -* OCR2A - PB3 * -* OCR2B - PD3 * -* * -\***************************************************************************/ -struct { - volatile uint8_t *heater_port; - uint8_t heater_pin; - volatile uint8_t *heater_pwm; -} heaters[NUM_HEATERS] = -{ - { - &PORTD, - PIND6, - &OCR0A - }, - { - &PORTB, - PINB4, - 0 - } -}; -#endif - -// #define HEATER_PIN DIO11 -// #define HEATER_PWM OCR2A -// -// #define BED_PIN DIO12 - -/* - Intercom -*/ -#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0) -#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0) /* Motors @@ -132,16 +82,4 @@ struct { #define enable_motors() do { TCCR0A |= MASK(COM0A1) | MASK(COM0B1); } while (0) #define disable_motors() do { TCCR0A &= ~MASK(COM0A1) & ~MASK(COM0B1); } while (0) -/* - Heater -*/ - -// #ifdef HEATER_PWM -// #define enable_heater() do { TCCR2A |= MASK(COM2A1); } while (0) -// #define disable_heater() do { TCCR2A &= ~MASK(COM2A1); } while (0) -// #else -// #define enable_heater() WRITE(HEATER_PIN, 1) -// #define disable_heater() WRITE(HEATER_PIN, 0) -// #endif - #endif /* _CONFIG_H */ diff --git a/extruder/debug.h b/extruder/debug.h index e96e268..08f0321 100644 --- a/extruder/debug.h +++ b/extruder/debug.h @@ -3,18 +3,12 @@ #include -#ifdef DEBUG - #define DEBUG_PID 1 - #define DEBUG_DDA 2 - #define DEBUG_POSITION 4 -#else - // by setting these to zero, the compiler should optimise the relevant code out - #define DEBUG_PID 0 - #define DEBUG_DDA 0 - #define DEBUG_POSITION 0 -#endif +// by setting these to zero, the compiler should optimise the relevant code out +#define DEBUG_PID 0 +#define DEBUG_DDA 0 +#define DEBUG_POSITION 0 -#define DEBUG_ECHO 128 +#define DEBUG_ECHO 0 extern volatile uint8_t debug_flags; diff --git a/extruder/extruder.c b/extruder/extruder.c index cc4bbb0..79d1eff 100644 --- a/extruder/extruder.c +++ b/extruder/extruder.c @@ -22,12 +22,18 @@ void io_init(void) { SET_INPUT(TRIM_POT); SET_INPUT(TEMP_PIN); + SET_INPUT(TEMP_BED_PIN); SET_INPUT(E_STEP_PIN); SET_INPUT(E_DIR_PIN); + // use pull up resistors to avoid noise + WRITE(E_STEP_PIN, 1); + WRITE(E_DIR_PIN, 1); + //Enable the RS485 transceiver SET_OUTPUT(RX_ENABLE_PIN); SET_OUTPUT(TX_ENABLE_PIN); + WRITE(RX_ENABLE_PIN,0); disable_transmit(); #ifdef HEATER_PIN @@ -38,6 +44,10 @@ void io_init(void) { WRITE(BED_PIN, 0); SET_OUTPUT(BED_PIN); #endif + #ifdef FAN_PIN + WRITE(FAN_PIN, 0); SET_OUTPUT(FAN_PIN); + #endif + // #if defined(HEATER_PWM) || defined(FAN_PWM) || defined(BED_PWM) // setup PWM timer: fast PWM, no prescaler TCCR2A = MASK(WGM21) | MASK(WGM20); @@ -64,13 +74,10 @@ void motor_init(void) { } ISR(PCINT0_vect) { - static uint8_t coil_pos, pwm, flag; + static uint8_t coil_pos, pwm; - if (flag == 1) flag = 0; - else flag = 1; - //if the step pin is high, we advance the motor - if (flag) { + if (READ(E_STEP_PIN)) { //Turn on motors only on first tick to save power I guess enable_motors(); @@ -81,12 +88,12 @@ ISR(PCINT0_vect) { else coil_pos--; - coil_pos &= 31; + coil_pos &= 7; //Grab the latest motor power to use pwm = motor_pwm; - switch(coil_pos >> 2) { + switch(coil_pos) { case 0: WRITE(H1D, 0); WRITE(H2D, 0); @@ -187,7 +194,9 @@ int main (void) temp_sensor_tick(); - update_send_cmd(temp_get(0) >> 2); - temp_set(0, get_read_cmd()); + send_temperature(0, temp_get(0)); + send_temperature(1, temp_get(1)); + temp_set(0, read_temperature(0)); + temp_set(1, read_temperature(1)); } } diff --git a/extruder/heater.c b/extruder/heater.c index 7d0d759..8779dc1 100644 --- a/extruder/heater.c +++ b/extruder/heater.c @@ -9,9 +9,21 @@ #ifndef EXTRUDER #include "sersendf.h" #endif +#include "temp.h" -#define HEATER_C -#include "config.h" +typedef struct { + volatile uint8_t *heater_port; + uint8_t heater_pin; + volatile uint8_t *heater_pwm; +} heater_definition_t; + +#undef DEFINE_HEATER +#define DEFINE_HEATER(name, port, pin, pwm) { &(port), (pin), &(pwm) }, +static const heater_definition_t heaters[NUM_HEATERS] = +{ + #include "config.h" +}; +#undef DEFINE_HEATER // this struct holds the heater PID factors that are stored in the EEPROM during poweroff struct { @@ -32,6 +44,8 @@ struct { uint16_t sanity_counter; uint16_t sane_temperature; #endif + + uint8_t heater_output; } heaters_runtime[NUM_HEATERS]; #define DEFAULT_P 8192 @@ -50,8 +64,7 @@ typedef struct { EE_factor EEMEM EE_factors[NUM_HEATERS]; void heater_init() { - #if NUM_HEATERS > 0 - uint8_t i; + heater_t i; // setup pins for (i = 0; i < NUM_HEATERS; i++) { *(heaters[i].heater_port) &= ~MASK(heaters[i].heater_pin); @@ -80,82 +93,96 @@ void heater_init() { // 0 is a "sane" temperature when we're trying to cool down heaters_runtime[i].sane_temperature = 0; #endif - - // read factors from eeprom - heaters_pid[i].p_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_p_factor); - heaters_pid[i].i_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_i_factor); - heaters_pid[i].d_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_d_factor); - heaters_pid[i].i_limit = eeprom_read_word((uint16_t *) &EE_factors[i].EE_i_limit); - - if ((heaters_pid[i].p_factor == 0) && (heaters_pid[i].i_factor == 0) && (heaters_pid[i].d_factor == 0) && (heaters_pid[i].i_limit == 0)) { - heaters_pid[i].p_factor = DEFAULT_P; - heaters_pid[i].i_factor = DEFAULT_I; - heaters_pid[i].d_factor = DEFAULT_D; - heaters_pid[i].i_limit = DEFAULT_I_LIMIT; - } + + #ifndef BANG_BANG + // read factors from eeprom + heaters_pid[i].p_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_p_factor); + heaters_pid[i].i_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_i_factor); + heaters_pid[i].d_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_d_factor); + heaters_pid[i].i_limit = eeprom_read_word((uint16_t *) &EE_factors[i].EE_i_limit); + + if ((heaters_pid[i].p_factor == 0) && (heaters_pid[i].i_factor == 0) && (heaters_pid[i].d_factor == 0) && (heaters_pid[i].i_limit == 0)) { + heaters_pid[i].p_factor = DEFAULT_P; + heaters_pid[i].i_factor = DEFAULT_I; + heaters_pid[i].d_factor = DEFAULT_D; + heaters_pid[i].i_limit = DEFAULT_I_LIMIT; + } + #endif /* BANG_BANG */ } - #endif } void heater_save_settings() { - uint8_t i; - for (i = 0; i < NUM_HEATERS; i++) { - eeprom_write_dword((uint32_t *) &EE_factors[i].EE_p_factor, heaters_pid[i].p_factor); - eeprom_write_dword((uint32_t *) &EE_factors[i].EE_i_factor, heaters_pid[i].i_factor); - eeprom_write_dword((uint32_t *) &EE_factors[i].EE_d_factor, heaters_pid[i].d_factor); - eeprom_write_word((uint16_t *) &EE_factors[i].EE_i_limit, heaters_pid[i].i_limit); - } + #ifndef BANG_BANG + heater_t i; + for (i = 0; i < NUM_HEATERS; i++) { + eeprom_write_dword((uint32_t *) &EE_factors[i].EE_p_factor, heaters_pid[i].p_factor); + eeprom_write_dword((uint32_t *) &EE_factors[i].EE_i_factor, heaters_pid[i].i_factor); + eeprom_write_dword((uint32_t *) &EE_factors[i].EE_d_factor, heaters_pid[i].d_factor); + eeprom_write_word((uint16_t *) &EE_factors[i].EE_i_limit, heaters_pid[i].i_limit); + } + #endif /* BANG_BANG */ } -void heater_tick(uint8_t h, uint16_t current_temp, uint16_t target_temp) { - #if NUM_HEATERS > 0 - int16_t heater_p; - int16_t heater_d; +void heater_tick(heater_t h, temp_sensor_t t, uint16_t current_temp, uint16_t target_temp) { uint8_t pid_output; - - int16_t t_error = target_temp - current_temp; - - heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer++] = current_temp; - heaters_runtime[h].temp_history_pointer &= (TH_COUNT - 1); - - // PID stuff - // proportional - heater_p = t_error; - - // integral - heaters_runtime[h].heater_i += t_error; - // prevent integrator wind-up - if (heaters_runtime[h].heater_i > heaters_pid[h].i_limit) - heaters_runtime[h].heater_i = heaters_pid[h].i_limit; - else if (heaters_runtime[h].heater_i < -heaters_pid[h].i_limit) - heaters_runtime[h].heater_i = -heaters_pid[h].i_limit; - - // derivative - // note: D follows temp rather than error so there's no large derivative when the target changes - heater_d = heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer] - current_temp; - - // combine factors - int32_t pid_output_intermed = ( - ( - (((int32_t) heater_p) * heaters_pid[h].p_factor) + - (((int32_t) heaters_runtime[h].heater_i) * heaters_pid[h].i_factor) + - (((int32_t) heater_d) * heaters_pid[h].d_factor) - ) / PID_SCALE - ); - - // rebase and limit factors - if (pid_output_intermed > 255) - pid_output = 255; - else if (pid_output_intermed < 0) - pid_output = 0; - else - pid_output = pid_output_intermed & 0xFF; - #ifdef DEBUG - if (debug_flags & DEBUG_PID) - sersendf_P(PSTR("T{E:%d, P:%d * %ld = %ld / I:%d * %ld = %ld / D:%d * %ld = %ld # O: %ld = %u}\n"), t_error, heater_p, heaters_pid[h].p_factor, (int32_t) heater_p * heaters_pid[h].p_factor / PID_SCALE, heaters_runtime[h].heater_i, heaters_pid[h].i_factor, (int32_t) heaters_runtime[h].heater_i * heaters_pid[h].i_factor / PID_SCALE, heater_d, heaters_pid[h].d_factor, (int32_t) heater_d * heaters_pid[h].d_factor / PID_SCALE, pid_output_intermed, pid_output); + #ifndef BANG_BANG + int16_t heater_p; + int16_t heater_d; + int16_t t_error = target_temp - current_temp; + #endif /* BANG_BANG */ + + if (h >= NUM_HEATERS || t >= NUM_TEMP_SENSORS) + return; + + #ifndef BANG_BANG + heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer++] = current_temp; + heaters_runtime[h].temp_history_pointer &= (TH_COUNT - 1); + + // PID stuff + // proportional + heater_p = t_error; + + // integral + heaters_runtime[h].heater_i += t_error; + // prevent integrator wind-up + if (heaters_runtime[h].heater_i > heaters_pid[h].i_limit) + heaters_runtime[h].heater_i = heaters_pid[h].i_limit; + else if (heaters_runtime[h].heater_i < -heaters_pid[h].i_limit) + heaters_runtime[h].heater_i = -heaters_pid[h].i_limit; + + // derivative + // note: D follows temp rather than error so there's no large derivative when the target changes + heater_d = heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer] - current_temp; + + // combine factors + int32_t pid_output_intermed = ( + ( + (((int32_t) heater_p) * heaters_pid[h].p_factor) + + (((int32_t) heaters_runtime[h].heater_i) * heaters_pid[h].i_factor) + + (((int32_t) heater_d) * heaters_pid[h].d_factor) + ) / PID_SCALE + ); + + // rebase and limit factors + if (pid_output_intermed > 255) + pid_output = 255; + else if (pid_output_intermed < 0) + pid_output = 0; + else + pid_output = pid_output_intermed & 0xFF; + + #ifdef DEBUG + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR("T{E:%d, P:%d * %ld = %ld / I:%d * %ld = %ld / D:%d * %ld = %ld # O: %ld = %u}\n"), t_error, heater_p, heaters_pid[h].p_factor, (int32_t) heater_p * heaters_pid[h].p_factor / PID_SCALE, heaters_runtime[h].heater_i, heaters_pid[h].i_factor, (int32_t) heaters_runtime[h].heater_i * heaters_pid[h].i_factor / PID_SCALE, heater_d, heaters_pid[h].d_factor, (int32_t) heater_d * heaters_pid[h].d_factor / PID_SCALE, pid_output_intermed, pid_output); + #endif + #else + if (current_temp >= target_temp) + pid_output = BANG_BANG_ON; + else + pid_output = BANG_BANG_OFF; #endif - + #ifdef HEATER_SANITY_CHECK // check heater sanity // implementation is a moving window with some slow-down to compensate for thermal mass @@ -208,16 +235,19 @@ void heater_tick(uint8_t h, uint16_t current_temp, uint16_t target_temp) { if (labs(current_temp - heaters_runtime[h].sane_temperature) > TEMP_HYSTERESIS) { // no change, or change in wrong direction for a long time- heater is broken! pid_output = 0; - sersendf_P(PSTR("!! heater %d broken- temp is %d.%dC, target is %d.%dC, didn't reach %d.%dC in %d0 milliseconds\n"), h, current_temp >> 2, (current_temp & 3) * 25, target_temp >> 2, (target_temp & 3) * 25, heaters_runtime[h].sane_temperature >> 2, (heaters_runtime[h].sane_temperature & 3) * 25, heaters_runtime[h].sanity_counter); + sersendf_P(PSTR("!! heater %d or temp sensor %d broken- temp is %d.%dC, target is %d.%dC, didn't reach %d.%dC in %d0 milliseconds\n"), h, t, current_temp >> 2, (current_temp & 3) * 25, target_temp >> 2, (target_temp & 3) * 25, heaters_runtime[h].sane_temperature >> 2, (heaters_runtime[h].sane_temperature & 3) * 25, heaters_runtime[h].sanity_counter); } #endif /* HEATER_SANITY_CHECK */ heater_set(h, pid_output); - #endif /* if NUM_HEATERS > 0 */ } -void heater_set(uint8_t index, uint8_t value) { - #if NUM_HEATERS > 0 +void heater_set(heater_t index, uint8_t value) { + if (index >= NUM_HEATERS) + return; + + heaters_runtime[index].heater_output = value; + if (heaters[index].heater_pwm) { *(heaters[index].heater_pwm) = value; #ifdef DEBUG @@ -231,21 +261,50 @@ void heater_set(uint8_t index, uint8_t value) { else *(heaters[index].heater_port) &= ~MASK(heaters[index].heater_pin); } - #endif /* if NUM_HEATERS > 0 */ } -void pid_set_p(uint8_t index, int32_t p) { - heaters_pid[index].p_factor = p; +uint8_t heaters_all_off() { + uint8_t i; + for (i = 0; i < NUM_HEATERS; i++) { + if (heaters_runtime[i].heater_output > 0) + return 0; + } + + return 255; } -void pid_set_i(uint8_t index, int32_t i) { - heaters_pid[index].i_factor = i; +void pid_set_p(heater_t index, int32_t p) { + #ifndef BANG_BANG + if (index >= NUM_HEATERS) + return; + + heaters_pid[index].p_factor = p; + #endif /* BANG_BANG */ } -void pid_set_d(uint8_t index, int32_t d) { - heaters_pid[index].d_factor = d; +void pid_set_i(heater_t index, int32_t i) { + #ifndef BANG_BANG + if (index >= NUM_HEATERS) + return; + + heaters_pid[index].i_factor = i; + #endif /* BANG_BANG */ } -void pid_set_i_limit(uint8_t index, int32_t i_limit) { - heaters_pid[index].i_limit = i_limit; +void pid_set_d(heater_t index, int32_t d) { + #ifndef BANG_BANG + if (index >= NUM_HEATERS) + return; + + heaters_pid[index].d_factor = d; + #endif /* BANG_BANG */ +} + +void pid_set_i_limit(heater_t index, int32_t i_limit) { + #ifndef BANG_BANG + if (index >= NUM_HEATERS) + return; + + heaters_pid[index].i_limit = i_limit; + #endif /* BANG_BANG */ } diff --git a/extruder/heater.h b/extruder/heater.h index fdc9dc9..edd3d23 100644 --- a/extruder/heater.h +++ b/extruder/heater.h @@ -1,20 +1,34 @@ #ifndef _HEATER_H #define _HEATER_H +#include "config.h" #include +#include "temp.h" #define enable_heater() heater_set(0, 64) #define disable_heater() heater_set(0, 0) +#undef DEFINE_HEATER +#define DEFINE_HEATER(name, port, pin, pwm) HEATER_ ## name, +typedef enum +{ + #include "config.h" + NUM_HEATERS, + HEATER_noheater +} heater_t; +#undef DEFINE_HEATER + void heater_init(void); void heater_save_settings(void); -void heater_set(uint8_t index, uint8_t value); -void heater_tick(uint8_t h, uint16_t current_temp, uint16_t target_temp); +void heater_set(heater_t index, uint8_t value); +void heater_tick(heater_t h, temp_sensor_t t, uint16_t current_temp, uint16_t target_temp); -void pid_set_p(uint8_t index, int32_t p); -void pid_set_i(uint8_t index, int32_t i); -void pid_set_d(uint8_t index, int32_t d); -void pid_set_i_limit(uint8_t index, int32_t i_limit); +uint8_t heaters_all_off(void); + +void pid_set_p(heater_t index, int32_t p); +void pid_set_i(heater_t index, int32_t i); +void pid_set_d(heater_t index, int32_t d); +void pid_set_i_limit(heater_t index, int32_t i_limit); #endif /* _HEATER_H */ diff --git a/extruder/intercom.c b/extruder/intercom.c index 7cab163..06cfa36 100644 --- a/extruder/intercom.c +++ b/extruder/intercom.c @@ -1,47 +1,55 @@ #include "intercom.h" +#include #include #include "config.h" #include "delay.h" -#ifdef GEN3 +#if (defined TEMP_INTERCOM) || (defined EXTRUDER) #define INTERCOM_BAUD 57600 -#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0) -#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0) +#define START 0x55 -/* - Defines a super simple intercom interface using the RS485 modules +enum { + ERROR_BAD_CRC +} err_codes; - Host will say: START1 START2 PWM_CMD PWM_CHK - Extruder will reply: START1 START2 TMP_CMD TMP_CHK +typedef struct { + uint8_t start; + union { + struct { + uint8_t dio0 :1; + uint8_t dio1 :1; + uint8_t dio2 :1; + uint8_t dio3 :1; + uint8_t dio4 :1; + uint8_t dio5 :1; + uint8_t dio6 :1; + uint8_t dio7 :1; + }; + uint8_t dio; + }; + uint8_t controller_num; + uint16_t temp[3]; + uint8_t err; + uint8_t crc; +} intercom_packet_t; - CHK = 255-CMD, if they match do the work, if not, ignore this packet +typedef union { + intercom_packet_t packet; + uint8_t data[sizeof(intercom_packet_t)]; +} intercom_packet; - in a loop -*/ +intercom_packet tx; // this packet will be send +intercom_packet rx; // the last received packet with correct checksum +intercom_packet _tx; // current packet in transmission +intercom_packet _rx; // receiving packet +uint8_t packet_pointer; +uint8_t rxcrc; -#define START1 0xAA -#define START2 0x55 - -typedef enum { - SEND_START1, - SEND_START2, - SEND_CMD, - SEND_CHK, - SEND_DONE, - - READ_START1, - READ_START2, - READ_CMD, - READ_CHK, -} intercom_state_e; - - -intercom_state_e state = READ_START1; -uint8_t cmd, chk, send_cmd, read_cmd; +volatile uint8_t intercom_flags; void intercom_init(void) { @@ -70,30 +78,67 @@ void intercom_init(void) UCSR0B |= MASK(RXCIE0) | MASK(TXCIE0); #endif + + intercom_flags = 0; } -void update_send_cmd(uint8_t new_send_cmd) { - send_cmd = new_send_cmd; +void send_temperature(uint8_t index, uint16_t temperature) { + tx.packet.temp[index] = temperature; } -uint8_t get_read_cmd(void) { - return read_cmd; +uint16_t read_temperature(uint8_t index) { + return rx.packet.temp[index]; } -static void write_byte(uint8_t val) { #ifdef HOST - UDR1 = val; +void set_dio(uint8_t index, uint8_t value) { + if (value) + tx.packet.dio |= (1 << index); + else + tx.packet.dio &= ~(1 << index); +} #else - UDR0 = val; +uint8_t get_dio(uint8_t index) { + return rx.packet.dio & (1 << index); +} #endif + +void set_err(uint8_t err) { + tx.packet.err = err; } +uint8_t get_err() { + return rx.packet.err; +} void start_send(void) { - state = SEND_START1; + uint8_t txcrc = 0, i; + + // atomically update flags + uint8_t sreg = SREG; + cli(); + intercom_flags = (intercom_flags & ~FLAG_TX_FINISHED) | FLAG_TX_IN_PROGRESS; + SREG = sreg; + + // set start byte + tx.packet.start = START; + + // calculate CRC for outgoing packet + for (i = 0; i < (sizeof(intercom_packet_t) - 1); i++) { + txcrc ^= tx.data[i]; + } + tx.packet.crc = txcrc; + + for (i = 0; i < (sizeof(intercom_packet_t) ); i++) { + _tx.data[i] = tx.data[i]; + } + + // enable transmit pin enable_transmit(); delay_us(15); - //Enable interrupts so we can send next characters + + // actually start sending the packet + packet_pointer = 0; #ifdef HOST UCSR1B |= MASK(UDRIE1); #else @@ -101,119 +146,114 @@ void start_send(void) { #endif } -static void finish_send(void) { - state = READ_START1; - disable_transmit(); -} - - /* Interrupts, UART 0 for mendel */ + +// receive data interrupt- stuff into rx #ifdef HOST ISR(USART1_RX_vect) #else ISR(USART_RX_vect) #endif { + // pull character static uint8_t c; -#ifdef HOST - c = UDR1; - UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1); -#else - c = UDR0; - UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0); -#endif - - if (state >= READ_START1) { - - switch(state) { - case READ_START1: - if (c == START1) state = READ_START2; - break; - case READ_START2: - if (c == START2) state = READ_CMD; - else state = READ_START1; - break; - case READ_CMD: - cmd = c; - state = READ_CHK; - break; - case READ_CHK: - chk = c; - - if (chk == 255 - cmd) { - //Values are correct, do something useful - WRITE(DEBUG_LED,1); - read_cmd = cmd; -#ifdef EXTRUDER - start_send(); -#endif + #ifdef HOST + c = UDR1; + UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1); + #else + c = UDR0; + UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0); + #endif + + // are we waiting for a start byte? is this one? + if ((packet_pointer == 0) && (c == START)) { + rxcrc = _rx.packet.start = START; + packet_pointer = 1; + intercom_flags |= FLAG_RX_IN_PROGRESS; + } + else if (packet_pointer > 0) { + // we're receiving a packet + // calculate CRC (except CRC character!) + if (packet_pointer < (sizeof(intercom_packet_t) - 1)) + rxcrc ^= c; + // stuff byte into structure + _rx.data[packet_pointer++] = c; + // last byte? + if (packet_pointer >= sizeof(intercom_packet_t)) { + // reset pointer + packet_pointer = 0; + + #ifndef HOST + if (rxcrc == _rx.packet.crc && + _rx.packet.controller_num == THIS_CONTROLLER_NUM){ + #else + if (rxcrc == _rx.packet.crc){ + #endif + // correct crc copy packet + static uint8_t i; + for (i = 0; i < (sizeof(intercom_packet_t) ); i++) { + rx.data[i] = _rx.data[i]; + } } - else - { - state = READ_START1; - } - break; - default: - break; + + intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; + #ifndef HOST + if (_rx.packet.controller_num == THIS_CONTROLLER_NUM) { + if (rxcrc != _rx.packet.crc) + tx.packet.err = ERROR_BAD_CRC; + // not sure why exactly this delay is needed, but wihtout it first byte never arrives. + delay_us(150); + start_send(); + } + #endif } } - } +// finished transmitting interrupt- only enabled at end of packet #ifdef HOST ISR(USART1_TX_vect) #else ISR(USART_TX_vect) #endif { - if (state == SEND_DONE) { - finish_send(); - - -#ifdef HOST - UCSR1B &= ~MASK(TXCIE1); -#else - UCSR0B &= ~MASK(TXCIE0); -#endif + if (packet_pointer >= sizeof(intercom_packet_t)) { + disable_transmit(); + packet_pointer = 0; + intercom_flags = (intercom_flags & ~FLAG_TX_IN_PROGRESS) | FLAG_TX_FINISHED; + #ifdef HOST + UCSR1B &= ~MASK(TXCIE1); + #else + UCSR0B &= ~MASK(TXCIE0); + #endif } } +// tx queue empty interrupt- send next byte #ifdef HOST ISR(USART1_UDRE_vect) #else ISR(USART_UDRE_vect) #endif { - switch(state) { - case SEND_START1: - write_byte(START1); - state = SEND_START2; - break; - case SEND_START2: - write_byte(START2); - state = SEND_CMD; - break; - case SEND_CMD: - write_byte(send_cmd); - state = SEND_CHK; - break; - case SEND_CHK: - write_byte(255 - send_cmd); - state = SEND_DONE; -#ifdef HOST - UCSR1B &= ~MASK(UDRIE1); - UCSR1B |= MASK(TXCIE1); -#else - UCSR0B &= ~MASK(UDRIE0); - UCSR0B |= MASK(TXCIE0); -#endif - break; - default: - break; + #ifdef HOST + UDR1 = _tx.data[packet_pointer++]; + #else + UDR0 = _tx.data[packet_pointer++]; + #endif + + if (packet_pointer >= sizeof(intercom_packet_t)) { + #ifdef HOST + UCSR1B &= ~MASK(UDRIE1); + UCSR1B |= MASK(TXCIE1); + #else + UCSR0B &= ~MASK(UDRIE0); + UCSR0B |= MASK(TXCIE0); + #endif } } -#endif /* GEN3 */ +#endif /* TEMP_INTERCOM */ diff --git a/extruder/intercom.h b/extruder/intercom.h index 5a6ab8e..1120a05 100644 --- a/extruder/intercom.h +++ b/extruder/intercom.h @@ -2,16 +2,49 @@ #define _INTERCOM_H #include +#include "config.h" + +#ifdef HOST + #define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); UCSR1B &= ~MASK(RXEN1); } while(0) + #define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR1B |= MASK(RXEN1); } while(0) +#else + #define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); UCSR0B &= ~MASK(RXEN0); } while(0) + #define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B |= MASK(RXEN0); } while(0) +#endif // initialise serial subsystem void intercom_init(void); -//Update the message we are sending over intercom -void update_send_cmd(uint8_t new_send_cmd); +// if host, send target temperature to extruder +// if extruder, send actual temperature to host +void send_temperature(uint8_t index, uint16_t temperature); +// if host, read actual temperature from extruder +// if extruder, read target temperature from host +uint16_t read_temperature(uint8_t index); + +// if host, set DIOs on extruder controller +// if extruder, report DIO state +void set_dio(uint8_t index, uint8_t value); + +// if host, read extruder DIO inputs +// if extruder, set DIO outputs +uint8_t get_dio(uint8_t index); + +// set error code to send to other end +void set_err(uint8_t err); + +// get error code sent from other end +uint8_t get_err(void); + +// if host, send packet to extruder +// if extruder, return packet to host void start_send(void); -//Read the message we are receiving over intercom -uint8_t get_read_cmd(void); +#define FLAG_RX_IN_PROGRESS 1 +#define FLAG_TX_IN_PROGRESS 2 +#define FLAG_NEW_RX 4 +#define FLAG_TX_FINISHED 8 +extern volatile uint8_t intercom_flags; #endif /* _INTERCOM_H */ diff --git a/extruder/temp.c b/extruder/temp.c index 4809218..e1d13a5 100644 --- a/extruder/temp.c +++ b/extruder/temp.c @@ -4,22 +4,6 @@ #include #include -typedef enum { - TT_THERMISTOR, - TT_MAX6675, - TT_AD595, - TT_PT100, - TT_INTERCOM -} temp_types; - -typedef enum { - PRESENT, - TCOPEN -} temp_flags_enum; - -#define TEMP_C -#include "config.h" - #include "arduino.h" #include "delay.h" #include "debug.h" @@ -27,10 +11,38 @@ typedef enum { #include "sersendf.h" #endif #include "heater.h" -#ifdef GEN3 +#ifdef TEMP_INTERCOM #include "intercom.h" #endif +typedef enum { + TT_THERMISTOR, + TT_MAX6675, + TT_AD595, + TT_PT100, + TT_INTERCOM, + TT_DUMMY, +} temp_types; + +typedef enum { + PRESENT, + TCOPEN +} temp_flags_enum; + +typedef struct { + uint8_t temp_type; + uint8_t temp_pin; + uint8_t heater_index; +} temp_sensor_definition_t; + +#undef DEFINE_TEMP_SENSOR +#define DEFINE_TEMP_SENSOR(name, type, pin) { (type), (pin), (HEATER_ ## name) }, +static const temp_sensor_definition_t temp_sensors[NUM_TEMP_SENSORS] = +{ + #include "config.h" +}; +#undef DEFINE_TEMP_SENSOR + // this struct holds the runtime sensor data- read temperatures, targets, etc struct { temp_flags_enum temp_flags; @@ -48,30 +60,7 @@ struct { #ifdef TEMP_THERMISTOR #include "analog.h" - -#define NUMTEMPS 20 -uint16_t temptable[NUMTEMPS][2] PROGMEM = { - {1, 841}, - {54, 255}, - {107, 209}, - {160, 184}, - {213, 166}, - {266, 153}, - {319, 142}, - {372, 132}, - {425, 124}, - {478, 116}, - {531, 108}, - {584, 101}, - {637, 93}, - {690, 86}, - {743, 78}, - {796, 70}, - {849, 61}, - {902, 50}, - {955, 34}, - {1008, 3} -}; +#include "ThermistorTable.h" #endif #ifdef TEMP_AD595 @@ -79,7 +68,7 @@ uint16_t temptable[NUMTEMPS][2] PROGMEM = { #endif void temp_init() { - uint8_t i; + temp_sensor_t i; for (i = 0; i < NUM_TEMP_SENSORS; i++) { switch(temp_sensors[i].temp_type) { #ifdef TEMP_MAX6675 @@ -100,10 +89,10 @@ void temp_init() { break;*/ #endif - #ifdef GEN3 + #ifdef TEMP_INTERCOM case TT_INTERCOM: intercom_init(); - update_send_cmd(0); + send_temperature(0, 0); break; #endif } @@ -111,7 +100,7 @@ void temp_init() { } void temp_sensor_tick() { - uint8_t i = 0; + temp_sensor_t i = 0; for (; i < NUM_TEMP_SENSORS; i++) { if (temp_sensors_runtime[i].next_read_time) { temp_sensors_runtime[i].next_read_time--; @@ -179,15 +168,50 @@ void temp_sensor_tick() { //Calculate real temperature based on lookup table for (j = 1; j < NUMTEMPS; j++) { if (pgm_read_word(&(temptable[j][0])) > temp) { - // multiply by 4 because internal temp is stored as 14.2 fixed point - temp = pgm_read_word(&(temptable[j][1])) * 4 + (pgm_read_word(&(temptable[j][0])) - temp) * 4 * (pgm_read_word(&(temptable[j-1][1])) - pgm_read_word(&(temptable[j][1]))) / (pgm_read_word(&(temptable[j][0])) - pgm_read_word(&(temptable[j-1][0]))); + // Thermistor table is already in 14.2 fixed point + #ifndef EXTRUDER + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR("pin:%d Raw ADC:%d table entry: %d"),temp_sensors[i].temp_pin,temp,j); + #endif + // Linear interpolating temperature value + // 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] + // y = + // Wikipedia's example linear interpolation formula. + temp = ( + // ((x - x₀)y₁ + ((uint32_t)temp - pgm_read_word(&(temptable[j-1][0]))) * pgm_read_word(&(temptable[j][1])) + // + + + + // (x₁-x) + (pgm_read_word(&(temptable[j][0])) - (uint32_t)temp) + // y₀ ) + * pgm_read_word(&(temptable[j-1][1]))) + // / + / + // (x₁ - x₀) + (pgm_read_word(&(temptable[j][0])) - pgm_read_word(&(temptable[j-1][0]))); + #ifndef EXTRUDER + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR(" temp:%d.%d"),temp/4,(temp%4)*25); + #endif break; } } + #ifndef EXTRUDER + if (debug_flags & DEBUG_PID) + sersendf_P(PSTR(" Sensor:%d\n"),i); + #endif + //Clamp for overflows if (j == NUMTEMPS) - temp = temptable[NUMTEMPS-1][1] * 4; + temp = temptable[NUMTEMPS-1][1]; temp_sensors_runtime[i].next_read_time = 0; } while (0); @@ -196,7 +220,7 @@ void temp_sensor_tick() { #ifdef TEMP_AD595 case TT_AD595: - temp = analog_read(temp_pin); + temp = analog_read(temp_sensors[i].temp_pin); // convert // >>8 instead of >>10 because internal temp is stored as 14.2 fixed point @@ -213,16 +237,30 @@ void temp_sensor_tick() { break #endif /* TEMP_PT100 */ - #ifdef GEN3 + #ifdef TEMP_INTERCOM case TT_INTERCOM: - temp = get_read_cmd() << 2; + temp = read_temperature(temp_sensors[i].temp_pin); start_send(); temp_sensors_runtime[i].next_read_time = 0; break; - #endif /* GEN3 */ + #endif /* TEMP_INTERCOM */ + + #ifdef TEMP_DUMMY + case TT_DUMMY: + temp = temp_sensors_runtime[i].last_read_temp; + + if (temp_sensors_runtime[i].target_temp > temp) + temp++; + else if (temp_sensors_runtime[i].target_temp < temp) + temp--; + + temp_sensors_runtime[i].next_read_time = 0; + + break; + #endif /* TEMP_DUMMY */ } temp_sensors_runtime[i].last_read_temp = temp; @@ -235,14 +273,16 @@ void temp_sensor_tick() { } if (temp_sensors[i].heater_index < NUM_HEATERS) { - heater_tick(temp_sensors[i].heater_index, temp_sensors_runtime[i].last_read_temp, temp_sensors_runtime[i].target_temp); + heater_tick(temp_sensors[i].heater_index, i, temp_sensors_runtime[i].last_read_temp, temp_sensors_runtime[i].target_temp); } } } } uint8_t temp_achieved() { - uint8_t i, all_ok = 255; + temp_sensor_t i; + uint8_t all_ok = 255; + for (i = 0; i < NUM_TEMP_SENSORS; i++) { if (temp_sensors_runtime[i].temp_residency < TEMP_RESIDENCY_TIME) all_ok = 0; @@ -250,26 +290,42 @@ uint8_t temp_achieved() { return all_ok; } -void temp_set(uint8_t index, uint16_t temperature) { +void temp_set(temp_sensor_t index, uint16_t temperature) { + if (index >= NUM_TEMP_SENSORS) + return; + temp_sensors_runtime[index].target_temp = temperature; temp_sensors_runtime[index].temp_residency = 0; -#ifdef GEN3 +#ifdef TEMP_INTERCOM if (temp_sensors[index].temp_type == TT_INTERCOM) - update_send_cmd(temperature >> 2); + send_temperature(temp_sensors[index].temp_pin, temperature); #endif } -uint16_t temp_get(uint8_t index) { +uint16_t temp_get(temp_sensor_t index) { + if (index >= NUM_TEMP_SENSORS) + return 0; + return temp_sensors_runtime[index].last_read_temp; } // extruder doesn't have sersendf_P #ifndef EXTRUDER -void temp_print(uint8_t index) { +void temp_print(temp_sensor_t index) { uint8_t c = 0; - + + if (index >= NUM_TEMP_SENSORS) + return; + c = (temp_sensors_runtime[index].last_read_temp & 3) * 25; + + sersendf_P(PSTR("T:%u.%u"), temp_sensors_runtime[index].last_read_temp >> 2, c); + #ifdef HEATER_BED + uint8_t b = 0; + b = (temp_sensors_runtime[HEATER_BED].last_read_temp & 3) * 25; - sersendf_P(PSTR("T: %u.%u\n"), temp_sensors_runtime[index].last_read_temp >> 2, c); + sersendf_P(PSTR(" B:%u.%u"), temp_sensors_runtime[HEATER_bed].last_read_temp >> 2 , b); + #endif + } #endif diff --git a/extruder/temp.h b/extruder/temp.h index b00ee95..1815c4c 100644 --- a/extruder/temp.h +++ b/extruder/temp.h @@ -1,6 +1,7 @@ #ifndef _TEMP_H #define _TEMP_H +#include "config.h" #include /* @@ -11,6 +12,15 @@ no point in specifying a port- all the different temp sensors we have must be on we still need to specify which analog pins we use in machine.h for the analog sensors however, otherwise the analog subsystem won't read them. */ +#undef DEFINE_TEMP_SENSOR +#define DEFINE_TEMP_SENSOR(name, type, pin) TEMP_SENSOR_ ## name, +typedef enum { + #include "config.h" + NUM_TEMP_SENSORS, + TEMP_SENSOR_none +} temp_sensor_t; +#undef DEFINE_TEMP_SENSOR + #define temp_tick temp_sensor_tick void temp_init(void); @@ -19,11 +29,9 @@ void temp_sensor_tick(void); uint8_t temp_achieved(void); -void temp_set(uint8_t index, uint16_t temperature); -uint16_t temp_get(uint8_t index); +void temp_set(temp_sensor_t index, uint16_t temperature); +uint16_t temp_get(temp_sensor_t index); -void temp_print(uint8_t index); - -uint16_t temp_read(uint8_t index); +void temp_print(temp_sensor_t index); #endif /* _TIMER_H */ diff --git a/home.c b/home.c index c72e100..e4b176b 100644 --- a/home.c +++ b/home.c @@ -45,7 +45,7 @@ void home_x_negative() { delay(5); unstep(); // wait until next step time - delay((uint32_t) (60.0 * ((float) F_CPU) / STEPS_PER_MM_X / ((float) MAXIMUM_FEEDRATE_X))); + delay((uint32_t) (60.0 * 1000000.0 / STEPS_PER_MM_X / ((float) MAXIMUM_FEEDRATE_X))); } denoise_count = 0; @@ -95,7 +95,7 @@ void home_x_positive() { delay(5); unstep(); // wait until next step time - delay((uint32_t) (60.0 * ((float) F_CPU) / STEPS_PER_MM_X / ((float) SEARCH_FEEDRATE_X))); + delay((uint32_t) (60.0 * 1000000.0 / STEPS_PER_MM_X / ((float) SEARCH_FEEDRATE_X))); } // set X home @@ -126,7 +126,7 @@ void home_y_negative() { delay(5); unstep(); // wait until neyt step time - delay((uint32_t) (60.0 * ((float) F_CPU) / STEPS_PER_MM_Y / ((float) MAXIMUM_FEEDRATE_Y))); + delay((uint32_t) (60.0 * 1000000.0 / STEPS_PER_MM_Y / ((float) MAXIMUM_FEEDRATE_Y))); } denoise_count = 0; @@ -176,7 +176,7 @@ void home_y_positive() { delay(5); unstep(); // wait until next step time - delay((uint32_t) (60.0 * ((float) F_CPU) / STEPS_PER_MM_Y / ((float) SEARCH_FEEDRATE_Y))); + delay((uint32_t) (60.0 * 1000000.0 / STEPS_PER_MM_Y / ((float) SEARCH_FEEDRATE_Y))); } // set Y home @@ -207,7 +207,7 @@ void home_z_negative() { delay(5); unstep(); // wait until next step time - delay((uint32_t) (60.0 * ((float) F_CPU) / STEPS_PER_MM_Z / ((float) MAXIMUM_FEEDRATE_Z))); + delay((uint32_t) (60.0 * 1000000.0 / STEPS_PER_MM_Z / ((float) MAXIMUM_FEEDRATE_Z))); } denoise_count = 0; @@ -257,7 +257,7 @@ void home_z_positive() { delay(5); unstep(); // wait until next step time - delay((uint32_t) (60.0 * ((float) F_CPU) / STEPS_PER_MM_Z / ((float) SEARCH_FEEDRATE_Z))); + delay((uint32_t) (60.0 * 1000000.0 / STEPS_PER_MM_Z / ((float) SEARCH_FEEDRATE_Z))); } // set Z home diff --git a/intercom.c b/intercom.c index c523d6e..06cfa36 100644 --- a/intercom.c +++ b/intercom.c @@ -1,47 +1,55 @@ #include "intercom.h" +#include #include #include "config.h" #include "delay.h" -#ifdef TEMP_INTERCOM +#if (defined TEMP_INTERCOM) || (defined EXTRUDER) #define INTERCOM_BAUD 57600 -#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0) -#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0) +#define START 0x55 -/* - Defines a super simple intercom interface using the RS485 modules +enum { + ERROR_BAD_CRC +} err_codes; - Host will say: START1 START2 PWM_CMD PWM_CHK - Extruder will reply: START1 START2 TMP_CMD TMP_CHK +typedef struct { + uint8_t start; + union { + struct { + uint8_t dio0 :1; + uint8_t dio1 :1; + uint8_t dio2 :1; + uint8_t dio3 :1; + uint8_t dio4 :1; + uint8_t dio5 :1; + uint8_t dio6 :1; + uint8_t dio7 :1; + }; + uint8_t dio; + }; + uint8_t controller_num; + uint16_t temp[3]; + uint8_t err; + uint8_t crc; +} intercom_packet_t; - CHK = 255-CMD, if they match do the work, if not, ignore this packet +typedef union { + intercom_packet_t packet; + uint8_t data[sizeof(intercom_packet_t)]; +} intercom_packet; - in a loop -*/ +intercom_packet tx; // this packet will be send +intercom_packet rx; // the last received packet with correct checksum +intercom_packet _tx; // current packet in transmission +intercom_packet _rx; // receiving packet +uint8_t packet_pointer; +uint8_t rxcrc; -#define START1 0xAA -#define START2 0x55 - -typedef enum { - SEND_START1, - SEND_START2, - SEND_CMD, - SEND_CHK, - SEND_DONE, - - READ_START1, - READ_START2, - READ_CMD, - READ_CHK, -} intercom_state_e; - - -intercom_state_e state = READ_START1; -uint8_t cmd, chk, send_cmd, read_cmd; +volatile uint8_t intercom_flags; void intercom_init(void) { @@ -70,30 +78,67 @@ void intercom_init(void) UCSR0B |= MASK(RXCIE0) | MASK(TXCIE0); #endif + + intercom_flags = 0; } -void update_send_cmd(uint8_t new_send_cmd) { - send_cmd = new_send_cmd; +void send_temperature(uint8_t index, uint16_t temperature) { + tx.packet.temp[index] = temperature; } -uint8_t get_read_cmd(void) { - return read_cmd; +uint16_t read_temperature(uint8_t index) { + return rx.packet.temp[index]; } -static void write_byte(uint8_t val) { #ifdef HOST - UDR1 = val; +void set_dio(uint8_t index, uint8_t value) { + if (value) + tx.packet.dio |= (1 << index); + else + tx.packet.dio &= ~(1 << index); +} #else - UDR0 = val; +uint8_t get_dio(uint8_t index) { + return rx.packet.dio & (1 << index); +} #endif + +void set_err(uint8_t err) { + tx.packet.err = err; } +uint8_t get_err() { + return rx.packet.err; +} void start_send(void) { - state = SEND_START1; + uint8_t txcrc = 0, i; + + // atomically update flags + uint8_t sreg = SREG; + cli(); + intercom_flags = (intercom_flags & ~FLAG_TX_FINISHED) | FLAG_TX_IN_PROGRESS; + SREG = sreg; + + // set start byte + tx.packet.start = START; + + // calculate CRC for outgoing packet + for (i = 0; i < (sizeof(intercom_packet_t) - 1); i++) { + txcrc ^= tx.data[i]; + } + tx.packet.crc = txcrc; + + for (i = 0; i < (sizeof(intercom_packet_t) ); i++) { + _tx.data[i] = tx.data[i]; + } + + // enable transmit pin enable_transmit(); delay_us(15); - //Enable interrupts so we can send next characters + + // actually start sending the packet + packet_pointer = 0; #ifdef HOST UCSR1B |= MASK(UDRIE1); #else @@ -101,118 +146,113 @@ void start_send(void) { #endif } -static void finish_send(void) { - state = READ_START1; - disable_transmit(); -} - - /* Interrupts, UART 0 for mendel */ + +// receive data interrupt- stuff into rx #ifdef HOST ISR(USART1_RX_vect) #else ISR(USART_RX_vect) #endif { + // pull character static uint8_t c; -#ifdef HOST - c = UDR1; - UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1); -#else - c = UDR0; - UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0); -#endif - - if (state >= READ_START1) { - - switch(state) { - case READ_START1: - if (c == START1) state = READ_START2; - break; - case READ_START2: - if (c == START2) state = READ_CMD; - else state = READ_START1; - break; - case READ_CMD: - cmd = c; - state = READ_CHK; - break; - case READ_CHK: - chk = c; - - if (chk == 255 - cmd) { - //Values are correct, do something useful - WRITE(DEBUG_LED,1); - read_cmd = cmd; -#ifdef EXTRUDER - start_send(); -#endif + #ifdef HOST + c = UDR1; + UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1); + #else + c = UDR0; + UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0); + #endif + + // are we waiting for a start byte? is this one? + if ((packet_pointer == 0) && (c == START)) { + rxcrc = _rx.packet.start = START; + packet_pointer = 1; + intercom_flags |= FLAG_RX_IN_PROGRESS; + } + else if (packet_pointer > 0) { + // we're receiving a packet + // calculate CRC (except CRC character!) + if (packet_pointer < (sizeof(intercom_packet_t) - 1)) + rxcrc ^= c; + // stuff byte into structure + _rx.data[packet_pointer++] = c; + // last byte? + if (packet_pointer >= sizeof(intercom_packet_t)) { + // reset pointer + packet_pointer = 0; + + #ifndef HOST + if (rxcrc == _rx.packet.crc && + _rx.packet.controller_num == THIS_CONTROLLER_NUM){ + #else + if (rxcrc == _rx.packet.crc){ + #endif + // correct crc copy packet + static uint8_t i; + for (i = 0; i < (sizeof(intercom_packet_t) ); i++) { + rx.data[i] = _rx.data[i]; + } } - else - { - state = READ_START1; - } - break; - default: - break; + + intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; + #ifndef HOST + if (_rx.packet.controller_num == THIS_CONTROLLER_NUM) { + if (rxcrc != _rx.packet.crc) + tx.packet.err = ERROR_BAD_CRC; + // not sure why exactly this delay is needed, but wihtout it first byte never arrives. + delay_us(150); + start_send(); + } + #endif } } - } +// finished transmitting interrupt- only enabled at end of packet #ifdef HOST ISR(USART1_TX_vect) #else ISR(USART_TX_vect) #endif { - if (state == SEND_DONE) { - finish_send(); - - -#ifdef HOST - UCSR1B &= ~MASK(TXCIE1); -#else - UCSR0B &= ~MASK(TXCIE0); -#endif + if (packet_pointer >= sizeof(intercom_packet_t)) { + disable_transmit(); + packet_pointer = 0; + intercom_flags = (intercom_flags & ~FLAG_TX_IN_PROGRESS) | FLAG_TX_FINISHED; + #ifdef HOST + UCSR1B &= ~MASK(TXCIE1); + #else + UCSR0B &= ~MASK(TXCIE0); + #endif } } +// tx queue empty interrupt- send next byte #ifdef HOST ISR(USART1_UDRE_vect) #else ISR(USART_UDRE_vect) #endif { - switch(state) { - case SEND_START1: - write_byte(START1); - state = SEND_START2; - break; - case SEND_START2: - write_byte(START2); - state = SEND_CMD; - break; - case SEND_CMD: - write_byte(send_cmd); - state = SEND_CHK; - break; - case SEND_CHK: - write_byte(255 - send_cmd); - state = SEND_DONE; -#ifdef HOST - UCSR1B &= ~MASK(UDRIE1); - UCSR1B |= MASK(TXCIE1); -#else - UCSR0B &= ~MASK(UDRIE0); - UCSR0B |= MASK(TXCIE0); -#endif - break; - default: - break; + #ifdef HOST + UDR1 = _tx.data[packet_pointer++]; + #else + UDR0 = _tx.data[packet_pointer++]; + #endif + + if (packet_pointer >= sizeof(intercom_packet_t)) { + #ifdef HOST + UCSR1B &= ~MASK(UDRIE1); + UCSR1B |= MASK(TXCIE1); + #else + UCSR0B &= ~MASK(UDRIE0); + UCSR0B |= MASK(TXCIE0); + #endif } } diff --git a/intercom.h b/intercom.h index 5a6ab8e..1120a05 100644 --- a/intercom.h +++ b/intercom.h @@ -2,16 +2,49 @@ #define _INTERCOM_H #include +#include "config.h" + +#ifdef HOST + #define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); UCSR1B &= ~MASK(RXEN1); } while(0) + #define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR1B |= MASK(RXEN1); } while(0) +#else + #define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); UCSR0B &= ~MASK(RXEN0); } while(0) + #define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B |= MASK(RXEN0); } while(0) +#endif // initialise serial subsystem void intercom_init(void); -//Update the message we are sending over intercom -void update_send_cmd(uint8_t new_send_cmd); +// if host, send target temperature to extruder +// if extruder, send actual temperature to host +void send_temperature(uint8_t index, uint16_t temperature); +// if host, read actual temperature from extruder +// if extruder, read target temperature from host +uint16_t read_temperature(uint8_t index); + +// if host, set DIOs on extruder controller +// if extruder, report DIO state +void set_dio(uint8_t index, uint8_t value); + +// if host, read extruder DIO inputs +// if extruder, set DIO outputs +uint8_t get_dio(uint8_t index); + +// set error code to send to other end +void set_err(uint8_t err); + +// get error code sent from other end +uint8_t get_err(void); + +// if host, send packet to extruder +// if extruder, return packet to host void start_send(void); -//Read the message we are receiving over intercom -uint8_t get_read_cmd(void); +#define FLAG_RX_IN_PROGRESS 1 +#define FLAG_TX_IN_PROGRESS 2 +#define FLAG_NEW_RX 4 +#define FLAG_TX_FINISHED 8 +extern volatile uint8_t intercom_flags; #endif /* _INTERCOM_H */ diff --git a/mendel.c b/mendel.c index 908d211..61118fe 100644 --- a/mendel.c +++ b/mendel.c @@ -20,6 +20,7 @@ #include "pinio.h" #include "arduino.h" #include "clock.h" +#include "intercom.h" void io_init(void) { // disable modules we don't use @@ -123,6 +124,14 @@ void io_init(void) { WRITE(MOSI, 1); SET_OUTPUT(MOSI); WRITE(MISO, 1); SET_INPUT(MISO); WRITE(SS, 1); SET_OUTPUT(SS); + + #ifdef TEMP_INTERCOM + // Enable the RS485 transceiver + SET_OUTPUT(RX_ENABLE_PIN); + SET_OUTPUT(TX_ENABLE_PIN); + WRITE(RX_ENABLE_PIN,0); + disable_transmit(); + #endif } void init(void) { diff --git a/temp.c b/temp.c index 96d268c..b0159f5 100644 --- a/temp.c +++ b/temp.c @@ -83,7 +83,7 @@ void temp_init() { #ifdef TEMP_INTERCOM case TT_INTERCOM: intercom_init(); - update_send_cmd(0); + send_temperature(0, 0); break; #endif @@ -163,8 +163,10 @@ void temp_sensor_tick() { for (j = 1; j < NUMTEMPS; j++) { if (pgm_read_word(&(temptable[j][0])) > temp) { // Thermistor table is already in 14.2 fixed point + #ifndef EXTRUDER if (debug_flags & DEBUG_PID) sersendf_P(PSTR("pin:%d Raw ADC:%d table entry: %d"),temp_sensors[i].temp_pin,temp,j); + #endif // Linear interpolating temperature value // y = ((x - x₀)y₁ + (x₁-x)y₀ ) / (x₁ - x₀) // y = temp @@ -188,13 +190,17 @@ void temp_sensor_tick() { / // (x₁ - x₀) (pgm_read_word(&(temptable[j][0])) - pgm_read_word(&(temptable[j-1][0]))); + #ifndef EXTRUDER if (debug_flags & DEBUG_PID) sersendf_P(PSTR(" temp:%d.%d"),temp/4,(temp%4)*25); + #endif break; } } + #ifndef EXTRUDER if (debug_flags & DEBUG_PID) sersendf_P(PSTR(" Sensor:%d\n"),i); + #endif //Clamp for overflows @@ -227,9 +233,7 @@ void temp_sensor_tick() { #ifdef TEMP_INTERCOM case TT_INTERCOM: - temp = get_read_cmd() << 2; - - start_send(); + temp = read_temperature(temp_sensors[i].temp_pin); temp_sensors_runtime[i].next_read_time = 0; @@ -289,7 +293,7 @@ void temp_set(temp_sensor_t index, uint16_t temperature) { temp_sensors_runtime[index].temp_residency = 0; #ifdef TEMP_INTERCOM if (temp_sensors[index].temp_type == TT_INTERCOM) - update_send_cmd(temperature >> 2); + send_temperature(temp_sensors[index].temp_pin, temperature); #endif }