/* --COPYRIGHT--,BSD * Copyright (c) 2016, 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. * --/COPYRIGHT--*/ //***************************************************************************** // // eusci_b_i2c.c - Driver for the eusci_b_i2c Module. // //***************************************************************************** //***************************************************************************** // //! \addtogroup eusci_b_i2c_api eusci_b_i2c //! @{ // //***************************************************************************** #include "inc/hw_memmap.h" #ifdef __MSP430_HAS_EUSCI_Bx__ #include "eusci_b_i2c.h" #include void EUSCI_B_I2C_initMaster(uint16_t baseAddress, EUSCI_B_I2C_initMasterParam *param) { uint16_t preScalarValue; //Disable the USCI module and clears the other bits of control register HWREG16(baseAddress + OFS_UCBxCTLW0) = UCSWRST; //Configure Automatic STOP condition generation HWREG16(baseAddress + OFS_UCBxCTLW1) &= ~UCASTP_3; HWREG16(baseAddress + OFS_UCBxCTLW1) |= param->autoSTOPGeneration; //Byte Count Threshold HWREG16(baseAddress + OFS_UCBxTBCNT) = param->byteCounterThreshold; /* * Configure as I2C master mode. * UCMST = Master mode * UCMODE_3 = I2C mode * UCSYNC = Synchronous mode */ HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCMST + UCMODE_3 + UCSYNC; //Configure I2C clock source HWREG16(baseAddress + OFS_UCBxCTLW0) |= (param->selectClockSource + 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. */ preScalarValue = (uint16_t)(param->i2cClk / param->dataRate); HWREG16(baseAddress + OFS_UCBxBRW) = preScalarValue; } void EUSCI_B_I2C_initSlave(uint16_t baseAddress, EUSCI_B_I2C_initSlaveParam *param) { //Disable the USCI module HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCSWRST; //Clear USCI master mode HWREG16(baseAddress + OFS_UCBxCTLW0) &= ~UCMST; //Configure I2C as Slave and Synchronous mode HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCMODE_3 + UCSYNC; //Set up the slave address. HWREG16(baseAddress + OFS_UCBxI2COA0 + param->slaveAddressOffset) = param->slaveAddress + param->slaveOwnAddressEnable; } void EUSCI_B_I2C_enable(uint16_t baseAddress) { //Reset the UCSWRST bit to enable the USCI Module HWREG16(baseAddress + OFS_UCBxCTLW0) &= ~(UCSWRST); } void EUSCI_B_I2C_disable(uint16_t baseAddress) { //Set the UCSWRST bit to disable the USCI Module HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCSWRST; } void EUSCI_B_I2C_setSlaveAddress(uint16_t baseAddress, uint8_t slaveAddress) { //Set the address of the slave with which the master will communicate. HWREG16(baseAddress + OFS_UCBxI2CSA) = (slaveAddress); } void EUSCI_B_I2C_setMode(uint16_t baseAddress, uint8_t mode) { HWREG16(baseAddress + OFS_UCBxCTLW0) &= ~EUSCI_B_I2C_TRANSMIT_MODE; HWREG16(baseAddress + OFS_UCBxCTLW0) |= mode; } uint8_t EUSCI_B_I2C_getMode(uint16_t baseAddress) { //Read the I2C mode. return ((HWREG16(baseAddress + OFS_UCBxCTLW0) & UCTR)); } void EUSCI_B_I2C_slavePutData(uint16_t baseAddress, uint8_t transmitData) { //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = transmitData; } uint8_t EUSCI_B_I2C_slaveGetData(uint16_t baseAddress) { //Read a byte. return (HWREG16(baseAddress + OFS_UCBxRXBUF)); } uint16_t EUSCI_B_I2C_isBusBusy(uint16_t baseAddress) { //Return the bus busy status. return (HWREG16(baseAddress + OFS_UCBxSTATW) & UCBBUSY); } uint16_t EUSCI_B_I2C_masterIsStopSent(uint16_t baseAddress) { return (HWREG16(baseAddress + OFS_UCBxCTLW0) & UCTXSTP); } uint16_t EUSCI_B_I2C_masterIsStartSent(uint16_t baseAddress) { return (HWREG16(baseAddress + OFS_UCBxCTLW0) & UCTXSTT); } void EUSCI_B_I2C_enableInterrupt(uint16_t baseAddress, uint16_t mask) { //Enable the interrupt masked bit HWREG16(baseAddress + OFS_UCBxIE) |= mask; } void EUSCI_B_I2C_disableInterrupt(uint16_t baseAddress, uint16_t mask) { //Disable the interrupt masked bit HWREG16(baseAddress + OFS_UCBxIE) &= ~(mask); } void EUSCI_B_I2C_clearInterrupt(uint16_t baseAddress, uint16_t mask) { //Clear the I2C interrupt source. HWREG16(baseAddress + OFS_UCBxIFG) &= ~(mask); } uint16_t EUSCI_B_I2C_getInterruptStatus(uint16_t baseAddress, uint16_t mask) { //Return the interrupt status of the request masked bit. return (HWREG16(baseAddress + OFS_UCBxIFG) & mask); } void EUSCI_B_I2C_masterSendSingleByte(uint16_t baseAddress, uint8_t txData) { //Store current TXIE status uint16_t txieStatus = HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE; //Disable transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) &= ~(UCTXIE); //Send start condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTR + UCTXSTT; //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; //Clear transmit interrupt flag before enabling interrupt again HWREG16(baseAddress + OFS_UCBxIFG) &= ~(UCTXIFG); //Reinstate transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) |= txieStatus; } uint8_t EUSCI_B_I2C_masterReceiveSingleByte(uint16_t baseAddress) { //Set USCI in Receive mode HWREG16(baseAddress + OFS_UCBxCTLW0) &= ~UCTR; //Send start HWREG16(baseAddress + OFS_UCBxCTLW0) |= (UCTXSTT + UCTXSTP); //Poll for receive interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG)) { ; } //Send single byte data. return (HWREG16(baseAddress + OFS_UCBxRXBUF)); } bool EUSCI_B_I2C_masterSendSingleByteWithTimeout(uint16_t baseAddress, uint8_t txData, uint32_t timeout) { // Creating variable for second timeout scenario uint32_t timeout2 = timeout; //Store current TXIE status uint16_t txieStatus = HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE; //Disable transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) &= ~(UCTXIE); //Send start condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTR + UCTXSTT; //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout2) { ; } //Check if transfer timed out if(timeout2 == 0) { return (STATUS_FAIL); } //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; //Clear transmit interrupt flag before enabling interrupt again HWREG16(baseAddress + OFS_UCBxIFG) &= ~(UCTXIFG); //Reinstate transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) |= txieStatus; return (STATUS_SUCCESS); } void EUSCI_B_I2C_masterSendMultiByteStart(uint16_t baseAddress, uint8_t txData) { //Store current transmit interrupt enable uint16_t txieStatus = HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE; //Disable transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) &= ~(UCTXIE); //Send start condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTR + UCTXSTT; //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Reinstate transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) |= txieStatus; } bool EUSCI_B_I2C_masterSendMultiByteStartWithTimeout(uint16_t baseAddress, uint8_t txData, uint32_t timeout) { //Store current transmit interrupt enable uint16_t txieStatus = HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE; //Disable transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) &= ~(UCTXIE); //Send start condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTR + UCTXSTT; //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Reinstate transmit interrupt enable HWREG16(baseAddress + OFS_UCBxIE) |= txieStatus; return(STATUS_SUCCESS); } void EUSCI_B_I2C_masterSendMultiByteNext(uint16_t baseAddress, uint8_t txData) { //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; } bool EUSCI_B_I2C_masterSendMultiByteNextWithTimeout(uint16_t baseAddress, uint8_t txData, uint32_t timeout) { //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; return(STATUS_SUCCESS); } void EUSCI_B_I2C_masterSendMultiByteFinish(uint16_t baseAddress, uint8_t txData) { //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; } bool EUSCI_B_I2C_masterSendMultiByteFinishWithTimeout(uint16_t baseAddress, uint8_t txData, uint32_t timeout) { uint32_t timeout2 = timeout; //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout2) { ; } //Check if transfer timed out if(timeout2 == 0) { return (STATUS_FAIL); } //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; return(STATUS_SUCCESS); } void EUSCI_B_I2C_masterSendStart(uint16_t baseAddress) { HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTT; } void EUSCI_B_I2C_masterSendMultiByteStop(uint16_t baseAddress) { //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } } //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; } bool EUSCI_B_I2C_masterSendMultiByteStopWithTimeout(uint16_t baseAddress, uint32_t timeout) { //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } } //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; return (STATUS_SUCCESS); } void EUSCI_B_I2C_masterReceiveStart(uint16_t baseAddress) { //Set USCI in Receive mode HWREG16(baseAddress + OFS_UCBxCTLW0) &= ~UCTR; //Send start HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTT; } uint8_t EUSCI_B_I2C_masterReceiveMultiByteNext(uint16_t baseAddress) { return (HWREG16(baseAddress + OFS_UCBxRXBUF)); } uint8_t EUSCI_B_I2C_masterReceiveMultiByteFinish(uint16_t baseAddress) { //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; //Wait for Stop to finish while(HWREG16(baseAddress + OFS_UCBxCTLW0) & UCTXSTP) { // Wait for RX buffer while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG)) { ; } } //Capture data from receive buffer after setting stop bit due to //MSP430 I2C critical timing. return (HWREG16(baseAddress + OFS_UCBxRXBUF)); } bool EUSCI_B_I2C_masterReceiveMultiByteFinishWithTimeout(uint16_t baseAddress, uint8_t *txData, uint32_t timeout) { uint32_t timeout2 = timeout; //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; //Wait for Stop to finish while((HWREG16(baseAddress + OFS_UCBxCTLW0) & UCTXSTP) && --timeout) { ; } //Check if transfer timed out if(timeout == 0) { return (STATUS_FAIL); } // Wait for RX buffer while((!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG)) && --timeout2) { ; } //Check if transfer timed out if(timeout2 == 0) { return (STATUS_FAIL); } //Capture data from receive buffer after setting stop bit due to //MSP430 I2C critical timing. *txData = (HWREG8(baseAddress + OFS_UCBxRXBUF)); return (STATUS_SUCCESS); } void EUSCI_B_I2C_masterReceiveMultiByteStop(uint16_t baseAddress) { //Send stop condition. HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCTXSTP; } void EUSCI_B_I2C_enableMultiMasterMode(uint16_t baseAddress) { HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCSWRST; HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCMM; } void EUSCI_B_I2C_disableMultiMasterMode(uint16_t baseAddress) { HWREG16(baseAddress + OFS_UCBxCTLW0) |= UCSWRST; HWREG16(baseAddress + OFS_UCBxCTLW0) &= ~UCMM; } uint8_t EUSCI_B_I2C_masterReceiveSingle(uint16_t baseAddress) { //Polling RXIFG0 if RXIE is not enabled if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCRXIE0)) { while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCRXIFG0)) { ; } } //Read a byte. return (HWREG16(baseAddress + OFS_UCBxRXBUF)); } uint32_t EUSCI_B_I2C_getReceiveBufferAddress(uint16_t baseAddress) { return (baseAddress + OFS_UCBxRXBUF); } uint32_t EUSCI_B_I2C_getTransmitBufferAddress(uint16_t baseAddress) { return (baseAddress + OFS_UCBxTXBUF); } void EUSCI_B_I2C_remapPins(uint16_t baseAddress, uint8_t pinsSelect) { #ifdef USCIBRMP HWREG16(SYS_BASE + OFS_SYSCFG2) &= ~USCIBRMP; HWREG16(SYS_BASE + OFS_SYSCFG2) |= pinsSelect << 11; #endif } #endif //***************************************************************************** // //! Close the doxygen group for eusci_b_i2c_api //! @} // //*****************************************************************************