simulator.h is already included in config.h/arduino.h, so it doesn't
need to be included again most of the time. In some cases it was
included twice on purpose to undo some intervening include file, but
these intervening includes were unnecessary. Remove some related
include file redundancy by re-ordering the include files and relocating
some nested includes up to the parent .c file.
Note by Traumflug: this code was written by Ruslan Popov a lot
earlier already. I picked it to i2c_test.c to get "something"
visible running. This is the commit finally adjusted to the new
display infrastructure.
As we usually talk to one device only, there's not much point in
carrying around the address all the time. Surprise, this saves
only 16 bytes binary size despite of heavy usage.
Naively restarting I2C immediately is certainly not the solution
and just leads to an interrupt flood. As I2C is currently meant
to drive displays, where successful data transmission isn't
crucial, we now simply stop transmission on errors.
This saves another 80 bytes binary size:
FLASH : 23094 bytes
RAM : 2051 bytes
EEPROM : 32 bytes
This commit squashes in some fixes found after debugging on the
topic branch. Test code by Traumflug, collected from Ruslan's
code on the topic branch.
Before, same as now without I2C:
FLASH : 22408 bytes
RAM : 1393 bytes
EEPROM : 32 bytes
Now with I2C:
FLASH : 23224 bytes
RAM : 2057 bytes
EEPROM : 32 bytes
This totals to some 800 bytes with a whole lot of test code, so
implementation is pretty small :-)
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.
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.
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.
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%
Only SET_OUTPUT() and WRITE() for now, reading follows later.
A loop like this:
SET_OUTPUT(PIO0_1);
for (;;) {
WRITE(PIO0_1, 0);
WRITE(PIO0_1, 1);
}
toggles a pin at about 5.3 MHz. The low period is 63 ns on the
scope, so 3 clock cycles. With this loop, the binary is 1648
bytes.
Assembly shows four instructions inside the loop, which is about
as good as it can get:
movs r2, #0
str r2, [r3, #8]
adds r2, #2
str r2, [r3, #8]
For comparison, using the MBED provided gpio routines give a
toggle frequency of about 300 kHz, with a low period of 72 clock
cycles. Microoptimisation isn't just the last few percent ...
Tested with this code before main():
static void delay(uint32_t delay) {
while (delay) {
__ASM volatile ("nop");
delay--;
}
}
... and in main():
SET_OUTPUT(PIO0_1);
SET_OUTPUT(PIO0_2);
SET_OUTPUT(PIO0_3);
SET_OUTPUT(PIO0_4);
__ASM (".balign 16");
while (1) {
// 1 pulse on pin 1, two pulses on pin 2, ...
WRITE(PIO0_1, 0);
WRITE(PIO0_1, 1);
WRITE(PIO0_2, 0);
WRITE(PIO0_2, 1);
WRITE(PIO0_2, 0);
WRITE(PIO0_2, 1);
WRITE(PIO0_3, 0);
WRITE(PIO0_3, 1);
WRITE(PIO0_3, 0);
WRITE(PIO0_3, 1);
WRITE(PIO0_3, 0);
WRITE(PIO0_3, 1);
// PIO0_4 needs a pullup 10k to 3.3V
// to show a visible signal.
WRITE(PIO0_4, 0);
delay(10);
WRITE(PIO0_4, 1);
delay(10);
WRITE(PIO0_4, 0);
delay(10);
WRITE(PIO0_4, 1);
delay(10);
WRITE(PIO0_4, 0);
delay(10);
WRITE(PIO0_4, 1);
delay(10);
WRITE(PIO0_4, 0);
delay(10);
WRITE(PIO0_4, 1);
delay(1000);
}
With a 10k pullup, PIO0_4 has a rise time of about 1 microsecond.
Pretty complex, this MBED system, it requires no less than
24 additional files. This will be fleshd out before too long.
SIZES ARM... lpc1114
FLASH : 5956 bytes 19%
RAM : 176 bytes 5%
EEPROM : 0 bytes 0%
Previously acknoledgement was sent as soon as the command was
parsed. Accordingly, the host would send the next command and
this command would wait in the RX buffer without being parsed.
This worked reasonably, unless an incoming line of G-code was
longer than the RX buffer, in which case the line end was dropped
and parsing of the line never completed. With a 64 bytes buffer
on AVR this was rarely the case, with the 16 bytes hardware buffer
on ARM LPC1114 it happens regularly. And there's no recovering
from such a situation.
This should solve issue #52.
Formerly we took efforts to read only small chunks into a
(small) buffer, just to read this buffer byte by byte yet
again for parsing. It's more efficient and requires less
code to parse the character at read time directly. This
way we can read in chunks of exactly one line, making the
buffer obsolete.
First step is to implement this in mendel.c and in sd.c/.h.
This gets rid of the buffer already.
Very inefficient in pff.c and pff_diskio.c so far, more
than 40 minutes / less than 500 bytes/s for reading this
1 MB comments file. Reason is, for every single byte a
whole sector is read. Nevertheless, this attempt appears
to be on the right track.
Binary is 156 bytes smaller, 16 bytes less RAM:
ATmega... '168 '328(P) '644(P) '1280
FLASH: 22052 bytes 153.82% 71.78% 34.73% 17.09%
RAM: 1331 bytes 129.98% 64.99% 32.50% 16.25%
EEPROM: 32 bytes 3.12% 1.56% 1.56% 0.78%
This raises abstraction and even makes the binary a bit smaller
(2 bytes without SD, 14 bytes with SD).
A G-code file with 16'384 lines of comments, 64 bytes per line
( = 1 MB file size), is read and parsed from SD card in 2:47
minutes, or at a speed of 5924 bytes/second.
Turned out to be pretty easy with all the more complex bits
already in place.
Strategy is to always parse a full line from one of the sources.
Accordingly, simply sending a character on the serial line stops
reading from SD until the line coming in over serial is completed.
As we're around here, lets see how fast this implementation is.
All measurements are raw reading performance, without actual
parsing of the G-code.
With SPI_2X disabled (see line 8 in spi.h), performance is
195 seconds per megabyte, equivalent to about 50'000 baud.
With SPI_2X enabled, performance is 159 seconds per megabyte,
or 60'000 baud.
Still, SPI_2X is left disabled to increase reliability. Reading
from SD is faster by design, because there is no checksumming and
also no waiting for the "ok" to be sent back. In case reading
G-code from SD ever becomes a bottleneck, there are even more
opportunities in addition to enabling SPI_2X, like making sdbuffer
bigger, like micro-optimizing spi_rw() and similar stuff.
Next to the implementation of sd_read_byte() as well as M24 and
M25, yet another demo: read the file and write it to the serial
line, to show correctness of the implementation.
This is all the commands to read from and write to SPI,
initializing the card, read in blocks and so on. This should
make Petit FatFs actually usable.
So far read-only and no M-codes to let end users play with
this stuff.
The demonstration code was changed to list the SD card's
top level directory over and over again.
For now this is just a nice demonstration on how to send bytes
over SPI. Add SD_CARD_SELECT_PIN to your configuration board
file manually to see data signals on MOSI dancing on the scope.
The TODO's about SS in arduino*.h were wrong, SS does have a
chip-specific special meaning (used in SPI multi-master or SPI
slave mode). Still, a #define MAX6675_SELECT_PIN is missing.
Squashed in this commit from the SPI development topic branch to
get this first step working:
Author: jbernardis <jeff.bernardis@gmail.com>
2015-02-04 22:35:07
mendel.c: disable SPI in power management only when not needed.
If we want to talk to a SD card connected to SPI, we need SPI
powered, of course.
From Traumflug: nice catch, Jeff!
It's also possible to do this by stringifying MCU, but this
requires double redirection, which isn't easily readable in a .c
file. For stringification, see the bottom example at
https://gcc.gnu.org/onlinedocs/cpp/Stringification.html