7

I'm trying to squeeze code onto an ATtiny10, but I'm just not getting there. I'm using 1060 bytes and only have space for 1024 bytes.

The code is simple enough; I need to read a button pin. If high it needs to pick a random value and that causes one of two random LEDs on the PCB to turn on for two seconds. Is there a way to optimize this code to work on this IC?

int buttonState = 0;

void setup() { pinMode(3, INPUT); }

void loop() { buttonState = digitalRead(3); if (buttonState == HIGH) { bool ranNum=random(0,1); if(ranNum == 0) { digitalWrite(0, HIGH); } else { digitalWrite(1, HIGH); } delay(2000); digitalWrite(1, LOW); digitalWrite(2, LOW); } }

Peter Mortensen
  • 435
  • 3
  • 12

4 Answers4

12

As I stated in a comment, this device would be too small for me to consider programming it using an Arduino core. I would rather stick with the avr-libc and direct port manipulation:

#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>

int main(void) { DDRB = _BV(PB0) // PB0 as output | _BV(PB1); // PB1 as output for (;;) { loop_until_bit_is_set(PINB, PB3); // wait for PB3 high if (rand() & 1) PORTB |= _BV(PB1); // PB1 high else PORTB |= _BV(PB0); // PB0 high _delay_ms(2000); PORTB &= ~_BV(PB0); // PB0 low PORTB &= ~_BV(PB1); // PB1 low } }

This is plain C, but I expect it to be accepted by the Arduino IDE as a valid .ino file. I tried compiling it like this:

avr-gcc -mmcu=attiny10 -Os -Wall -Wextra -DF_CPU=8000000 prog.c -o prog.elf

And it resulted in a program that uses 660 bytes of flash. Most of that is in the implementation of rand() and its dependencies (multiplication and division routines).

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81
7

If the button is pressed by a human and your clock is high enough (MHz range), you can use a trick and get rid of the RNG.

You can replace it with a free running counter like this:

unsigned char count = 0;

void loop() {

count += 1;

buttonState = digitalRead(3);

if (buttonState == HIGH) {
    if( (count &amp; 1) == 0) {
        digitalWrite(0, HIGH);
    }
    else {
        digitalWrite(1, HIGH);
    }
    delay(2000);
    digitalWrite(1, LOW);
    digitalWrite(2, LOW);
}

}

You have count incremented every ⪝10 us (depending on your clock speed, attiny executes one instruction per cycle), so when the user pushes the button, the counter will be sampled.

Note: I assumed loop() is all what the microcontroller has to do, and it's constantly called.

Redy000
  • 171
  • 2
3

Are you sure the pins are correct?

Maybe use a smaller random number generator per https://arduino.stackexchange.com/a/18092/6628 ?

static uint8_t lfsr = 0x01;
const byte LFSR_MASK = 0x8e;

void setup() { pinMode(0, OUTPUT); pinMode(1, OUTPUT); pinMode(3, INPUT); } void loop() { // int buttonState = digitalRead(3); if (digitalRead(3)) { if (generateNoise()) { digitalWrite(0, HIGH); } else { digitalWrite(1, HIGH); } //delay(2000) //for (int i = 31; i; i--)_delay_us(64516); _delay_ms(2000); digitalWrite(0, LOW); digitalWrite(1, LOW); } }

uint8_t generateNoise() { // Return 1 bit of noise using a Galois Linear Feedback Shift Register // See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs

if (lfsr & 1) { lfsr = (lfsr >> 1) ^ LFSR_MASK ; return (1); } else { lfsr >>= 1; return (0); } }

The RNG didn't help as much as changing the much-disparaged delay.

Dave X
  • 2,350
  • 15
  • 29
1

An 8-bit chip requires multiple instructions for processing 16 bit. Changing ints to either uint8_t or int8_t will save code.

Depending on compiler optimization, replacing

if ( (count & 1) == 0) {
    digitalWrite(0, HIGH);
}
else {
    digitalWrite(1, HIGH);
}

with

digitalWrite((count & 1), HIGH);

could save bytes.

CWallach
  • 111
  • 1