Explosión de bits a I2C EEPROM MSP430

Encontré un código para Bit Bang en una EEPROM en el MSP430 aquí , pero si cambio los pines a lo que está en mi diseño, no puede leer ni escribir. También agregué un LED para la salida, esto debería parpadear si falla, lo que sucede 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 usando MSP430-GCC como compilador, no CCS o IAR, por eso tengo mi propia _delay_cyclesfunción. Lo he probado con CCS y sigue el mismo problema. He adjuntado un Pull up al SDA.

La hoja de datos de mi EEPROM está aquí . Entonces, ¿cómo haría para depurar esto?

los 3 lugares principales para verificar cuando sucede este tipo de cosas: que realmente cambió el código correctamente en cada lugar; que los nuevos pines respalden lo que está tratando de hacer; que los nuevos pines no tienen periféricos de mayor prioridad acaparando el pin. debería ser bastante fácil con un alcance para verificar los pines de salida, la entrada puede ser más difícil.
Lo único conectado a los pines es la EEPROM, nada más. Y en la hoja de datos está bien usarlos para GPIO estándar.
¿Por qué bit-bang EEPROM? La mayoría de los MSP430 tienen interfaces I2C y esto lo ayudará a funcionar a la máxima velocidad.

Respuestas (1)

Realmente hay poco que hacer aquí, excepto conectar un analizador lógico y ver qué está pasando. Debido a que el golpe de bits depende de la CPU para el tiempo (ya que no hay temporizador), necesita ver qué está sucediendo realmente.

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

Cuando estás haciendo bitbanging, estás presionando P1OUT High y Low. Esto no es lo que debes hacer. Debería cambiar el GPIO entre la conducción de baja y alta impedancia (P1DIR &= ~BIT) para que el pullup que tiene en las líneas (¿las tiene, verdad?), las suba a alta. Recuerde que I2C es drenaje abierto y necesita emularlo usando el MSP430. Ambos pines deben tener una impedancia alta por defecto para que el pull up pueda subir. No veo en su código la inicialización de SDA. Asegúrese inicialmente de que ambos estén ingresados ​​(esto suele ser predeterminado, pero hágalo explícito para que no haya que adivinar).

Le recomiendo que use el módulo I2C si lo tiene disponible en la parte que ha elegido. 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 ser manejado.

¿Spi no sería más rápido?
@GradyPlayer: SPI es compatible con algunas EEPROM. Los estándar generalmente admiten I2C porque no se necesita más rápido. EEPROM no está destinado a ser rápido, por lo que no tiene mucho sentido usar SPI.
A menudo me he preguntado por qué hay 5 veces más EEPROM i2c que cualquier otra interfaz serial.
@GradyPlayer: Eche un vistazo a los tiempos de acceso especificados en las hojas de datos de EEPROM. Son relativamente lentos.