Hi,
Many posts talk about a UCBBUSY always set because of SDA line held low by a slave.
My problem is the opposite, the UCBBUSY is set but the SDA line is always high.
I use the USCI I2C Master Library without DMA support (I modified it to fit to MSP430F5510).
Any known solution is wellcome !
this is my source code :
#include <msp430f5510.h> // more devices are possible
#include "i2c_engine.h"
#include "..\tools\timer.h"
signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
//------------------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//-----------------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
unsigned char prescale){
P4SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B1
UCB1CTL1 = UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = prescale; // set prescaler
UCB1BR1 = 0;
UCB1I2CSA = slave_address; // set slave address
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB1IE |= UCNACKIE + UCRXIE; // Enable RX interrupt
}
//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-transmit operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
unsigned char prescale){
P4SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
UCB1CTL1 = UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = prescale; // set prescaler
UCB1BR1 = 0;
UCB1I2CSA = slave_address; // Set slave address
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB1IE |= UCNACKIE + UCTXIE;
}
//------------------------------------------------------------------------------
// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-receiver mode.
//
// IN: unsigned char byteCount => number of bytes that should be read
// unsigned char *field => array variable used to store received data
//------------------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
TI_receive_field = field;
if ( byteCount == 1 ){
byteCtr = 0 ;
__disable_interrupt();
UCB1CTL1 |= UCTXSTT; // I2C start condition
while (UCB1CTL1 & UCTXSTT); // Start condition sent?
UCB1CTL1 |= UCTXSTP; // I2C stop condition
__enable_interrupt();
} else if ( byteCount > 1 ) {
byteCtr = byteCount - 2 ;
UCB1CTL1 |= UCTXSTT; // I2C start condition
} else
while (1); // illegal parameter
}
//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-transmit mode.
//
// IN: unsigned char byteCount => number of bytes that should be transmitted
// unsigned char *field => array variable. Its content will be sent.
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
TI_transmit_field = field;
byteCtr = byteCount;
UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
}
//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus.
//
// IN: unsigned char slave_address => Slave Address
// OUT: unsigned char => 0: address was not found,
// 1: address found
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
unsigned char slaveadr_bak, ucb0i2cie, returnValue;
ucb0i2cie = UCB1IE ; // restore old UCB1IE
slaveadr_bak = UCB1I2CSA; // store old slave address
UCB1IE &= ~ UCNACKIE; // no NACK interrupt
UCB1I2CSA = slave_address; // set slave address
UCB1IE &= ~(UCTXIE + UCRXIE); // no RX or TX interrupts
__disable_interrupt();
UCB1CTL1 |= UCTR + UCTXSTT + UCTXSTP; // I2C TX, start condition
while (UCB1CTL1 & UCTXSTP); // wait for STOP condition
returnValue = !(UCB1IFG & UCNACKIFG);
__enable_interrupt();
UCB1I2CSA = slaveadr_bak; // restore old slave address
UCB1IE = ucb0i2cie; // restore old UCB1CTL1
return returnValue; // return whether or not
// a NACK occured
}
//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
//
// OUT: unsigned char => 0: I2C bus is idle,
// 1: communication is in progress
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_notready(){
return (UCB1STAT & UCBBUSY);
}
#pragma vector = USCI_B1_VECTOR
__interrupt void USCIAB1RX_ISR(void)
{
if (UCB1IFG & UCNACKIFG){ // send STOP if slave sends NACK
UCB1CTL1 |= UCTXSTP;
UCB1STAT &= ~UCNACKIFG;
}
if (UCB1IFG & UCRXIFG){
if ( byteCtr == 0 ){
UCB1CTL1 |= UCTXSTP; // I2C stop condition
*TI_receive_field = UCB1RXBUF;
TI_receive_field++;
}
else {
*TI_receive_field = UCB1RXBUF;
TI_receive_field++;
byteCtr--;
}
}
if (UCB1IFG & UCTXIFG){
if (byteCtr == 0){
UCB1CTL1 |= UCTXSTP; // I2C stop condition
UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
}
else {
UCB1TXBUF = *TI_transmit_field;
TI_transmit_field++;
byteCtr--;
}
}
}