This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I've just done a fresh install of CCS 6.1.3.00034.
I've also just installed Energia 0101E0017.
I am attempting to use code from an Arduino project to detect I2C devices. The code is quite simple:
void findAddress() { for (int a = fromAddress; a < toAddress; a++) { Wire.beginTransmission(a); Wire.write(0); int endStatus = Wire.endTransmission(); if (endStatus == 0) { Serial.print("Found device at: "); printHex(a, true); } } }
In the Arduino environmnet, it would output the address of all I2C devices that were connected. However, this basically says that every address is a device..
Anyway, I believe there is a bug fix somewhere with the Energia project. It is quite frustrating that we have to go find and install code hacks in order to get Energia to run and play nicely with CCS...
Perhaps there could be some encouragement by TI or somebody with more clout than me to get the latest Energia release to work well with the MSP430G2553 Launchpad.
Please let me know if there is a known fix for this problem, as it is currently stalling my project and making me ask why CCS has Energia as a project type when Energia doesn't appear to work with TI MSP430G2553 Launchpad right out of the box...
Thanks, and sorry if my post has turned into a slight rant.. Just frustrated fighting the tools that are supposed to make my job as a developer easier... :-<
Hi Curtis,
Sorry to hear this is not working for you. The issue was fixed after the release of Energia 17. Energia 18 took a bit longer than expected but will be out shortly.
With that said, it's easy to patch Energia 17 to make this work.
With that in place you should not be able to run the Sketch below and successfully scan the bus.
Robert @ Energia
#include <Wire.h> void setup() { Serial.begin(9600); Serial.println("Start!"); Wire.setModule(0); Wire.begin(); } void loop() { findAddress(); delay(1000); } uint8_t fromAddress = 0; uint8_t toAddress = 127; void findAddress() { for (uint8_t a = fromAddress; a < toAddress; a++) { Wire.beginTransmission(a); int endStatus = Wire.endTransmission(); if (endStatus == 0) { Serial.print("Found device at: 0x"); Serial.println(a, HEX); } } }
I really thought that I had attached them but must have forgotten. Sorry about that.
/* ************************************************************************ * twi.c * * Arduino core files for MSP430 * Copyright (c) 2012 Robert Wessels. All right reserved. * * *********************************************************************** Derived from: twi.c - TWI/I2C library for Wiring & Arduino Copyright (c) 2006 Nicholas Zambetti. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <math.h> #include <stdlib.h> #include "Energia.h" // for digitalWrite #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #include "wiring_private.h" #include "pins_energia.h" #include "twi.h" #include "usci_isr_handler.h" #if DEFAULT_I2C == -1 // SW I2C implementation on default port #include "twi_sw.h" // software I2C interface #endif static volatile uint8_t twi_state; static volatile uint8_t twi_sendStop; // should the transaction end with a stop static volatile uint8_t twi_inRepStart; // in the middle of a repeated start static void (*twi_onSlaveTransmit)(void); static void (*twi_onSlaveReceive)(uint8_t*, int); static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_masterBufferIndex; static uint8_t twi_masterBufferLength; static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_txBufferIndex; static volatile uint8_t twi_txBufferLength; #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) \ || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B0__) static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_rxBufferIndex; #endif static volatile uint8_t twi_error; #if defined(__MSP430_HAS_USI__) static uint8_t twi_slarw; static uint8_t twi_my_addr; #endif #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__) #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) #define UCB0_BASE ((uint16_t)&UCB0CTLW0) #endif #if defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__) #define UCB1_BASE ((uint16_t)&UCB1CTLW0) #endif #define UCBxCTLW0 (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW0) - UCB0_BASE)))) #define UCBxCTLW1 (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW1) - UCB0_BASE)))) #define UCBxCTL0 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW0)+1- UCB0_BASE)))) #define UCBxCTL1 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW0) - UCB0_BASE)))) #define UCBxBRW (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BRW) - UCB0_BASE)))) #define UCBxBR0 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BRW) - UCB0_BASE)))) #define UCBxBR1 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BRW)+1 - UCB0_BASE)))) #define UCBxMCTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0MCTL) - UCB0_BASE)))) #define UCBxMCTLW (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0MCTLW) - UCB0_BASE)))) #define UCBxSTAT (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0STAT) - UCB0_BASE)))) #define UCBxTBCNT (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0TBCNT) - UCB0_BASE)))) #define UCBxRXBUF (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0RXBUF) - UCB0_BASE)))) #define UCBxTXBUF (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0TXBUF) - UCB0_BASE)))) #define UCBxABCTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ABCTL) - UCB0_BASE)))) #define UCBxIRCTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IRCTL) - UCB0_BASE)))) #define UCBxIRTCTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IRTCTL) - UCB0_BASE)))) #define UCBxIRRCTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IRRCTL0 - UCB0_BASE)))) #define UCBxICTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL) - UCB0_BASE)))) #define UCBxI2COA (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2COA) - UCB0_BASE)))) #define UCBxI2COA0 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2COA0) - UCB0_BASE)))) #define UCBxI2CSA (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CSA) - UCB0_BASE)))) #if defined(UCB0ICTL_) #define UCBxIE (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL) - UCB0_BASE)))) #define UCBxIFG (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL)+1 - UCB0_BASE)))) #else #define UCBxIE (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IE) - UCB0_BASE)))) #define UCBxIFG (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IFG) - UCB0_BASE)))) #endif #define UCBxI2CIE (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CIE) - UCB0_BASE)))) #define UCBxIV (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IV) - UCB0_BASE)))) #else // #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__) #if defined(__MSP430_HAS_USCI__) #define UCB0_BASE ((uint16_t)&UCB0CTL0) #define UCB1_BASE ((uint16_t)&UCB1CTL0) #define UCBxCTL0 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTL0) - UCB0_BASE)))) #define UCBxCTL1 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTL1) - UCB0_BASE)))) #define UCBxBR0 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BR0) - UCB0_BASE)))) #define UCBxBR1 (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BR1) - UCB0_BASE)))) //#define UCBxMCTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0MCT) - UCB0_BASE)))) #define UCBxSTAT (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0STAT) - UCB0_BASE)))) #define UCBxRXBUF (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0RXBUF) - UCB0_BASE)))) #define UCBxTXBUF (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0TXBUF) - UCB0_BASE)))) //#define UCBxICTL (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL) - UCB0_BASE)))) #define UCBxI2COA (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2COA) - UCB0_BASE)))) #define UCBxI2CSA (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CSA) - UCB0_BASE)))) #define UCxIE UC0IE #define UCBxI2CIE (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CIE) - UCB0_BASE)))) #define UCxIFG UC0IFG #if defined(UCB1RXIE) #define UCBxRXIE UCB0RXIE ? (I2C_baseAddress == UCB0_BASE) : UCB1RXIE #define UCBxRXIFG UCB0RXIFG ? (I2C_baseAddress == UCB0_BASE) : UCB1RXIFG #else #define UCBxRXIE UCB0RXIE #define UCBxRXIFG UCB0RXIFG #endif #if defined(UCB1TXIE) #define UCBxTXIE UCB0TXIE ? (I2C_baseAddress == UCB0_BASE) : UCB1TXIE #define UCBxTXIFG UCB0TXIFG ? (I2C_baseAddress == UCB0_BASE) : UCB1TXIFG #else #define UCBxTXIE UCB0TXIE #define UCBxTXIFG UCB0TXIFG #endif #endif //#if defined(__MSP430_HAS_USCI__) #endif // #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__) #if DEFAULT_I2C == -1 // SW I2C implementation on default port uint16_t I2C_baseAddress = -1; #endif #if DEFAULT_I2C == 0 uint16_t I2C_baseAddress = UCB0_BASE; #endif #if DEFAULT_I2C == 1 uint16_t I2C_baseAddress = UCB1_BASE; #endif /* * Function twi_setModule * Desc Selects the I2C module to use * Input Module instance * Output none */ void twi_setModule(uint8_t _i2cModule) { #if DEFAULT_I2C == -1 // SW I2C implementation on default port if (_i2cModule == -1) { I2C_baseAddress = -1; } #endif if (_i2cModule == 0) { #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) I2C_baseAddress = UCB0_BASE; #endif } if (_i2cModule == 1) { #if defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__) I2C_baseAddress = UCB1_BASE; #endif } } /* * Function twi_init_port * Desc initialises the port pins * Input none * Output none */ static void twi_init_port(void) { #if DEFAULT_I2C == -1 // SW I2C implementation on default port if (I2C_baseAddress == -1) { //pinMode_int(TWISDA1, TWISDA1_SET_MODE); //pinMode_int(TWISCL1, TWISCL1_SET_MODE); i2c_sw_init(); return; } #endif #if defined(__MSP430_HAS_USCI__) if (I2C_baseAddress == UCB0_BASE) { pinMode_int(TWISDA0, TWISDA0_SET_MODE); pinMode_int(TWISCL0, TWISCL0_SET_MODE); return; } #endif #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) if (I2C_baseAddress == UCB0_BASE) { /* Set pins to I2C mode */ pinMode_int(TWISDA0, INPUT_PULLUP); if (digitalRead(TWISDA0) == 0){ // toggle SCL if SDA is low at startup pinMode_int(TWISCL0, INPUT_PULLUP); digitalWrite(TWISCL0, LOW); pinMode(TWISCL0, OUTPUT); pinMode_int(TWISCL0, INPUT_PULLUP); } #if defined(__MSP430_HAS_USCI_B0__) if ((TWISDA0_SET_MODE & INPUT_PULLUP) == 0) { pinMode(TWISDA0, INPUT); // some device do not allow the pull up to be enabled pinMode(TWISCL0, INPUT); } #endif pinMode_int(TWISDA0, TWISDA0_SET_MODE); pinMode_int(TWISCL0, TWISCL0_SET_MODE); } #endif #if defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__) if (I2C_baseAddress == UCB1_BASE) { /* Set pins to I2C mode */ pinMode_int(TWISDA1, INPUT_PULLUP); if (digitalRead(TWISDA1) == 0){ // toggle SCL if SDA is low at startup pinMode_int(TWISCL1, INPUT_PULLUP); digitalWrite(TWISCL1, LOW); pinMode(TWISCL1, OUTPUT); pinMode_int(TWISCL1, INPUT_PULLUP); } #if defined(__MSP430_HAS_USCI_B1__) if ((TWISDA1_SET_MODE & INPUT_PULLUP) == 0) { pinMode(TWISDA1, INPUT); // some device do not allow the pull up to be enabled pinMode(TWISCL1, INPUT); } #endif pinMode_int(TWISDA1, TWISDA1_SET_MODE); pinMode_int(TWISCL1, TWISCL1_SET_MODE); } #endif } /* * Function twi_init * Desc readys twi pins and sets twi bitrate * Input none * Output none */ void twi_init(void) { // initialize state twi_state = TWI_IDLE; twi_sendStop = true; // default value twi_inRepStart = false; #if DEFAULT_I2C == -1 // SW I2C implementation on default port if (I2C_baseAddress == -1) { twi_init_port(); return; } #endif #if defined(__MSP430_HAS_USI__) /* 100 KHz for all */ #if (F_CPU >= 16000000L) || (F_CPU >= 12000000L) USICKCTL = USIDIV_7; #elif defined(CALBC1_8MHZ_) && (F_CPU >= 8000000L) USICKCTL = USIDIV_6; #elif defined(CALBC1_1MHZ_) && (F_CPU >= 1000000L) USICKCTL = USIDIV_3; #endif /* Enable USI I2C mode. */ USICTL1 = USII2C; /* SDA/SCL port enable and hold in reset */ USICTL0 = (USIPE6 | USIPE7 | USISWRST); /* SMCLK and SCL inactive state is high */ USICKCTL |= (USISSEL_2 | USICKPL); /* Disable automatic clear control */ USICNT |= USIIFGCC; /* Enable USI */ USICTL0 &= ~USISWRST; /* Counter interrupt enable */ USICTL1 |= USIIE; #endif #if defined(__MSP430_HAS_USCI__) \ || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) /* Calling this dummy function prevents the linker * from stripping the USCI interupt vectors.*/ usci_isr_install(); twi_init_port(); //Disable the USCI module and clears the other bits of control register UCBxCTL1 = UCSWRST; /* * Configure as I2C Slave. * UCMODE_3 = I2C mode * UCSYNC = Synchronous mode * UCCLK = SMCLK */ UCBxCTL0 = UCMODE_3 | UCSYNC; /* * Compute the clock divider that achieves less than or * equal to 100kHz. The numerator is biased to favor a larger * clock divider so that the resulting clock is always less than or equal * to the desired clock, never greater. */ UCBxBR0 = (unsigned char)((F_CPU / TWI_FREQ) & 0xFF); UCBxBR1 = (unsigned char)((F_CPU / TWI_FREQ) >> 8); UCBxCTL1 &= ~(UCSWRST); #if defined(__MSP430_HAS_USCI__) /* Set I2C state change interrupt mask */ UCBxI2CIE |= (UCALIE|UCNACKIE|UCSTTIE|UCSTPIE); /* Enable state change and TX/RX interrupts */ UCxIE |= UCBxRXIE | UCBxTXIE; #else /* Set I2C state change interrupt mask and TX/RX interrupts */ UCBxIE |= (UCALIE|UCNACKIE|UCSTTIE|UCSTPIE|UCRXIE|UCTXIE); #endif #endif #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__) twi_init_port(); //Disable the USCI module and clears the other bits of control register UCBxCTLW0 = UCSWRST; //Configure Automatic STOP condition generation UCBxCTLW1 &= ~UCASTP_3; /* * Configure as I2C master mode. * UCMODE_3 = I2C mode * UCSYNC = Synchronous mode (read/write 1 for eUSCI_B) * UCCLK = SMCLK */ UCBxCTLW0 = UCMODE_3 | UCSSEL__SMCLK | UCSYNC | UCSWRST; /* * Compute the clock divider that achieves the fastest speed less than or * equal to the desired speed. The numerator is biased to favor a larger * clock divider so that the resulting clock is always less than or equal * to the desired clock, never greater. */ UCBxBRW = (unsigned short)(F_CPU / 400000); UCBxCTLW0 &= ~(UCSWRST); UCBxIE |= (UCRXIE0|UCTXIE0|UCSTTIE|UCSTPIE); // Enable I2C interrupts #endif } /* * Function twi_setAddress * Desc sets slave address and enables interrupt * Input none * Output none */ void twi_setAddress(uint8_t address) { #if defined(__MSP430_HAS_USI__) twi_my_addr = address << 1; #endif #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) /* UCGCEN = respond to general Call */ UCBxI2COA = (address | UCGCEN); #endif #if defined(__MSP430_HAS_EUSCI_B0__) /* UCGCEN = respond to general Call */ UCBxI2COA0 = (address | UCOAEN | UCGCEN); #endif } /* * Function twi_readFrom * Desc attempts to become twi bus master and read a * series of bytes from a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes to read into array * Output number of bytes read */ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) { uint8_t i; #if (DEFAULT_I2C == -1) if (I2C_baseAddress == -1) { i2c_sw_read(address, length, data, sendStop); return length; } #endif #if defined(__MSP430_HAS_USI__) /* Disable START condition interrupt */ USICTL1 &= ~USISTTIE; /* I2C master mode */ USICTL0 |= USIMST; #endif #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) UCBxCTL1 = UCSWRST; // Enable SW reset UCBxCTL1 |= (UCSSEL_2); // I2C Master, synchronous mode UCBxCTL0 |= (UCMST | UCMODE_3 | UCSYNC); // I2C Master, synchronous mode UCBxCTL1 &= ~(UCTR); // Configure in receive mode UCBxI2CSA = address; // Set Slave Address UCBxCTL1 &= ~UCSWRST; // Clear SW reset, resume operation #if defined(__MSP430_HAS_USCI__) UCBxI2CIE |= (UCALIE|UCNACKIE|UCSTPIE); // Enable I2C interrupts UCxIE |= (UCBxRXIE | UCBxTXIE); // Enable I2C interrupts #else UCBxIE |= (UCALIE|UCNACKIE|UCSTPIE|UCRXIE|UCTXIE); // Enable I2C interrupts #endif #endif #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__) UCBxCTLW0 |= UCSWRST; // Enable SW reset UCBxCTLW0 |= (UCMST); // I2C Master, synchronous mode UCBxCTLW0 &= ~(UCTR); // Configure in receive mode UCBxI2CSA = address; // Set Slave Address UCBxTBCNT = length; // set number of bytes to transmit UCBxCTLW0 &= ~UCSWRST; // Clear SW reset, resume operation UCBxIE |= (UCRXIE0|UCALIE|UCNACKIE|UCSTTIE|UCSTPIE); // Enable I2C interrupts #endif // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 0; } // initialize buffer iteration vars twi_masterBufferIndex = 0; twi_masterBufferLength = length-1; // This is not intuitive, read on... // On receive, the previously configured ACK/NACK setting is transmitted in // response to the received byte before the interrupt is signalled. // Therefor we must actually set NACK when the _next_ to last byte is // received, causing that NACK to be sent in response to receiving the last // expected byte of data. #if defined(__MSP430_HAS_USI__) /* build sla+w, slave device address + w bit */ twi_slarw = 1; twi_slarw |= address << 1; // send start condition twi_state = TWI_SND_START; // this will trigger an interrupt kicking off the state machine in the isr USICTL1 |= USIIFG; #endif #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) twi_state = TWI_MRX; // Master receive mode UCBxCTL1 |= UCTXSTT; // I2C start condition if(length == 1) { // When only receiving 1 byte.. while(UCBxCTL1 & UCTXSTT); // Wait for start bit to be sent UCBxCTL1 |= UCTXSTP; // Send I2C stop condition after recv } #endif #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__) twi_state = TWI_MRX; // Master receive mode //while (UCBxCTLW0 & UCTXSTP); // Ensure stop condition got sent UCBxCTLW0 |= UCTXSTT; // I2C start condition #endif /* Wait in low power mode for read operation to complete */ while(twi_state != TWI_IDLE){ __bis_SR_register(LPM0_bits); } if (twi_masterBufferIndex < length) length = twi_masterBufferIndex; for(i = 0; i < length; ++i){ data[i] = twi_masterBuffer[i]; } #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) /* Ensure stop condition got sent before we exit. */ while (UCBxCTL1 & UCTXSTP); #endif return length; } /* * Function twi_writeTo * Desc attempts to become twi bus master and write a * series of bytes to a device on the bus * Input address: 7bit i2c device address * data: pointer to byte array * length: number of bytes in array * wait: boolean indicating to wait for write or not * Output 0 .. success * 1 .. length to long for buffer * 2 .. address send, NACK received * 3 .. data send, NACK received * 4 .. other twi error (lost bus arbitration, bus error, ..) */ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) { uint8_t i; twi_error = TWI_ERRROR_NO_ERROR; twi_sendStop = sendStop; #if (DEFAULT_I2C == -1) if (I2C_baseAddress == -1) { return (i2c_sw_write(address, length, data, sendStop)); } #endif #if defined(__MSP430_HAS_USI__) /* Disable START condition interrupt */ USICTL1 &= ~USISTTIE; /* I2C master mode */ USICTL0 |= USIMST; #endif #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) UCBxCTL1 = UCSWRST; // Enable SW reset UCBxCTL1 |= UCSSEL_2; // SMCLK UCBxCTL0 |= (UCMST | UCMODE_3 | UCSYNC); // I2C Master, synchronous mode UCBxCTL1 |= UCTR; // Configure in transmit mode UCBxI2CSA = address; // Set Slave Address UCBxCTL1 &= ~UCSWRST; // Clear SW reset, resume operation #if defined(__MSP430_HAS_USCI__) UCBxI2CIE |= (UCALIE|UCNACKIE|UCSTPIE); // Enable I2C interrupts UCxIE |= UCBxTXIE; // Enable I2C interrupts #else UCBxIE |= (UCALIE|UCNACKIE|UCSTPIE|UCTXIE); // Enable I2C interrupts #endif #endif #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__) UCBxCTLW0 |= UCSWRST; // Enable SW reset UCBxCTLW0 |= (UCMST | UCTR); // I2C Master, transmit mode UCBxI2CSA = address; // Set Slave Address UCBxTBCNT = length; // set number of bytes to transmit if((sendStop) && (length > 0)) { UCBxCTLW1 |= UCASTP_2; // do generate Stop after last Byte to send } else { UCBxCTLW1 &= ~UCASTP_2; // do not generate Stop } UCBxCTLW0 &= ~UCSWRST; // Clear SW reset, resume operation UCBxIE |= (UCRXIE|UCTXIE0|UCALIE|UCNACKIE|UCSTPIE); // Enable I2C interrupts #endif /* Ensure data will fit into buffer */ if(length > TWI_BUFFER_LENGTH){ return TWI_ERROR_BUF_TO_LONG; } /* initialize buffer iteration vars */ twi_masterBufferIndex = 0; twi_masterBufferLength = length; for(i = 0; i < length; ++i){ twi_masterBuffer[i] = data[i]; } #if defined(__MSP430_HAS_USI__) /* build sla+w, slave device address + w bit */ twi_slarw = 0; twi_slarw |= address << 1; twi_state = TWI_SND_START; /* This will trigger an interrupt kicking off the state machine in the isr */ USICTL1 |= USIIFG; #endif #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) twi_state = TWI_MTX; // Master Transmit mode UCBxCTL1 |= UCTXSTT; // I2C start condition #endif #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__) twi_state = TWI_MTX; // Master Transmit mode //while (UCBxCTLW0 & UCTXSTP); // Ensure stop condition got sent UCBxCTLW0 |= UCTXSTT; // I2C start condition #endif /* Wait for the transaction to complete */ while(twi_state != TWI_IDLE) { __bis_SR_register(LPM0_bits); } #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) /* Ensure stop/start condition got sent before we exit. */ if(sendStop) { while (UCBxCTL1 & UCTXSTP); // end with stop condition } else { while (UCBxCTL1 & UCTXSTT); // end with (re)start condition } #endif return twi_error; } /* * Function twi_transmit * Desc fills slave tx buffer with data * must be called in slave tx event callback * Input data: pointer to byte array * length: number of bytes in array * Output 1 length too long for buffer * 2 not slave transmitter * 0 ok */ uint8_t twi_transmit(const uint8_t* data, uint8_t length) { uint8_t i; twi_state = TWI_STX; // Slave transmit mode // ensure data will fit into buffer if(TWI_BUFFER_LENGTH < length){ return 1; } // set length and copy data into tx buffer twi_txBufferLength = length; for(i = 0; i < length; ++i){ twi_txBuffer[i] = data[i]; } return 0; } /* * Function twi_attachSlaveRxEvent * Desc sets function called before a slave read operation * Input function: callback function to use * Output none */ void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) { twi_onSlaveReceive = function; } /* * Function twi_attachSlaveTxEvent * Desc sets function called before a slave write operation * Input function: callback function to use * Output none */ void twi_attachSlaveTxEvent( void (*function)(void) ) { twi_onSlaveTransmit = function; } #if defined(__MSP430_HAS_USI__) void send_start() { USISRL = 0x00; USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; USISRL = twi_slarw; USICNT = (USICNT & 0xE0) + 0x08; } #endif #if defined(__MSP430_HAS_USI__) __attribute__((interrupt(USI_VECTOR))) void USI_ISR(void) { if (!(USICTL0 & USIMST) && (USICTL1 & USISTTIFG)) { twi_state = TWI_SL_START; } switch(twi_state){ /* Master transmit / receive */ case TWI_SND_START: send_start(); twi_state = TWI_PREP_SLA_ADDR_ACK; break; case TWI_PREP_SLA_ADDR_ACK: // reveive (N)ACK USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1 twi_state = TWI_MT_PROC_ADDR_ACK; break; case TWI_MT_PROC_ADDR_ACK: if (USISRL & 0x01) { twi_error = TWI_ERROR_ADDR_NACK; USICTL0 |= USIOE; USISRL = 0x00; USICNT |= 0x01; twi_state = TWI_EXIT; break; } if(twi_slarw & 1) goto mtre; else goto mtpd; break; /* Prepare to receive data (N)ACK */ case TWI_MT_PREP_DATA_ACK: /* SDA = input */ USICTL0 &= ~USIOE; /* Bit counter = 1 */ USICNT |= 0x01; twi_state = TWI_MT_PROC_DATA_ACK; break; case TWI_MT_PROC_DATA_ACK: mtpd: if (USISRL & 0x01) { twi_error = TWI_ERROR_DATA_NACK; USICTL0 |= USIOE; USISRL = 0x00; USICNT |= 0x01; twi_state = TWI_EXIT; break; } if(twi_masterBufferIndex == twi_masterBufferLength) { USICTL0 |= USIOE; USISRL = 0x00; USICNT |= 0x01; twi_state = TWI_EXIT; break; } USICTL0 |= USIOE; USISRL = twi_masterBuffer[twi_masterBufferIndex++]; USICNT |= 0x08; twi_state = TWI_MT_PREP_DATA_ACK; break; // Master receiver mtre: case TWI_MR_PREP_DATA_RECV: /* SDA input */ USICTL0 &= ~USIOE; /* bit counter = 8 */ USICNT |= 0x08; twi_state = TWI_MR_PROC_DATA_RECV; break; case TWI_MR_PROC_DATA_RECV: /* SDA output */ USICTL0 |= USIOE; twi_masterBuffer[twi_masterBufferIndex++] = USISRL; if(twi_masterBufferIndex > twi_masterBufferLength ) { USISRL = 0xFF; // that was the last byte send NACK twi_state = TWI_MR_PREP_STOP; } else { USISRL = 0x00; // keep on receiving and send ACK twi_state = TWI_MR_PREP_DATA_RECV; } USICNT |= 0x01; break; case TWI_MR_PREP_STOP: USICTL0 |= USIOE; USISRL = 0x00; USICNT |= 0x01; twi_state = TWI_EXIT; break; /* All */ case TWI_EXIT: /* Load FF into output shift register */ USISRL = 0x0FF; /* Output latch transparant. MSB of USISR to the SDO pin. */ USICTL0 |= USIGE; /* Latch disabled and make SDA input */ USICTL0 &= ~(USIGE+USIOE); twi_state = TWI_IDLE; break; case TWI_IDLE: /* Nothing to do. Fall thru and clear interrupt flag. */ default: break; } /* Clear counter interrupt */ USICTL1 &= ~USIIFG; } #endif /* __MSP430_HAS_USI__ */ #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__) uint16_t i2c_txrx_isr(void) // RX/TX Service { uint16_t stay_active = false; /* USCI I2C mode. USCI_B0 receive interrupt flag. * UCBxRXIFG is set when UCBxRXBUF has received a complete character. */ #if defined(__MSP430_HAS_USCI__) if (UCxIFG & UCBxRXIFG){ #else if (UCBxIFG & UCRXIFG){ #endif /* Master receive mode. */ if (twi_state == TWI_MRX) { twi_masterBuffer[twi_masterBufferIndex++] = UCBxRXBUF; if(twi_masterBufferIndex == twi_masterBufferLength ) /* Only one byte left. Generate STOP condition. * In master mode a STOP is preceded by a NACK */ UCBxCTL1 |= UCTXSTP; if(twi_masterBufferIndex > twi_masterBufferLength ) { /* All bytes received. We are idle*/ stay_active = true; twi_state = TWI_IDLE; } /* Slave receive mode. (twi_state = TWI_SRX) */ } else { // if there is still room in the rx buffer if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ // put byte in buffer and ack twi_rxBuffer[twi_rxBufferIndex++] = UCBxRXBUF; } else { // otherwise nack UCBxCTL1 |= UCTXNACK; // Generate NACK condition } } } /* USCI I2C mode. USCI_Bx transmit interrupt flag. * UCBxTXIFG is set when UCBxTXBUF is empty.*/ #if defined(__MSP430_HAS_USCI__) if (UCxIFG & UCBxTXIFG){ #else if (UCBxIFG & UCTXIFG){ #endif /* Master transmit mode */ if (twi_state == TWI_MTX) { // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // Copy data to output register and ack. UCBxTXBUF = twi_masterBuffer[twi_masterBufferIndex++]; } else { if (twi_sendStop) { /* All done. Generate STOP condition and IDLE */ UCBxCTL1 |= UCTXSTP; } else { twi_inRepStart = true; // we're gonna send the START // don't enable the interrupt. We'll generate the start, but we // avoid handling the interrupt until we're in the next transaction, // at the point where we would normally issue the start. UCBxCTL1 |= UCTXSTT; } twi_state = TWI_IDLE; stay_active = true; } /* Slave transmit mode (twi_state = TWI_STX) */ } else { // copy data to output register UCBxTXBUF = twi_txBuffer[twi_txBufferIndex++]; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ } else { UCBxCTL1 |= UCTXNACK; // Generate NACK condition } } } return(stay_active); } uint16_t i2c_state_isr(void) // I2C Service { uint16_t stay_active = false; /* Arbitration lost interrupt flag */ #if defined(__MSP430_HAS_USCI__) if (UCBxSTAT & UCALIFG) { UCBxSTAT &= ~UCALIFG; #else if (UCBxIFG & UCALIFG) { UCBxIFG &= ~UCALIFG; #endif /* TODO: Handle bus arbitration lost */ } /* Not-acknowledge received interrupt flag. * UCNACKIFG is automatically cleared when a START condition is received.*/ #if defined(__MSP430_HAS_USCI__) if (UCBxSTAT & UCNACKIFG) { UCBxSTAT &= ~UCNACKIFG; #else if (UCBxIFG & UCNACKIFG) { UCBxIFG &= ~UCNACKIFG; #endif ////UCBxCTL1 |= UCTXSTP; /* TODO: This can just as well be an address NACK. * Figure out a way to distinguish between ANACK and DNACK */ if (twi_masterBufferIndex == 0) twi_error = TWI_ERROR_ADDR_NACK; else twi_error = TWI_ERROR_DATA_NACK; //twi_state = TWI_IDLE; //stay_active = true; } /* Start condition interrupt flag. * UCSTTIFG is automatically cleared if a STOP condition is received. */ #if defined(__MSP430_HAS_USCI__) if (UCBxSTAT & UCSTTIFG) { UCBxSTAT &= ~UCSTTIFG; #else if (UCBxIFG & UCSTTIFG) { UCBxIFG &= ~UCSTTIFG; #endif /* UCTR is automagically set by the USCI module upon a START condition. */ if (UCBxCTL1 & UCTR) { /* Slave TX mode. */ twi_state = TWI_STX; /* Ready the tx buffer index for iteration. */ twi_txBufferIndex = 0; /* Set tx buffer length to be zero, to verify if user changes it. */ twi_txBufferLength = 0; /* Request for txBuffer to be filled and length to be set. */ /* note: user must call twi_transmit(bytes, length) to do this */ twi_onSlaveTransmit(); /* If they didn't change buffer & length, initialize it * TODO: Is this right? Shouldn't we reply with a NACK if there is no data to send? */ if (0 == twi_txBufferLength) { twi_txBufferLength = 1; twi_txBuffer[0] = 0x00; } } else { /* Slave receive mode. */ twi_state = TWI_SRX; /* Indicate that rx buffer can be overwritten and ACK */ twi_rxBufferIndex = 0; } } /* Stop condition interrupt flag. * UCSTPIFG is automatically cleared when a STOP condition is received. */ #if defined(__MSP430_HAS_USCI__) if (UCBxSTAT & UCSTPIFG) { UCBxSTAT &= ~UCSTPIFG; #else if (UCBxIFG & UCSTPIFG) { UCBxIFG &= ~UCSTPIFG; #endif if (twi_state == TWI_SRX) { /* Callback to user defined callback */ twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); } twi_state = TWI_IDLE; stay_active = true; } return(stay_active); } #endif #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__) uint16_t eusci_isr_handler(void) { uint16_t exit_lpm = 0; // switch(twi_state){ switch(UCBxIV){ case USCI_NONE: // No Interrupt pending break; case USCI_I2C_UCALIFG: // USCI I2C Mode: UCALIFG // enter slave transmitter mode twi_state = TWI_STX; // ready the tx buffer index for iteration twi_txBufferIndex = 0; // set tx buffer length to be zero, to verify if user changes it twi_txBufferLength = 0; // request for txBuffer to be filled and length to be set // note: user must call twi_transmit(bytes, length) to do this twi_onSlaveTransmit(); // if they didn't change buffer & length, initialize it if(0 == twi_txBufferLength){ twi_txBufferLength = 1; twi_txBuffer[0] = 0x00; } // transmit first byte from buffer, fall // copy data to output register UCBxTXBUF = twi_txBuffer[twi_txBufferIndex++]; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ //twi_reply(1); } else { UCBxCTLW0 |= UCTXNACK; // Generate NACK condition } // leave slave receiver state twi_state = TWI_IDLE; break; case USCI_I2C_UCNACKIFG: // USCI I2C Mode: UCNACKIFG if (twi_masterBufferIndex == 0) // when no data, we received the address twi_error = TWI_ERROR_ADDR_NACK; else twi_error = TWI_ERROR_DATA_NACK; // leave slave receiver state twi_state = TWI_IDLE; if (UCBxTBCNT == 0) UCBxCTLW0 |= UCTXSTP; // Generate I2C stop condition manually exit_lpm = 1; //__bic_SR_register_on_exit(LPM4_bits); // Exit LPM break; case USCI_I2C_UCSTTIFG: // USCI I2C Mode: UCSTTIFG UCBxIFG &= ~UCSTTIFG; if (twi_state == TWI_IDLE){ if (UCBxCTLW0 & UCTR){ twi_state = TWI_STX; // Slave Transmit mode // ready the tx buffer index for iteration twi_txBufferIndex = 0; // set tx buffer length to be zero, to verify if user changes it twi_txBufferLength = 0; // request for txBuffer to be filled and length to be set // note: user must call twi_transmit(bytes, length) to do this twi_onSlaveTransmit(); // if they didn't change buffer & length, initialize it if(0 == twi_txBufferLength){ twi_txBufferLength = 1; twi_txBuffer[0] = 0x00; } } else { twi_state = TWI_SRX; // Slave receive mode // indicate that rx buffer can be overwritten and ack twi_rxBufferIndex = 0; } } break; case USCI_I2C_UCSTPIFG: // USCI I2C Mode: UCSTPIFG //UCBxIFG &= ~UCSTPIFG; if (twi_state == TWI_SRX){ // callback to user defined callback twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); } twi_state = TWI_IDLE; // IDLE mode /* Work around for: * If the master does a read and then a write the START interrupt occurs * but the RX interrupt never fires. Clearing bit 4 and 5 of UCBxCTLW0 solves this. * bit 4 and 5 are however marked as reserved in the datasheet. */ UCBxCTLW0 &= ~0x18; exit_lpm = 1; //__bic_SR_register_on_exit(LPM4_bits); // Exit LPM break; case USCI_I2C_UCRXIFG3: // USCI I2C Mode: UCRXIFG3 break; case USCI_I2C_UCTXIFG3: // USCI I2C Mode: UCTXIFG3 break; case USCI_I2C_UCRXIFG2: // USCI I2C Mode: UCRXIFG2 break; case USCI_I2C_UCTXIFG2: // USCI I2C Mode: UCTXIFG2 break; case USCI_I2C_UCRXIFG1: // USCI I2C Mode: UCRXIFG1 break; case USCI_I2C_UCTXIFG1: // USCI I2C Mode: UCTXIFG1 break; case USCI_I2C_UCRXIFG0: // USCI I2C Mode: UCRXIFG0 //UCBxIFG &= ~UCRXIFG; // Clear USCI_B0 TX int flag if (twi_state == TWI_MRX) { // Master receive mode twi_masterBuffer[twi_masterBufferIndex++] = UCBxRXBUF; // Get RX data if(twi_masterBufferIndex == twi_masterBufferLength ) UCBxCTLW0 |= UCTXSTP; // Generate I2C stop condition if(twi_masterBufferIndex > twi_masterBufferLength ) { twi_state = TWI_IDLE; //Idle } else { } } else { // if there is still room in the rx buffer if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ // put byte in buffer and ack twi_rxBuffer[twi_rxBufferIndex++] = UCBxRXBUF; } else { // otherwise nack UCBxCTLW0 |= UCTXNACK; // Generate NACK condition } } break; case USCI_I2C_UCTXIFG0: // USCI I2C Mode: UCTXIFG0 //UCBxIFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag if (twi_state == TWI_MTX) { // Master transmit mode // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // copy data to output register and ack UCBxTXBUF = twi_masterBuffer[twi_masterBufferIndex++]; // Transmit data at address PTxData }else{ if (twi_sendStop) { if (UCBxTBCNT == 0) UCBxCTLW0 |= UCTXSTP; // Generate I2C stop condition manually } else { twi_inRepStart = true; // we're gonna send the START // don't enable the interrupt. We'll generate the start, but we // avoid handling the interrupt until we're in the next transaction, // at the point where we would normally issue the start. UCBxCTLW0 |= UCTXSTT; twi_state = TWI_IDLE; exit_lpm = 1; //__bic_SR_register_on_exit(LPM4_bits); // Exit LPM } } } else if (twi_state == TWI_MRX) { // Master receive mode // copy data to output register UCBxTXBUF = twi_txBuffer[twi_txBufferIndex++]; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ } else { UCBxCTLW0 |= UCTXNACK; // Generate NACK condition } } break; case USCI_I2C_UCBCNTIFG: // USCI I2C Mode: UCBCNTIFG break; case USCI_I2C_UCCLTOIFG: // USCI I2C Mode: UCCLTOIFG/ break; case USCI_I2C_UCBIT9IFG: // USCI I2C Mode: UCBIT9IFG break; } return (exit_lpm); } #if defined(__MSP430_HAS_EUSCI_B0__) __attribute__((interrupt(USCI_B0_VECTOR))) void USCI_B0_ISR(void) { if (eusci_isr_handler()) __bic_SR_register_on_exit(LPM4_bits); // Exit LPM } #endif #if defined(__MSP430_HAS_EUSCI_B1__) __attribute__((interrupt(USCI_B1_VECTOR))) void USCI_B1_ISR(void) { if (eusci_isr_handler()) __bic_SR_register_on_exit(LPM4_bits); // Exit LPM } #endif #endif // #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
/* ************************************************************************ * twi_sw.c * * twi software files for MSP430 * Copyright (c) 2015 StefanSch. All right reserved. * * V1.1 : updates to correct SCL and SDA assignments * support of connected device scan with return values defined in twi.h * *********************************************************************** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "twi_sw.h" #include "twi.h" #if DEFAULT_I2C == -1 /* indicates SW I2C on pseudo module 1 */ #define I2C_DELAY1() __delay_cycles(F_CPU / 1000000UL * 10) #define I2C_DELAY2() __delay_cycles(F_CPU / 1000000UL * 20) #define I2C_READ BIT0 #define I2C_WRITE 0 uint8_t i2c_sw_start(uint8_t address, uint8_t rw); uint8_t i2c_sw_txByte(uint8_t data); void i2c_sw_ack(void); uint8_t i2c_sw_rxByte(uint8_t lastChar); void i2c_sw_stop(void); void i2c_sw_init(void) { digitalWrite(TWISDA, LOW); digitalWrite(TWISCL, LOW); pinMode(TWISDA, INPUT); pinMode(TWISCL, INPUT); } uint8_t i2c_sw_read(uint8_t slaveAddress, uint16_t numBytes, uint8_t* data, uint8_t sendStop) { uint16_t i; uint8_t ack_error; ack_error = i2c_sw_start(slaveAddress, I2C_READ); // Send Start condition // [ADDR] + R/W bit = 1 if (ack_error) return (ack_error); for (i = 0; i < numBytes-1; i++) { *data++ = i2c_sw_rxByte(0); // Read data } *data++ = i2c_sw_rxByte(1); // Read last data if (sendStop) i2c_sw_stop(); // Send Stop condition return (0); } uint8_t i2c_sw_write(uint8_t slaveAddress, uint16_t numBytes, uint8_t* data, uint8_t sendStop) { uint16_t i; uint8_t status; status = i2c_sw_start(slaveAddress, I2C_WRITE); // Send Start condition // [ADDR] + R/W bit = 0 if (status) { i2c_sw_stop(); // Send Stop condition return (TWI_ERROR_ADDR_NACK); } for (i = 0; i < numBytes; i++) { status |= i2c_sw_txByte(*data++); // Send data and ack } if (sendStop) i2c_sw_stop(); // Send Stop condition if (status) return (TWI_ERROR_DATA_NACK); return (status); } uint8_t i2c_sw_start(uint8_t address, uint8_t rw) // Set up start condition for I2C { pinMode(TWISDA, OUTPUT); I2C_DELAY2(); // delay pinMode(TWISCL, OUTPUT); I2C_DELAY2(); // delay return(i2c_sw_txByte((address << 1) | rw)); // [ADDR] + R/W bit } uint8_t i2c_sw_txByte(uint8_t data) { uint8_t bits = 0x08; uint8_t ack_error; while (bits != 0x00) // Loop until all bits are shifted { if (data & BIT7) // Test data bit pinMode(TWISDA, INPUT); else pinMode(TWISDA, OUTPUT); I2C_DELAY2(); pinMode(TWISCL, INPUT); data <<= 1; // Shift bits 1 place to the left I2C_DELAY1(); // Quick delay pinMode(TWISCL, OUTPUT); bits--; // Loop until 8 bits are sent } pinMode(TWISDA, INPUT); // Get acknowledge I2C_DELAY2(); pinMode(TWISCL, INPUT); I2C_DELAY2(); ack_error = digitalRead(TWISDA); pinMode(TWISCL, OUTPUT); return (ack_error); } void i2c_sw_ack(void) // Check for I2C acknowledge { I2C_DELAY2(); pinMode(TWISCL, INPUT); I2C_DELAY2(); pinMode(TWISCL, OUTPUT); } uint8_t i2c_sw_rxByte(uint8_t lastChar) // Read 8 bits of I2C data { uint8_t bits = 0x08; uint8_t data = 0; pinMode(TWISDA, INPUT); I2C_DELAY1(); while (bits > 0) // Loop until all bits are read { pinMode(TWISCL, INPUT); I2C_DELAY1(); data <<= 1; // Shift bits 1 place to the left if (digitalRead(TWISDA)) // Check digital input data |= 1; // If input is 'H' store a '1' pinMode(TWISCL, OUTPUT); I2C_DELAY1(); bits--; // Decrement I2C bit counter } if (lastChar == 0) pinMode(TWISDA, OUTPUT); // Set acknowledge I2C_DELAY1(); pinMode(TWISCL, INPUT); I2C_DELAY1(); pinMode(TWISCL, OUTPUT); I2C_DELAY1(); return (data); // Return 8-bit data byte } void i2c_sw_stop(void) // Send I2C stop command { pinMode(TWISDA, OUTPUT); I2C_DELAY2(); pinMode(TWISCL, INPUT); I2C_DELAY2(); pinMode(TWISDA, INPUT); I2C_DELAY2(); } #endif // #if DEFAULT_I2C = -1 /* indicates SW I2C on pseudo module 1 */
The stars have aligned !!! It works like a charm now !!! Life are GROOVY !!! Thanks a bunch Robert !!
Well, we've changed chips over to the MSP430G2553IRHB32R. It's got 32 pins and ses pins 21 and 22 for I2C_SCL and I2C_SDA respectively. This is a QFN package.
My problem is that I cannot get I2C to work with this chip. I've tried all of the above, but am using version 18 of energia. I've replaced the pins_energia.h with the following and still cannot seem to get any response from my I2C devices. Do you have any suggestions or recommendations?
/*
************************************************************************
* pins_energia.h
*
* Energia core files for MSP430
* Copyright (c) 2012 Robert Wessels. All right reserved.
*
* Contribution: Rei VILO
*
***********************************************************************
Derived from:
pins_arduino.h - Pin definition functions for Arduino
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2007 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
#define __MSP430_HAS_PORT3_R__
//#define IOT_SENSOR_NODE
#ifndef Pins_Energia_h
#define Pins_Energia_h
#ifndef BV
#define BV(x) (1 << (x))
#endif
#if defined(__MSP430_HAS_USCI__)
static const uint8_t SS = 16; /* P2.4 */
static const uint8_t SCK = 5; /* P1.5 */
static const uint8_t MOSI = 22; /* P1.7 */
static const uint8_t MISO = 21; /* P1.6 */
static const uint8_t TWISDA = 22; /* P1.6 */
static const uint8_t TWISCL = 21; /* P1.7 */
static const uint8_t TWISCL1 = 11; /* P2.1 SW I2C */
static const uint8_t TWISDA1 = 12; /* P2.2 SW I2C */
static const uint8_t TWISDA0 = 23; /* P1.7 */
static const uint8_t TWISCL0 = 22; /* P1.6 */
static const uint8_t DEBUG_UARTRXD = 1; /* Receive Data (RXD) at P1.1 */
static const uint8_t DEBUG_UARTTXD = 2; /* Transmit Data (TXD) at P1.2 */
#define TWISDA1_SET_MODE (INPUT)
#define TWISCL1_SET_MODE (INPUT)
#define TWISDA0_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/) /* do not enable the pull ups for this device */
#define TWISCL0_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/)
#define TWISDA_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/) /* do not enable the pull ups for this device */
#define TWISCL_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/)
#define DEBUG_UARTRXD_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 | INPUT)
#define DEBUG_UARTTXD_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 | OUTPUT)
#define SPISCK_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1)
#define SPIMOSI_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1)
#define SPIMISO_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1)
#endif
#define DEBUG_UART_MODULE_OFFSET 0x0
#if defined(__MSP430_HAS_USI__)
static const uint8_t SS = 16; /* P2.4 */
static const uint8_t SCK = 5; /* P1.5 */
static const uint8_t MOSI = 22; /* P1.7 */
static const uint8_t MISO = 21; /* P1.6 */
static const uint8_t TWISDA = 22; /* P1.6 */
static const uint8_t TWISCL = 21; /* P1.7 */
static const uint8_t DEBUG_UARTRXD = 1; /* Receive Data (RXD) at P1.1 */
static const uint8_t DEBUG_UARTTXD = 2; /* Transmit Data (TXD) at P1.2 */
#define TWISDA_SET_MODE (PORT_SELECTION0 | INPUT_PULLUP)
#define TWISCL_SET_MODE (PORT_SELECTION0 | INPUT_PULLUP)
#define DEBUG_UARTRXD_SET_MODE (PORT_SELECTION0 | INPUT)
#define DEBUG_UARTTXD_SET_MODE (PORT_SELECTION0 | OUTPUT)
#endif
#define DEBUG_UART_MODULE 0x0
static const uint8_t A0 = 31;
static const uint8_t A1 = 1;
static const uint8_t A2 = 2;
static const uint8_t A3 = 3;
static const uint8_t A4 = 4;
static const uint8_t A5 = 5;
static const uint8_t A6 = 21;
static const uint8_t A7 = 22;
static const uint8_t A10 = 128 + 10; // special. This is the internal temp sensor
// +-+-+-+-+-+-+-+-+-+
// VCC 1| |20 GND
// (A0) P1.0 2| |19 XIN
// (A1) P1.1 3| |18 XOUT
// (A2) P1.2 4| |17 TEST
// (A3) P1.3 5| |16 RST#
// (A4) P1.4 6| |15 P1.7 (A7) (SCL) (MISO) depends on chip
// (A5) P1.5 7| |14 P1.6 (A6) (SDA) (MOSI)
// P2.0 8| |13 P2.5
// P2.1 9| |12 P2.4
// P2.2 10| |11 P2.3
// +-+-+-+-+-+-+-+-+-+
//
// Pin names based on the silkscreen
//
static const uint8_t P1_1 = 1;
static const uint8_t P1_2 = 2;
static const uint8_t P1_3 = 3;
static const uint8_t P1_4 = 4;
static const uint8_t P1_5 = 5;
static const uint8_t P3_1 = 6;
static const uint8_t P3_0 = 7;
static const uint8_t P2_0 = 9;
static const uint8_t P2_1 = 10;
static const uint8_t P2_2 = 11;
static const uint8_t P3_2 = 12;
static const uint8_t P3_3 = 13;
static const uint8_t P3_4 = 14;
static const uint8_t P2_3 = 15;
static const uint8_t P2_4 = 16;
static const uint8_t P2_5 = 17;
static const uint8_t P3_5 = 18;
static const uint8_t P3_6 = 19;
static const uint8_t P3_7 = 20;
static const uint8_t P1_6 = 21;
static const uint8_t P1_7 = 22;
static const uint8_t P2_7 = 25;
static const uint8_t P2_6 = 26;
static const uint8_t P1_0 = 31;
static const uint8_t RED_LED = 25;
static const uint8_t GREEN_LED = 26;
#define PIN_MOSI P1_7
#define PIN_MISO P1_6
#define PIN_CLK P1_5
#define PIN_CE P3_5
#define PIN_nCS P3_6
#define PIN_IRQ P2_5
#define PIN_SCL P1_6
#define PIN_SDA P1_7
#define BATTERY_ADC A0
static const uint8_t TEMPSENSOR = 10; // depends on chip
#ifdef ARDUINO_MAIN
const uint16_t port_to_input[] = {
NOT_A_PORT,
(uint16_t) &P1IN,
(uint16_t) &P2IN,
#ifdef __MSP430_HAS_PORT3_R__
(uint16_t) &P3IN,
#endif
};
const uint16_t port_to_output[] = {
NOT_A_PORT,
(uint16_t) &P1OUT,
(uint16_t) &P2OUT,
#ifdef __MSP430_HAS_PORT3_R__
(uint16_t) &P3OUT,
#endif
};
const uint16_t port_to_dir[] = {
NOT_A_PORT,
(uint16_t) &P1DIR,
(uint16_t) &P2DIR,
#ifdef __MSP430_HAS_PORT3_R__
(uint16_t) &P3DIR,
#endif
};
const uint16_t port_to_ren[] = {
NOT_A_PORT,
(uint16_t) &P1REN,
(uint16_t) &P2REN,
#ifdef __MSP430_HAS_PORT3_R__
(uint16_t) &P3REN,
#endif
};
const uint16_t port_to_sel0[] = { /* put this PxSEL register under the group of PxSEL0 */
NOT_A_PORT,
(uint16_t) &P1SEL,
(uint16_t) &P2SEL,
#ifdef __MSP430_HAS_PORT3_R__
(uint16_t) &P3SEL,
#endif
};
const uint16_t port_to_sel2[] = {
NOT_A_PORT,
#ifdef P1SEL2_
(uint16_t) &P1SEL2,
#else
NOT_A_PORT,
#endif
#ifdef P2SEL2_
(uint16_t) &P2SEL2,
#else
NOT_A_PORT,
#endif
#ifdef P3SEL2_
(uint16_t) &P3SEL2,
#else
NOT_A_PORT,
#endif
};
/*
* Defines for devices with 2x TA3 timers (e.g. MSP430g2553). On the 20pin devices, upto 3 analog outputs are available
* T0A1, T1A1 and T1A2
*/
const uint8_t digital_pin_to_timer[] = {
NOT_ON_TIMER, /* dummy */
NOT_ON_TIMER, /* 1 - VCC */
NOT_ON_TIMER, /* 2 - P1.0 */
T0A0, /* 3 - P1.1, note: A0 output cannot be used with analogWrite */
T0A1, /* 4 - P1.2 */
NOT_ON_TIMER, /* 5 - P1.3 */
NOT_ON_TIMER, /* 6 - P1.4 note: special case. Leaving as no timer due to difficulty determining if available */
T0A0, /* 7 - P1.5 note: A0 output cannot be used with analogWrite */
#if defined(__MSP430_HAS_T1A3__)
T1A0, /* 8 - P2.0 note: A0 output cannot be used with analogWrite */
T1A1, /* 9 - P2.1 */
T1A1, /* 10 - P2.2 */
T1A0, /* 11 - P2.3 note: A0 output cannot be used with analogWrite */
T1A2, /* 12 - P2.4 */
T1A2, /* 13 - P2.5 */
#else
NOT_ON_TIMER, /* 8 - P2.0 */
NOT_ON_TIMER, /* 9 - P2.1 */
NOT_ON_TIMER, /* 10 - P2.3 */
NOT_ON_TIMER, /* 11 - P2.4 */
NOT_ON_TIMER, /* 12 - P2.5 */
NOT_ON_TIMER, /* 13 - P2.6 */
#endif
T0A1, /* 14 - P1.6 */
NOT_ON_TIMER, /* 15 - P1.7 */
NOT_ON_TIMER, /* 16 - /RESET */
NOT_ON_TIMER, /* 17 - TEST */
NOT_ON_TIMER, /* 18 - XOUT - P2.7 */
T0A1, /* 19 - XIN - P2.6: */
NOT_ON_TIMER, /* 20 - GND */
};
const uint8_t digital_pin_to_port[] = {
NOT_A_PIN, /* dummy */
P1, /* 1 */
P1, /* 2 */
P1, /* 3 */
P1, /* 4 */
P1, /* 5 */
P3, /* 6 */
P3, /* 7 */
NOT_A_PIN, /* 8 */
P2, /* 9 */
P2, /* 10 */
P2, /* 11 */
P3, /* 12 */
P3, /* 13 */
P3, /* 14 */
P2, /* 15 */
P2, /* 16 */
P2, /* 17 */
P3, /* 18 */
P3, /* 19 */
P3, /* 20 */
P1, /* 21 */
P1, /* 22 */
NOT_A_PIN, /* 23 */
NOT_A_PIN, /* 24 */
P2, /* 25 */
P2, /* 26 */
NOT_A_PIN, /* 27 */
NOT_A_PIN, /* 28 */
NOT_A_PIN, /* 29 */
NOT_A_PIN, /* 30 */
P1, /* 31 */
NOT_A_PIN, /* 32 */
};
const uint8_t digital_pin_to_bit_mask[] = {
NOT_A_PIN, /* 0, pin count starts at 1 */
BV(1), /* 1, P1.1 */
BV(2), /* 2, port P1.2 */
BV(3), /* 3, port P1.3 */
BV(4), /* 4, port P1.4 */
BV(5), /* 5, port P1.5 */
BV(1), /* 6, port P3.1 */
BV(0), /* 7, port P3.0 */
NOT_A_PIN, /* 8, NC */
BV(0), /* 9, port P2.0 */
BV(1), /* 10, port P2.1 */
BV(2), /* 11, port P2.2 */
BV(2), /* 12, port P3.2 */
BV(3), /* 13, port P3.3 */
BV(4), /* 14, port P3.4 */
BV(3), /* 15, port P2.3 */
BV(4), /* 16, P2.4 */
BV(5), /* 17, P2.5 */
BV(5), /* 18, P3.5 */
BV(6), /* 19, P3.6 */
BV(7), /* 20, P3.7 */
BV(6), /* 21, P1.6 */
BV(7), /* 22, P1.7 */
NOT_A_PIN, /* 23, RST */
NOT_A_PIN, /* 24, TEST */
BV(7), /* 25, P2.7 */
BV(6), /* 26, P2.6 */
NOT_A_PIN, /* 27, GND */
NOT_A_PIN, /* 28, GND */
NOT_A_PIN, /* 29, VCC */
NOT_A_PIN, /* 30, VCC */
BV(0), /* 31, P1.0 */
NOT_A_PIN, /* 32, NC */
};
const uint32_t digital_pin_to_analog_in[] = {
NOT_ON_ADC, /* 0, pin count starts at 1 */
1, /* 1, A1 */
2, /* 2, A2 */
3, /* 3, A3 */
4, /* 4, A4 */
5, /* 5, A5 */
NOT_ON_ADC, /* 6, port P3.1 */
NOT_ON_ADC, /* 7, port P3.0 */
NOT_ON_ADC, /* 8, NC */
NOT_ON_ADC, /* 9, port P2.0 */
NOT_ON_ADC, /* 10, port P2.1 */
NOT_ON_ADC, /* 11, port P2.2 */
NOT_ON_ADC, /* 12, port P3.2 */
NOT_ON_ADC, /* 13, port P3.3 */
NOT_ON_ADC, /* 14, port P3.4 */
NOT_ON_ADC, /* 15, port P2.3 */
NOT_ON_ADC, /* 16, P2.4 */
NOT_ON_ADC, /* 17, P2.5 */
NOT_ON_ADC, /* 18, P3.5 */
NOT_ON_ADC, /* 19, P3.6 */
NOT_ON_ADC, /* 20, P3.7 */
6, /* 21, A6 */
7, /* 22, A7 */
NOT_ON_ADC, /* 23, RST */
NOT_ON_ADC, /* 24, TEST */
NOT_ON_ADC, /* 25, P2.7 */
NOT_ON_ADC, /* 26, P2.6 */
NOT_ON_ADC, /* 27, GND */
NOT_ON_ADC, /* 28, GND */
NOT_ON_ADC, /* 29, VCC */
NOT_ON_ADC, /* 30, VCC */
0, /* 31, A0 */
NOT_ON_ADC /* 32, NC */
};
#endif
#endif