From d7b59e2d33b6fa9c0f551500ceefc457cbfd4d3f Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sat, 8 Aug 2015 14:06:47 +0200 Subject: [PATCH] ARM: implement heater-arm.c partially. Currently at a fixed frequency of 1 kHz and with a fixed duty cycle of 10%, but PWM does work. As it turns out, PIO0_11 is not usable for PWM, because its timer is already in use for the Step timer, and had to be disabled for Gen7-ARM. Test: define a heater in board.gen7-arm.h and a square signal of 1 kHz with 10% duty cycle should appear on the heater pin. --- Makefile-ARM | 4 +- arduino_lpc1114.h | 26 ++++++++ clock.c | 5 +- config/board.gen7-arm.h | 10 +-- config_wrapper.h | 29 +++++++++ gcode_process.c | 4 -- heater-arm.c | 132 ++++++++++++++++++++++++++++++++++++++++ heater.c | 2 +- mendel.c | 5 +- 9 files changed, 197 insertions(+), 20 deletions(-) create mode 100644 heater-arm.c diff --git a/Makefile-ARM b/Makefile-ARM index 9703c88..a657a29 100644 --- a/Makefile-ARM +++ b/Makefile-ARM @@ -100,10 +100,10 @@ TARGET = $(PROGRAM).hex SOURCES = mendel.c cpu.c serial.c sermsg.c sersendf.c delay.c SOURCES += gcode_parse.c gcode_process.c pinio.c timer.c clock.c SOURCES += dda_queue.c dda_maths.c dda_kinematics.c dda.c dda_lookahead.c -SOURCES += analog.c temp.c +SOURCES += analog.c temp.c heater.c # Sources left: # home.c crc.c intercom.c debug.c spi.c usb_serial.c -# graycode.c pff.c watchdog.c heater.c pff_diskio.c +# graycode.c pff.c watchdog.c pff_diskio.c ifeq ($(MCU), lpc1114) SOURCES += cmsis-system_lpc11xx.c diff --git a/arduino_lpc1114.h b/arduino_lpc1114.h index e9b1576..3c2d66c 100644 --- a/arduino_lpc1114.h +++ b/arduino_lpc1114.h @@ -95,6 +95,7 @@ #define PIO0_1_PIN 1 #define PIO0_1_PORT LPC_GPIO0 #define PIO0_1_OUTPUT 0x00 +// Timer pin CT32B0_MAT2, but timer used for Step interrupt. #define PIO0_2_CMSIS PIO0_2 #define PIO0_2_PIN 2 @@ -130,22 +131,32 @@ #define PIO0_8_PIN 8 #define PIO0_8_PORT LPC_GPIO0 #define PIO0_8_OUTPUT 0x00 +#define PIO0_8_TIMER LPC_TMR16B0 +#define PIO0_8_MATCH 1 +#define PIO0_8_PWM (0x02 << 0) #define PIO0_9_CMSIS PIO0_9 #define PIO0_9_PIN 9 #define PIO0_9_PORT LPC_GPIO0 #define PIO0_9_OUTPUT 0x00 +#define PIO0_9_TIMER LPC_TMR16B0 +#define PIO0_9_MATCH 1 +#define PIO0_9_PWM (0x02 << 0) #define PIO0_10_CMSIS SWCLK_PIO0_10 #define PIO0_10_PIN 10 #define PIO0_10_PORT LPC_GPIO0 #define PIO0_10_OUTPUT (0x01 << 0) +#define PIO0_10_TIMER LPC_TMR16B0 +#define PIO0_10_MATCH 2 +#define PIO0_10_PWM (0x03 << 0) #define PIO0_11_CMSIS R_PIO0_11 #define PIO0_11_PIN 11 #define PIO0_11_PORT LPC_GPIO0 #define PIO0_11_OUTPUT ((0x01 << 0) | (0x01 << 7)) #define PIO0_11_ADC 0 +// Timer pin CT32B0_MAT3, but timer used for Step interrupt. #define PIO1_0_CMSIS R_PIO1_0 #define PIO1_0_PIN 0 @@ -158,24 +169,34 @@ #define PIO1_1_PORT LPC_GPIO1 #define PIO1_1_OUTPUT ((0x01 << 0) | (0x01 << 7)) #define PIO1_1_ADC 2 +#define PIO1_1_TIMER LPC_TMR32B1 +#define PIO1_1_MATCH 0 +#define PIO1_1_PWM (0x03 << 0) #define PIO1_2_CMSIS R_PIO1_2 #define PIO1_2_PIN 2 #define PIO1_2_PORT LPC_GPIO1 #define PIO1_2_OUTPUT ((0x01 << 0) | (0x01 << 7)) #define PIO1_2_ADC 3 +#define PIO1_2_TIMER LPC_TMR32B1 +#define PIO1_2_MATCH 1 +#define PIO1_2_PWM (0x03 << 0) #define PIO1_3_CMSIS SWDIO_PIO1_3 #define PIO1_3_PIN 3 #define PIO1_3_PORT LPC_GPIO1 #define PIO1_3_OUTPUT ((0x01 << 0) | (0x01 << 7)) #define PIO1_3_ADC 4 +#define PIO1_3_TIMER LPC_TMR32B1 +#define PIO1_3_MATCH 2 +#define PIO1_3_PWM (0x03 << 0) #define PIO1_4_CMSIS PIO1_4 #define PIO1_4_PIN 4 #define PIO1_4_PORT LPC_GPIO1 #define PIO1_4_OUTPUT (0x01 << 7) #define PIO1_4_ADC 5 +// Timer pin CT32B1_MAT3, but match used for PWM reset. #define PIO1_5_CMSIS PIO1_5 #define PIO1_5_PIN 5 @@ -186,11 +207,13 @@ #define PIO1_6_PIN 6 #define PIO1_6_PORT LPC_GPIO1 #define PIO1_6_OUTPUT 0x00 +// Timer pin CT32B0_MAT0, but timer used for Step interrupt. #define PIO1_7_CMSIS PIO1_7 #define PIO1_7_PIN 7 #define PIO1_7_PORT LPC_GPIO1 #define PIO1_7_OUTPUT 0x00 +// Timer pin CT32B0_MAT1, but timer used for Step interrupt. #define PIO1_8_CMSIS PIO1_8 #define PIO1_8_PIN 8 @@ -201,3 +224,6 @@ #define PIO1_9_PIN 9 #define PIO1_9_PORT LPC_GPIO1 #define PIO1_9_OUTPUT 0x00 +#define PIO1_9_TIMER LPC_TMR16B1 +#define PIO1_9_MATCH 0 +#define PIO1_9_PWM (0x01 << 0) diff --git a/clock.c b/clock.c index 61f92fd..e72464b 100644 --- a/clock.c +++ b/clock.c @@ -71,11 +71,8 @@ void clock_tick(void) { called from clock_10ms(), do not call directly */ static void clock_250ms(void) { - #ifndef __ARMEL_NOTYET__ + if (heaters_all_zero()) { - #else - if (1) { - #endif /* __ARMEL_NOTYET__, ! __ARMEL_NOTYET__ */ if (psu_timeout > (30 * 4)) { power_off(); } diff --git a/config/board.gen7-arm.h b/config/board.gen7-arm.h index d958348..7c1239b 100644 --- a/config/board.gen7-arm.h +++ b/config/board.gen7-arm.h @@ -163,8 +163,8 @@ */ //DEFINE_TEMP_SENSORS_START // name type pin additional -DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PIO1_1,THERMISTOR_EXTRUDER) -DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, PIO1_0,THERMISTOR_BED) +DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PIO1_0,THERMISTOR_EXTRUDER) +//DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, PIO1_1,THERMISTOR_BED) // Beta algorithm r0 beta r2 vadc // Steinhart-Hart rp t0 r0 t1 r1 t2 r2 @@ -220,11 +220,11 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, PIO1_0,THERMISTOR_BED) */ //DEFINE_HEATERS_START // name port pwm -DEFINE_HEATER(extruder, PIO0_11, 1) -DEFINE_HEATER(bed, PIO0_10, 1) +DEFINE_HEATER(extruder, PIO0_10, 1) +//DEFINE_HEATER(bed, PIO0_11, 1) #define HEATER_EXTRUDER HEATER_extruder -#define HEATER_BED HEATER_bed +//#define HEATER_BED HEATER_bed //DEFINE_HEATERS_END diff --git a/config_wrapper.h b/config_wrapper.h index 31dab57..6f2b77a 100644 --- a/config_wrapper.h +++ b/config_wrapper.h @@ -42,3 +42,32 @@ Lookahead disabled. #undef LOOKAHEAD #endif + +/** + Silently discard EECONFIG on ARM. Silently to not disturb regression tests. + + TODO: + + - EECONFIG is currently misplaced as a printer property. Move EECONFIG to + the board configuration or drop it entirely in favour of PID settings in + Configtool. + + - Remove this silent discard in favour of the #error in heater-arm.c. +*/ +#if defined __ARMEL__ && defined EECONFIG + #undef EECONFIG +#endif + +/** + Silently discard BANG_BANG on ARM. Silently to not disturb regression tests. + + TODO: + + - BANG_BANG is currently misplaced as a printer property. Move BANG_BANG to + the board configuration. + + - Remove this silent discard in favour of the #error in heater-arm.c. +*/ +#if defined __ARMEL__ && defined BANG_BANG + #undef BANG_BANG +#endif diff --git a/gcode_process.c b/gcode_process.c index d2e3fb3..ebac33b 100644 --- a/gcode_process.c +++ b/gcode_process.c @@ -724,7 +724,6 @@ void process_gcode_command() { serial_writechar('\n'); break; - #ifndef __ARMEL_NOTYET__ #ifdef EECONFIG case 130: //? --- M130: heater P factor --- @@ -787,7 +786,6 @@ void process_gcode_command() { heater_save_settings(); break; #endif /* EECONFIG */ - #endif /* __ARMEL_NOTYET__ */ #ifdef DEBUG case 136: @@ -800,9 +798,7 @@ void process_gcode_command() { #else next_target.P = 0; #endif - #ifndef __ARMEL_NOTYET__ heater_print(next_target.P); - #endif /* __ARMEL_NOTYET__ */ break; #endif /* DEBUG */ diff --git a/heater-arm.c b/heater-arm.c new file mode 100644 index 0000000..6879173 --- /dev/null +++ b/heater-arm.c @@ -0,0 +1,132 @@ + +/** \file + \brief Manage heaters, including PID and PWM, ARM specific part. +*/ + +#if defined TEACUP_C_INCLUDE && defined __ARMEL__ + +/** + Test configuration. +*/ +#ifdef EECONFIG + #error EEPROM handling (EECONFIG) not yet supported on ARM. +#endif + +#ifdef BANG_BANG + #error BANG_BANG not supported on ARM. You may set PWM frequency of one \ + or all heater(s) to zero, which gives similar, better behaviour. +#endif + +/** \def PWM_SCALE + + G-code standard (if such a thing exists at all) gives a heater setting + range between 0 (off) and 255 (full on), so we let the PWM timers count up + to 255. Doing so allows to set the prescaler for these frequencies (all on + a 48 MHz CPU clock): + + prescaler frequency prescaler frequency + + 0 188.2 kHz 4 37.6 kHz + 1 91.1 kHz 5 31.4 kHz + 2 62.7 kHz ... ... + 3 47.0 kHz 65535 2.87 Hz + + As one can see, frequency steps are rather coarse on the high end and + become finer grained the lower it gets. + + If this range is generally too high for your purposes, you can set PWM_SCALE + to multiples of 255 to lower the range. Doubling it to 510 moves the + frequency range to 1.4 Hz...91.1 kHz, quadrupling it to 1020 moves the range + to 0.7 Hz...46.9 kHz and so on. The highest allowed number is 65535. + + That said, code below calculates the best prescaler value for a configured + frequency, so you should bother about PWM_SCALE only of you need frequencies + below 3 Hz. +*/ +#define PWM_SCALE 255 + + +/** Initialise heater subsystem. + + Initialise PWM timers, etc. Inspired by pwm.c in LPC1343CodeBase: + + https://github.com/microbuilder/LPC1343CodeBase + + Note that PWM is inversed, pins start at Low by chip design. When the pin's + counter is reached, they're set to High. Reaching the timer reset counter is + programmed to reset everything and start over. Thus, having both counter + matches similar gives a low duty, having the pin counter match zero gives + full on. + + For simplicity we reset all timer counters always on Match 3 and always + at PWM_SCALE (255 per default), so setting a pin match to PWM_SCALE / 2 + gives 50% duty, setting it to PWM_SCALE gives full off. This choice disallows + using a pin connected to a Match 3, working around this would make code much + more complicated (and still not allow to use more than 3 pins per timer). + + On ARM we can define a PWM frequency pretty fine grained, so we take the + 'pwm' value of DEFINE_HEATER() not only wether to use PWM at all, but also + to define the PWM frequency. Float values are allowed. + + If there's more than one pin on a timer, they share the same PWM frequency; + the frequency choosen is the one of the pin defined last. +*/ +void heater_init() { + /** + Pins on the LPC1114 are usable as following, capture pins not listed: + + pin timer/match func for PWM other uses + + PIO0_1 CT32B0_MAT2 0x2 --- + PIO0_8 CT16B0_MAT0 0x2 MISO0 + PIO0_9 CT16B0_MAT1 0x2 MOSI0 + PIO0_10 CT16B0_MAT2 0x3 SCK0 (also on PIO0_6) + PIO0_11 CT32B0_MAT3 0x3 AD0, Step timer + PIO1_1 CT32B1_MAT0 0x3 AD2 + PIO1_2 CT32B1_MAT1 0x3 AD3 + PIO1_3 CT32B1_MAT2 0x3 AD4 + PIO1_4 CT32B1_MAT3 0x2 AD5, PWM reset + PIO1_6 CT32B0_MAT0 0x2 RXD, Step timer + PIO1_7 CT32B0_MAT1 0x2 TXD, Step timer + PIO1_9 CT16B1_MAT0 0x1 --- + */ + if (NUM_HEATERS) { // At least one channel in use. + + // For simplicity, turn on all timers, not only the used ones. + // TODO: turn on only the used ones. we know pin ## TIMER. + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7); // Turn on CT16B0 power. + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); // Turn on CT16B1 power. + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10); // Turn on CT32B1 power. + + // Auto-generate pin setup. + #undef DEFINE_HEATER + #define DEFINE_HEATER(name, pin, pwm) \ + LPC_IOCON->pin ## _CMSIS = pin ## _PWM; /* Connect to timer. */ \ + /*pin ## _TIMER->IR = 0; ( = reset value) No interrupts. */ \ + pin ## _TIMER->TCR = (1 << 0); /* Enable counter. */ \ + /* TODO: set PWM frequency here according to configuration. */ \ + /* TODO: check wether configured freq. is within range (1..65536). */ \ + pin ## _TIMER->PR = /* Prescaler to */ \ + F_CPU / PWM_SCALE / 1000 - 1; /* 1000 Hz. */ \ + pin ## _TIMER->MCR = (1 << 10); /* Reset on Match 3. */ \ + /* PWM_SCALE - 1, so match = 255 is full off. */ \ + pin ## _TIMER->MR[3] = PWM_SCALE - 1; /* Match 3 at 254. */ \ + /* TODO: Heaters should start at zero, of course. 10% is as demo. */ \ + pin ## _TIMER->MR[pin ## _MATCH] = /* Match pin = duty. */ \ + (PWM_SCALE * 0.9); \ + /*pin ## _TIMER->CCR = 0; ( = reset value) No pin capture. */ \ + pin ## _TIMER->EMR |= ((1 << pin ## _MATCH) /* Connect to pin. */ \ + | (0x03 << ((pin ## _MATCH * 2) + 4))); /* Toggle pin on match.*/ \ + /*pin ## _TIMER->CTCR = 0; ( = reset value) Timer mode. */ \ + pin ## _TIMER->PWMC |= ((1 << 3) /* 3 to PWM mode. */ \ + | (1 << pin ## _MATCH)); /* Pin to PWM mode. */ + #include "config_wrapper.h" + #undef DEFINE_HEATER + } /* NUM_HEATERS */ + +#if 0 + pid_init(i); +#endif /* 0 */ +} + +#endif /* defined TEACUP_C_INCLUDE && defined __ARMEL__ */ diff --git a/heater.c b/heater.c index 70c685b..43617ef 100644 --- a/heater.c +++ b/heater.c @@ -7,7 +7,7 @@ #define TEACUP_C_INCLUDE #include "heater-avr.c" -//#include "heater-arm.c" +#include "heater-arm.c" #undef TEACUP_C_INCLUDE #include diff --git a/mendel.c b/mendel.c index c05eb47..d1f7d9e 100644 --- a/mendel.c +++ b/mendel.c @@ -38,8 +38,8 @@ #ifndef __ARMEL_NOTYET__ #include "watchdog.h" #include "debug.h" -#include "heater.h" #endif /* __ARMEL_NOTYET__ */ +#include "heater.h" #include "analog.h" #include "pinio.h" #include "clock.h" @@ -97,10 +97,7 @@ void init(void) { // set up timers timer_init(); - #ifndef __ARMEL_NOTYET__ - // read PID settings from EEPROM heater_init(); - #endif /* __ARMEL_NOTYET__ */ // set up dda dda_init();