Grove_LED_Bar (MY9221 LED controlling chip)


#1

Seeking some advice on how best to convert this Arduino library.

I wondered whether Electric Imp could offer up a more elegant GPIO digitalWrite solution than what this library uses, via the Imp pin output configure options.

All other suggestions welcomed.

Hardware is described here: http://wiki.seeed.cc/Grove-LED_Bar/


#2

Not really, no - this appears to be a custom protocol they’ve come up with themselves, talking to a microcontroller on the board. eg they send data on both edges of the clock, do a weird data only thing to latch, etc.

They could have just done i2c given that they have two wires… sigh.


#3

Thanks @hugo.

Working through the library but could not get it to work… any clues

`
class Grove_LED_Bar {
// Avoid name conflict
static GLB_CMDMODE = 0x00; // Work on 8-bit mode
static GLB_ON = 0xff; // 8-bit 1 data
static GLB_OFF = 0x00; // 8-bit 0 data

static version = [1,0,0];

// Class properties; those defined in the Constructor must be null

__pinClock = 0;  				// Clock pin
__pinData = 0;   				// Data pin
__greenToRed = 0;        	// Orientation (0 = red to green, 1 = green to red)
__state = null;					// Led state, brightness for each LED

constructor(pinClock = 0, pinData = 0, greenToRed = 0) {
    __pinClock = pinClock;
    __pinData = pinData;
    __greenToRed = greenToRed;
	
	__state = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
	
	__pinClock.configure(DIGITAL_OUT,1);
	__pinData.configure(DIGITAL_OUT,1);

}

// Send the latch command
function latchData() {
	__pinData.write(0);
	imp.sleep(0.00001);
	for (local i = 0; i < 4; i++) {
		__pinData.write(1);
		__pinData.write(0);
	}
}

// Send 16 bits of data
function sendData(data) {
	for (local i = 0; i < 16; i++) {
		local state = (data & 0x8000) ? 1 : 0;
		__pinData.write (state);

		state = __pinClock.read() ? 1 : 0;
		__pinClock.write(state);

		data = data << 1;
	}
}

// Change the orientation
// Green to red, or red to green
function setGreenToRed(greenToRed) {
	__greenToRed = greenToRed;
	setData(__state);
}

// Set level (0-10)
// Level 0 means all leds off
// Level 10 means all leds on
// Level 4.5 means 4 LEDs on and the 5th LED's half on
function setLevel(level = 0.0) {
	local minLevel = (10.0 < level) ? 10.0 : level;
	level = (0.0 > minLevel) ? 0.0 : minLevel;
  
	level *= 8; 		// there are 8 (noticable) levels of brightness on each segment
  
	// Place number of 'level' of 1-bits on __state
	for (local i = 0; i < 10; i++) {
		__state[i] = (level > 8) ? ~0 : (level > 0) ? ~(~0 << (level).tointeger()) : 0;
		level -= 8;
	}

	setData(__state);
}

// Set a single led
// led (1-10)
// brightness (0-1)
function setLed(led = 0, brightness = 0.0) {
	local minLed = (10 < led) ? 10 : led;
	led = (1 > minLed) ? 1 : minLed;
	
	local minBright = (1.0 < brightness) ? 1.0 : brightness;
	brightness = (0.0 > minBright) ? 0.0 : minBright;

	// Zero based index 0-9 for bitwise operations
	led--;

	// 8 (noticable) levels of brightness
	// 00000000 darkest
	// 00000011 brighter
	// ........
	// 11111111 brightest
	__state[led] = ~(~0 << (brightness*8).tointeger());

	setData(__state);
}

// Toggle a single led
// led (1-10)
function toggleLed(led = 0) {
	local minLed = (10 < led) ? 10 : led;
	led = (1 > minLed) ? 1: minLed;

	// Zero based index 0-9 for bitwise operations
	led--;

	__state[led] = __state[led] ? 0 : ~0;

	setData(__state);
}

// each element in the state will hold the brightness level
// 00000000 darkest
// 00000011 brighter
// ........
// 11111111 brightest
function setData(__state) {
	sendData(GLB_CMDMODE);

	for (local i = 0; i < 10; i++) {
		if (__greenToRed) {
			// Go backward on __state
			sendData(__state[10-i-1]);
		}
		else {
			// Go forward on __state
			sendData(__state[i]);
		}
	}

	// Two extra empty bits for padding the command to the correct length
	sendData(0x00);
	sendData(0x00);

	latchData();
}

function setBits(bits = 0) {
	for (local i = 0; i < 10; i++) {
		if ((bits % 2) == 1) __state[i] = 0xFF;
		else __state[i] = 0x00;
		
		bits /= 2;
	}

	setData(__state);
}

// Return the current bits
function getBits() {
	local __bits = 0x00;
	for (local i = 0; i < 10; i++) {
		if (__state[i] != 0x0) __bits = __bits || (0x1 << i);
	}
	return __bits;
}

}
`


#4

Having reviewed what I quickly stuck together, I see the main problem lies in my total lack of use of blobs (and in the use of blob.writen methods) as well as a few errors here and there.

I’m also hoping that as this is not a huge coding job it could quickly morph into a standard imp library (@smittytone is this probable/possible).


#5

Turns out the code works, after I corrected one small error.

state = __pinClock.read() ? 1 : 0; should read state = __pinClock.read() ? 0 : 1;

Tested class with a simple script:

first assign LEDBar <- Grove_LED_Bar(yourLEDclockPin, yourLEDdataPin, true);

Then ran this test code
// Start as green to red // Walk through the 10 levels LEDBar.setGreenToRed(1); for (local i = 0; i <= 10; i++) { LEDBar.setLevel(i); imp.sleep(0.2); } LEDBar.setLevel(0); // Now start as red to green & repeat LEDBar.setGreenToRed(0); imp.sleep(0.2); for (local i = 0; i <= 10; i++) { LEDBar.setLevel(i); imp.sleep(0.2); } LEDBar.setLevel(0);