reorganise intercom to send packets from extruder main loop, also generalise protocol as discussed in forum

This commit is contained in:
Michael Moon 2011-03-01 23:32:53 +11:00
parent 088f79aa11
commit d0601716e8
15 changed files with 349 additions and 83 deletions

View File

@ -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
##############################################################################
# #

24
extruder/crc.c Normal file
View File

@ -0,0 +1,24 @@
#include "crc.h"
#include <util/crc16.h>
// 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;
}

8
extruder/crc.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _CRC_H
#define _CRC_H
#include <stdint.h>
uint16_t crc_block(void *data, uint16_t len);
#endif /* _CRC_H */

View File

@ -9,6 +9,7 @@
#include "watchdog.h"
#include "heater.h"
#include "temp.h"
#include "timer.h"
static uint8_t motor_pwm;
@ -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;
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();
}
}
}

View File

@ -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
{

View File

@ -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 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,12 +135,9 @@ 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
@ -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
}
}

View File

@ -6,10 +6,10 @@
#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 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 disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B &= ~(MASK(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0)
#endif
// initialise serial subsystem

View File

@ -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 */

164
extruder/timer.c Normal file
View File

@ -0,0 +1,164 @@
#include "timer.h"
#include <avr/interrupt.h>
#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 */

30
extruder/timer.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef _TIMER_H
#define _TIMER_H
#include <stdint.h>
#include <avr/io.h>
// 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 */

View File

@ -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
{

View File

@ -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 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,12 +135,9 @@ 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
@ -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
}
}

View File

@ -6,10 +6,10 @@
#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 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 disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B &= ~(MASK(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0)
#endif
// initialise serial subsystem

1
temp.h
View File

@ -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"

View File

@ -2,7 +2,12 @@
#include <avr/interrupt.h>
#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 */