Keil Logo

Simulating an I²C Device

The user can implement hardware components that are connected to the I²C bus through specific signal functions. The following example shows a signal function that simulates an I²C Memory (256 bytes, like the NXP PCF8570.

The I²C Memory Slave address is set trough the SADR variable. Example:

SADR = 0x3F// I²C Memory Slave Address

The signal function is invoked from the command window as:

I2C_Memory()

The I²C Memory is mapped to the memory region V:0 .. V:0xFF.

Once the simulator detects a START condition in the I2C_OUT VTReg, then the next byte will be interpreted as an address byte. This address byte contains the 7-bit Slave address in the bits 7 .. 1 and the direction (0=Write, 1=Read) in bit 0.

  • If the Slave Memory is addressed, then the Memory device sends an ACK back to the microcontroller.
  • If the direction bit was '1' (Memory Read), then the microcontroller reads data bytes from the simulated memory device. Every byte read through the IC2_IN VTReg increments the address automatically and sends an ACK back to the memory device. The memory device must return an ACK after the byte was received. NACK is sent if this is the last data byte read.
  • If the direction bit was '0' (Memory Write), then the microcontroller first sends a byte with the new memory address. The memory device must return ACK. Then, data bytes are sent and written to the memory device. The address is incremented automatically after each written byte. The memory device must return ACK after each received byte.
// Simulation of I²C Memory (Slave): like NXP PCF8570 (256 byte I²C RAM)

MAP V:0,V:0xFF READ WRITE                    // Map User Memory region

DEFINE int SADR                              // Slave Address

signal void I2C_Memory (void) {
  unsigned long adr;

  adr = V:0;
  while (1) {
    wwatch (I2C_OUT);                        // Wait for data from Microcontroller
    while (I2C_OUT == 0x0100) {              // START detected
      wwatch (I2C_OUT);                      // Wait for data from Microcontroller
      if (I2C_OUT > 0xFF) continue;
      if ((I2C_OUT >> 1) != SADR) continue;  // test if Slave is addressed
      I2C_IN = 0xFF00;                       // ACK to Microcontroller
      if (I2C_OUT & 1) {                     // Slave Read
        while (1) {
          I2C_IN = _RBYTE(adr);              // Read Byte from Memory
          adr++;                             // Increment Address
          wwatch (I2C_OUT);                  // Wait for ACK from Microcontroller
          if (I2C_OUT != 0xFF00) break;
        }
      }
      else {                                 // Slave Write
        wwatch (I2C_OUT);                    // Wait for data from Microcontroller
        if (I2C_OUT > 0xFF) continue;
        adr = I2C_OUT | V:0;                 // Set Memory Address
        I2C_IN = 0xFF00;                     // ACK to Microcontroller
        while (1) {
          wwatch (I2C_OUT);                  // Wait for data from Microcontroller
          if (I2C_OUT > 0xFF) break;
          _WBYTE (adr, I2C_OUT);             // Store Byte in Memory
          adr++;                             // Increment Address
          I2C_IN = 0xFF00;                   // ACK to Microcontroller
        }
      }
    }
  }
  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.