This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52840 TWI with EEPROM using registers directly

I am trying to interface I2C EEPROM (AT24C512) with nrf52840 and I am directly writing to and reading from the registers mentioned in the datasheet. I am seeing the i2c waveforms on DSO and I think I am getting the start pulse correctly but not the further address and ACK and data. I tried to run and debug the code to check the data written and read but I am not getting the correct data.

Also I think I have not really written the ACK or NACK conditions correctly .  ERRORSRC This is the register I am checking for ACK.

I have attached the code. Please can anyone help me figure out what is going wrong. Because I really need to make it work ASAP.

Thank You


#define	EEPROM_SIZE 0xFFFF
#define EEPROM_DEVADDR 	0xA0
#define EEReadAddress 0xA1
#define EEWriteAddress 0x00

#define TWI_SCL 27
#define TWI_SDA 26

uint8_t *MAIN_u8buffer1 ;
//uint8_t MAIN_u8temp12[2][2]={0,1,2,3};
uint8_t MAIN_u8temp12[2] ;
uint8_t MAIN_u8buffer2[20] ;
uint8_t MAIN_u8temp = 0;

/*
Initialize I2C (TWI) interface
*/

void I2CInit()
{

 /* NRF_GPIO->PIN_CNF[TWI_SCL] = 0x0000000F ; //configure pins with pullup
  NRF_GPIO->PIN_CNF[TWI_SDA] = 0x0000000F ;*/
  NRF_TWI0->SHORTS = 0 ; //disable all shortcuts
  NRF_TWI0->INTENSET = 0 ; //disable all twi interrupts 
  NRF_TWI0->FREQUENCY = NRF_DRV_TWI_FREQ_100K ;
  NRF_TWI0->PSEL.SCL = TWI_SCL ;
  NRF_TWI0->PSEL.SDA = TWI_SDA ;
 // NRF_TWI0->ADDRESS = EEPROM_DEVADDR ; //I2C EEPROM Address AT24C512
  NRF_TWI0->ENABLE = 5 ;   //For enabling TWI we need to write 5 to the enable register according to datasheet
 
}


/*
Writes data to EEPROM.
Return:	True on successful write and 
		False on time out or any error with device 
*/
unsigned char I2C_WriteToEEPROM (unsigned int u32startAddr, unsigned char *u8data, unsigned int u32len)
{
       unsigned int u32i,u32j;
	
	//1. Check for upper limit
	if (u32startAddr + u32len > EEPROM_SIZE)
		return false;

       //2.Generate Start
       NRF_TWI0->TASKS_STARTTX = 1 ;

       //3.Transmit Device Address+Write
        NRF_TWI0->ADDRESS = EEWriteAddress ;

       //4.Wait for ACK
        while(!((NRF_TWI0->ERRORSRC & 0x00000002) == 0x00000000))     //ANACK Address NACK is 0 that is Address ACK is received
          {
               //wait till bit B in ERRORSRC register is not 0
          }
        

       //5.First Word Address (u32startAddr & 0x000000FF)(MSB)
          NRF_TWI0->ADDRESS = (u32startAddr & 0x000000FF);


       //6.Wait for ACK
         while(!((NRF_TWI0->ERRORSRC & 0x00000002) == 0x00000000))     //ANACK Address NACK is 0 that is Data ACK is received
          {
            //wait till bit B in ERRORSRC register is not 0
          }

       //7.Second Word Address (((u32startAddr & 0x0000FF00)>>8) &0xFF)(LSB)
       //8.Wait for ACK

       //9.Data
          NRF_TWI0->TXD = ((u8data[u32i])&0x000000FF);
          u32startAddr++;

       //10.Wait for ACK
         while(!((NRF_TWI0->ERRORSRC & 0x00000004) == 0x00000000))     //DNACK Address NACK is 0 that is Data ACK is received
          {
              //wait till bit B in ERRORSRC register is not 0
          }

       //11.Generate Stop
            NRF_TWI0->TASKS_STOP = 1 ;

         
         return true ;
         
}



/*
Reads data from EEPROM.
Return:	True on valid data and 
		False on time out or any error with device 
*/
unsigned char I2C_ReadFromEEPROM (unsigned int u32startAddr, unsigned char *u8data, unsigned int u32len)
{
	unsigned int	u32i;

        //1.Dummy Write. Reapeat the write routine
     for(u32i=0;u32i<u32len;u32i++)
     {
        //1. Check for upper limit
	if (u32startAddr + u32len > EEPROM_SIZE)
		return false;

       //2.Generate Start
       NRF_TWI0->TASKS_STARTTX = 1 ;

       //3.Transmit Device Address+Write
        NRF_TWI0->ADDRESS = EEWriteAddress ;

       //4.Wait for ACK
        while(!((NRF_TWI0->ERRORSRC & 0x00000002) == 0x00000000))     //ANACK Address NACK is 0 that is Address ACK is received
          {
               //wait till bit B in ERRORSRC register is not 0
          }
        

       //5.First Word Address (u32startAddr & 0x000000FF)(MSB)
          NRF_TWI0->ADDRESS = (u32startAddr & 0x000000FF);


       //6.Wait for ACK
         while(!((NRF_TWI0->ERRORSRC & 0x00000002) == 0x00000000))     //ANACK Address NACK is 0 that is Data ACK is received
          {
            //wait till bit B in ERRORSRC register is not 0
          }

       //7.Second Word Address (((u32startAddr & 0x0000FF00)>>8) &0xFF)(LSB)
       //8.Wait for ACK

       // Read data - Sequential mode.
         //1.Generate Start
           NRF_TWI0->TASKS_STARTRX = 1 ;

        //2.Transmit Device Address+Read
         NRF_TWI0->ADDRESS = EEReadAddress ;

       //3.Wait for ACK
        while(!((NRF_TWI0->ERRORSRC & 0x00000002) == 0x00000000))     //ANACK Address NACK is 0 that is Address ACK is received
          {
               //wait till bit B in ERRORSRC register is not 0
          }

        //4.Read Data
  /*      while(!(NRF_TWI0->EVENTS_RXDREADY))
         {
            //Wait till received data is ready
         }*/

         u8data[u32i] = (unsigned char)(NRF_TWI0->RXD) ;
		u32startAddr++;
                        
         //5.Transmit STOP
         NRF_TWI0->TASKS_STOP = 1 ;

     }

     return true ;

}


I2CInit() ;
    //for(uint8_t i = 0 ; i < 10 ; i++) ;
   MAIN_u8buffer1 = 0 ;
    MAIN_u8temp12[0] = 'a' ;
   // MAIN_u8temp=MAIN_u8temp12[0]; 
  MAIN_u8buffer1 = /*(uint8_t*)*/MAIN_u8temp12[0];
   

    while (true)
    {
      
     if (I2C_WriteToEEPROM(0,  MAIN_u8buffer1, 1) == true) ;
      

     if (I2C_ReadFromEEPROM(0, MAIN_u8buffer2 , 1) == true) ;

    }
}

Parents
  • Hi PoojaK,

    In your application you don't have to send ACK or NACK. It's handled by the TWI module itself. 

    Could you try to capture a logic analyzer trace of the communication ? 

    I would suggest you to have a look at this bare metal example here: https://github.com/andenore/NordicSnippets/tree/master/examples/i2c_master

  • Hi Hung Bui,

    I am not sending ACK or NACK in my code. I am just waiting for the slave to send a ACK pulse. The data sheet of AT24C512 says that once address has been transmitted we need to wait for the ACK bit and then continue further communication .

    I will try the code 

    Thank you

  • I think you are doing it wrong. Please study the TWI peripheral in the datasheet. The address in NRF_TWI0->ADDRESS is not the address in the EEPROM you want to read, but it's the address of the EEPROM it self. It's the A0 A1 that you need to hardwire on your EEPROM (so it's either 0,1,2 or 3) 

    I attached here a bare metal code to do some read or write with a TWI address 0x2A:

    #include <nrf.h>
    
    #define DEVICE_ADDRESS   (0x2A)
    #define PIN_SCL        (3)
    #define PIN_SDA        (4)
    uint8_t tx_buf[1];
    uint8_t rx_buf[3];
     
    void i2c_write(uint8_t addr, uint8_t data)
    {
      uint8_t tx_buf[2];
      NRF_TWIM0->SHORTS = TWIM_SHORTS_LASTTX_STOP_Msk;
    
      tx_buf[0] = addr;
      tx_buf[1] = data;
      NRF_TWIM0->TXD.MAXCNT = sizeof(tx_buf);
      NRF_TWIM0->TXD.PTR = (uint32_t)&tx_buf[0];
    
      NRF_TWIM0->EVENTS_STOPPED = 0;
      NRF_TWIM0->TASKS_STARTTX = 1;
      while (NRF_TWIM0->EVENTS_STOPPED == 0);
    }
    
    void i2c_read(uint8_t addr)
    {
      
      NRF_TWIM0->SHORTS = TWIM_SHORTS_LASTTX_STARTRX_Msk | TWIM_SHORTS_LASTRX_STOP_Msk;
    
      tx_buf[0] = addr;
      //tx_buf[1] = addr;
      NRF_TWIM0->TXD.MAXCNT = sizeof(tx_buf);
      NRF_TWIM0->TXD.PTR = (uint32_t)&tx_buf[0];
    
      NRF_TWIM0->RXD.MAXCNT = 1;
      NRF_TWIM0->RXD.PTR = (uint32_t)&rx_buf[0];
    
      NRF_TWIM0->EVENTS_STOPPED = 0;
      NRF_TWIM0->TASKS_STARTTX = 1;
      while (NRF_TWIM0->EVENTS_STOPPED == 0);
    
     // return rx_buf[0];
    }
    #include <stdint.h>
    int main(void)
    {
    uint16_t i ,i1,i2;
      volatile uint8_t data;
     NRF_GPIO->PIN_CNF[PIN_SCL] = 
            (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
          | (GPIO_PIN_CNF_DRIVE_S0D1     << GPIO_PIN_CNF_DRIVE_Pos)
          | (GPIO_PIN_CNF_PULL_Pullup    << GPIO_PIN_CNF_PULL_Pos)
          | (GPIO_PIN_CNF_INPUT_Connect  << GPIO_PIN_CNF_INPUT_Pos)
          | (GPIO_PIN_CNF_DIR_Input      << GPIO_PIN_CNF_DIR_Pos);    
     NRF_GPIO->PIN_CNF[PIN_SDA] = 
            (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
          | (GPIO_PIN_CNF_DRIVE_S0D1     << GPIO_PIN_CNF_DRIVE_Pos)
          | (GPIO_PIN_CNF_PULL_Pullup    << GPIO_PIN_CNF_PULL_Pos)
          | (GPIO_PIN_CNF_INPUT_Connect  << GPIO_PIN_CNF_INPUT_Pos)
          | (GPIO_PIN_CNF_DIR_Input      << GPIO_PIN_CNF_DIR_Pos);    
          
      NRF_TWIM0->PSEL.SCL = PIN_SCL;
      NRF_TWIM0->PSEL.SDA = PIN_SDA;
    
      NRF_TWIM0->ADDRESS = DEVICE_ADDRESS;
      
      NRF_TWIM0->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K400 << TWIM_FREQUENCY_FREQUENCY_Pos;
      NRF_TWIM0->SHORTS = 0;
      NRF_TWIM0->ENABLE = TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos;
     i2c_write(0x0, 0xFF);
    
    
      i2c_read(0x23);
     
      while (1)
      {
        __WFE();
      }
    }
    

  • I tried the code you have sent. I changed the code as per my device address and i2c pins.But I am not getting any data on the dso. Also as per the EEPROM I need to send Device address which is 8 bit then Start Address which is 16 bit and then the data to be transmitted. 

    So I made the following changes

    void i2c_write(uint8_t addr, uint8_t data1)
    {
      uint8_t tx_buf[3];
      NRF_TWIM0->SHORTS = TWIM_SHORTS_LASTTX_STOP_Msk;
    
      tx_buf[0] = 0x00 ; //(addr&&0x000000FF);
      tx_buf[1] = 0x01 ; //((addr&&0x0000FF00)>>8);
      tx_buf[2] = 0x55;
    
      NRF_TWIM0->TXD.MAXCNT = sizeof(tx_buf);
      NRF_TWIM0->TXD.PTR = (uint32_t)&tx_buf[0];
    
      NRF_TWIM0->EVENTS_STOPPED = 0;
      NRF_TWIM0->TASKS_STARTTX = 1;
      while (NRF_TWIM0->EVENTS_STOPPED == 0);
    }

    But I cannot see any data.

    Also I tried writing my own routine in this manner which is working but the data sequence is getting mismatched

     while (1)
          {
            TimCnt = 0 ;
            NRF_TWI0->ADDRESS = 0x50 ;//(EEWriteAddress) ;//>>1) ; // EEWriteAddress ;
            NRF_TWI0->TXD = 0x55 ;//(u32startAddr & 0x000000FF);
            TimCnt = 0 ; 
            NRF_TWI0->EVENTS_STOPPED = 0 ; 
            NRF_TWI0->TASKS_STARTTX = 1 ;
            while((NRF_TWI0->EVENTS_TXDSENT) == 0)
            {
             
            }
            NRF_TWI0->TXD = 0x0f ;
            while((NRF_TWI0->EVENTS_TXDSENT) == 0)
            {
             
            }
            NRF_TWI0->TXD = 0x66 ;
            while((NRF_TWI0->EVENTS_TXDSENT) == 0)
            {
             
            }
            NRF_TWI0->TASKS_STOP = 1 ;
            while (NRF_TWI0->EVENTS_STOPPED == 0)
            {
            }
            TimCnt = 0 ; 
            while(TimCnt < 200) ;

    As in I am getting Start Pulse->0x50->0x0F->0x66->0x55 as per the given code.

    One more issue is that when I am sending the stop condition I am getting neither of the above.

    Just Start->0x50->Stop

    Please help me out here.

Reply Children
Related