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 Reply Children
  • 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.

  • Hi,

    I tried a lot but the .cpp file and project is not working in my ses. 

    And I am still stuck with my i2c.

    I really need help Disappointed

  • SES does not support C++ sorry.  Can't be used with SES but you can use CrossWorks with external GCC compiler or IAR or Eclipse. See README.md of the repo

Related