msp430f2013 I2C frustrations
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | /* --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 // 122Hz@3.0V #define LCD_OSC_131HZ 0x01 // 131Hz@3.0V #define LCD_OSC_144HZ 0x02 // 144Hz@3.0V #define LCD_OSC_161HZ 0x03 // 161Hz@3.0V #define LCD_OSC_183HZ 0x04 // 183Hz@3.0V #define LCD_OSC_221HZ 0x05 // 221Hz@3.0V #define LCD_OSC_274HZ 0x06 // 274Hz@3.0V #define LCD_OSC_347HZ 0x07 // 347Hz@3.0V // 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 } |