/*
  ATtiny85 with 8x8 LED matrix (max7219)
  by Anderson Costa
  with ❤ for the Wokwi community
*/
#include <avr/io.h>
#include <util/delay.h>

#define CLK_HIGH()  PORTB |= (1 << PB2)
#define CLK_LOW()   PORTB &= ~(1 << PB2)
#define CS_HIGH()   PORTB |= (1 << PB1)
#define CS_LOW()    PORTB &= ~(1 << PB1)
#define DATA_HIGH() PORTB |= (1 << PB0)
#define DATA_LOW()  PORTB &= ~(1 << PB0)
#define INIT_PORT() DDRB |= (1 << PB0) | (1 << PB1) | (1 << PB2)

const uint8_t pacman1[8] = {
  0b00011100,
  0b00111110,
  0b01110111,
  0b01111111,
  0b00001111,
  0b01111111,
  0b00111110,
  0b00011100,
};

const uint8_t pacman2[8] = {
  0b00011100,
  0b00111110,
  0b00010111,
  0b00001111,
  0b00001111,
  0b00011111,
  0b00111110,
  0b00011100,
};

uint8_t display[8];

void spi_send(uint8_t data)
{
  uint8_t i;

  for (i = 0; i < 8; i++, data <<= 1) {
    CLK_LOW();
    if (data & 0x80) {
      DATA_HIGH();
    } else {
      DATA_LOW();
    }
    CLK_HIGH();
  }
}

void max7219_writec(uint8_t high_byte, uint8_t low_byte)
{
  CS_LOW();
  spi_send(high_byte);
  spi_send(low_byte);
  CS_HIGH();
}

void max7219_clear(void)
{
  uint8_t i;

  for (i = 0; i < 8; i++) {
    max7219_writec(i + 1, 0);
  }
}

void max7219_init(void)
{
  INIT_PORT();
  max7219_writec(0x09, 0);   // Set decode mode to none
  max7219_writec(0x0A, 1);   // Set the intensity to (0-15)
  max7219_writec(0x0B, 7);   // Set scan limit for all digits
  max7219_writec(0x0C, 1);   // Shutdown register for display
  max7219_writec(0x0F, 0);   // Display test off
  max7219_clear();
}

void set_pixels(uint8_t pixel[8])
{
  uint8_t i;

  for (i = 0; i < 8; i++) {
    display[i] = pixel[i];
  }
}

void update_display(void)
{
  uint8_t i;

  for (i = 0; i < 8; i++) {
    max7219_writec(i + 1, display[i]);
  }
}

int main(void)
{
  uint8_t i;

  max7219_init();

  while (1) {
    set_pixels(pacman1);
    update_display();
    _delay_ms(500);
    set_pixels(pacman2);
    update_display();
    _delay_ms(500);
  }

  return (0);
}
ATTINY8520PU