msp430f2013 I2C frustrations

display

UPDATE: See this post which shows how I finally got it working.

I’ve been trying to get a ST7032i based display working with a msp430f2013 on a EZ430-F2013. Unfortunately without much success. After hours of debugging I discovered that the glass on the display was fractured… guess I’ll be ordering some more.

Anyway, it did get as far as acknowledging my commands. And I found a working I2C sample. It was hidden pretty well on the TI site, I think in a zip called slac080l.zip. The file I was working from was msp430x20x3_usi_07.c. My hacked version is reproduced below, you can almost feel the frustration I’m sure (it’s an absolute mess). But it does work with the MSP430GCC compiler, and produce working I2C output.

/* --COPYRIGHT--,BSD_EX
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************
 * 
 *                       MSP430 CODE EXAMPLE DISCLAIMER
 *
 * MSP430 code examples are self-contained low-level programs that typically
 * demonstrate a single peripheral function or device feature in a highly
 * concise manner. For this the code may rely on the device's power-on default
 * register values and settings such as the clock configuration and care must
 * be taken when combining code from several examples to avoid potential side
 * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
 * for an API functional library-approach to peripheral configuration.
 *
 * --/COPYRIGHT--*/
//******************************************************************************
//  MSP430F20xx Demo - I2C Master Transmitter, single byte
//
//  Description: I2C Master communicates with I2C Slave using
//  the USI. Master data is sent and increments from 0x00 with each transmitted
//  byte which is verified by the slave.
//  LED off for address or data Ack; LED on for address or data NAck.
//  ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
//
//  ***THIS IS THE MASTER CODE***
//
//                  Slave                      Master
//          (msp430x20x3_usi_08.c)
//               MSP430F20x2/3              MSP430F20x2/3
//             -----------------          -----------------
//         /|\|              XIN|-    /|\|              XIN|-
//          | |                 |      | |                 |
//          --|RST          XOUT|-     --|RST          XOUT|-
//            |                 |        |                 |
//      LED <-|P1.0             |        |                 |
//            |                 |        |             P1.0|-> LED
//            |         SDA/P1.7|<-------|P1.7/SDA         |
//            |         SCL/P1.6|<-------|P1.6/SCL         |
//
//  Note: internal pull-ups are used in this example for SDA & SCL
//
//  Z. Albus
//  Texas Instruments Inc.
//  May 2006
//  Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.41A
//******************************************************************************
#include <msp430.h>


// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
#define LCD_EX_SETBIASOSC 0x10 // Bias selection / Internal OSC frequency adjust
#define LCD_EX_SETICONRAMADDR 0x40 // Set ICON RAM address
#define LCD_EX_POWICONCONTRASTH 0x50 // Power / ICON control / Contrast set(high byte)
#define LCD_EX_FOLLOWERCONTROL 0x60 // Follower control
#define LCD_EX_CONTRASTSETL 0x70 // Contrast set(low byte)
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
#define LCD_EX_INSTRUCTION 0x01 // IS: instruction table select
// flags for Bias selection
#define LCD_BIAS_1_4 0x08 // bias will be 1/4
#define LCD_BIAS_1_5 0x00 // bias will be 1/5
// flags Power / ICON control / Contrast set(high byte)
#define LCD_ICON_ON 0x08 // ICON display on
#define LCD_ICON_OFF 0x00 // ICON display off
#define LCD_BOOST_ON 0x04 // booster circuit is turn on
#define LCD_BOOST_OFF 0x00 // booster circuit is turn off
#define LCD_OSC_122HZ 0x00 // [email protected]
#define LCD_OSC_131HZ 0x01 // [email protected]
#define LCD_OSC_144HZ 0x02 // [email protected]
#define LCD_OSC_161HZ 0x03 // [email protected]
#define LCD_OSC_183HZ 0x04 // [email protected]
#define LCD_OSC_221HZ 0x05 // [email protected]
#define LCD_OSC_274HZ 0x06 // [email protected]
#define LCD_OSC_347HZ 0x07 // [email protected]
// flags Follower control
#define LCD_FOLLOWER_ON 0x08 // internal follower circuit is turn on
#define LCD_FOLLOWER_OFF 0x00 // internal follower circuit is turn off
#define LCD_RAB_1_00 0x00 // 1+(Rb/Ra)=1.00
#define LCD_RAB_1_25 0x01 // 1+(Rb/Ra)=1.25
#define LCD_RAB_1_50 0x02 // 1+(Rb/Ra)=1.50
#define LCD_RAB_1_80 0x03 // 1+(Rb/Ra)=1.80
#define LCD_RAB_2_00 0x04 // 1+(Rb/Ra)=2.00
#define LCD_RAB_2_50 0x05 // 1+(Rb/Ra)=2.50
#define LCD_RAB_3_00 0x06 // 1+(Rb/Ra)=3.00
#define LCD_RAB_3_75 0x07 // 1+(Rb/Ra)=3.75



char MST_Data = 0x40;                     // Variable for transmitted data
char SLV_Addr = 0x7C;                  // Address is 0x48 << 1 bit + 0 for Write
int I2C_State = 0;                     // State variable

int main(void)
{
  volatile unsigned int i;             // Use volatile to prevent removal

  WDTCTL = WDTPW + WDTHOLD;            // Stop watchdog
                __delay_cycles(250000);
  if (CALBC1_1MHZ==0xFF)			   // If calibration constants erased
  {											
    while(1);                          // do not load, trap CPU!!	
  }
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_1MHZ;               // Set DCO
  DCOCTL = CALDCO_1MHZ;

  P1OUT = 0xC0;                        // P1.6 & P1.7 Pullups, others to 0
  P1REN |= 0xC0;                       // P1.6 & P1.7 Pullups
  P1DIR = 0xFF;                        // Unused pins as outputs
  P2OUT = 0;
  P2DIR = 0xFF;

  USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
  USICTL1 = USII2C+USIIE;              // Enable I2C mode & USI interrupt
  USICKCTL = USIDIV_3+USISSEL_2+USICKPL; // Setup USI clocks: SCL = SMCLK/8 (~125kHz) // was USIDIV_3
  USICNT |= USIIFGCC;                  // Disable automatic clear control
  USICTL0 &= ~USISWRST;                // Enable USI
  USICTL1 &= ~USIIFG;                  // Clear pending flag
  __enable_interrupt();

  int a=0;
  for(int n=0;;n++)
  {
    if(n==0) MST_Data = 0x00;
    if(n==1) MST_Data = LCD_EX_SETBIASOSC | LCD_BIAS_1_5 | LCD_OSC_183HZ;
    if(n==2) MST_Data = 0x00;
    if(n==3) MST_Data = LCD_EX_FOLLOWERCONTROL | LCD_FOLLOWER_ON | LCD_RAB_2_00;
    if(n==4) MST_Data = 0x00;
    if(n==5) MST_Data = LCD_DISPLAYON | LCD_CURSORON | LCD_BLINKON;
    if(n==6) MST_Data = 0x00;
    if(n==7) MST_Data = LCD_ENTRYMODESET | LCD_ENTRYLEFT;

    if(n==9) MST_Data = 0x00;
    if(n==10) MST_Data = LCD_EX_CONTRASTSETL | (0x0c & 0x0f);
    if(n==11) MST_Data = 0x00;
    if(n==12) MST_Data = LCD_EX_POWICONCONTRASTH | LCD_ICON_ON | LCD_BOOST_ON | ((0x0c >> 4) & 0x03);
    if(n==14) MST_Data = 0x00;
    if(n==15) MST_Data = LCD_CLEARDISPLAY;
    if(n==16) MST_Data = 0x00;
    if(n==17) MST_Data = 0x40;
    if(n==18) MST_Data = 'a'+a;
    USICTL1 |= USIIFG;                 // Set flag and start communication
    LPM0;                              // CPU off, await USI interrupt
   // __no_operation();                  // Used for IAR
//    for (i = 0; i < 5000; i++);        // Dummy delay between communication cycles
    P1OUT &= ~0x01;           // LED off
    __delay_cycles(500000);
    if(n==18)n=16;
    a++;
  }
}

/******************************************************
// USI interrupt service routine
******************************************************/
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USI_VECTOR))) USI_TXRX (void)
#else
#error Compiler not supported!
#endif
{
  switch(I2C_State)
    {
      case 0: // Generate Start Condition & send address to slave
              P1OUT &= ~0x01;           // LED off
              USISRL = 0x00;           // Generate Start Condition...
              USICTL0 |= USIGE+USIOE;
              USICTL0 &= ~USIGE;
              USISRL = SLV_Addr;       // ... and transmit address, R/W = 0
              USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
              I2C_State = 2;           // Go to next state: receive address (N)Ack
              break;

      case 2: // Receive Address Ack/Nack bit
              USICTL0 &= ~USIOE;       // SDA = input
              USICNT |= 0x01;          // Bit counter = 1, receive (N)Ack bit
              I2C_State = 4;           // Go to next state: check (N)Ack
              break;

      case 4: // Process Address Ack/Nack & handle data TX
              USICTL0 |= USIOE;        // SDA = output
              if (USISRL & 0x01)       // If Nack received...
              { // Send stop...
                USISRL = 0x00;
                USICNT |=  0x01;       // Bit counter = 1, SCL high, SDA low
                I2C_State = 10;        // Go to next state: generate Stop
              //  P1OUT |= 0x01;         // Turn on LED: error
                P1OUT |= 0x01;         // Turn on LED: error
                __delay_cycles(5000000);
              }
              else
              { // Ack received, TX data to slave...
                USISRL = MST_Data;     // Load data byte
                USICNT |=  0x08;       // Bit counter = 8, start TX
                I2C_State = 6;         // Go to next state: receive data (N)Ack
                P1OUT &= ~0x01;        // Turn off LED
              }
              break;

      case 6: // Receive Data Ack/Nack bit
              USICTL0 &= ~USIOE;       // SDA = input
              USICNT |= 0x01;          // Bit counter = 1, receive (N)Ack bit
              I2C_State = 8;           // Go to next state: check (N)Ack
              break;

      case 8: // Process Data Ack/Nack & send Stop
              USICTL0 |= USIOE;
              if (USISRL & 0x01)       // If Nack received...
              ;//  P1OUT |= 0x01;         // Turn on LED: error
              else                     // Ack received
              {
                MST_Data++;            // Increment Master data
              //  P1OUT &= ~0x01;        // Turn off LED
              }
              // Send stop...
              USISRL = 0x00;
              USICNT |=  0x01;         // Bit counter = 1, SCL high, SDA low
              I2C_State = 10;          // Go to next state: generate Stop
              break;

      case 10:// Generate Stop Condition
              USISRL = 0x0FF;          // USISRL = 1 to release SDA
              USICTL0 |= USIGE;        // Transparent latch enabled
              USICTL0 &= ~(USIGE+USIOE);// Latch/SDA output disabled
              I2C_State = 0;           // Reset state machine for next transmission
              LPM0_EXIT;               // Exit active for next transfer
              break;
    }

  USICTL1 &= ~USIIFG;                  // Clear pending flag
}

Comments are closed.