stephen_usher wrote:To do something more you'd probably need something like an Arduino, which will probably not fit in the drive.
Ok, slightly off topic, but...there are options! For example, if the code is written in the Arduino IDE using the features of the Arduino "Language" (aka library) then you are potentially wasting a lot of Flash RAM. You could convert from the Arduino Language, to use plain AVR C/C++ and hit the various registers directly. Using an Uno and the "standard" blink sketch as an example:
Code: Select all
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
becomes:
Code: Select all
void setup() {
DDRB |= (1 << DDB5);
}
void loop() {
PINB |= (1 << PINB5);
delay(1000);
}
Which saves a whole lot of code:
Arduino Blink: 924 bytes of Flash plus 9 bytes of Static RAM.
AVR Blink: 596 bytes of Flash plus 9 bytes of Static RAM.
But, this
still includes the Arduino "hidden" stuff to make "millis()" and "micros()" etc work, and all the setup to get the three timer/counters configured for "analogWrite()" etc. Can we reduce it even more while still using the Arduino IDE? Too right we can:
Code: Select all
#include "avr/io.h"
#include "util/delay.h"
int main() {
// SETUP:
DDRB |= (1 << DDB5);
// LOOP:
PINB |= (1 << PINB5);
_delay_ms(1000);
}
This version takes on 160 bytes of Flash and zero bytes of Static RAM.
Not many people know that if you wipe out the entire sketch offered by the Arduino IDE after File->New, and replace it with plain old C++ written for the AVR, you don't get any of the hidden stuff (or hand holding!) of the Arduino Language.
Someone should write a book about this stuff!
How small can we go? Assembly language?
Code: Select all
;=============================================================
; This program flashes the LED on an Arduino board, using the
; Atmel ATmega328 microprocessor. The LED is on Pin 5 of
; Port B, aka PB5 (Arduino D13).
;
; Assemble with:
; gavrasm QuickStart.asm
;
; Upload with:
; avrdude -p m328p -c arduino -P /dev/ttyUSB0 -C \
; <config_file> -U flash:w:QuickStart.hex
;
; Norman Dunbar
; 01 February 2021
;=============================================================
;-------------------------------------------------------------
; Declare the device, the microcontroller, we are using.
;-------------------------------------------------------------
.DEVICE ATmega328P
;-------------------------------------------------------------
; Tell the assembler we are in the code segment. This is not
; strictly necessary, but it's wise to be explicit.
;-------------------------------------------------------------
.CSEG
;-------------------------------------------------------------
; Tell the assembler to begin at address 0 in the flash. This
; is where the device will start executing on a power up or a
; reset.
;-------------------------------------------------------------
.ORG 0
;-------------------------------------------------------------
; Normally, the interrupt vectors go at address 0 (depending
; on a fuse setting) but as we have no interrupts enabled, we
; can use the vector space for code.
; As we also don't make any subroutine calls, the stack is not
; used. In this case, we don't bother to initialise the stack
; pointer.
; Register Usage:
;
; R16 is a temporary register used to initialise others.
; R17 is the lowest byte of the delay counter.
; R18 is the middle byte of the delay counter.
; R19 is the high byte of the delay counter.
;-------------------------------------------------------------
;-------------------------------------------------------------
; Here we give names to the various registers we are using. It
; is an advisable practice to follow and allows you to change
; registers if necessary without having to scan the whole code
; file/files to find every usage of the register name you need
; to change.
;-------------------------------------------------------------
.DEF bit5reg = R16 ; Holds the value 0b00100000 (bit 5)
.DEF delay_l = R17 ; Delay low, mid and high bytes
.DEF delay_m = R18
.DEF delay_h = R19
;-------------------------------------------------------------
;-------------------------------------------------------------
main:
ldi bit5reg, (1 << DDB5) ; 0b00100000 = PORTB, Pin 5 is OUTPUT.
out DDRB, bit5reg ; pin DDRB:5 is set to output
out PORTB, bit5reg ; initialize the output line to ’high’
;-------------------------------------------------------------
; With r19 set to an initial value of 240 (0xF0) we get a
; delay around 0.197 each time through the delay loop. We need
; two delay period per waveform remember!
;-------------------------------------------------------------
d_lay:
ldi r19, 0xF0 ; Gives about half a second or so.
;-------------------------------------------------------------
; The delay loop increments r17 until it overflows. This takes
; 767 cycles in total.
;-------------------------------------------------------------
r17lp:
inc delay_l ; Three byte counter delay
brne r17lp
;-------------------------------------------------------------
; The delay loop increments r18 until it too overflows. If it
; has not overflowed, we skip back and overflow r17 again, and
; again and again until it does.This takes a total of 117,119
; cycles in total.
;-------------------------------------------------------------
r18lp:
inc delay_m
brne r17lp
;-------------------------------------------------------------
; The delay loop increments r19 until it too overflows. If it
; has not overflowed, we skip back and overflow r18/r17 again,
; and again and again until it does.This takes a total of
; 3,153,952 cycles in total.
;-------------------------------------------------------------
r19lp:
inc delay_h
brne r17lp
;-------------------------------------------------------------
; The delay loop expires after 3,153,952 cycles. We drop in to
; load PINB:5 with a 1 which will toggle PORTB:5.
;-------------------------------------------------------------
toggle:
out PINB, bit5reg ; Toggle the LED on PB5.
;-------------------------------------------------------------
; The pin is high (or low), delay again before we change it to
; low (or high).
;-------------------------------------------------------------
rjmp d_lay ; Back to outer loop
Assembling the above code with the Arduino IDE uses 156 bytes of Flash. This is because the GNU Assembler is used and it insists in setting up all the vectors for all the interrupts, regardless of whether they are used or not. Actually, there's a very slight difference between the code above and that required for the Arduino IDE, but not much, and it's only requiring to make the label "main" a global, and creating a one line *.ino file to register the assembly module as:
Using the Gavrasm assembler, we get 24 bytes.
Of course, all this is moot if the problem is the amount of Static RAM you need for data!
Just sticking my oar in again!
Cheers,
Norm.