Bit Bang a I2C EEPROM MSP430

1

Encontré un código para Bit Bang en una EEPROM en el MSP430 aquí , pero cambiar los pines a lo que está en mi diseño que no puede leer y escribir. También he agregado un LED para la salida; esto debería parpadear si falla, lo que hace constantemente.

// required
#define SCL BIT6
#define SDA BIT4
#define LED BIT0
#define READ 0xA1
#define WRITE 0xA0
#define FAILURE -1
#define SUCCESS 0
// required
void sendByte(void);
void receiveByte(void);
void sendAck(void);
void receiveAck(void);
void start(void);
void stop(void);
// required
unsigned char txData = 0;
unsigned char rxData = 0;
unsigned char ackFlag = 0;
unsigned char bitCounter = 0;
unsigned int address = 0; // 12 bit address, upper 4 bits should be 0s.

// optional
int writeChar(void);
int readChar(void);
int readCurrentChar(void);
int writeInt(void);
int readInt(void);

// optional
unsigned char charData = 0;
unsigned int intData = 0;

static void __inline__ _delay_cycles(register unsigned int n)
{
    __asm__ __volatile__ (
        "1: \n"
        " dec   %[n] \n"
        " jne   1b \n"
        : [n] "+r"(n));
}

void main(void) {

    WDTCTL = WDTPW + WDTHOLD;

    P1OUT  |= SCL + LED;
    P1DIR |= SCL + LED;
    address = 2; // set address to 2
    charData = 0xEF;
    int result = writeChar();
    _delay_cycles(100000);

    while(1) {
// write char to address 2
        int read = readChar();

        _delay_cycles(100000);
        if(read == FAILURE && result == FAILURE) {
            P1OUT ^= LED;
        }

        _delay_cycles(100000);
    }
}


// optional
int readCurrentChar(void) {
    start();
    txData = READ;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    receiveByte();
    ackFlag = 0;
    sendAck();
    stop();
    charData = rxData;
    return SUCCESS;
}
// optional
int readChar(void) {
    start();
    txData = WRITE;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address >> 8;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address;
    sendByte();
    receiveAck();
    start();
    txData = READ;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    receiveByte();
    ackFlag = 0;
    sendAck();
    charData = rxData;
    stop();
    return SUCCESS;
}
// optional
int writeChar(void) {
    start();
    txData = WRITE;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address >> 8;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = charData;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    stop();
    return SUCCESS;
}
// optional
int readInt(void) {
    start();
    txData = WRITE;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address >> 8;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address;
    sendByte();
    receiveAck();
    start();
    txData = READ;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    receiveByte();
    ackFlag = 1;
    sendAck();
    intData = rxData;
    intData <<= 8;
    receiveByte();
    ackFlag = 0;
    sendAck();
    intData |= rxData;
    stop();
    return SUCCESS;
}

// optional
int writeInt(void) {
    start();
    txData = WRITE;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address >> 8;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = address;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = intData >> 8;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    txData = intData;
    sendByte();
    receiveAck();
    if(!ackFlag)
        return FAILURE;
    stop();
    return SUCCESS;
}

// required
// send byte to slave
void sendByte(void) {
    P1DIR |= SDA;
    bitCounter = 0;
    while(bitCounter < 8) {
        (txData & BIT4) ? (P1OUT |= SDA) : (P1OUT &= ~SDA);
        P1OUT |= SCL;
        txData <<= 1;
        bitCounter++;
        P1OUT &= ~SCL;
    }
    P1OUT |= SDA;
    P1DIR &= ~SDA;
}
// required
// receive byte from slave
void receiveByte(void) {
    bitCounter = 0;
    while(bitCounter < 8) {
        P1OUT |= SCL;
        rxData <<= 1;
        bitCounter++;
        if(P1IN & SDA) {
            rxData |= BIT0;
        }
        P1OUT &= ~SCL;
    }
}
// required
// send master's ACK
void sendAck(void) {
    P1DIR |= SDA;
    (ackFlag) ? (P1OUT &= ~SDA) : (P1OUT |= SDA);
    P1OUT |= SCL;
    P1OUT &= ~SCL;
    P1OUT |= SDA;
    P1DIR &= ~SDA;
}
// required
// receive slave's ACK
void receiveAck(void) {
    P1OUT |= SCL;
    (P1IN & SDA) ? (ackFlag = 0) : (ackFlag = 1);
    P1OUT &= ~SCL;
}
// required
// start condition
void start(void) {
    P1OUT |= SCL;
    P1DIR |= SDA;
    P1OUT &= ~SDA;
    P1OUT &= ~SCL;
    P1OUT |= SDA;
    P1DIR &= ~SDA;

}
// required
// stop condition
void stop(void) {
    P1DIR |= SDA;
    P1OUT &= ~SDA;
    P1OUT |= SCL;
    P1OUT |= SDA;
    P1DIR &= ~SDA;
}

Estoy utilizando MSP430-GCC como un compilador que no es CCS o IAR. Por eso tengo mi propia función _delay_cycles . Lo he intentado con CCS y sigue siendo el mismo problema. He adjuntado un Pull up a la SDA.

La hoja de datos de mi EEPROM es aquí . Entonces, ¿cómo voy a tratar de depurar esto?

    
pregunta Dean

1 respuesta

4

Aquí hay muy poco que hacer, pero conectar un analizador lógico y ver qué está pasando. Debido a que el bit bitging depende de la CPU para la temporización (ya que no hay temporizador), necesita ver lo que realmente está sucediendo.

Su código hace muchas suposiciones que creo que son incorrectas, esto es especialmente cierto con el tiempo. La sincronización en este caso es crítica, y un módulo I2C lo maneja por usted. En este caso, en lugar de utilizar ciclos de retardo, use un temporizador para esperar un tiempo específico. El uso de ciclos de retardo debe reservarse para esperar un tiempo, sin necesidad de precisión. Aquí tienes que cumplir con los requisitos de I2C. El MSP430 es mucho más rápido que 400 kHz y probablemente esté violando el tiempo de I2C a menos que espere el tiempo requerido. Como ejemplo, a la espera de leer, debe esperar hasta que el esclavo haya cambiado la salida de bits.

Cuando estás golpeando, estás presionando P1OUT High and Low. Esto no es lo que debes hacer. Debería cambiar el GPIO entre la conducción de baja y alta impedancia (P1DIR & = ~ BIT) de modo que el pullup que tiene en las líneas (¿los tiene, ¿no?), Tire de ellos hacia arriba. Recuerde que I2C es un drenaje abierto y necesita emular esto utilizando el MSP430. Ambos los pines deben predeterminarse a una impedancia alta para que se permita que el pull up se levante. No veo en su código la inicialización de SDA. Asegúrate de que inicialmente ambos son datos de entrada (esto suele ser predeterminado, pero hazlo explícito para que no haya dudas).

Le recomiendo que use el módulo I2C si lo tiene disponible en la parte que eligió. En parte, descargará la CPU y se asegurará de que las transacciones se manejen correctamente. Si se usa el código bit bang, a veces pueden suceder cosas que arruinan el tiempo y esto tiene que manejarse.

    
respondido por el Gustavo Litovsky

Lea otras preguntas en las etiquetas