Keil Logo Arm Logo

Simulating an I²C Device

With specific signal functions the user can implement hardware components that are connected to the I²C bus. The following example shows a signal function that simulates an I²C Memory (256 bytes) like the Philips 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, the next byte will be interpreted as address byte. This address byte contains the 7-bit Slave address in bits 7 .. 1 and in bit 0 the direction (0 = Write, 1 = Read).

  • If the Slave Memory is addressed the Memory Device sends an ACK back to the Microcontroller.
  • If the direction bit was '1' (Memory Read) the Microcontroller reads data bytes from the Memory (from the current address which is automatically incremented after each read byte) trough the I2C_IN VTReg. The Microcontroller sends an ACK to the Memory Device after each byte if more data bytes should be read or an NACK if this is the last data byte read.
  • If the direction bit was '0' (Memory Write) the Microcontroller sends first a byte with the new Memory address (Memory must return an ACK) and then sends data bytes which will be written to the Memory (to current address which is auto incremented after each written byte). The Memory Device must return an ACK after each received byte.
// Simulation of I²C Memory (Slave): like Philips 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
        }
      }
    }
  }

Keil logo

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