program condensing for use on ATTINY 24

So guys, i set myself one heck of a challenge (for me at least) and its something the lecturers at my uni in electronics have never seen before.

The premise of my challenge is simply to change the colour of a strip of RGB LEDs with one potentiometer, that part is fine, (and bench tested it using the hardware, an arduino and breadboard)

I have researched and tried to understand the code that i have found elsewhere on the interballs (to change the colour ect ect) but cant get my head around it.

If someone could please help me to understand and condense the code id be very grateful.
I wanted to condense it so made a pcb that takes power in, uses an attiny 24 as the computational brain, then outputs straight to the LED strip.

Ive managed to write to the board and have a blink program setup to run (and it works great) but when i tried to upload the file to the attiny it was reading that the code was too large.

The below is the code i would like to use but am not sure how to condense it further but keep the function of it the same, thanks in advance.



  • Code for making one potentiometer control 3 LEDs, red, grn and blu, or one tri-color LED
  • The program cross-fades from red to grn, grn to blu, and blu to red
  • Clay Shirky

// INPUT: Potentiometer should be connected to 5V and GND
int potPin = 3; // Potentiometer output connected to analog pin 3
int potVal = 0; // Variable to store the input from the potentiometer

// OUTPUT: Use digital pins 9-11, the Pulse-width Modulation (PWM) pins
// LED’s cathodes should be connected to digital GND
int redPin = 9; // Red LED, connected to digital pin 9
int grnPin = 10; // Green LED, connected to digital pin 10
int bluPin = 11; // Blue LED, connected to digital pin 11

// Program variables
int redVal = 0; // Variables to store the values to send to the pins
int grnVal = 0;
int bluVal = 0;

void setup()
pinMode(redPin, OUTPUT); // sets the pins as output
pinMode(grnPin, OUTPUT);
pinMode(bluPin, OUTPUT);

// Main program
void loop()
potVal = analogRead(potPin); // read the potentiometer value at the input pin

if (potVal < 341) // Lowest third of the potentiometer’s range (0-340)
potVal = (potVal * 3) / 4; // Normalize to 0-255

redVal = 256 - potVal; // Red from full to off
grnVal = potVal; // Green from off to full
bluVal = 1; // Blue off
else if (potVal < 682) // Middle third of potentiometer’s range (341-681)
potVal = ( (potVal-341) * 3) / 4; // Normalize to 0-255

redVal = 1; // Red off
grnVal = 256 - potVal; // Green from full to off
bluVal = potVal; // Blue from off to full
else // Upper third of potentiometer"s range (682-1023)
potVal = ( (potVal-683) * 3) / 4; // Normalize to 0-255

redVal = potVal; // Red from off to full
grnVal = 1; // Green off
bluVal = 256 - potVal; // Blue from full to off
analogWrite(redPin, redVal); // Write values to LED pins
analogWrite(grnPin, grnVal);
analogWrite(bluPin, bluVal);


Note this is not my code but the code i have found and would like to use / modify to work in my scenario

The premise of my challenge is simply to change the colour of a strip of RGB LEDs with one potentiometer, that part is fine, (and bench tested it using the hardware, an arduino and breadboard)

What’s the problem?
Inexperienced lecturers?

Please remember to use code tags when posting code.

Replace the pinMode() calls with a direct write to the DDRx register or registers.

potPin, the color pins and the color values can be declared byte instead of int.

You're doing analogWrite; the pinMode calls are superfluous.

You're doing analogWrite; the pinMode calls are superfluous.

Ugh, yup. And you can't get rid of the pinmode bloat as a result.

This is the main reason that using an attiny24 is so hard with arduino - there is a fixed overhead for things like analogRead, digitalWrite, pinMode, analogWrite, and this is a real killer when you only have 2k flash total.

Try replacing the /4 with >>2 - I have seen cases where the compiler isn't smart enough to do this, and pulls in the whole division algorithm (I ran into it with the implementation of millis/micros with speeds other than 16 and 8 MHz)

Is it really worth saving a few cents to use the 24 instead of the 44?

AWOL and DrAzzy thank you, the problem isn't inexperienced lecturers, its that this is extra curricular so they cant put as much time into helping me as they wished, and also have no experience at all in the writing to attiny using an arduino and would like me to show them how i did it once im all done, as i said im quite new to coding in this sense, i wouldn't know where to begin, you mention DDRx ... i have no idea what that is unfortunately and as for writing things multiple times, okay thank you do i remove the potpin section then or do i need to replace with something else shorter ? and ahh okay ill try replacing /4 with >>2 as you say DrAzzy and my reasoning behind using the 24 was just the first one i came across that had the correct number of input / output pins, so the 44 has larger flash memory then i presume ??

Take a breath.
Edit your last post, but use capitals, punctuation, and line breaks this time.

Hi steviej5598,

… you mention DDRx … i have no idea what that is …

This weird, capitalized and unpronounceable words, that you see in some programs are the names for registers associated with the pins. Your AT Tiny24 has 11 pins (well, 12 if you count reset.) You probably know them by their Arduino numbers: 0 through 10. But the ATTiny looks at them a bit differently. The pins are organized into groups of 8.

The first 8 pins (pins PA0, PA1, PA2, …, PA7) are called port A. There are only 3 (or 4, counting reset) pins left, so they don’t need a whole byte, so port b is a 4 bit number.

This is how the microcontroller deals with pins internally. The Arduino words, pinMode(), digitalWrite(), digital Read(), etc. run machine code that directly manipulates the values of the two ports. They also run some value checking and type correcting code, to keep runtime errors to a minimum. If you bypass those high level words, your program will be smaller, and run faster. The chip’s manufacturer Atmel (now MicroChip) has a document, the datasheet, that details how to directly manipulate the pin registers (along with everything else the chip does. The datasheet is over 200 pages long!)

The three registers associated with each pin are DDxn, PORTxn, and PINxn. The word you asked about, DDRxn is the Data Direction Registers. It sets the pinMode of a pin to input or output. If DDRxn is 0, then the pin is an input pin, If it’s 1 then it is an output. If a pin is in input mode, DDxn works in conjunction with the PORTxn registers. If PORTxn is 1, then the internal resistors are connected, and the input is pulled up. If PORTxn is 0, then it’s just a regular input pin, and you can pull it up or down externally.

When a pin is configured as an output, PORTxn determines the state of the pin. If PORTxn is 1 the pin will be HIGH, and if it’s 0, then the pin will be low.

PINxn reads the state of the pin if it’s configured as an input. PINxn toggles the state of a pin (HIGH becomes LOW, and vice versa) if the pin is an output.

In the above, the names use the letters “xn” as place keepers. They do not actually appear in the register names. DDRA refers to the data direction register for port a. The letter ‘n’ is the bit number (representing each pin.) You specify the pin by using “bit arithmetic” on the contents of the port.

Below is a short example that shows how to use these names. It consists of a 7 segment display chip wired directly to pins 0 through 7 of an AT Tiny x4, and button is connected to pin 8. Pins 9 and 10 are not used, or are connected to a crystal.

Not too exciting, but it demonstrates the programming, Every time you press the button, the next hex number is shown. It just goes 0, 1, 2, … d, E, F, 0, 1, 2, …

/* lowLevelATTinyx4.ino - press a button and count in HEX.
   102018a2 clh 601/31

   left: ATTiny 84 (
     (parenthetical page numbers reference the above data sheet)
   right: NTE3052 (
     common cathode 'seven segment' numeric display
                ___   ___                          ____    ____
           Vcc =|  \_/  |= GND        7 segment: A|    \__/    |Vcc
    XTAL1  PB0 =|10    0|= PA0                   F|    _a__    |B
    XTAL2_ PB1 =|9     1|= PA1                 Vcc|  f|    |b  |no pin
         RESET =|      2|= PA2              no pin|   |_g__|   |G
    INT0   PB2 =|8     3|= PA3              no pin|  e|    |c  |C
           PA7 =|7     4|= PA4 SCK              nc|p2 |_d__| p1|DP
      MOSI PA6 =|6_____5|= PA5 MISO              E|____________|D

     pins 0 through 6 connected to LED A through LED G via 220Ω resistor
     pin 7 connected to DP via 4K7Ω resistor
     tactile push button switch (pull_up) from pin 8 to GND
     0.1µF tantalum capacitor from pin 8 to GND at the push button
     0.1µF ceramic capicitor from Vcc to GND across the µController
     3x 1.5 aa battery on Vcc(switched) and GND

#include <avr/io.h>

unsigned int counts;

// timing stuff
const long goToSleepMillis = 256L;
unsigned long lastSleepMillis;

//  7 segment common cathode LED display, eg NTE3052 (see diagram above)
const byte numerals[] = {
  //pgfedcba       n
  0b11000000, //   0    --- a ---
  0b11111001, //   1   |         |    a = pin PA0
  0b10100100, //   2   f         b    b = pin PA1
  0b10110000, //   3   |         |    c = pin PA2
  0b10011001, //   4   |--- g ---|    d = pin PA3
  0b10010010, //   5   |         |    e = pin PA4
  0b10000010, //   6   e         c    f = pin PA5
  0b11111000, //   7   |         |    g = pin PA6
  0b10000000, //   8    --- d ---  p  p = pin PA7
  0b10011000, //   9
  0b10001000, //   A
  0b10000011, //   b
  0b11000110, //   C
  0b10100001, //   d
  0b10000110, //   E
  0b10001110, //   F

void setup() {
  DDRA = 0b11111111;  // pins 0 - 7 are OUTPUT  (p56)
  PORTA = -1;  // turn display off (p55, 67)

  // it's easier to do INPUT_PULLUP the old way
  pinMode(8, INPUT_PULLUP);

void loop() {
  if (!(PINB & 0b0100)) lastSleepMillis = millis();  //  start timer (p56-58)

  if (millis() - lastSleepMillis >= goToSleepMillis) {
    lastSleepMillis += goToSleepMillis;

    PORTA = -1;  // turn display off
    while (PINB & 0b0100) { } // wake to check button
    PORTA = numerals[counts++ & 0b1111]; // display low 4 bits of counts

Thank you ChrisTenone for the explanation. i shall trry and read into it a bit more as of how it works and see where i end up, thank you.