SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By tomonaga
#45315
Hi All,
I'm recently working with LM4970, audio synchronized LED driver.
I wrote an Arduino code, based on BlinkM's example, which sets up LM4970 via I2C commands.
It looks fine but my LM4970 never worked.
Could you give me an advise or test it if you have them??

tom


Code: Select all
// SDA -- Analog In 4
// SCL -- Analog In 5

#include "Wire.h"
#include "LM4970_funcs.h"

#define LM4970_ARDUINO_POWERED 1

int lm4970_addr = LM4970_ADDR_0;
int ledPin = 13;

void setup()
{
    pinMode(ledPin, OUTPUT);
    if( LM4970_ARDUINO_POWERED ) {
        LM4970_beginWithPower();
    } else {
        LM4970_begin();
    }
    Serial.begin(19200);
    Serial.println("LM4970 ready");
    
    digitalWrite(ledPin, HIGH);  // say we're working on it
#if 1 // audio synchronization mode
    LM4970_setMode(lm4970_addr);
    LM4970_setFreq(lm4970_addr);
    LM4970_setPattern(lm4970_addr);
    LM4970_setLEDDrive(lm4970_addr);
    LM4970_setGain(lm4970_addr);    
#elif 0 // audio synchronization mode (raw data ver according to sparkfun pdf)
    byte cmd[] = {0x04, 0x50, 0x60, 0xBF, 0xF2};
    LM4970_sendCmd(lm4970_addr, cmd, 5);
#else // i2c led mode
    LM4970_setMode(lm4970_addr, false, false, false);
    LM4970_setPattern(lm4970_addr, true, true, true, true);    
#endif
    digitalWrite(ledPin, LOW);
}


void loop()
{
}


LM4970_funcs.h:
Code: Select all
#define DEBUG

#include <Wire.h>

static byte LM4970_ADDR_0 = 0xF4; // with ADR pin LOW
static byte LM4970_ADDR_1 = 0xF6; // with ADR pin HIGH

// Call this first (when powering LM4970 from a power supply)
static void LM4970_begin()
{
    Wire.begin(); // join i2c bus (address optional for master)
}

// General version of LM4970_beginWithPower().
// Call this first when LM4970 is plugged directly into Arduino
static void LM4970_beginWithPowerPins(byte pwrpin, byte gndpin)
{
    DDRC |= _BV(pwrpin) | _BV(gndpin);
    PORTC &=~ _BV(gndpin);
    PORTC |=  _BV(pwrpin);
    delay(100);  // wait for things to stabilize

    Wire.begin();
}

// Call this first when LM4970 is plugged directly into Arduino
static void LM4970_beginWithPower()
{
    LM4970_beginWithPowerPins( PC3, PC2 );
}

// sends a generic command
static void LM4970_sendCmd(byte addr, byte* cmd, int cmdlen)
{
    Wire.beginTransmission(addr);
    for( byte i=0; i<cmdlen; i++) {
        Wire.send((int)cmd[i]);
#ifdef DEBUG
        Serial.print(cmd[i], HEX);
        Serial.print(' ');
#endif
    }
    Wire.endTransmission();
    delay(50);
}


static void LM4970_setMode(byte addr, boolean shutdown = false, boolean reset = false, boolean audioSync = true)
{
    byte cmd = 0;
    cmd |= shutdown << 0;
    cmd |= reset << 1;
    cmd |= audioSync << 2;
    LM4970_sendCmd(addr, &cmd, 1);
}

static void LM4970_setFreq(byte addr, byte pwmFreq = 0 /* 0 to 3 (15k, 60, 7, 4 Hz) */, byte highPass = 2 /* 0 to 3 (3.5k, 6.3k, 6.3k, 8.9k Hz) */)
{
    byte cmd = 0x40;
    cmd |= pwmFreq << 0;
    cmd |= highPass << 3;
    LM4970_sendCmd(addr, &cmd, 1);
}

static void LM4970_setPattern(byte addr, boolean i2cMode = false, boolean led1 = false /* only i2c mode*/, boolean led2 = false /* only i2c mode*/, boolean led3 = false /* only i2c mode*/)
{
    byte cmd = 0x60;
    cmd |= i2cMode << 0;
    cmd |= led1 << 1;
    cmd |= led2 << 2;
    cmd |= led3 << 3;
    LM4970_sendCmd(addr, &cmd, 1);
}

static void LM4970_setLEDDrive(byte addr, byte led1 = 3 /* 0 to 3 (0.66x, 1x,1.33x, 2x) */, byte led2 = 3 /* 0 to 3 (0.66x, 1x,1.33x, 2x) */, byte led3 = 3 /* 0 to 3 (0.66x, 1x,1.33x, 2x) */)
{
    byte cmd = 0x80;
    cmd |= led1 << 0;
    cmd |= led2 << 2;
    cmd |= led3 << 4;
    LM4970_sendCmd(addr, &cmd, 1);
}


static void LM4970_setGain(byte addr, byte mid = 2 /* 0 to 4 (min to max) */, byte sum = 6 /* 0 to 6 (-11, -6.5, 0, 3.5, 6, 10, 12db)  */)
{
    byte cmd = 0x80;
    cmd |= mid << 0;
    cmd |= sum << 3;
    LM4970_sendCmd(addr, &cmd, 1);
}
[/size]

update:
Code: Select all
static byte LM4970_ADDR_0 = 0xF4; // with ADR pin LOW
static byte LM4970_ADDR_1 = 0xF6; // with ADR pin HIGH
should be
Code: Select all
static byte LM4970_ADDR_0 = 0x7A; // with ADR pin LOW
static byte LM4970_ADDR_1 = 0x7B; // with ADR pin HIGH
Still not working, though.
By CollinMel
#59864
like the OP, I'm SOL here - anyone been able to initialize this thing w/ Arduino?
By busonerd
#59931
When I last played with one of those boards; I recall it being a stickler for exact protocol accuracy. Make sure you're sending _Exactly_ what is in the datasheets.

Cheers,

--David Carne
By BroHogan
#61230
tomonaga,

One thing I noticed about your sketch is that you are using the full 8 bit address of the chip.

With I2C, the low order bit specifies read or write. The Wire lib. is nice enough to change this bit as needed - but not nice enough to document that you should only supply it with the first 7 bits of the address.

So for LM4970_ADDR_0 you should use 0x7A instead of 0xF4.
For LM4970_ADDR_1 you should use 0x7B instead of 0xF6.

I don't know about the rest, but last night I wrote a working example for the LM4970 on the Arduino. I'll post it here when I get home tonight.

It seems to set up the chip properly and I can access the 3 LEDs via I2C.
It works with audio, but the "high" LED comes on a bit even if there is no audio input. It's possible I got a bad chip.

So I have only 1 possible TODO for the sketch but I'll post it here.

BroHogan
By BroHogan
#61240
Here is my code for the SparkFun LM4970 breakout board. Nothing fancy, just a working example.
Enjoy! BroHogan
Code: Select all
/* LM4970 Example - Proof of concept for LM4970 interface to Arduino    BroHogan (12/06/08)
 * - Uses SparkFun LM4970 Breakout (see schematic).
 * - Max output 42 mA / channel. Common Anode LEDs
 * - 2 addresses - pin 6 LOW, ADR 0, - pin 6 HIGH, ADR 1
 * - The first 2 or 3 bits describe the register, so they can be written to individually
 * - Tweak gain, midband filter & randomizer to match audio charistics.
 * This sourcecode is released under the Terms of the GNU Lesser General Public License.
 */

#include <Wire.h>                // for I2C

// defines for LM4970
#define LM4970_ADDR_0      0x7A  // first 7 bits of address 0 (ADR = LOW)
#define LM4970_ADDR_1      0x7B  // first 7 bits of address 1 (ADR = HIGH)

#define LM4970_MODE_NORM   0x00  // power up, normal I2C, no random
#define LM4970_MODE_RAND   0x04  // power up, normal I2C, random
#define LM4970_FREQ        0x50  // 6.3kHz High Pass / 15kHz PWM
#define LM4970_PATT_AUDIO  0x60  // pattern gen by audio input
#define LM4970_PATT_I2C    0x61  // pattern gen by I2C - all off
#define LM4970_CURR        0xAA  // 1x current (21mA)on LED 1-3
#define LM4970_GAIN        0xEA  // gain = 10dB / midband = medium
// More defines can be created based on the data sheet

byte LM4970_Address = LM4970_ADDR_0; // using address 0 (ADR = LOW)

void setup() {
  Wire.begin(); 
  LM4970_Hello();                          // light up some LEDs in I2C mode
  LM4970_Init();                           // set for audio control of LEDs
}

void loop(){
  // nice clean example 
}

void LM4970_Init(){  // Init based on #defines above
  Wire.beginTransmission(LM4970_Address);
  Wire.send(LM4970_MODE_NORM);             // set the mode
  Wire.send(LM4970_FREQ);                  // set the freq
  Wire.send(LM4970_PATT_AUDIO);            // set the pattern
  Wire.send(LM4970_CURR);                  // set the current
  Wire.send(LM4970_GAIN);                  // set the gain  
  Wire.endTransmission(); 
  delay(5);                                // safety - may not be needed
}

void LM4970_I2C_Led(boolean LED1,boolean LED2,boolean LED3){ // I2C control of LEDs
  byte pattern = LM4970_PATT_I2C;          // pattern set to I2C control - all off
  pattern |= LED1 << 1;                    // shift in status for LED1
  pattern |= LED2 << 2;                    // shift in status for LED2
  pattern |= LED3 << 3;                    // shift in status for LED3
  Wire.beginTransmission(LM4970_Address);
  Wire.send(pattern);                      // send the command for the LEDs to light
  Wire.send(LM4970_CURR);                  // set the current
  Wire.endTransmission(); 
  delay(5);                               // safety - may not be needed
}

void LM4970_Hello(){
  LM4970_I2C_Led(true,false,false);        // turn on LED-1
  delay(500);
  LM4970_I2C_Led(false,true,false);        // turn on LED-2
  delay(500);
  LM4970_I2C_Led(false,false,true);        // turn on LED-1
  delay(500);
  LM4970_I2C_Led(true,true,true);          // turn on all 3
  delay(1000);
  LM4970_I2C_Led(false,false,false);       // turn em off
  delay(1000);
}

By tomonaga
#61247
hi brohogan, thanks for the code.
i've also tried the 7bit address before but couldn't work it, maybe something was wrong.
i'll try yours soon. thanks.
By One~Zero
#69729
BroHogan, thanks for posting the code for this project. I uploaded and it seems to work great. Admittedly, I am very new to Arduino and I2C. If it's not too much trouble, could you tell me how to determine the hex from the LM4970 addresses. I.e., I want to change a couple of the configurations that you have in yours, but am not sure how you determine what the hex is for a given option. Any help would be greatly appreciated.

**Edit**: Never mind...got it figured out :wink: