Just like with AVR, they're simply set as a GPIO output and
turned on and off as needed.
Bed heater and temp sensor not yet re-enabled, because Gen7-ARM
has a driver MOSFET for the bed, which needs an inverted signal.
It can be enabled for testing; M106 P1 S2 turns it on, M106 P1 S20
turns it off. Not the way it should work.
Especially at high frequencies the achieved one is only close,
but that's entirely sufficient for our purposes.
Test: the PWM frequency on the scope should be similar to the
one configures in the board file with DEFINE_HEATER().
Works very nicely from full off (M106 S0) to full on (M106 S255).
Test: M106 should work now as expected. M106 S0 should turn full
off, M106 S255 should turn full on, both without any spike on the
scope.
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.
Also move #defines from heater.c to heater.h
This operation became bigger than expected, because PID handling
hat to be separated from heater handling. Code and strategy wasn't
changed, but some chunks of code had to be moved.
No code changes, but quite a few removals of __ARMEL_NOTYET__
guards. 20 such guards left.
Test: M105 should work and report plausible temperatures.
Current code size:
SIZES ARM... lpc1114
FLASH : 9460 bytes 29%
RAM : 1258 bytes 31%
EEPROM : 0 bytes 0%
Very simple, because the LPC1114 features a hardware scan mode,
which automatically scans a given set of pins in freerunning mode
and stores all the values separately. No need for an interrupt!
Not yet done: configure not PIO1_0 and PIO1_1, but the pins
actually defined in the board file.
For testing, add this to ifclock(clock_flag_1s) in clock.c:
uint8_t i;
for (i = 0; i <= 7; i++) {
sersendf_P(PSTR("%lu "), analog_read(i));
}
serial_writechar('\n');
This should print all 8 ADC values repeatedly. Only two pins are
actually set up, these values should change depending on the
thermistor temperature. More precisely: depending on the voltage
on the pin.
We know already wether we start from a pause or not, so let's
take advantage of this knowledge instead of checking for
plausibility of a timer delay at interrupt time.
Costs just 8 bytes binary size:
SIZES ARM... lpc1114
FLASH : 7764 bytes 24%
RAM : 960 bytes 24%
EEPROM : 0 bytes 0%
Due to the less code at interrupt time, maximum step rate was
raised from 127.9 kHz to 130.6 kHz.
As dda_clock() is potantially too slow for high step rates, we
call it with a secondary interrupt with slightly slower priority.
This makes sure the slow part is ignored on high system load,
still reasonably synchonized with the clock tick.
Test: steppers should move and accelerate now.
Current binary size:
SIZES ARM... lpc1114
FLASH : 7756 bytes 24%
RAM : 960 bytes 24%
EEPROM : 0 bytes 0%
Works nicely, much less code than on AVR, because we have 32-bit
hardware timers.
Test: steppers should move. Only slowly, because dda_clock() isn't
called, yet, so no acceleration.
Pulse time on the Debug LED is 5.21 us or 250 clock ticks.
All in one chunk, because it's all hardware-independent and doing
them one by one would end up on not more than some typing
exercises.
Compiles fine. For testing, remove if (DEBUG... for M114 in
gcode_process.c. Then one can see how the queue fills up when
sending movements and M114 repeatedly. This time with actual
coordinates.
No stepper movements, yet, because set_timer() is still empty.
Compiles fine. For testing, remove if (DEBUG... for M114 in
gcode_process.c. Then one can see how the queue fills up when
sending movements and M114 repeatedly.
queue_step() isn't called, yet, the stepper timer is still missing.
This test code in SysTickHanlder() should give you a rather
accurate clock with only a few seconds deviation per hour:
#include "serial.h"
#include "sersendf.h"
void SysTick_Handler(void) {
static uint32_t count = 0;
static uint8_t minutes = 0, seconds = 0;
count++;
if ( ! (count % 500)) { // A full second.
seconds++;
if ( ! (seconds % 60)) {
seconds = 0;
minutes++;
}
sersendf_P(PSTR("%su:"), minutes);
if (seconds < 10)
serial_writechar('0');
sersendf_P(PSTR("%su\n"), seconds);
}
[...]
This enables pinio_init(), power_on() and power_off(). Now one
can turn on the power supply with M119 and turn it off with M2.
Code changes were neccessary. Setting a pin first, then making
it an output doesn't work on ARM. A pin has to be an output
before it permanently accepts a given state. As I was never
sure the former strategy actually worked on AVR, the order of
these two steps was changed for both, AVR and ARM.
Again, the whole file compiled flawlessly without change. Still,
to get it linked as well, most of the functionality had to
be #ifdef'd out.
Nevertheless, the firmware shows first signs of life, e.g. M115
works.
This uses 4 bytes less RAM, without any loss, due to fewer holes
in variable arrangements.
The general strategy is simple:
- Ideally, all variables are aligned in groups of 4 bytes
(32 bits). This allows fastest access on 32-bit CPUs and doesn't
change anything on 8 or 16 bit ones.
- 1x 32-bits variable = 4 bytes = 4-byte group.
- 2x 16-bits variable together = 4-byte group.
- 4x 8-bits variable together = 4-byte group.
- Have as few incomplete groups as possible.
Another strategy is to simply order variables by size.
There's a compiler flag to pack such variable arrangements, but
this costs Flash size and processing time.
Just did it, no code changes neccessary. Except ajusting the
boundaries to not yet ported code.
Successful tests: controller answers with "ok", just like an AVR.
Binary size raised, of course:
SIZES ARM... lpc1114
FLASH : 3064 bytes 10%
RAM : 194 bytes 5%
EEPROM : 0 bytes 0%
This is, reformat the "Changes for Teacup" section, change tabs
for spaces, remove trailing whitespace and keep the file as close
to the original as possible.
This is a pretty complex and, as system clock and baudrate are
known at compile time and never changed at runtime, unneccessary.
Replacing this calculation with fixed values makes the binary
a whopping 564 bytes smaller.
However, how to get these values? Well, we do kind of an
easter-egg. If parameters arenot known, we calculate them at
runtime anyways, and also report them to the user. So she can
insert them into the code and after doing so, whoops, serial
fast and binary small :-)
With known parameters:
SIZES ARM... lpc1114
FLASH : 1092 bytes 4%
RAM : 132 bytes 4%
EEPROM : 0 bytes 0%
Without (1428 bytes more):
SIZES ARM... lpc1114
FLASH : 2520 bytes 8%
RAM : 132 bytes 4%
EEPROM : 0 bytes 0%
On ARM we use only the 16 byte hardware buffer for sending and
receiving over the serial line, which is often too short for
debugging messages. This implementation works fine and still
neither blocks nor introduces delays for short messages.
Costs 72 bytes binary size, mostly because it's the first usage
of delay_us():
SIZES ARM... lpc1114
FLASH : 1656 bytes 6%
RAM : 136 bytes 4%
EEPROM : 0 bytes 0%
Accuracy is pretty good, see committed comments :-)
Code used for testing, in main():
uint32_t i;
SET_OUTPUT(PIO0_1);
while (1) {
// 10 seconds for each frequency, so we
// can measure all three with one upload.
for (i = 10000; i > 0; i--) {
WRITE(PIO0_1, 1);
delay_us(1000);
WRITE(PIO0_1, 0);
delay_us(1000);
}
for (i = 1000; i > 0; i--) {
WRITE(PIO0_1, 1);
delay_us(10000);
WRITE(PIO0_1, 0);
delay_us(10000);
}
for (i = 200; i > 0; i--) {
WRITE(PIO0_1, 1);
delay_us(65000);
WRITE(PIO0_1, 0);
delay_us(65000);
}
}
(Hopefully) no functional change.
Also remove these wd_reset()s in delay_us() to match the behaviour
promised in delay.h. Not that this matters much, watchdog is
disabled by default.