为.NET Microframework创建自己的SpiDevice的最佳方法是什么?

时间:2013-07-19 14:45:53

标签: .net-micro-framework spi netduino

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

现在,我已经看到人们不必模拟SPI总线的东西,因为.NET Microframework已经有一个仿真的SPI总线,太棒了。

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

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

1 个答案:

答案 0 :(得分: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>