#include "bhorealMini.h" // DEFINITION PINS FOR MINI #define PIN_LED 8 // ?????? int NUM_LEDS = 16; const uint16_t numBytes = 48; byte row[4] = { // ROW pins for matrix pushbottons 13, 5, 10, 9}; byte column[4] = { // COL pins for matrix pushbottons 8, 6, 12, 4}; BhorealMini Bhoreal_; uint8_t pixels[numBytes]; // boolean pressed[4][4] = { // pushbottons states matrix // {1,1,1,1}, // {1,1,1,1}, // {1,1,1,1}, // {1,1,1,1} // }; boolean pressed[8][8] = { // pushbottons states matrix {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1} }; const byte remap[4][4] = // mapping matrix for Mini { { 3, 4, 11, 12 }, { 2, 5, 10, 13 }, { 1, 6, 9, 14 }, { 0, 7, 8, 15 } }; ////////////////////////////////////////////////////////////////////// ////////////////////// BHOREAL BEGIN ////////////////////// ////////////////////////////////////////////////////////////////////// void BhorealMini::begin() { port = portOutputRegister(digitalPinToPort(PIN_LED)); pinMask = digitalPinToBitMask(PIN_LED); } //////////////////////////////////////////////////////////////// ////////////////////// STARTUP ////////////////////// //////////////////////////////////////////////////////////////// // Run this animation once at startup. Currently unfinished. void BhorealMini::startup(){ for(int x = 0; x < NUM_LEDS; ++x){ uint32_t c = hue2rgb((x+1)*8); // 128 HUE steps / 16 leds, 8 steps x led if (x == (NUM_LEDS-1)) c = hue2rgb(1); // 128 HUE steps / 64 leds, 2 steps x led uint8_t r = (uint8_t)(c >> 16), g = (uint8_t)(c >> 8), b = (uint8_t)c; setPixelColor(remap[x>>2][x%4], r, g, b); } show(); } ////////////////////////////////////////////////////////////////////// ////////////////////// MIDI PRESS & RELEASE ////////////////////// ////////////////////////////////////////////////////////////////////// void BhorealMini::on_press(byte r, byte c){ } void BhorealMini::on_release(byte r, byte c){ } /////////////////////////////////////////////////////////////// ////////////////////// CHECK BUTTONS ////////////////////// /////////////////////////////////////////////////////////////// byte count_column = 0; byte count_file = 0; unsigned long time_button = 0; void BhorealMini::checkButtons(){ } //////////////////////////////////////////////////////////////// ////////////////////// REFRESH LED ////////////////////// //////////////////////////////////////////////////////////////// byte refresh_led = 0; unsigned long time_led = 0; void BhorealMini::displayRefresh(){ if (((refresh_led>0)&&((micros()-time_led)>1000))||(refresh_led>=NUM_LEDS)||((refresh_led25000))&&(refresh_led>0)) { refresh_led=0; show(); } } //////////////////////////////////////////////////////////////// ////////////////////// REFRESH MIDI & LED ///////////////////// //////////////////////////////////////////////////////////////// void BhorealMini::midiRefresh(){ } //////////////////////////////////////////////////////////////// ////////////////////// CHECK ADC INPUTS ////////////////////// //////////////////////////////////////////////////////////////// void BhorealMini::checkADC(){ } /////////////////////////////////////////////////////////////// ////////////////////// HUE -> RGB ////////////////////// /////////////////////////////////////////////////////////////// uint8_t rh; uint8_t gh; uint8_t bh; uint32_t BhorealMini::hue2rgb(uint16_t hueValue) { if (hueValue==0) { rh = 0; gh = 0; bh = 0; } else if (hueValue>=127) { rh = 255; gh = 255; bh = 255; } else { hueValue<<= 3; // 128 midi steps -> 1024 hue steps if (hueValue < 341) { // Lowest third of the potentiometer's range (0-340) hueValue = (hueValue * 3) / 4; // Normalize to 0-255 rh = 255 - hueValue; // Red from full to off gh = hueValue; // Green from off to full bh = 1; // Blue off } else if (hueValue < 682) { // Middle third of potentiometer's range (341-681) hueValue = ( (hueValue-341) * 3) / 4; // Normalize to 0-255 rh = 1; // Red off gh = 255 - hueValue; // Green from full to off bh = hueValue; // Blue from off to full } else { // Upper third of potentiometer"s range (682-1023) hueValue = ( (hueValue-683) * 3) / 4; // Normalize to 0-255 rh = hueValue; // Red from off to full gh = 1; // Green off bh = 255 - hueValue; // Blue from full to off } } return ((uint32_t)rh << 16) | ((uint32_t)gh << 8) | bh; } /////////////////////////////////////////////////////////////// ////////////////////// Control led ////////////////////// /////////////////////////////////////////////////////////////// void BhorealMini::show(void) { if(!pixels) return; // Data latch = 50+ microsecond pause in the output stream. Rather than // put a delay at the end of the function, the ending time is noted and // the function will simply hold off (if needed) on issuing the // subsequent round of data until the latch time has elapsed. This // allows the mainline code to start generating the next frame of data // rather than stalling for the latch. while((micros() - endTime) < 50L); // endTime is a private member (rather than global var) so that mutliple // instances on different pins can be quickly issued in succession (each // instance doesn't delay the next). // In order to make this code runtime-configurable to work with any pin, // SBI/CBI instructions are eschewed in favor of full PORT writes via the // OUT or ST instructions. It relies on two facts: that peripheral // functions (such as PWM) take precedence on output pins, so our PORT- // wide writes won't interfere, and that interrupts are globally disabled // while data is being issued to the LEDs, so no other code will be // accessing the PORT. The code takes an initial 'snapshot' of the PORT // state, computes 'pin high' and 'pin low' values, and writes these back // to the PORT register as needed. noInterrupts(); // Need 100% focus on instruction timing volatile uint16_t i = numBytes; // Loop counter volatile uint8_t *ptr = pixels; // Pointer to next byte volatile uint8_t b = *ptr++; // Current byte value volatile uint8_t hi; // PORT w/output bit set high volatile uint8_t lo; // PORT w/output bit set low // WS2811 and WS2812 have different hi/lo duty cycles; this is // similar but NOT an exact copy of the prior 400-on-8 code. // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL // ST instructions: ^ ^ ^ (T=0,5,13) volatile uint8_t next, bit; hi = *port | pinMask; lo = *port & ~pinMask; next = lo; bit = 8; asm volatile( "head20:" "\n\t" // Clk Pseudocode (T = 0) "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) "dec %[bit]" "\n\t" // 1 bit-- (T = 5) "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) "rjmp .+0" "\n\t" // 2 nop nop (T = 12) "nop" "\n\t" // 1 nop (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "rjmp .+0" "\n\t" // 2 nop nop (T = 18) "rjmp head20" "\n\t" // 2 -> head20 (next bit out) "nextbyte20:" "\n\t" // (T = 10) "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) : [port] "+e" (port), [byte] "+r" (b), [bit] "+r" (bit), [next] "+r" (next), [count] "+w" (i) : [ptr] "e" (ptr), [hi] "r" (hi), [lo] "r" (lo)); interrupts(); endTime = micros(); // Save EOD time for latch on next call } // Set pixel color from separate R,G,B components: void BhorealMini::setPixelColor( uint16_t n, uint8_t r, uint8_t g, uint8_t b) { if(n < NUM_LEDS) { uint8_t *p = &pixels[n * 3]; *p++ = g; *p++ = r; *p = b; } }