【ARM】如何使用Keil仿真中的SPI仿真?-2022

串行外设接口 (SPI) 允许在板级连接设备。µVision 调试器在主从模式下模拟多个微控制器的SPI接口。

虚拟仿真寄存器 (VTREG)

以下 VTREG 用于模拟 SPI 通信:

VTREG描述
SPIxIN是SPI输入寄存器,获取当前接收到的数据。
SPIxOUT是保存当前传输数据的 SPI 输出寄存器。

SPIx 的 VTREG 命名约定因器件而异。一些设备提供了不止一个 SPI 接口。因此,VTREG 名称可能以 SPI0 或 SPI1 为前缀。使用命令 DIR VTREG检查 SPI 接口的虚拟仿真寄存器名称。

SPI仿真示例

以下脚本定义了调试器信号函数,这些函数使用带有switch语句的简单状态机模拟 Atmel AT250X0 SPI 存储设备。

/* Define the state and address for the AT250x0.*/

define char spi_at250x0_state

define int  spi_at250x0_address

define char spi_at250x0_status

/* MAP the memory area to use for the SPI RAM. */

map X:0x700000,X:0x70FFFF READ WRITE

/*-----------------------------------------------

This function implements the state matching for

the AT250x0.

State       Transition

-------------------------------------------------

0: WREN  -> 0

0: WRDI  -> 0

0: RDSR  -> 0

0: Read  -> 1: Get Address LSB -> 2: Read Byte <-

0: Write -> 3: Get Address LSB -> 4: Write Byte -> 5 <-

1: Get Addr LSB -> 2

2: Read Byte(s) -> 2

3: Get Addr LSB -> 4

4: Write Byte   -> 5

-----------------------------------------------*/

func char spi_at250x0 (char st) {

  unsigned char opcode;

  printf ("AT250X0: STATE %un", (unsigned) st);

  switch (st)  {

    case 0:  /* Get OPCode */

      opcode = SPI_OUT & 0x0007;

      printf ("AT250X0: OPCODE %un", (unsigned) opcode);

    switch (opcode)

      {

      case 1: /* WRSR */

        return (0);

      case 2: /* Write */

        printf ("AT250X0: WRITE OPCODE Detectedn");

        spi_at250x0_address = (SPI_OUT & 0x08) << 5;

        return (3);

      case 3: /* Read */

        printf ("AT250X0: READ OPCODE Detectedn");

        spi_at250x0_address = (SPI_OUT & 0x08) << 5;

        return (1);

      case 4: /* WRDI */

        spi_at250x0_status &= ~0x02; /* Clear Write Enable Bit */

        return (0);

      case 5: /* RDSR */

        SPI_IN = spi_at250x0_status;

        return (5);

      case 6: /* WREN */

        spi_at250x0_status |= 0x02; /* Set Write Enable Bit */

        return (0);

      }

    return (0);

  case 1:  /* Get Address LSB for READ */

    spi_at250x0_address |= (SPI_OUT & 0xFF);

    printf ("AT250X0: Address %4.4X Detectedn", spi_at250x0_address);

    return (2);

  case 2:  /* Read */

    printf ("AT250X0: Read %2.2X from address %4.4Xn", 'A', spi_at250x0_address);

    SPI_IN = _rbyte(X:0x700000 + spi_at250x0_address);

    spi_at250x0_address = (spi_at250x0_address + 1) % 512;

    return (2);

  case 3:  /* Get Address LSB for WRITE */

    spi_at250x0_address |= (SPI_OUT & 0xFF);

    printf ("AT250X0: Address %4.4X Detectedn", spi_at250x0_address);

    return (4);

  case 4:  /* Write */

    if (spi_at250x0_status & 0x02)

      {

      printf ("AT250X0: Write %2.2X to address %4.4Xn", SPI_OUT, spi_at250x0_address);

      _wbyte(X:0x700000 + spi_at250x0_address, SPI_OUT);

      spi_at250x0_status |= 0x01;

      }

    return (5);

  case 5:  /* Instruction End */

    return (5);

  }

return (0);

}

/*

 * This signal function watches the AT89S8252 SPI port for writes.  If there

 * is an SPI port output and if P1.0 is LO (AT250X0 chip select) then interpret

 * the SPI output data and run the state machine.

 */

signal void spi_watcher (void) {

spi_at250x0_state = 0;

while (1) {

  wwatch (SPI_OUT);

  printf ("SPI_OUT Detectedn");

  if ((PORT1 & 0x01) == 0)

    {

    printf ("Calling AT250X0 Routinesn");

    spi_at250x0_state = spi_at250x0 (spi_at250x0_state);

    if (spi_at250x0_status & 0x01)

      swatch (0.000100);

      spi_at250x0_status &= ~0x01;

    }

  else

    {

    printf ("Resetting AT250X0 Routinesn");

    spi_at250x0_state = 0;

    }

  }

}

/*-----------------------------------------------

Enable the signal function for SPI writes.

-----------------------------------------------*/

spi_watcher ();