fj604 34 Posted June 2, 2011 Share Posted June 2, 2011 As promised here: http://www.43oh.com/forum/viewtopic.php?f=10&t=1015 MAX6956 is an I2C LED driver / port expander, here is a demo: /* * Interfacing MSP430G2231 to MAX6956 I2C LED driver and I/O expander Pins MSP430G2231 MAX6956 1 DVCC ----------- 28 V+ 8 P1.6/SCL ----------- 26 SCL 9 P1.7/SDA ----------- 25 SDA 14 DVSS ----------- 2 GND ----------- GND 3 GND ----------- GND 4 AD0 ----------- GND 27 AD1 ----------- GND 1 ISET -/\/39K\/\- GND 12 P19 ----------- LED1 13 P20 ----------- LED2 14 P21 ----------- LED3 8 P15 ----/ ----- GND Upon startup, LED1-3 will light up for about 1.5 seconds, then LED2-3 will start glowing intermittently. While a button on P15 is pushed, LED1 will change brightness. */ #include #define PIN_CS BIT1 #define PIN_SCL BIT6 #define PIN_SDA BIT7 #define DELAY 40000 #define MAX6956_ADDR 0x80 #define ACK 0x00 #define NACK 0xFF void i2c_init(void) { BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1REN |= PIN_SCL | PIN_SDA; // Enable pullup resistors for I2C termination P1OUT |= PIN_SCL | PIN_SDA; USICTL0 = USIPE7 | USIPE6 | USIMST | USISWRST; // SDA enable, SCL enable, Master mode, release USICTL1 = USII2C | USIIE ; // USICKPH; // CKPH = 1, I2C, Interrupt Enable; USICKCTL = USIDIV_7 | USISSEL_2 | USICKPL; // Clock / 128, SMCLK, SCL inactive is high USICTL0 &= ~USISWRST; // Release from reset } void timer_init(void) { TACTL = TASSEL_2 | MC_0; // SMCLK, stop timer TACCTL0 = CCIE; // Enable timer compare interrupt } void sleep(unsigned int count) { TACCR0 = count; // Load top value in compare register TACTL |= TACLR | MC_1; // Clear counter, start timer in up mode _low_power_mode_0(); // Sleep in LPM0 until interrupt TACTL &= ~MC_1; // Stop timer } void i2c_tx_start(void) { USISRL = 0; USICTL0 |= USIGE | USIOE; // Latch enable, SDA enable USICTL0 &= ~USIGE; // Latch disable } void i2c_tx_stop(void) { USICTL0 |= USIOE; // SDA enable USISRL = 0; USICNT = 1; // Transmit 1 bit _low_power_mode_0(); // Sleep in LPM0 until interrupt USISRL = 0xFF; USICTL0 |= USIGE; // Latch enable USICTL0 &= ~(USIGE | USIOE); // Latch disable, SDA disable } unsigned char i2c_tx_byte(unsigned char byte) { USICTL0 |= USIOE; USISRL = byte; USICNT = 8; _low_power_mode_0(); // Sleep in LPM0 until interrupt USICTL0 &= ~USIOE; // SDA disable USICNT = 1; // Receive ACK bit _low_power_mode_0(); // Sleep in LPM0 until interrupt return USISRL & BIT0; // Return ACK = first bit of USISRL } unsigned char i2c_rx_byte(void) { unsigned char v; USICTL0 &= ~USIOE; USICNT = 8; _low_power_mode_0(); // Sleep in LPM0 until interrupt v = USISRL; return v; } void i2c_tx_ack(unsigned char ack) { USICTL0 |= USIOE; USISRL = ack; // Send ACK/NACK bit USICNT = 1; _low_power_mode_0(); // Sleep in LPM0 until interrupt } void max6956_send(unsigned char addr, unsigned char data) { i2c_tx_start(); i2c_tx_byte(MAX6956_ADDR); i2c_tx_byte(addr); i2c_tx_byte(data); i2c_tx_stop(); } unsigned char max6956_recv(unsigned char addr) { unsigned char v; i2c_tx_start(); i2c_tx_byte(MAX6956_ADDR); i2c_tx_byte(addr); i2c_tx_stop(); i2c_tx_start(); i2c_tx_byte(MAX6956_ADDR | BIT0); v = i2c_rx_byte(); // Read and send NACK to stop transmission i2c_tx_ack(NACK); i2c_tx_stop(); return v; } void sense(void) { static unsigned char g=0; if (!(max6956_recv(0x2F) & BIT0)) // Send No-op command and check bit 0 = button pushed max6956_send(0x19, g++ << 4); // Increase brightness of LED on port 19 } void leds(unsigned char v) { max6956_send(0x1A, v | (0x0F-v) << 4); // control brightness of LEDs on ports 20-21 sense(); } void main(void) { signed char i=0; WDTCTL = WDTPW + WDTHOLD; // Disable WDT i2c_init(); timer_init(); _enable_interrupts(); max6956_send(0x0C, 0x00); // set ports 16-19 to LED max6956_send(0x0D, 0x00); // set ports 20-23 to LED max6956_send(0x0B, 0xFF); // set ports 12-15 to GPIO Input with pullup max6956_send(0x33, 0x01); // Port 19 on max6956_send(0x34, 0x01); // Port 20 on max6956_send(0x35, 0x01); // Port 21 on max6956_send(0x07, 0x01); // Display test on _delay_cycles(1500000); // ~ 1.5s pause max6956_send(0x07, 0x00); // Display test off max6956_send(0x04, BIT0 | BIT6); // Individual segment current control, normal operation for (; { for (i=0; i<0x10; i++) { leds(i); sleep(DELAY); } for (i=0x0F; i>=0; i--) { leds(i); sleep(DELAY); } } } #pragma vector=USI_VECTOR __interrupt void usi_interrupt(void) { USICTL1 &= ~USIIFG; // Clear interrupt flag _low_power_mode_off_on_exit(); // Return from LPM } #pragma vector=TIMERA0_VECTOR __interrupt void timer_A_interrupt(void) { _low_power_mode_off_on_exit(); // Return from LPM } Simbo, RobG, bluehash and 2 others 5 Quote Link to post Share on other sites
fj604 34 Posted June 3, 2011 Author Share Posted June 3, 2011 Here is a slightly modified version that implements a repeat start on I2C. It is explained here: http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/t/105688.aspx /* * Interfacing MSP430G2231 to MAX6956 I2C LED driver and I/O expander Pins MSP430G2231 MAX6956 1 DVCC ----------- 28 V+ 8 P1.6/SCL ----------- 26 SCL 9 P1.7/SDA ----------- 25 SDA 14 DVSS ----------- 2 GND ----------- GND 3 GND ----------- GND 4 AD0 ----------- GND 27 AD1 ----------- GND 1 ISET -/\/39K\/\- GND 12 P19 ----------- LED1 13 P20 ----------- LED2 14 P21 ----------- LED3 8 P15 ----/ ----- GND Upon startup, LED1-3 will light up for about 1.5 seconds, then LED2-3 will start glowing intermittently. While a button on P15 is pushed, LED1 will change brightness. */ #include #define PIN_CS BIT1 #define PIN_SCL BIT6 #define PIN_SDA BIT7 #define DELAY 40000 #define MAX6956_ADDR 0x80 #define ACK 0x00 #define NACK 0xFF void i2c_init(void) { BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1REN |= PIN_SCL | PIN_SDA; // Enable pullup resistors for I2C termination P1OUT |= PIN_SCL | PIN_SDA; USICTL0 = USIPE7 | USIPE6 | USIMST | USISWRST; // SDA enable, SCL enable, Master mode, release USICTL1 = USII2C | USIIE ; // USICKPH; // CKPH = 1, I2C, Interrupt Enable; USICKCTL = USIDIV_7 | USISSEL_2 | USICKPL; // Clock / 128, SMCLK, SCL inactive is high USICTL0 &= ~USISWRST; // Release from reset } void timer_init(void) { TACTL = TASSEL_2 | MC_0; // SMCLK, stop timer TACCTL0 = CCIE; // Enable timer compare interrupt } void sleep(unsigned int count) { TACCR0 = count; // Load top value in compare register TACTL |= TACLR | MC_1; // Clear counter, start timer in up mode _low_power_mode_0(); // Sleep in LPM0 until interrupt TACTL &= ~MC_1; // Stop timer } void i2c_tx_start(void) { USISRL = 0; USICTL0 |= USIGE | USIOE; // Latch enable, SDA enable USICTL0 &= ~USIGE; // Latch disable } void i2c_tx_rpt_start(void) { USICTL0 |= USIOE; // SDA enable USISRL = 0xFF; // Set MSB of USISRL to high USICNT = 1; // Transmit 1 bit for a surplus clock cycle _low_power_mode_0(); // Sleep in LPM0 until interrupt i2c_tx_start(); } void i2c_tx_stop(void) { USICTL0 |= USIOE; // SDA enable USISRL = 0; USICNT = 1; // Transmit 1 bit _low_power_mode_0(); // Sleep in LPM0 until interrupt USISRL = 0xFF; USICTL0 |= USIGE; // Latch enable USICTL0 &= ~(USIGE | USIOE); // Latch disable, SDA disable } unsigned char i2c_tx_byte(unsigned char byte) { USICTL0 |= USIOE; USISRL = byte; USICNT = 8; _low_power_mode_0(); // Sleep in LPM0 until interrupt USICTL0 &= ~USIOE; // SDA disable USICNT = 1; // Receive ACK bit _low_power_mode_0(); // Sleep in LPM0 until interrupt return USISRL & BIT0; // Return ACK = first bit of USISRL } unsigned char i2c_rx_byte(void) { unsigned char v; USICTL0 &= ~USIOE; USICNT = 8; _low_power_mode_0(); // Sleep in LPM0 until interrupt v = USISRL; return v; } void i2c_tx_ack(unsigned char ack) { USICTL0 |= USIOE; USISRL = ack; // Send ACK/NACK bit USICNT = 1; _low_power_mode_0(); // Sleep in LPM0 until interrupt } void max6956_send(unsigned char addr, unsigned char data) { i2c_tx_start(); i2c_tx_byte(MAX6956_ADDR); i2c_tx_byte(addr); i2c_tx_byte(data); i2c_tx_stop(); } unsigned char max6956_recv(unsigned char addr) { unsigned char v; i2c_tx_start(); i2c_tx_byte(MAX6956_ADDR); i2c_tx_byte(addr); i2c_tx_rpt_start(); // Generate a repeat start i2c_tx_byte(MAX6956_ADDR | BIT0); v = i2c_rx_byte(); // Read and send NACK to stop transmission i2c_tx_ack(NACK); i2c_tx_stop(); return v; } void sense(void) { static unsigned char g=0; if (!(max6956_recv(0x2F) & BIT0)) // Send No-op command and check bit 0 = button pushed max6956_send(0x19, g++ << 4); // Increase brightness of LED on port 19 } void leds(unsigned char v) { max6956_send(0x1A, v | (0x0F-v) << 4); // control brightness of LEDs on ports 20-21 sense(); } void main(void) { signed char i=0; WDTCTL = WDTPW + WDTHOLD; // Disable WDT i2c_init(); timer_init(); _enable_interrupts(); max6956_send(0x0C, 0x00); // set ports 16-19 to LED max6956_send(0x0D, 0x00); // set ports 20-23 to LED max6956_send(0x0B, 0xFF); // set ports 12-15 to GPIO Input with pullup max6956_send(0x33, 0x01); // Port 19 on max6956_send(0x34, 0x01); // Port 20 on max6956_send(0x35, 0x01); // Port 21 on max6956_send(0x07, 0x01); // Display test on _delay_cycles(1500000); // ~ 1.5s pause max6956_send(0x07, 0x00); // Display test off max6956_send(0x04, BIT0 | BIT6); // Individual segment current control, normal operation for (; { for (i=0; i<0x10; i++) { leds(i); sleep(DELAY); } for (i=0x0F; i>=0; i--) { leds(i); sleep(DELAY); } } } #pragma vector=USI_VECTOR __interrupt void usi_interrupt(void) { USICTL1 &= ~USIIFG; // Clear interrupt flag _low_power_mode_off_on_exit(); // Return from LPM } #pragma vector=TIMERA0_VECTOR __interrupt void timer_A_interrupt(void) { _low_power_mode_off_on_exit(); // Return from LPM } Simbo and timotet 2 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.