From d0601716e847684ac433cd7d2f16c42418ee5a23 Mon Sep 17 00:00:00 2001 From: Michael Moon Date: Tue, 1 Mar 2011 23:32:53 +1100 Subject: [PATCH] reorganise intercom to send packets from extruder main loop, also generalise protocol as discussed in forum --- extruder/Makefile | 2 +- extruder/crc.c | 24 +++++++ extruder/crc.h | 8 +++ extruder/extruder.c | 52 +++++++++----- extruder/heater.h | 1 + extruder/intercom.c | 56 +++++++-------- extruder/intercom.h | 8 +-- extruder/temp.h | 12 +++- extruder/timer.c | 164 ++++++++++++++++++++++++++++++++++++++++++++ extruder/timer.h | 30 ++++++++ heater.h | 1 + intercom.c | 56 +++++++-------- intercom.h | 8 +-- temp.h | 1 + timer.c | 9 +++ 15 files changed, 349 insertions(+), 83 deletions(-) create mode 100644 extruder/crc.c create mode 100644 extruder/crc.h create mode 100644 extruder/timer.c create mode 100644 extruder/timer.h diff --git a/extruder/Makefile b/extruder/Makefile index 5b4518b..e2d7e5a 100644 --- a/extruder/Makefile +++ b/extruder/Makefile @@ -31,7 +31,7 @@ PROGRAM = extruder -SOURCES = $(PROGRAM).c intercom.c delay.c analog.c watchdog.c heater.c temp.c +SOURCES = $(PROGRAM).c intercom.c delay.c analog.c watchdog.c heater.c temp.c timer.c crc.c ############################################################################## # # diff --git a/extruder/crc.c b/extruder/crc.c new file mode 100644 index 0000000..2a8a10c --- /dev/null +++ b/extruder/crc.c @@ -0,0 +1,24 @@ +#include "crc.h" + +#include + +// uint16_t _crc16_update(uint16_t crc, uint8_t a) { +// int i; +// crc ^= a; +// for (i = 0; i < 8; ++i) +// { +// if (crc & 1) +// crc = (crc >> 1) ^ 0xA001; +// else +// crc = (crc >> 1); +// } +// return crc; +// } + +uint16_t crc_block(void *data, uint16_t len) { + uint16_t crc = 0; + for (; len; data++, len--) { + crc = _crc16_update(crc, *((uint8_t *) data)); + } + return crc; +} diff --git a/extruder/crc.h b/extruder/crc.h new file mode 100644 index 0000000..7cd9852 --- /dev/null +++ b/extruder/crc.h @@ -0,0 +1,8 @@ +#ifndef _CRC_H +#define _CRC_H + +#include + +uint16_t crc_block(void *data, uint16_t len); + +#endif /* _CRC_H */ diff --git a/extruder/extruder.c b/extruder/extruder.c index c7e1e2f..6e97cd0 100644 --- a/extruder/extruder.c +++ b/extruder/extruder.c @@ -9,6 +9,7 @@ #include "watchdog.h" #include "heater.h" #include "temp.h" +#include "timer.h" static uint8_t motor_pwm; @@ -22,14 +23,14 @@ void io_init(void) { SET_INPUT(TRIM_POT); SET_INPUT(TEMP_PIN); - SET_INPUT(TEMP_BED_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); - + // 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); @@ -44,10 +45,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 - + #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); @@ -74,10 +75,10 @@ void motor_init(void) { } ISR(PCINT0_vect) { - static uint8_t coil_pos, pwm; + static uint8_t coil_pos, pwm; //if the step pin is high, we advance the motor - if (READ(E_STEP_PIN)) { + if (READ(E_STEP_PIN)) { //Turn on motors only on first tick to save power I guess enable_motors(); @@ -88,12 +89,12 @@ ISR(PCINT0_vect) { else coil_pos--; - coil_pos &= 7; + coil_pos &= 7; //Grab the latest motor power to use pwm = motor_pwm; - switch(coil_pos) { + switch(coil_pos) { case 0: WRITE(H1D, 0); WRITE(H2D, 0); @@ -168,6 +169,9 @@ void init(void) { // set up extruder motor driver motor_init(); + // set up clock + timer_init(); + // enable interrupts sei(); @@ -190,11 +194,21 @@ int main (void) //Read motor PWM motor_pwm = analog_read(TRIM_POT_CHANNEL) >> 2; - temp_sensor_tick(); - - send_temperature(0, temp_get(0)); - send_temperature(1, temp_get(1)); - temp_set(0, read_temperature(0)); - temp_set(1, read_temperature(1)); + ifclock(CLOCK_FLAG_10MS) { + // check temperatures and manage heaters + temp_sensor_tick(); + } + + // check if we've had a new intercom packet + if (intercom_flags & FLAG_NEW_RX) { + intercom_flags &= ~FLAG_NEW_RX; + + send_temperature(0, temp_get(0)); + send_temperature(1, temp_get(1)); + temp_set(0, read_temperature(0)); + temp_set(1, read_temperature(1)); + + start_send(); + } } } diff --git a/extruder/heater.h b/extruder/heater.h index 58c4129..d327fab 100644 --- a/extruder/heater.h +++ b/extruder/heater.h @@ -9,6 +9,7 @@ #define disable_heater() heater_set(0, 0) #undef DEFINE_HEATER +#undef _CONFIG_H #define DEFINE_HEATER(name, port, pin, pwm) HEATER_ ## name, typedef enum { diff --git a/extruder/intercom.c b/extruder/intercom.c index 06cfa36..bf89ece 100644 --- a/extruder/intercom.c +++ b/extruder/intercom.c @@ -17,21 +17,16 @@ enum { 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 dio; uint8_t controller_num; - uint16_t temp[3]; + uint8_t control_word; + uint8_t control_index; + union { + int32_t control_data_int32; + uint32_t control_data_uint32; + float control_data_float; + uint16_t temp[2]; + }; uint8_t err; uint8_t crc; } intercom_packet_t; @@ -120,9 +115,16 @@ void start_send(void) { intercom_flags = (intercom_flags & ~FLAG_TX_FINISHED) | FLAG_TX_IN_PROGRESS; SREG = sreg; + // enable transmit pin + enable_transmit(); + // set start byte tx.packet.start = START; + // set packet type + tx.packet.control_word = 105; + tx.packet.control_index = 0; + // calculate CRC for outgoing packet for (i = 0; i < (sizeof(intercom_packet_t) - 1); i++) { txcrc ^= tx.data[i]; @@ -133,17 +135,14 @@ void start_send(void) { _tx.data[i] = tx.data[i]; } - // enable transmit pin - enable_transmit(); - delay_us(15); + packet_pointer = 0; // actually start sending the packet - packet_pointer = 0; -#ifdef HOST - UCSR1B |= MASK(UDRIE1); -#else - UCSR0B |= MASK(UDRIE0); -#endif + #ifdef HOST + UCSR1B |= MASK(UDRIE1); + #else + UCSR0B |= MASK(UDRIE0); + #endif } /* @@ -199,15 +198,18 @@ ISR(USART_RX_vect) } } - intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; #ifndef HOST - if (_rx.packet.controller_num == THIS_CONTROLLER_NUM) { + if (rx.packet.controller_num == THIS_CONTROLLER_NUM) { if (rxcrc != _rx.packet.crc) tx.packet.err = ERROR_BAD_CRC; + else + intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; // not sure why exactly this delay is needed, but wihtout it first byte never arrives. - delay_us(150); - start_send(); +// delay_us(150); +// start_send(); } + #else + intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; #endif } } diff --git a/extruder/intercom.h b/extruder/intercom.h index 1120a05..0e826fe 100644 --- a/extruder/intercom.h +++ b/extruder/intercom.h @@ -5,11 +5,11 @@ #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) + #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(TXCIE1) | MASK(UDRIE1)); 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) + #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(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0) #endif // initialise serial subsystem diff --git a/extruder/temp.h b/extruder/temp.h index 1815c4c..5e56038 100644 --- a/extruder/temp.h +++ b/extruder/temp.h @@ -13,6 +13,7 @@ we still need to specify which analog pins we use in machine.h for the analog se */ #undef DEFINE_TEMP_SENSOR +#undef _CONFIG_H #define DEFINE_TEMP_SENSOR(name, type, pin) TEMP_SENSOR_ ## name, typedef enum { #include "config.h" @@ -21,6 +22,15 @@ typedef enum { } temp_sensor_t; #undef DEFINE_TEMP_SENSOR +typedef enum { + TT_THERMISTOR, + TT_MAX6675, + TT_AD595, + TT_PT100, + TT_INTERCOM, + TT_DUMMY, +} temp_type_t; + #define temp_tick temp_sensor_tick void temp_init(void); @@ -34,4 +44,4 @@ uint16_t temp_get(temp_sensor_t index); void temp_print(temp_sensor_t index); -#endif /* _TIMER_H */ +#endif /* _TEMP_H */ diff --git a/extruder/timer.c b/extruder/timer.c new file mode 100644 index 0000000..296f2bc --- /dev/null +++ b/extruder/timer.c @@ -0,0 +1,164 @@ +#include "timer.h" + +#include + +#include "arduino.h" +#include "config.h" + +#ifdef HOST +#include "dda_queue.h" +#endif + +/* + how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535) +*/ +#define TICK_TIME 2 MS +#define TICK_TIME_MS (TICK_TIME / (F_CPU / 1000)) + +volatile uint32_t next_step_time; + +uint8_t clock_counter_10ms = 0; +uint8_t clock_counter_250ms = 0; +uint8_t clock_counter_1s = 0; +volatile uint8_t clock_flag = 0; + +// comparator B is the "clock", happens every TICK_TIME +ISR(TIMER1_COMPB_vect) { + // set output compare register to the next clock tick + OCR1B = (OCR1B + TICK_TIME) & 0xFFFF; + + /* + clock stuff + */ + clock_counter_10ms += TICK_TIME_MS; + if (clock_counter_10ms >= 10) { + clock_counter_10ms -= 10; + clock_flag |= CLOCK_FLAG_10MS; + + clock_counter_250ms += 1; + if (clock_counter_250ms >= 25) { + clock_counter_250ms -= 25; + clock_flag |= CLOCK_FLAG_250MS; + + clock_counter_1s += 1; + if (clock_counter_1s >= 4) { + clock_counter_1s -= 4; + clock_flag |= CLOCK_FLAG_1S; + } + } + } +} + +#ifdef HOST +void timer1_compa_isr(void) __attribute__ ((hot)); +void timer1_compa_isr() { + // led on + WRITE(SCK, 1); + + // disable this interrupt. if we set a new timeout, it will be re-enabled when appropriate + TIMSK1 &= ~MASK(OCIE1A); + + // stepper tick + queue_step(); + + // led off + WRITE(SCK, 0); +} + +// comparator A is the step timer. It has higher priority then B. +ISR(TIMER1_COMPA_vect) { + // Check if this is a real step, or just a next_step_time "overflow" + if (next_step_time < 65536) { + next_step_time = 0; + // step! + timer1_compa_isr(); + return; + } + + next_step_time -= 65536; + + // similar algorithm as described in setTimer below. + if (next_step_time < 65536) { + OCR1A = (OCR1A + next_step_time) & 0xFFFF; + } else if(next_step_time < 75536){ + OCR1A = (OCR1A - 10000) & 0xFFFF; + next_step_time += 10000; + } + // leave OCR1A as it was +} +#endif /* ifdef HOST */ + +void timer_init() +{ + // no outputs + TCCR1A = 0; + // Normal Mode + TCCR1B |= MASK(CS10); + // set up "clock" comparator for first tick + OCR1B = TICK_TIME & 0xFFFF; + // enable interrupt + TIMSK1 |= MASK(OCIE1B); +} + +#ifdef HOST +void setTimer(uint32_t delay) +{ + // save interrupt flag + uint8_t sreg = SREG; + uint16_t step_start = 0; + // disable interrupts + cli(); + + // re-enable clock interrupt in case we're recovering from emergency stop + TIMSK1 |= MASK(OCIE1B); + + if (delay > 0) { + if (delay <= 16) { + // unfortunately, force registers don't trigger an interrupt, so we do the following + // "fire" ISR- maybe it sets a new timeout + timer1_compa_isr(); + } + else { + // Assume all steps belong to one move. Within one move the delay is + // from one step to the next one, which should be more or less the same + // as from one step interrupt to the next one. The last step interrupt happend + // at OCR1A, so start delay from there. + step_start = OCR1A; + if (next_step_time == 0) { + // new move, take current time as start value + step_start = TCNT1; + } + + next_step_time = delay; + if (next_step_time < 65536) { + // set the comparator directly to the next real step + OCR1A = (next_step_time + step_start) & 0xFFFF; + } + else if (next_step_time < 75536) { + // Next comparator interrupt would have to trigger another + // interrupt within a short time (possibly within 1 cycle). + // Avoid the impossible by firing the interrupt earlier. + OCR1A = (step_start - 10000) & 0xFFFF; + next_step_time += 10000; + } + else { + OCR1A = step_start; + } + + TIMSK1 |= MASK(OCIE1A); + } + } else { + // flag: move has ended + next_step_time = 0; + TIMSK1 &= ~MASK(OCIE1A); + } + + // restore interrupt flag + SREG = sreg; +} + +void timer_stop() { + // disable all interrupts + TIMSK1 = 0; +} +#endif /* ifdef HOST */ diff --git a/extruder/timer.h b/extruder/timer.h new file mode 100644 index 0000000..dd6b6be --- /dev/null +++ b/extruder/timer.h @@ -0,0 +1,30 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#include +#include + +// time-related constants +#define US * (F_CPU / 1000000) +#define MS * (F_CPU / 1000) + +/* +clock stuff +*/ +extern volatile uint8_t clock_flag; + +#define CLOCK_FLAG_10MS 1 +#define CLOCK_FLAG_250MS 2 +#define CLOCK_FLAG_1S 4 +#define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F)) + +/* +timer stuff +*/ +void timer_init(void) __attribute__ ((cold)); + +void setTimer(uint32_t delay); + +void timer_stop(void); + +#endif /* _TIMER_H */ diff --git a/heater.h b/heater.h index 58c4129..d327fab 100644 --- a/heater.h +++ b/heater.h @@ -9,6 +9,7 @@ #define disable_heater() heater_set(0, 0) #undef DEFINE_HEATER +#undef _CONFIG_H #define DEFINE_HEATER(name, port, pin, pwm) HEATER_ ## name, typedef enum { diff --git a/intercom.c b/intercom.c index 06cfa36..bf89ece 100644 --- a/intercom.c +++ b/intercom.c @@ -17,21 +17,16 @@ enum { 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 dio; uint8_t controller_num; - uint16_t temp[3]; + uint8_t control_word; + uint8_t control_index; + union { + int32_t control_data_int32; + uint32_t control_data_uint32; + float control_data_float; + uint16_t temp[2]; + }; uint8_t err; uint8_t crc; } intercom_packet_t; @@ -120,9 +115,16 @@ void start_send(void) { intercom_flags = (intercom_flags & ~FLAG_TX_FINISHED) | FLAG_TX_IN_PROGRESS; SREG = sreg; + // enable transmit pin + enable_transmit(); + // set start byte tx.packet.start = START; + // set packet type + tx.packet.control_word = 105; + tx.packet.control_index = 0; + // calculate CRC for outgoing packet for (i = 0; i < (sizeof(intercom_packet_t) - 1); i++) { txcrc ^= tx.data[i]; @@ -133,17 +135,14 @@ void start_send(void) { _tx.data[i] = tx.data[i]; } - // enable transmit pin - enable_transmit(); - delay_us(15); + packet_pointer = 0; // actually start sending the packet - packet_pointer = 0; -#ifdef HOST - UCSR1B |= MASK(UDRIE1); -#else - UCSR0B |= MASK(UDRIE0); -#endif + #ifdef HOST + UCSR1B |= MASK(UDRIE1); + #else + UCSR0B |= MASK(UDRIE0); + #endif } /* @@ -199,15 +198,18 @@ ISR(USART_RX_vect) } } - intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; #ifndef HOST - if (_rx.packet.controller_num == THIS_CONTROLLER_NUM) { + if (rx.packet.controller_num == THIS_CONTROLLER_NUM) { if (rxcrc != _rx.packet.crc) tx.packet.err = ERROR_BAD_CRC; + else + intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; // not sure why exactly this delay is needed, but wihtout it first byte never arrives. - delay_us(150); - start_send(); +// delay_us(150); +// start_send(); } + #else + intercom_flags = (intercom_flags & ~FLAG_RX_IN_PROGRESS) | FLAG_NEW_RX; #endif } } diff --git a/intercom.h b/intercom.h index 1120a05..0e826fe 100644 --- a/intercom.h +++ b/intercom.h @@ -5,11 +5,11 @@ #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) + #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(TXCIE1) | MASK(UDRIE1)); 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) + #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(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0) #endif // initialise serial subsystem diff --git a/temp.h b/temp.h index 6a1d5e5..5e56038 100644 --- a/temp.h +++ b/temp.h @@ -13,6 +13,7 @@ we still need to specify which analog pins we use in machine.h for the analog se */ #undef DEFINE_TEMP_SENSOR +#undef _CONFIG_H #define DEFINE_TEMP_SENSOR(name, type, pin) TEMP_SENSOR_ ## name, typedef enum { #include "config.h" diff --git a/timer.c b/timer.c index fe60c65..296f2bc 100644 --- a/timer.c +++ b/timer.c @@ -2,7 +2,12 @@ #include +#include "arduino.h" +#include "config.h" + +#ifdef HOST #include "dda_queue.h" +#endif /* how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535) @@ -44,6 +49,7 @@ ISR(TIMER1_COMPB_vect) { } } +#ifdef HOST void timer1_compa_isr(void) __attribute__ ((hot)); void timer1_compa_isr() { // led on @@ -80,6 +86,7 @@ ISR(TIMER1_COMPA_vect) { } // leave OCR1A as it was } +#endif /* ifdef HOST */ void timer_init() { @@ -93,6 +100,7 @@ void timer_init() TIMSK1 |= MASK(OCIE1B); } +#ifdef HOST void setTimer(uint32_t delay) { // save interrupt flag @@ -153,3 +161,4 @@ void timer_stop() { // disable all interrupts TIMSK1 = 0; } +#endif /* ifdef HOST */