· 

MPSSEでSPI(1)

FTDIの一部のチップはMPSSEという機能でピンからSPI波形を出すことができます。自力で波形を形成する同期BitBangや非同期BitBangより良いのではないかってことで確認する。BitBangを試した時の記事はこちら

FTDIのホームページによるとMPSSEができるのは以下のチップ。

FT232HPQ

FT233HPQ

FT2232HPQ

FT2233HPQ

FT4232HPQ

FT4233HPQ

FT2232D (NRND)

FT4232HAQ

FT4232H-56Q

FT4232HQ

FT4232HL

FT2232H-56Q

FT2232HL

FT2232HQ

FT232HQ

FT232HL

 

ドキュメントはこちらで"MPSSE"で検索。こちら(D2XX_Programmer's_Guide(FT_000071))

 BitBangではFT_Writeをすると、そのデータが指示通りにポート状態に反映されていたけど、MPSSEではコマンド指示するような感じになる。そのコマンドやら引数やらは、AN_108に書いてあるんだけど、これを理解するのがまぁまぁしんどい。

と思っていると、なんと、SPIを出すためのDLLがFTDIから提供されている。こちら(LibMPSSE-SPI Examples)。そして、使い方はこちら(AN_178)。何事もしんどい初老の中年は易きに流れてみることにする。

で、今回は秋月のFD2232Dモジュールを使う。

こんな感じで。

 

import ctypes
from ctypes import wintypes
import time

#/******************************************************************************/
#/*                                                             Macro defines                                                             */
#/******************************************************************************/
#/* Bit definition of the transferOptions parameter in SPI_Read, SPI_Write & SPI_Transfer  */

#/* transferOptions-Bit0: If this bit is 0 then it means that the transfer size provided is in bytes */
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES=0x00000000
#/* transferOptions-Bit0: If this bit is 1 then it means that the transfer size provided is in bytes */
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS=0x00000001
#/* transferOptions-Bit1: if BIT1 is 1 then CHIP_SELECT line will be enabled at start of transfer */
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE=0x00000002
#/* transferOptions-Bit2: if BIT2 is 1 then CHIP_SELECT line will be disabled at end of transfer */
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE=0x00000004
#/* transferOptions-Bit3: if BIT3 is 1 then LSB will be processed first */
SPI_TRANSFER_OPTIONS_LSB_FIRST=0x00000008


#/* Bit definition of the Options member of configOptions structure */
SPI_CONFIG_OPTION_MODE_MASK=0x00000003
SPI_CONFIG_OPTION_MODE0=0x00000000
SPI_CONFIG_OPTION_MODE1=0x00000001
SPI_CONFIG_OPTION_MODE2=0x00000002
SPI_CONFIG_OPTION_MODE3=0x00000003

SPI_CONFIG_OPTION_CS_MASK=0x0000001C            #/* 111 00 */
SPI_CONFIG_OPTION_CS_DBUS3=0x00000000           #/* 000 00 */
SPI_CONFIG_OPTION_CS_DBUS4=0x00000004           #/* 001 00 */
SPI_CONFIG_OPTION_CS_DBUS5=0x00000008           #/* 010 00 */
SPI_CONFIG_OPTION_CS_DBUS6=0x0000000C           #/* 011 00 */
SPI_CONFIG_OPTION_CS_DBUS7=0x00000010           #/* 100 00 */

SPI_CONFIG_OPTION_CS_ACTIVEHIGH=0x00000000
SPI_CONFIG_OPTION_CS_ACTIVELOW=0x00000020

class ChannelConfig(ctypes.Structure):
    _fields_=[("ClockRate",wintypes.DWORD),
              ("LatencyTimer",ctypes.c_uint8),
              ("configOptions",wintypes.DWORD),
              ("Pin",wintypes.DWORD),
              ("currentPinState",ctypes.c_uint16)]

class FT_DEVICE_LIST_INFO_NODE(ctypes.Structure):
    SerialNumberArray16=ctypes.c_char*16
    DescriptionArray64=ctypes.c_char*64
    _fields_=[("Flags",wintypes.ULONG),
              ("Type",wintypes.ULONG),
              ("ID",wintypes.ULONG),
              ("LocId",wintypes.DWORD),
              ("SerialNumber",SerialNumberArray16),
              ("Description",DescriptionArray64),
              ("ftHandle",ctypes.c_void_p)
              ]

channels=wintypes.DWORD(0)

verMPSSE=wintypes.DWORD(0)
verD2XX=wintypes.DWORD(0)
dllfile='.\\libmpsse.dll'
dll = ctypes.CDLL(dllfile)

res=dll.Ver_libMPSSE(ctypes.pointer(verMPSSE),ctypes.pointer(verD2XX))
print(verMPSSE)
print(verD2XX)

res=dll.SPI_GetNumChannels(ctypes.pointer(channels))
print(channels)

devList=FT_DEVICE_LIST_INFO_NODE()
res=dll.SPI_GetChannelInfo(0,ctypes.pointer(devList))

handle = ctypes.c_void_p()
res=dll.SPI_OpenChannel(0,ctypes.pointer(handle))

channelConf=ChannelConfig()
channelConf.ClockRate=1000000
channelConf.LatencyTimer=2
channelConf.configOptions=0x00000020
channelConf.Pin=0
res=dll.SPI_InitChannel(handle, ctypes.pointer(channelConf))

inBuffer=(ctypes.c_uint8*128)()
outData=[0x55,0xAA,0x55]
#sizeToTransfer=wintypes.DWORD(24)
sizeToTransfer=wintypes.DWORD(3)
sizeTransferred=wintypes.DWORD()
#transferOptions=wintypes.DWORD(SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE)
transferOptions=wintypes.DWORD(SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE)

res=dll.SPI_ReadWrite(handle,inBuffer,(ctypes.c_ubyte * len(outData))(*outData),sizeToTransfer,ctypes.pointer(sizeTransferred),transferOptions)
res=dll.SPI_ReadWrite(handle,inBuffer,(ctypes.c_ubyte * len(outData))(*outData),sizeToTransfer,ctypes.pointer(sizeTransferred),transferOptions)

res=dll.SPI_CloseChannel(handle)

まぁ、こうなる。

LatencyTimer=2

はデバイスによって推奨範囲が違うので、デバイスのデータシートもいちおう目は通しておこう。まぁピン配置見るので目通すわな。

3バイト送ってみる。

で、

まぁできてる。

ではビット単位で送る(SPI_TRANSFER_OPTIONS_SIZE_IN_BITS)とどうなるのか。

とても残念なことに8bitづつ間隔をおいて出てきます。

、、、いけてないなー。好きなビット数のSPIを遅れなく撃つことを期待してたのに。まぁ普通にデバイスと通信するのには使える。

おぬしは何がしたいのかっていうと、、、超高速(そんなでもなくてもいい)SWD。やっぱFPGAだなー、、、しかし手ごろなFPGAが手に入らんのよねーこれが。半導体不足なんとかならんのかねー

最近マジで休みは寝てるか登城しているか、、、

平日は参勤者が多くて座席がないので登城したくない。さらに、もともと顔見知りの人や同じ仕事をしている人が隣になれば話すこともあるけど、初めましてに近い人とフュージョンは起こらん。このシステム、だめだと思う。

なので休日に広々使ってやる。ってことで、日曜技術者活動は停滞気味なのであります(勝手な言い訳)。決して最強ピカチュウ対策で忙しいわけではない。