/* Cube project throug mcp23017 */ #include static const byte MCP_ADDR = 0x20; // I2C Address of MCP23017 Chip static const byte GPIO_A = 0x12; // Register Address of Port A static const byte GPIO_B = 0x13; // Register Address of Port B /* global state of gpio ports */ static byte gpio_a; static byte gpio_b; /* Working with a 3x3 Cube */ static const unsigned CUBE_SIDE = 3; /* each pin belongs in a bank and has a mask */ struct pin { const byte gpio; const byte mask; }; /* 3 Levels of 3x3=9 leds each */ static const struct pin LVL_0 = { GPIO_B, 0b00000001 }; static const struct pin LVL_1 = { GPIO_B, 0b00000100 }; static const struct pin LVL_2 = { GPIO_B, 0b00000010 }; static const struct pin levels[CUBE_SIDE] = { LVL_0, LVL_1, LVL_2 }; /* 3x3=9 columns in a grid - COL_ */ static const struct pin COL_00 = { GPIO_B, 0b00100000 }; static const struct pin COL_01 = { GPIO_B, 0b00001000 }; static const struct pin COL_02 = { GPIO_B, 0b00010000 }; static const struct pin COL_10 = { GPIO_A, 0b00000100 }; static const struct pin COL_11 = { GPIO_A, 0b00010000 }; static const struct pin COL_12 = { GPIO_A, 0b00001000 }; static const struct pin COL_20 = { GPIO_A, 0b00100000 }; static const struct pin COL_21 = { GPIO_A, 0b01000000 }; static const struct pin COL_22 = { GPIO_A, 0b10000000 }; static const pin columns[CUBE_SIDE][CUBE_SIDE] = { { COL_00, COL_01, COL_02 }, { COL_10, COL_11, COL_12 }, { COL_20, COL_21, COL_22 }, }; /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ /* DEBUG HELPERS */ /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ static void check_mcp(void) { byte error, address; int nDevices; Serial.println("Scanning for I2C..."); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); nDevices++; } else if (error == 4) { Serial.print("Unknow error at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); } static void print_gpio_state(const byte gpio) { Serial.print("gpio state: "); Serial.println(gpio, BIN); } /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ /* INIT STATE */ /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ void setup(void) { Wire.begin(); Serial.begin(9600); Wire.beginTransmission(MCP_ADDR); Wire.write(0b00000000); Wire.write(0b00000000); // set all of GPIO A to outputs Wire.write(0b00000000); // set all of GPIO B to outputs Wire.endTransmission(); /* clear all GPIO A pins */ Wire.beginTransmission(MCP_ADDR); Wire.write(GPIO_A); Wire.write(0b00000000); Wire.endTransmission(); /* clear all GPIO B pins */ Wire.beginTransmission(MCP_ADDR); Wire.write(GPIO_B); Wire.write(0b00000000); Wire.endTransmission(); /* initialize randomizer */ randomSeed(analogRead(0)); } /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ /* MAIN EXECUTION */ /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ static inline const byte bit_clear(byte * const gpio, const struct pin pin) { return (*gpio &= ~pin.mask); } static inline const byte bit_set (byte * const gpio, const struct pin pin) { return (*gpio |= pin.mask); } static const byte (* const operation[2])(byte * const gpio, const struct pin pin) = { bit_clear, bit_set }; static void set_pin(const struct pin pin, const bool state) { Wire.beginTransmission(MCP_ADDR); Wire.write(pin.gpio); switch (pin.gpio) { case GPIO_A: Wire.write((operation[state](&gpio_a, pin))); break; case GPIO_B: Wire.write((operation[state](&gpio_b, pin))); break; } Wire.endTransmission(); } /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ static void set_led(const unsigned z, const unsigned y, const unsigned x, const bool state) { set_pin(levels[z], state); set_pin(columns[y][x], state); } static void set_all_lvls(const bool state) { for (unsigned lvl=0; lvl=0; --lvl) { set_pin(levels[lvl], HIGH); set_pin(columns[y1][x1], HIGH); set_pin(columns[y2][x2], HIGH); delay(d); set_pin(levels[lvl], LOW); set_pin(columns[y1][x1], LOW); set_pin(columns[y2][x2], LOW); } } } /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ static void set_slice(const unsigned slice, const char axis, const uint8_t state) { switch (axis) { case 'x': set_all_lvls(state); for (unsigned x=0; xrepeat; ++i) e->effect(e->interval); }