Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Adafruit IS31FL3741 library #3

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 35 additions & 204 deletions MrRobotStarterPack/RobotGFX.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@

#include <gfxfont.h>
#include <Adafruit_GFX.h>
#include <Adafruit_IS31FL3741.h>
#include <Fonts/FreeSerif9pt7b.h>
#include "brzo_i2c.h"


#define ARRAY_WIDTH 18 // LED Array Width
#define ARRAY_HEIGHT 18 // LED Array Height
#define BULK_CMD_SZ 4 // Size of a single LED command
// The ISSI chip has two pages of differing size.
#define PAGE_0_SZ 180
#define PAGE_1_SZ 171
// The I2C address of the ISSI chip interface.
#define ADDR_GND 0x60
#define ADDR_GND 0x30
// Clock pins
#define SDA_PIN 4
#define SCL_PIN 5

TwoWire *i2c = &Wire;

/*
* A simple pixel sprite kept in a flat array.
Expand Down Expand Up @@ -87,16 +83,29 @@ struct Animation
/*
* Mr. Robot Badge uses a non-standard layout relative to the ISSI
* chip. This lookup struct maps the (x,y) position of a given LED
* to its device address.
* to its device address.
*/
struct Lookup
{
uint8_t x; // x pixel, if the address is unused then set to -1
uint8_t y; // y pixel, if the address is unused set to -1
uint8_t addr;// the addr !!! THIS IS ONLY FOR REFERENCE / DEBUG
Lookup(uint8_t x, uint8_t y, uint8_t addr) : x(x), y(y), addr(addr){}
};

const uint16_t Lookup[ARRAY_HEIGHT][ARRAY_WIDTH] = {
{ 17, 47, 77, 107, 137, 167, 197, 227, 257, 18, 48, 78, 108, 138, 168, 198, 228, 258},
{ 16, 46, 76, 106, 136, 166, 196, 226, 256, 19, 49, 79, 109, 139, 169, 199, 229, 259},
{ 15, 45, 75, 105, 135, 165, 195, 225, 255, 20, 50, 80, 110, 140, 170, 200, 230, 260},
{ 14, 44, 74, 104, 134, 164, 194, 224, 254, 21, 51, 81, 111, 141, 171, 201, 231, 261},
{ 13, 43, 73, 103, 133, 163, 193, 223, 253, 22, 52, 82, 112, 142, 172, 202, 232, 262},
{ 12, 42, 72, 102, 132, 162, 192, 222, 252, 23, 53, 83, 113, 143, 173, 203, 233, 263},
{ 11, 41, 71, 101, 131, 161, 191, 221, 251, 24, 54, 84, 114, 144, 174, 204, 234, 264},
{ 10, 40, 70, 100, 130, 160, 190, 220, 250, 25, 55, 85, 115, 145, 175, 205, 235, 265},
{ 9, 39, 69, 99, 129, 159, 189, 219, 249, 26, 56, 86, 116, 146, 176, 206, 236, 266},
{ 8, 38, 68, 98, 128, 158, 188, 218, 248, 27, 57, 87, 117, 147, 177, 207, 237, 267},
{ 7, 37, 67, 97, 127, 157, 187, 217, 247, 28, 58, 88, 118, 148, 178, 208, 238, 268},
{ 6, 36, 66, 96, 126, 156, 186, 216, 246, 29, 59, 89, 119, 149, 179, 209, 239, 269},
{ 5, 35, 65, 95, 125, 155, 185, 215, 245, 270, 279, 288, 297, 306, 315, 324, 333, 342},
{ 4, 34, 64, 94, 124, 154, 184, 214, 244, 271, 280, 289, 298, 307, 316, 325, 334, 343},
{ 3, 33, 63, 93, 123, 153, 183, 213, 243, 272, 281, 290, 299, 308, 317, 326, 335, 344},
{ 2, 32, 62, 92, 122, 152, 182, 212, 242, 273, 282, 291, 300, 309, 318, 327, 336, 345},
{ 1, 31, 61, 91, 121, 151, 181, 211, 241, 274, 283, 292, 301, 310, 319, 328, 337, 346},
{ 0, 30, 60, 90, 120, 150, 180, 210, 240, 275, 284, 293, 302, 311, 320, 329, 338, 347}
};

/*
* If we ran all of the LEDs at full brightness your retinas would burn out
Expand All @@ -120,99 +129,8 @@ struct Lookup
* The adafruit text rendering is meant for larger screens so the scrolls are
* a great way to print bulk text to the screen.
*/
class AGFXShim : public Adafruit_GFX
class AGFXShim : public Adafruit_GFX, public Adafruit_IS31FL3741_buffered
{
public:
// This is where we keep the next set of data to render.
uint16_t frame_buffer[18][18];
uint16_t fame_buffer_sz = 324;

// Fill this out *SEQUENTIALLY* from Page0 address 00 to A7.
// If an LED's slot is unused set x and y to zero
// The addr field is not used, but kept for reference.

/*
* The following look up tables are used to map LED X,Y positions to their respective page and
* and address on the ISSI chips. The mapping is a bit strange due to the routing. The idea here
* is that for any given address we can quickly look up its value in the frame buffer and squirt
* that over to ISSI LED driver.
*/
int16_t lut0_sz = PAGE_0_SZ;
Lookup const page0LUT[PAGE_0_SZ] = { Lookup(0,17,0x00),
Lookup(0,16,0x01), Lookup(0,15,0x02), Lookup(0,14,0x03), Lookup(0,13,0x04), Lookup(0,12,0x05),
Lookup(0,11,0x06), Lookup(0,10,0x07), Lookup(0,9,0x08), Lookup(0,8,0x09), Lookup(0,7,0x0A),
Lookup(0,6,0x0B), Lookup(0,5,0x0C ), Lookup(0,4,0x0D), Lookup(0,3,0x0E), Lookup(0,2,0x0F),
Lookup(0,1,0x10), Lookup(0,0,0x11), Lookup(9,0,0x12), Lookup(9,1,0x13), Lookup(9,2,0x14),
Lookup(9,3,0x15), Lookup(9,4,0x16), Lookup(9,5,0x17), Lookup(9,6,0x18), Lookup(9,7,0x19),
Lookup(9,8,0x1A), Lookup(9,9,0x1B), Lookup(9,10,0x1C), Lookup(9,11,0x1D), Lookup(1,17,0x1E),
Lookup(1,16,0x1F), Lookup(1,15,0x20), Lookup(1,14,0x21), Lookup(1,13,0x22), Lookup(1,12,0x23),
Lookup(1,11,0x24), Lookup(1,10,0x25), Lookup(1,9,0x26), Lookup(1,8,0x27), Lookup(1,7,0x28),
Lookup(1,6,0x29), Lookup(1,5,0x2A), Lookup(1,4,0x2B), Lookup(1,3,0x2C), Lookup(1,2,0x2D),
Lookup(1,1,0x2E), Lookup(1,0,0x2F), Lookup(10,0,0x30), Lookup(10,1,0x31), Lookup(10,2,0x32),
Lookup(10,3,0x33), Lookup(10,4,0x34), Lookup(10,5,0x35), Lookup(10,6,0x36), Lookup(10,7,0x37),
Lookup(10,8,0x38), Lookup(10,9,0x39), Lookup(10,10,0x3A), Lookup(10,11,0x3B), Lookup(2,17,0x3C),
Lookup(2,16,0x3D), Lookup(2,15,0x3E), Lookup(2,14,0x3F), Lookup(2,13,0x40), Lookup(2,12,0x41),
Lookup(2,11,0x42), Lookup(2,10,0x43), Lookup(2,9,0x44), Lookup(2,8,0x45), Lookup(2,7,0x46),
Lookup(2,6,0x47), Lookup(2,5,0x48), Lookup(2,4,0x49), Lookup(2,3,0x4A), Lookup(2,2,0x4B),
Lookup(2,1,0x4C), Lookup(2,0,0x4D), Lookup(11,0,0x4E), Lookup(11,1,0x4F), Lookup(11,2,0x50),
Lookup(11,3,0x51), Lookup(11,4,0x52), Lookup(11,5,0x53), Lookup(11,6,0x54), Lookup(11,7,0x55),
Lookup(11,8,0x56), Lookup(11,9,0x57), Lookup(11,10,0x58), Lookup(11,11,0x59), Lookup(3,17,0x5A),
Lookup(3,16,0x5B), Lookup(3,15,0x5C), Lookup(3,14,0x5D), Lookup(3,13,0x5E), Lookup(3,12,0x5F),
Lookup(3,11,0x60), Lookup(3,10,0x61), Lookup(3,9,0x62), Lookup(3,8,0x63), Lookup(3,7,0x64),
Lookup(3,6,0x65), Lookup(3,5,0x66), Lookup(3,4,0x67), Lookup(3,3,0x68), Lookup(3,2,0x69),
Lookup(3,1,0x6A), Lookup(3,0,0x6B), Lookup(12,0,0x6C), Lookup(12,1,0x6D), Lookup(12,2,0x6E),
Lookup(12,3,0x6F), Lookup(12,4,0x70), Lookup(12,5,0x71), Lookup(12,6,0x72), Lookup(12,7,0x73),
Lookup(12,8,0x74), Lookup(12,9,0x75), Lookup(12,10,0x76), Lookup(12,11,0x77), Lookup(4,17,0x78),
Lookup(4,16,0x79), Lookup(4,15,0x7A), Lookup(4,14,0x7B ), Lookup(4,13,0x7C), Lookup(4,12,0x7D),
Lookup(4,11,0x7E ), Lookup(4,10,0x7F), Lookup(4,9,0x80), Lookup(4,8,0x81), Lookup(4,7,0x82),
Lookup(4,6,0x83), Lookup(4,5,0x84), Lookup(4,4,0x85), Lookup(4,3,0x86), Lookup(4,2,0x87),
Lookup(4,1,0x88), Lookup(4,0,0x89), Lookup(13,0,0x8A), Lookup(13,1,0x8B), Lookup(13,2,0x8C),
Lookup(13,3,0x8D), Lookup(13,4,0x8E), Lookup(13,5,0x8F), Lookup(13,6,0x90), Lookup(13,7,0x91),
Lookup(13,8,0x92), Lookup(13,9,0x93), Lookup(13,10,0x94), Lookup(13,11,0x95), Lookup(5,17,0x96),
Lookup(5,16,0x97), Lookup(5,15,0x98), Lookup(5,14,0x99), Lookup(5,13,0x9A), Lookup(5,12,0x9B),
Lookup(5,11,0x9C), Lookup(5,10,0x9D), Lookup(5,9,0x9E), Lookup(5,8,0x9F), Lookup(5,7,0xA0),
Lookup(5,6,0xA1), Lookup(5,5,0xA2), Lookup(5,4,0xA3), Lookup(5,3,0xA4), Lookup(5,2,0xA5),
Lookup(5,1,0xA6), Lookup(5,0,0xA7), Lookup(14,0,0xA8), Lookup(14,1,0xA9), Lookup(14,2,0xAA),
Lookup(14,3,0xAB), Lookup(14,4,0xAC), Lookup(14,5,0xAD), Lookup(14,6,0xAE), Lookup(14,7,0xAF),
Lookup(14,8,0xB0), Lookup(14,9,0xB1), Lookup(14,10,0xB2), Lookup(14,11,0xB3)};

int16_t lut1_sz = PAGE_1_SZ;
Lookup const page1LUT[PAGE_1_SZ] = { Lookup(6,17,0x00),
Lookup(6,16,0x01), Lookup(6,15,0x02), Lookup(6,14,0x03), Lookup(6,13,0x04), Lookup(6,12,0x05),
Lookup(6,11,0x06), Lookup(6,10,0x07), Lookup(6,9,0x08), Lookup(6,8,0x09), Lookup(6,7,0x0A),
Lookup(6,6,0x0B), Lookup(6,5,0x0C), Lookup(6,4,0x0D), Lookup(6,3,0x0E), Lookup(6,2,0x0F),
Lookup(6,1,0x10), Lookup(6,0,0x11), Lookup(15,0,0x12), Lookup(15,1,0x13), Lookup(15,2,0x14),
Lookup(15,3,0x15), Lookup(15,4,0x16), Lookup(15,5,0x17), Lookup(15,6,0x18), Lookup(15,7,0x19),
Lookup(15,8,0x1A), Lookup(15,9,0x1B), Lookup(15,10,0x1C), Lookup(15,11,0x1D), Lookup(7,17,0x1E),
Lookup(7,16,0x1F), Lookup(7,15,0x20), Lookup(7,14,0x21), Lookup(7,13,0x22), Lookup(7,12,0x23),
Lookup(7,11,0x24), Lookup(7,10,0x25), Lookup(7,9,0x26), Lookup(7,8,0x27), Lookup(7,7,0x28),
Lookup(7,6,0x29), Lookup(7,5,0x2A), Lookup(7,4,0x2B), Lookup(7,3,0x2C), Lookup(7,2,0x2D),
Lookup(7,1,0x2E), Lookup(7,0,0x2F), Lookup(16,0,0x30), Lookup(16,1,0x31), Lookup(16,2,0x32),
Lookup(16,3,0x33), Lookup(16,4,0x34), Lookup(16,5,0x35), Lookup(16,6,0x36), Lookup(16,7,0x37),
Lookup(16,8,0x38), Lookup(16,9,0x39), Lookup(16,10,0x3A), Lookup(16,11,0x3B), Lookup(8,17,0x3C),
Lookup(8,16,0x3D), Lookup(8,15,0x3E), Lookup(8,14,0x3F), Lookup(8,13,0x40), Lookup(8,12,0x41),
Lookup(8,11,0x42), Lookup(8,10,0x43), Lookup(8,9,0x44), Lookup(8,8,0x45), Lookup(8,7,0x46),
Lookup(8,6,0x47), Lookup(8,5,0x48), Lookup(8,4,0x49), Lookup(8,3,0x4A), Lookup(8,2,0x4B),
Lookup(8,1,0x4C), Lookup(8,0,0x4D), Lookup(17,0,0x4E), Lookup(17,1,0x4F), Lookup(17,2,0x50),
Lookup(17,3,0x51), Lookup(17,4,0x52), Lookup(17,5,0x53), Lookup(17,6,0x54), Lookup(17,7,0x55),
Lookup(17,8,0x56), Lookup(17,9,0x57), Lookup(17,10,0x58), Lookup(17,11,0x59), Lookup(9,12,0x5A),
Lookup(9,13,0x5B), Lookup(9,14,0x5C), Lookup(9,15,0x5D), Lookup(9,16,0x5E), Lookup(9,17,0x5F),
Lookup(-1,-1,0x60), Lookup(-1,-1,0x61), Lookup(-1,-1,0x62), Lookup(10,12,0x63), Lookup(10,13,0x64),
Lookup(10,14,0x65), Lookup(10,15,0x66), Lookup(10,16,0x67), Lookup(10,17,0x68), Lookup(-1,-1,0x69),
Lookup(-1,-1,0x6A), Lookup(-1,-1,0x6B), Lookup(11,12,0x6C), Lookup(11,13,0x6D), Lookup(11,14,0x6E),
Lookup(11,15,0x6F), Lookup(11,16,0x70), Lookup(11,17,0x71), Lookup(-1,-1,0x72), Lookup(-1,-1,0x73),
Lookup(-1,-1,0x74), Lookup(12,12,0x75), Lookup(12,13,0x76), Lookup(12,14,0x77), Lookup(12,15,0x78),
Lookup(12,16,0x79), Lookup(12,17,0x7A), Lookup(-1,-1,0x7B), Lookup(-1,-1,0x7C), Lookup(-1,-1,0x7D),
Lookup(13,12,0x7E), Lookup(13,13,0x7F), Lookup(13,14,0x80), Lookup(13,15,0x81), Lookup(13,16,0x82),
Lookup(13,17,0x83), Lookup(-1,-1,0x84), Lookup(-1,-1,0x85), Lookup(-1,-1,0x86), Lookup(14,12,0x87),
Lookup(14,13,0x88), Lookup(14,14,0x89), Lookup(14,15,0x8A), Lookup(14,16,0x8B), Lookup(14,17,0x8C),
Lookup(-1,-1,0x8D), Lookup(-1,-1,0x8E), Lookup(-1,-1,0x8F), Lookup(15,12,0x90), Lookup(15,13,0x91),
Lookup(15,14,0x92), Lookup(15,15,0x93), Lookup(15,16,0x94), Lookup(15,17,0x95), Lookup(-1,-1,0x96),
Lookup(-1,-1,0x97), Lookup(-1,-1,0x98), Lookup(16,12,0x99), Lookup(16,13,0x9A), Lookup(16,14,0x9B),
Lookup(16,15,0x9C), Lookup(16,16,0x9D), Lookup(16,17,0x9E), Lookup(-1,-1,0x9F), Lookup(-1,-1,0xA0),
Lookup(-1,-1,0xA1), Lookup(17,12,0xA2), Lookup(17,13,0xA3), Lookup(17,14,0xA4), Lookup(17,15,0xA5),
Lookup(17,16,0xA6), Lookup(17,17,0xA7), Lookup(-1,-1,0xA8), Lookup(-1,-1,0xA9), Lookup(-1,-1,0xAA)};

public:
uint8_t sda_pin = 4;
uint8_t scl_pin = 5;
Expand All @@ -225,66 +143,24 @@ class AGFXShim : public Adafruit_GFX
};
///////////////////////////////////////////////////////////////////
void init(void){
uint8_t data = 255;
uint8_t i = 0;
// Use I2C to setup ISSI chip
brzo_i2c_setup(sda_pin, scl_pin, 2000);
writeByte(ADDR_GND,0xfe,0xc5);//unlock
writeByte(ADDR_GND,0xfD,0x02);//write page 2
for(i=0;i<0xB4;i++){
writeByte(ADDR_GND,i,data);//R LED Scaling
}

writeByte(ADDR_GND,0xfe,0xc5);//unlock
writeByte(ADDR_GND,0xfD,0x03);//write page 3
for(i=0;i<0xAB;i++){
writeByte(ADDR_GND,i,data);//R LED Scaling
}

writeByte(ADDR_GND,0xfe,0xc5);//unlock
writeByte(ADDR_GND,0xfD,0x00);//write page 0
for(i=0;i<0xB4;i++){
writeByte(ADDR_GND,i,0x00);//write all PWM set 0x00
}
writeByte(ADDR_GND,0xfe,0xc5);//unlock
writeByte(ADDR_GND,0xfD,0x01);//write page 1

for(i=0;i<0xAB;i++){
writeByte(ADDR_GND,i,0x00);//write all PWM set 0x00
} //init all the PWM data to 0

writeByte(ADDR_GND,0xfe,0xc5);//unlock
writeByte(ADDR_GND,0xfD,0x04);//write page 4
writeByte(ADDR_GND,0x01,0x08);//global current
writeByte(ADDR_GND,0x00,0x01);//normal operation
begin(ADDR_GND, i2c);
i2c->setClock(1000000);
setLEDscaling(0xFF);
setGlobalCurrent(0x08);//global current
enable(true);
};
////////////////////////////////////////////////////////////////////
/* Write a single byte to the ISSI chip using I2C
*/
void writeByte(uint8_t Dev_Add,uint8_t Reg_Add,uint8_t Reg_Dat){
uint8_t buffer[2];
brzo_i2c_start_transaction(Dev_Add/2, 400); // open I2C to ISSI at 400kHz
buffer[0] = Reg_Add; // select register address
buffer[1] = Reg_Dat; // select register data
brzo_i2c_write(buffer, 2, false); // write two bites with no repeated start
brzo_i2c_end_transaction();
}
////////////////////////////////////////////////////////////////////
virtual ~AGFXShim()
{

};

////////////////////////////////////////////////////////////////////
/*
* Clear out the frame buffer.
*/
void zero_buffer(){
uint8_t i,j;
for(i = 0; i < ARRAY_WIDTH; i++){
for(j = 0; j < ARRAY_HEIGHT; j++){
frame_buffer[i][j]=0;
}
}
memset(getBuffer(), 0, 351);
};

////////////////////////////////////////////////////////////////////
Expand All @@ -293,62 +169,17 @@ class AGFXShim : public Adafruit_GFX
* the results to the LED matrix.
*/
void execute() {
uint16_t idx = 0;
uint8_t buffer[2];
uint8_t buffSz = 2;

uint8_t buff0[lut0_sz+BULK_CMD_SZ];

// Copy the frame buff into a local buffer that's going to get sent to
// the chip. The chip layout is weird so we use a LUT to get it right
for( idx = 0; idx < lut0_sz; idx++ ){ // we're not using the full address space of the driver chip
if( page0LUT[idx].x >= 0 ){
buff0[BULK_CMD_SZ+idx]= frame_buffer[page0LUT[idx].x][page0LUT[idx].y];
}
}
// Same for page two of the chip
uint8_t buff1[lut1_sz+BULK_CMD_SZ];
for( idx = 0; idx < lut1_sz; idx++ ){
if( page1LUT[idx].x >= 0 ){
buff1[BULK_CMD_SZ+idx]= frame_buffer[page1LUT[idx].x][page1LUT[idx].y];
}
}
brzo_i2c_start_transaction(0x60/2, 400); // open I2C to ISSI at 400kHz
buffer[0] = 0xFE; // unlock
buffer[1] = 0xC5; // unlock
brzo_i2c_write(buffer, 2, false); // write two bites with no repeated start
brzo_i2c_end_transaction();

brzo_i2c_start_transaction(0x60/2, 400); // open I2C to ISSI at 400kHz
buff0[0] = 0xFD; // Set page
buff0[1] = 0x00; // page 0
buff0[2] = 0x00; // first index
brzo_i2c_write(buff0, lut0_sz+BULK_CMD_SZ, false); // Dump the page 0 buffer
brzo_i2c_end_transaction();

// now repeat for page 1
brzo_i2c_start_transaction(0x60/2, 400); // open I2C to ISSI at 400kHz
buffer[0] = 0xFE; // unlock
buffer[1] = 0xC5; // unlock
brzo_i2c_write(buffer, 2, false); // write two bites with no repeated start
brzo_i2c_end_transaction();

brzo_i2c_start_transaction(0x60/2, 400); // open I2C to ISSI at 400kHz
buff1[0] = 0xFD; // Set page
buff1[1] = 0x01; // page 1
buff1[2] = 0x00; // first index
brzo_i2c_write(buff1, lut1_sz+BULK_CMD_SZ, false);//lut0_sz, false); // write two bites with no repeated start
brzo_i2c_end_transaction();
show();
if( autoClear ){
zero_buffer();
}
};
}
////////////////////////////////////////////////////////////////////
/*
* Set a single pixel in the frame buffer.
*/
virtual void drawPixel(int16_t x, int16_t y, uint16_t color){
frame_buffer[x][y] = (uint8_t) color;
getBuffer()[Lookup[y][x]] = (uint8_t) color;
};
////////////////////////////////////////////////////////////////////
/*
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ The Mr. Robot Badge consists of:
![Add library](./img/addlib.png)
* The first library we'll add is the Adafruit graphics library. We implement the Adafruit interface for rendering. In the dialog search for `Adafruit GFX` and install the library.
![GFX](./img/gfx.png)
* The second library we need is [Brzo](https://github.com/pasko-zh/brzo_i2c). Brzo is a fast I2C (eye-squared-see) interface written in assembly for ESP8266. It is much better than the built-in one for Arduino. We use it because our frame buffer is 324 bytes and the Arduino I2C library only let's you move 32 bytes at a time. This lets us send images to display as one big chunk. To install it search for `Brzo` in the library dialog.
![brzo](./img/brzo.png)
* The second library we need is [Adafruit IS31FL3741 Library](https://github.com/adafruit/Adafruit_IS31FL3741) to help talk to the ISSI matrix LED driver chip. Take care to install the correct library as there is a a very similarly-named IS31FL3731 and it's easy to get them mixed up.
![Adafruit IS31FL3741 Library](./img/adafruit_is31fl3741.png)
* That should be it. You should now be able to build your own firmware.
## Image Tool Chain Setup
* The image toolchain is still in beta form. It was developed for linux systems and should work on OSX reasonably well. For Windows, reformat your hard drive and install linux.
Expand Down
Binary file added img/adafruit_is31fl3741.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img/brzo.png
Binary file not shown.