0

在一个新设计(.NET Micro 的新设计)中,我有一系列 LED 7 段显示器,它们通过带有 Netduino 的 SPI 总线进行控制。

现在,我已经看到不必模拟 SPI 总线的东西,因为 .NET 微框架已经有一个模拟的 SPI 总线,太棒了。

由于我的“模块”是由 SPI 控制的,我想通过 SPIDevice 和 SPIBus 来抽象它,但是我已经在整个互联网上搜索过,并且无法找到一个如何滚动您自己的自定义 SPIDevice(并控制它)的示例) 用于 .NET MF DeviceEmulator 项目。

基本上,在我的 SPIDevice 中,我将拥有一系列控制寄存器以及每个 LED 的数据,但我迫切需要一个可以引导正确方向的示例。当我安装 .NET MF 4.3 时,它没有安装任何示例。

4

1 回答 1

0

一个选项可能是使用聚合来实现您正在寻找的东西。

例如,您可以创建一个名为 SevenSegmentDisplay 的类,它公开方法/属性以与 7 段 LED 模块交互并包装一个私有 SPI 实例。在内部,这些方法调用私有 SPI 实例以实际与物理设备通信。

对于模拟器,这是我为具有 SPI 接口的闪存芯片编写的代码 + 配置。这用于在等待物理设备时进行内部测试。

using System;
using Microsoft.SPOT.Emulator;
using Microsoft.SPOT.Emulator.Spi;
using System.Diagnostics;

namespace dotnetwarrior.Emulator.Hardware
{
  class MX25l3206FlashMemory : SpiDevice
  {
    private byte[] _memory;

    public int MemorySize { get; set; }
    public int SectorSize { get; set; }
    public int PageSize { get; set; }

    private Status _status;

    [Flags]
    enum Status
    {
      Wip = 1,
      Wel = 2,
      Bp0 = 4,
      Bp1 = 8,
      Bp2 = 16,
      E_Err = 32,
      P_Err = 64,
      SRWD = 128
    }

    public MX25l3206FlashMemory()
    {     
    }

    public byte GetByte(int address)
    {
      return _memory[address];
    }

    public override void SetupComponent()
    {
      base.SetupComponent();
      _memory = new byte[MemorySize];
    }

    protected override byte[] Write(byte[] data)
    {
      switch (data[0])
      {
        case 0x03: return Read(data);
        case 0x9f: return ReadIdentification(data);
        case 0x90: return ReadManufacturer(data);
        case 0x06: return WriteEnable(data);
        case 0x04: return WriteDisable(data);
        case 0x20: return Erase4K(data);
        case 0x40: return Erase8K(data);
        case 0xd8: return EraseSector(data);
        case 0x60:
        case 0xC7: return EraseDevice(data);
        case 0x02: return PagePrograme(data);
        case 0x05: return ReadStatus(data);
        case 0x01: return WriteStatus(data);
        case 0x35: return ReadConfig(data);        
      }
      throw new NotImplementedException("Unexpected Flash command : " + data[0].ToString());
    }

    private int GetAddress(byte[] data)
    {
      byte[] address = new byte[4];
      Buffer.BlockCopy(data, 1, address, 1, 3);
      Array.Reverse(address);
      return (BitConverter.ToInt32(address, 0) % MemorySize);
    }

    private byte[] Read(byte[] data)
    {
      int address = GetAddress(data);
      Buffer.BlockCopy(_memory, address, data, 4, data.Length - 4);
      return data;      
    }

    private byte[] ReadIdentification(byte[] data)
    {
      return new byte[]{0x01, 0x02, 0x15, 0x4d};
    }

    private byte[] ReadManufacturer(byte[] data)
    {
      return new byte[]{0x01, 0x02};
    }

    private byte[] WriteEnable(byte[] data)
    {
      _status |= Status.Wel;      
      return new byte[]{};
    }

    private byte[] WriteDisable(byte[] data)
    {
      _status &= ~Status.Wel;

      return new byte[]{};
    }

    private byte[] ReadStatus(byte[] data)
    {
      return new byte[] { (byte)_status, (byte)_status };
    }

    private byte[] WriteStatus(byte[] data)
    {
      _status = (Status)data[1];
      return new byte[] { };
    }

    private byte[] Erase4K(byte[] data)
    {
      if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
      try
      {
        _status |= Status.Wip;

      }
      finally
      {
        _status &= ~(Status.Wel | Status.Wip);        
      }
      return new byte[] { };
    }

    private byte[] Erase8K(byte[] data)
    {
      if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
      _status |= Status.Wip;
      try
      {


      }
      finally
      {
        _status &= ~(Status.Wel | Status.Wip);
      }
      return new byte[] { };
    }

    private byte[] EraseSector(byte[] data)
    {
      if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
      _status |= Status.Wip;
      try
      {
        int address = GetAddress(data);
        int sector = address / SectorSize;
        int sectorStartAddress = sector * SectorSize;
        for (int i = 0; i < SectorSize; i++)
        {
          _memory[sectorStartAddress + i] = 0xff;
        }
      }
      finally
      {
        _status &= ~(Status.Wel | Status.Wip);
      }

      return new byte[] { };      
    }

    private byte[] EraseDevice(byte[] data)
    {
      if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
      _status |= Status.Wip;

      try
      {
        for (int i = 0; i < MemorySize; i++)
        {
          _memory[i] = 0xff;
        }
      }
      finally
      {
        _status &= ~(Status.Wel | Status.Wip);
      }


      return new byte[] { };
    }

    private byte[] PagePrograme(byte[] data)
    {
      if (!_status.HasFlag(Status.Wel) || _status.HasFlag(Status.Wip)) return new byte[] { };
      _status |= Status.Wip;

      try
      {
        int address = GetAddress(data);
        int offset = address % PageSize;

        for (int i = 0; i < data.Length - 4; i++)
        {
          _memory[address + ((offset + i) % PageSize)] &= (byte)data[i + 4];
        }
      }
      finally
      {
        _status &= ~(Status.Wel | Status.Wip);
      }


      return new byte[] { };
    }


    private byte[] ReadConfig(byte[] data)
    {
      return new byte[] { };
    }
  }
}

将闪存配置到模拟器中的相应配置如下(注意这是在自定义模拟器中使用的)。

  <Types>
    <MX25l3206>dotnetwarrior.Emulator.Hardware.MX25l3206FlashMemory, dotnetwarrior.Emulator</MX25l3206>
    <AccessIndicator>dotnetwarrior.Emulator.Hardware.AccessIndicator, dotnetwarrior.Emulator</AccessIndicator>
  </Types>

  <EmulatorComponents>
    <MX25l3206 id="myFlash">
      <MemorySize>4194304</MemorySize>
      <SectorSize>65536</SectorSize>
      <PageSize>256</PageSize>

      <ChipSelectPin>10</ChipSelectPin>      
      <!--SPI-->
      <ChipSelectActiveState>false</ChipSelectActiveState>
      <ChipSelectSetupTime>1</ChipSelectSetupTime>
      <ChipSelectHoldTime>1</ChipSelectHoldTime>
      <ClockRateKHz>36000</ClockRateKHz>
      <ClockIdleState>false</ClockIdleState>
      <ClockEdge>false</ClockEdge>
      <SpiModule>Spi1</SpiModule>
      <!--Hardware Provider-->
      <Mask>1</Mask>
      <Mosi>2</Mosi>
      <Miso>3</Miso>
    </MX25l3206>
于 2013-07-20T09:09:11.993 回答