STM32f030C8 I2C EEPROM: no se reciben datos cuando se lee después de escribir

Estoy desarrollando una biblioteca para I2C eeprom at24c04 con stm32f030c8 . Mis funciones de lectura y escritura funcionan, pero cuando trato de leer inmediatamente después de escribir en la eeprom, la eeprom no devuelve ningún dato. sin embargo, podría hacer inmediatamente una escritura consecutiva. El problema ocurre solo cuando leo después de una declaración de escritura. Intenté habilitar y deshabilitar el bit de habilitación de I2C pero el problema aún existe. ¿Alguien puede decirme cuál es el problema?

void main()
{
   Configure_GPIO_I2C2();
   Configure_I2C2_Master(0xA0,1);

    I2C_WriteByte(5,'k');
    charr= I2C_ReadByte(5);//the program get stuck here because no byte is 
                            //received from eeprom
    UART_Send_String(1,&charr);

}

void I2C_WriteByte(uint8_t addr,uint8_t bytetowrite)
            {
                I2C2->ISR=0x01;
                I2C2_StartWrite(2);//start

                I2C2->TXDR = addr;//write addr
                while(!(I2C2->ISR & I2C_ISR_TXE));

                //I2C2_StartWrite(1);

                I2C2->TXDR = bytetowrite;
                while(!(I2C2->ISR & I2C_ISR_TXE));

                I2C2->CR2 |= I2C_CR2_STOP;//stop
                while(I2C2->CR2 & I2C_CR2_STOP);

            }

            uint8_t I2C_ReadByte(uint8_t byteToRead)
            {
                I2C2->ISR=0x01;
                I2C2_StartWrite(1);

                I2C2->TXDR = byteToRead;
                while(!(I2C2->ISR & I2C_ISR_TXE));

                I2C2_StartRead(1);  
                while(!(I2C2->ISR & I2C_ISR_RXNE));
                UART_Send_String(1,"r strt");
                uint8_t recv_data=I2C2->RXDR;   


                I2C2->CR2 |= I2C_CR2_STOP;
                while(I2C2->CR2 & I2C_CR2_STOP);

                return recv_data;

            }


            /////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////
            void Configure_GPIO_I2C2(void)
            {

                RCC->AHBENR |= RCC_AHBENR_GPIOFEN;  
                GPIOF->MODER |= (2<<12) | (2<<14);  
                GPIOF->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; 

                GPIOF->OSPEEDR &=  ~(1<<12);
                GPIOF->OSPEEDR &=  ~(1<<14);

                GPIOF->PUPDR &= ~(1<<12);
                GPIOF->PUPDR &= ~(1<<12);
            }

        void Configure_I2C2_Master(uint8_t slave_addr,uint8_t no_of_bytes)
            {

                RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;

                /* (1) Timing register value is computed with the AN4235 xls file,
                 fast Mode @400kHz with I2CCLK = 48MHz, rise time = 140ns, fall time = 40ns */  
                I2C2->CR1 &= ~I2C_CR1_PE;
                I2C2->TIMINGR |= (uint32_t)0x00B01A4B; /* (1) */
                I2C2->CR2 |= (uint8_t)slave_addr;
                I2C2->CR2 |= no_of_bytes<<16;   
                I2C2->CR1 |= I2C_CR1_PE;
                //NVIC_SetPriority(I2C2_IRQn, 0); /* (7) */
                //NVIC_EnableIRQ(I2C2_IRQn); /* (8) */
            }

    void I2C2_StartWrite(int bytesToWrite)
            {

                I2C2->CR2 &= ~I2C_CR2_RD_WRN;

                I2C2->CR2 |= bytesToWrite<<16;

                I2C2->CR2 |= I2C_CR2_START;
                while(I2C2->CR2 & I2C_CR2_START);
            }



            void I2C2_StartRead(int bytesToRead)
            {
            I2C2->CR2 |= I2C_CR2_RD_WRN;

                I2C2->CR2 |= bytesToRead<<16;

                I2C2->CR2 |= I2C_CR2_START;
                while(I2C2->CR2 & I2C_CR2_START);
            }
¿Está haciendo algún tipo de verificación para asegurarse de que la escritura haya terminado antes de leerla tan pronto?
Intenté un sondeo de reconocimiento como se menciona en la hoja de datos. e incluso un retraso. pero el resultado es el mismo
¿Qué hace I2C2_StartWrite? ¿Conoce la secuencia exacta de escritura y lectura con I2C? Debería verse como las formas de onda en la página 11 de la hoja de datos. Entonces, ¿sabes cómo se hace una lectura? Una vez más, los detalles están en la hoja de datos. ¿Qué muestra su alcance que realmente está sucediendo en comparación con lo que cree que debería estar sucediendo?
agregué las funciones I2C2_StartWrite e I2C2_StartRead. Desarrollé el código del tutorial y de la hoja de datos. Creo que estoy siguiendo el método correcto porque pude escribir y leer individualmente. Estoy siguiendo el ciclo i2c que se muestra en la hoja de datos. @DiBosco
En primer lugar, me gustaría repetir: ¿Qué muestra su alcance? Espero estar equivocado, pero sospecho que debido a que eludió esa pregunta, aún no la ha usado. En segundo lugar, no veo suficientes accesos a TXDR. Mi sospecha es que no entiende muy bien cómo necesita escribir la dirección del hardware, luego la dirección interna y luego los datos. La lectura de datos es aún más complicada. I2C requiere mucho tiempo para acostumbrarse, es bastante complicado cuando lo pruebas por primera vez. Este tutorial en mi humilde opinión es bueno: robot-electronics.co.uk/i2c-tutorial
Todavía no pude obtener un alcance, lo estoy intentando. Sobre la TXDR. Seguí el siguiente tutorial. y por eso tuve la impresión de que el stm32 i2c escribirá la dirección del esclavo que se proporcionó durante la configuración y no tengo que dar la dirección del esclavo como extra. Gracias por el enlace. @DiBosco ( youtube.com/… )
Parece que tienes razón sobre la dirección del hardware. ¿Tiene A0, A1 y A2 en el EE todos configurados en 0? Sin embargo, no he seguido completamente ese largo tutorial y no he verificado su código con el suyo, por lo que puede haber alguna línea que se haya perdido. Encuentro un osciloscopio o un analizador I2C vital cuando hago cosas como esta, a menudo me hace darme cuenta de que he cometido un error estúpido en alguna parte.
Sí, A0, A1 A2 están todos conectados a tierra. lo que me preocupa es que ambas funciones funcionan individualmente y si escribo después de leer no hay problema. El problema ocurre solo cuando hago una lectura después de escribir. Estoy siguiendo el flujo I2C como se menciona en la hoja de datos. Estoy comprobando el alcance.

Respuestas (2)

Mis funciones de lectura y escritura funcionan, pero cuando trato de leer inmediatamente después de escribir en la eeprom, la eeprom no devuelve ningún dato. sin embargo, podría hacer inmediatamente una escritura consecutiva.

Parece que no estás esperando que la EEPROM termine de escribir. No miré tu EEPROM, pero con todas las que he usado, una secuencia de escritura o borrado solo inicia la acción. Luego, la EEPROM está ocupada durante algún tiempo.

La mayoría de las EEPROM tienen algo así como un registro de estado donde puede sondear un poco para ver si está ocupado. Esta acción de lectura se puede realizar tanto si está ocupado como si no.

La arquitectura de software más general siempre sondea el bit ocupado antes de intentar hacer algo. Si la EEPROM está ocupada, sigue sondeando hasta que no lo está, luego continúa con la acción que se solicitó. Las implementaciones más sofisticadas establecen un indicador de escritura y borrado, lo que indica que la EEPROM podría estar ocupada. La verificación de ocupado solo se realiza cuando se establece este indicador. Las implementaciones ingenuas siempre solo esperan después de borrar o escribir.

Mire su código cuidadosamente, especialmente qué es exactamente lo que se envía a la EEPROM cuando una escritura es seguida inmediatamente por una lectura. Mi conjetura es que la verificación ocupada se omite de alguna manera en ese caso.

Modifiqué la función de lectura en dos ciclos, una escritura para cargar la dirección de lectura y una lectura de la dirección actual. Está funcionando ahora. Sin embargo, no estoy seguro de por qué el ciclo de lectura de direcciones aleatorias como se menciona en la hoja de datos no funciona.

Sospecho que no estabas retransmitiendo la secuencia de inicio previamente. Si tuviera que apostar, diría que en realidad no estabas siguiendo el procedimiento de lectura aleatoria anteriormente y ahora lo estás haciendo. Supongo que estabas escribiendo y leyendo sin volver a enviar esa secuencia de inicio. Ese enlace de tutorial que envié es muy bueno para explicar claramente eso. Los analizadores I2C, como el Beagle, también son excelentes para señalar estos problemas de inmediato. Herramientas como esa ahorran mucho tiempo y vale la pena gastar dinero en ellas, especialmente al comenzar en mi humilde opinión.
@DiBosco, estaba enviando la instrucción de inicio anteriormente, como puede ver en el código. pero ahora agregué una condición de parada entre los dos ciclos de inicio. Ese es el único cambio que hice. Invertiré en un analizador.