跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python

Python 基于 FTDI FT2232H 实现 SPI 通信控制

使用 Python 语言配合 ctypes 库调用 FTDI ftd2xx.dll 动态链接库,通过 FT2232H 芯片的 MPSSE 模式实现 SPI 通信控制的代码示例。主要功能包括设备初始化、时钟配置、CS 信号控制以及寄存器的读写操作(单字节、连续、增量等)。代码包含状态枚举定义、缓冲区结构体封装及具体的 SPI 指令发送逻辑。

静心发布于 2026/3/25更新于 2026/7/1243 浏览

Python 基于 FTDI FT2232H 实现 SPI 通信控制

本文介绍了使用 Python 语言配合 ctypes 库调用 FTDI ftd2xx.dll 动态链接库,通过 FT2232H 芯片的 MPSSE 模式实现 SPI 通信控制的代码示例。

核心功能

  • 设备初始化与 MPSSE 模式配置
  • 时钟频率设置与 CS 信号控制
  • 寄存器读写(单字节、连续、增量)
  • EEPROM 操作支持

代码实现

import os
import time
import array
import ctypes
from ctypes import *
from enum import Enum
import math
import re

class Device_status(Enum):
    FT_OK = 0
    FT_INVALID_HANDLE = 1
    FT_DEVICE_NOT_FOUND = 2
    FT_DEVICE_NOT_OPENED = 3
    FT_IO_ERROR = 4
    FT_INSUFFICIENT_RESOURCES = 5
    FT_INVALID_PARAMETER = 6
    FT_INVALID_BAUD_RATE = 7
    FT_DEVICE_NOT_OPENED_FOR_ERASE = 8
    FT_DEVICE_NOT_OPENED_FOR_WRITE = 9
    FT_FAILED_TO_WRITE_DEVICE = 10
    FT_EEPROM_READ_FAILED = 11
    FT_EEPROM_WRITE_FAILED = 12
    FT_EEPROM_ERASE_FAILED = 13
    FT_EEPROM_NOT_PRESENT = 14
    FT_EEPROM_NOT_PROGRAMMED = 15
    FT_INVALID_ARGS = 16
    FT_NOT_SUPPORTED = 17
    FT_OTHER_ERROR = 18
    FT_DEVICE_LIST_NOT_READY = 19

MemSize = 512
SPIDATALENGTH = 11
READ = 0xC0
WRITE = 0xA0
WREN = 0x98
ERAL = 0x90
BAD_COMMAND_RESPONSE = 0xFA

MSB_RISING_EDGE_CLOCK_BYTE_OUT = 0x10
MSB_FALLING_EDGE_CLOCK_BYTE_OUT = 0x11
MSB_RISING_EDGE_CLOCK_BIT_OUT = 0x12
MSB_FALLING_EDGE_CLOCK_BIT_OUT = 0x13
MSB_RISING_EDGE_CLOCK_BYTE_IN = 0x20
MSB_RISING_EDGE_CLOCK_BIT_IN = 0x22
MSB_FALLING_EDGE_CLOCK_BYTE_IN = 0x24
MSB_FALLING_EDGE_CLOCK_BIT_IN = 0x26

class OutBuffer(ctypes.Structure):
    _fields_ = [('data', ctypes.c_ubyte * 65535)]

class InBuffer(ctypes.Structure):
    _fields_ = [('data', ctypes.c_ubyte * 65535)]

class OutDataBuffer(ctypes.Structure):
    _fields_ = [('data', ctypes.c_ubyte * MemSize)]

class InDataBuffer(ctypes.Structure):
    _fields_ = [('data', ctypes.c_ubyte * MemSize)]

class FT_DEVICE_LIST_INFO_NODE(ctypes.Structure):
    _fields_ = [
        ('flags', ctypes.c_ulong),
        ('type', ctypes.c_ulong),
        ('id', ctypes.c_ulong),
        ('locId', ctypes.c_ulong),
        ('serial_number', ctypes.c_char * 16),
        ('description', ctypes.c_char * 64),
        ('devInfo', ctypes.c_char_p),
        ('ft_handle', ctypes.c_void_p)
    ]

class SPI:
    def __init__(self):
        self.output_buffer = OutBuffer()
        self.input_buffer = InBuffer()
        self.clock_div = 29
        self.num_bytes_to_send = 0
        self.num_bytes_send = ctypes.c_ulong()
        self.num_bytes_read = ctypes.c_ulong()
        self.num_input_buffer = ctypes.c_ulong()
        self.byte_data_read = 0
        self.mem_addr = 0x00
        self.data_out_buffer = OutDataBuffer()
        self.data_in_buffer = InDataBuffer()
        self.ft_status = 0
        self.dummy_rd = 8
        self.dummy_wr = 8
        self.high_addr = 0
        self.bit_wr_flag = 0
        self.ftdiHandle = ctypes.c_void_p()
        self.ftd2xx = ctypes.cdll.LoadLibrary
        current_dir = os.path.dirname(os.path.abspath(__file__))
        file_name = os.path.join(current_dir, 'ftd2xx64.dll')
        self.lib_ftd2xx = self.ftd2xx(file_name)
        self.debug = 0
        self.reg_config_all_file_path = r'D:\reg_config_all.txt'
        self.reg_config_file_path = r'D:\reg_config.txt'
        fid = open(self.reg_config_file_path, 'w')
        fid.write('{}\t{}\t{}\n'.format('Type'.ljust(2, ' '), 'Addr'.ljust(10, ' '), 'Value'.ljust(10, ' ')))
        fid.close()
        fid = open(self.reg_config_all_file_path, 'w')
        fid.write('Type\tBit_h\tBit_l\tAddr\tBalue\n')
        fid.close()

    @staticmethod
    def split_list(lst, size):
        result = []
        for i in range(0, len(lst), size):
            result.append(lst[i:i + size])
        return result

    @staticmethod
    def set_reg(data, bit_h, bit_l, val, bit_len=32):
        b_len = bit_h - bit_l + 1
        if val > 2 ** (bit_h - bit_l + 1) - 1:
            raise ValueError('val={}超过 bit 位宽{}.'.format(val, b_len))
        data_bin = bin(data)[2:].rjust(bit_len, '0')
        data_bin_list = list(data_bin)[::-1]
        val_bin = bin(val)[2:].rjust(b_len, '0')
        val_bin_list = list(val_bin)[::-1]
        k = 0
        for i in range(bit_l, bit_h + 1):
            data_bin_list[i] = val_bin_list[k]
            k += 1
        data_final = ''.join(data_bin_list[::-1])
        return int(data_final, 2)

    def SPI_CSEnable(self):
        for i in range(5):
            self.output_buffer.data[self.num_bytes_to_send] = 0x80
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0x00
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0x0b
            self.num_bytes_to_send += 1

    def SPI_CSDisable(self):
        for loop in range(5):
            self.output_buffer.data[self.num_bytes_to_send] = 0x80
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0x08
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0x0b
            self.num_bytes_to_send += 1

    def ft2232_write(self, addr, value):
        addr = addr >> 2
        high_addr = addr >> 20
        if high_addr != self.high_addr:
            self.ft2232_write_high_addr(high_addr)
        addr = addr & 0xFFFFF
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b00010000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ((addr >> 16) & 0xF) << 4
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (addr >> 8) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = addr & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (value >> 24) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (value >> 16) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (value >> 8) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = value & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = math.ceil(self.dummy_wr/8) - 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        ft_status = self.lib_ftd2xx.FT_Read(self.ftdiHandle, self.input_buffer.data, 4, byref(self.num_bytes_read))
        self.num_bytes_to_send = 0
        return ft_status

    def ft2232_write_inc(self, value):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b00110000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (value >> 24) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (value >> 16) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (value >> 8) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = value & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = math.ceil(self.dummy_wr / 8) - 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        return ft_status

    def ft2232_read_con(self, addr, length):
        addr = addr >> 2
        high_addr = addr >> 20
        if high_addr != self.high_addr:
            self.ft2232_write_high_addr(high_addr)
        addr = addr & 0xFFFFF
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b10000000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ((addr >> 16) & 0xF) << 4
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (addr >> 8) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = addr & 0xFF
        self.num_bytes_to_send += 1
        for i in range(length):
            self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_IN
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 4
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0
            self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        ft_status = self.lib_ftd2xx.FT_Read(self.ftdiHandle, self.input_buffer.data, length*5, byref(self.num_bytes_read))
        bdata = []
        for n in range(int(length)):
            bdata.append(hex(((self.input_buffer.data[1+5*n] << 24) + (self.input_buffer.data[2+5*n] << 16) + (self.input_buffer.data[3+5*n] << 8) + self.input_buffer.data[4+5*n])))
        self.num_bytes_to_send = 0
        return bdata

    def ft2232_write_con(self, addr, data_list):
        addr = addr >> 2
        high_addr = addr >> 20
        if high_addr != self.high_addr:
            self.ft2232_write_high_addr(high_addr)
        addr = addr & 0xFFFFF
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b10010000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ((addr >> 16) & 0xF) << 4
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (addr >> 8) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = addr & 0xFF
        self.num_bytes_to_send += 1
        for i in range(len(data_list)):
            value = data_list[i]
            self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 3
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = (value >> 24) & 0xFF
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = (value >> 16) & 0xFF
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = (value >> 8) & 0xFF
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = value & 0xFF
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = (math.ceil(self.dummy_wr / 8) - 1)
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0
            self.num_bytes_to_send += 1
            self.output_buffer.data[self.num_bytes_to_send] = 0
            self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        return ft_status

    def ft2232_write_dly(self, dummy_wr):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        dummy_wr = math.ceil(dummy_wr/8) * 8
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b01010000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 7
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = dummy_wr
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        self.dummy_wr = dummy_wr
        return ft_status

    def ft2232_write_high_addr(self, high_addr):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b01100000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 7
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = high_addr >> 2
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (high_addr & 0x3) << 6
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        self.high_addr = high_addr
        return ft_status

    def write(self, addr, value):
        if self.debug == 0:
            self.ft2232_write(addr, value)
        if self.bit_wr_flag == 0:
            with open(self.reg_config_file_path, 'r') as fid:
                lines = fid.readlines()
            fid.close()
            if len(lines) > 1:
                if 'delay' in lines[-1] or '[R]' in lines[-1] or '#' in lines[-1]:
                    last_addr = 0x0
                else:
                    last_addr = int(re.split('\t', lines[-1])[1].strip(), 16)
            else:
                last_addr = 0x0
            if last_addr == addr:
                final_lines = lines[:-1]
                final_lines.append('[W]:\t{}\t{}\n'.format(hex(addr).ljust(10, ' '), hex(value).ljust(10, ' ')))
            else:
                final_lines = lines
                final_lines.append('[W]:\t{}\t{}\n'.format(hex(addr), hex(value)))
            with open(self.reg_config_file_path, 'w') as fid:
                for line in final_lines:
                    fid.write(line)
                fid.close()
            with open(self.reg_config_all_file_path, 'a+') as fid:
                fid.write('[W]:\t{}\t{}\t{}\t{}\n'.format(
                    hex(addr).ljust(10, ' '), hex(value).ljust(10, ' '), '-'.ljust(2, ' '), '-'.ljust(2, ' ', )))
                fid.close()

    def write_bits(self, addr, bit_h, bit_l, value):
        self.bit_wr_flag = 1
        if self.debug == 0:
            data = int(self.read(addr), 16)
            w_data = self.set_reg(data, bit_h, bit_l, value)
            self.write(addr, w_data)
        self.bit_wr_flag = 0
        with open(self.reg_config_file_path, 'r') as fid:
            lines = fid.readlines()
        fid.close()
        if len(lines) > 1:
            if 'delay' in lines[-1] or '[R]' in lines[-1] or '#' in lines[-1]:
                last_addr = 0x0
            else:
                last_addr = int(re.split('\t', lines[-1])[1].strip(), 16)
        else:
            last_addr = 0x0
        if last_addr == addr:
            final_lines = lines[:-1]
            final_lines.append('[W]:\t{}\t{}\n'.format(hex(addr).ljust(10, ' '), hex(w_data).ljust(10, ' ')))
        else:
            final_lines = lines
            final_lines.append('[W]:\t{}\t{}\n'.format(hex(addr), hex(w_data)))
        with open(self.reg_config_file_path, 'w') as fid:
            for line in final_lines:
                fid.write(line)
            fid.close()
        with open(self.reg_config_all_file_path, 'a+') as fid:
            fid.write('[W]:\t{}\t{}\t{}\t{}\n'.format(
                hex(addr).ljust(10, ' '), hex(value).ljust(10, ' '), str(bit_h).ljust(2, ' '), str(bit_l).ljust(2, ' ', )))
            fid.close()

    def ft2232_read(self, addr):
        self.num_bytes_send = ctypes.c_ulong(0)
        addr = addr >> 2
        high_addr = addr >> 20
        if high_addr != self.high_addr:
            self.ft2232_write_high_addr(high_addr)
        addr = addr & 0xFFFFF
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b00000000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ((addr >> 16) & 0xF) << 4
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = (addr >> 8) & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = addr & 0xFF
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = self.dummy_rd - 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_IN
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        ft_status = self.lib_ftd2xx.FT_Read(self.ftdiHandle, self.input_buffer.data, 4, byref(self.num_bytes_read))
        bdata = ((self.input_buffer.data[0] << 24) +(self.input_buffer.data[1] << 16) +(self.input_buffer.data[2] << 8) + self.input_buffer.data[3])
        return hex(bdata)[2:].upper()

    def ft2232_read_inc(self):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b00100000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = math.ceil(self.dummy_rd/8) - 1 + 4
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        ft_status = self.lib_ftd2xx.FT_Read(self.ftdiHandle, self.input_buffer.data, 4, byref(self.num_bytes_read))
        bdata = ((self.input_buffer.data[0] << 24) +(self.input_buffer.data[1] << 16) +(self.input_buffer.data[2] << 8) + self.input_buffer.data[3])
        return hex(bdata)[2:].upper()

    def ft2232_read_dly(self, dummy_rd):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        dummy_rd = math.ceil(dummy_rd / 8) * 8
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 3
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0b01000000
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 7
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = dummy_rd
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(self.ftdiHandle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        self.dummy_rd = dummy_rd
        return ft_status

    def read(self, addr):
        if self.debug == 0:
            b_data = self.ft2232_read(addr)
        else:
            b_data = '0'
        if self.bit_wr_flag == 0:
            with open(self.reg_config_file_path, 'a+') as fid:
                fid.write('[R]:\t{}\t{}\n'.format(
                    hex(addr).ljust(10, ' '), b_data.ljust(10, ' ')))
                fid.close()
            with open(self.reg_config_all_file_path, 'a+') as fid:
                fid.write('[R]:\t{}\t0x{}\n'.format(
                    hex(addr).ljust(10, ' '), b_data.ljust(10, ' ')))
                fid.close()
        return b_data

    def read_bits(self, addr, bit_h, bit_l):
        self.bit_wr_flag = 1
        if self.debug == 0:
            data = self.read(addr)
        else:
            data = '0'
        self.bit_wr_flag = 0
        data_bin = bin(int(data, 16))[2:].rjust(32, '0')
        data_list = list(data_bin)
        data_list.reverse()
        data_ret = data_list[bit_l:bit_h + 1]
        data_ret.reverse()
        ret = ''.join(data_ret)
        data_hex = hex(int(ret, 2))[2:]
        with open(self.reg_config_file_path, 'a+') as fid:
            fid.write('[R]:\t{}\t{}\n'.format(
                hex(addr).ljust(10, ' '), data.ljust(10, ' ')))
            fid.close()
        with open(self.reg_config_all_file_path, 'a+') as fid:
            fid.write('[R]:\t{}\t0x{}\t{}\t{}\n'.format(
                hex(addr).ljust(10, ' '), data.ljust(10, ' '), str(bit_h).ljust(2, ' '), str(bit_l).ljust(2, ' ', )))
            fid.close()
        return data_hex

    def SPI_Initial(self, ft_handle):
        ft_status = self.lib_ftd2xx.FT_ResetDevice(ft_handle)
        ft_status |= self.lib_ftd2xx.FT_GetQueueStatus(ft_handle, byref(self.num_input_buffer))
        if ft_status == Device_status.FT_OK.value and self.num_input_buffer.value > 0:
            ft_status |= self.lib_ftd2xx.FT_Read(ft_handle, self.input_buffer, self.num_input_buffer, self.num_bytes_read)
        ft_status |= self.lib_ftd2xx.FT_SetUSBParameters(ft_handle, 65535, 65535)
        ft_status |= self.lib_ftd2xx.FT_SetChars(ft_handle, False, 0, False, 0)
        ft_status |= self.lib_ftd2xx.FT_SetTimeouts(ft_handle, 3000, 3000)
        ft_status |= self.lib_ftd2xx.FT_SetLatencyTimer(ft_handle, 1)
        ft_status |= self.lib_ftd2xx.FT_SetBitMode(ft_handle, 0x0, 0x00)
        ft_status |= self.lib_ftd2xx.FT_SetBitMode(ft_handle, 0x0, 0x02)
        if ft_status != Device_status.FT_OK.value:
            print("fail on initialize FT2232H device ! ")
            return False
        time.sleep(0.05)
        self.num_bytes_to_send = 0
        self.output_buffer.data[self.num_bytes_to_send] = 0xAA
        self.num_bytes_to_send += 1
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        while self.num_input_buffer.value == 0 and ft_status == Device_status.FT_OK.value:
            ft_status = self.lib_ftd2xx.FT_GetQueueStatus(ft_handle, byref(self.num_input_buffer))
            b_command_echod = False
            ft_status = self.lib_ftd2xx.FT_Read(ft_handle, self.input_buffer.data, self.num_input_buffer, byref(self.num_bytes_read))
            for dw_count in range(0, self.num_bytes_read.value - 1):
                if self.input_buffer.data[dw_count] == 0xFA and self.input_buffer.data[dw_count + 1] == 0xAA:
                    b_command_echod = True
                    break
            if not b_command_echod:
                print("fail to synchronize MPSSE with command '0xAA' \n")
                return False
        self.num_bytes_to_send = 0
        self.output_buffer.data[self.num_bytes_to_send] = 0xAB
        self.num_bytes_to_send += 1
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        while (self.num_input_buffer == 0) and (ft_status == Device_status.FT_OK):
            ft_status = self.lib_ftd2xx.FT_GetQueueStatus(ft_handle, byref(self.num_input_buffer))
            b_command_echod = False
            ft_status = self.lib_ftd2xx.FT_Read(ft_handle, self.input_buffer.data, self.num_input_buffer, byref(self.num_bytes_read))
            for dw_count in range(0, self.num_bytes_read.value - 1):
                if self.input_buffer.data[dw_count] == 0xFA and self.input_buffer.data[dw_count + 1] == 0xAB:
                    b_command_echod = True
                    break
            if not b_command_echod:
                print("fail to synchronize MPSSE with command '0xAB' \n")
                return False
        self.output_buffer.data[self.num_bytes_to_send] = 0x8A
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x97
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x8D
        self.num_bytes_to_send += 1
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        self.output_buffer.data[self.num_bytes_to_send] = 0x80
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x00
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x0b
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x86
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ctypes.c_ubyte(self.clock_div & 0xFF)
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ctypes.c_ubyte(self.clock_div >> 8)
        self.num_bytes_to_send += 1
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        time.sleep(0.02)
        self.output_buffer.data[self.num_bytes_to_send] = 0x85
        self.num_bytes_to_send += 1
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        time.sleep(0.03)
        print("SPI initial successful\n")
        return True

    def SPI_WriteByte2RandomAddr(self, ft_handle, address, bdata):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 2
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = WRITE
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 7
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ctypes.c_ubyte(address)
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 1
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = bdata >> 8
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = bdata & 0xff
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        return ft_status

    def SPI_ReadByteRandomAddr(self, ft_handle, address):
        self.num_bytes_send = ctypes.c_ulong(0)
        self.SPI_CSEnable()
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 2
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = READ
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BIT_OUT
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 7
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = ctypes.c_ubyte(address)
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = MSB_FALLING_EDGE_CLOCK_BYTE_IN
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x01
        self.num_bytes_to_send += 1
        self.output_buffer.data[self.num_bytes_to_send] = 0x00
        self.num_bytes_to_send += 1
        self.SPI_CSDisable()
        ft_status = self.lib_ftd2xx.FT_Write(ft_handle, self.output_buffer.data, self.num_bytes_to_send, byref(self.num_bytes_send))
        self.num_bytes_to_send = 0
        ft_status = self.lib_ftd2xx.FT_Read(ft_handle, self.input_buffer.data, 2, byref(self.num_bytes_read))
        bdata = [((self.input_buffer.data[0] << 8) + self.input_buffer.data[1])]
        return ft_status

    def ft2232_init(self):
        self.lib_ftd2xx.FT_Close(self.ftdiHandle)
        numDevs = ctypes.c_ulong()
        devInfo = FT_DEVICE_LIST_INFO_NODE()
        ft_status = self.lib_ftd2xx.FT_CreateDeviceInfoList(ctypes.byref(numDevs))
        if ft_status == Device_status.FT_OK.value:
            print("Number of devices is {}".format(numDevs.value))
        else:
            print("error")
            return 1
        if int(numDevs.value) > 0:
            devInfo = (FT_DEVICE_LIST_INFO_NODE * numDevs.value)()
            ft_status = self.lib_ftd2xx.FT_GetDeviceInfoList(devInfo, byref(numDevs))
            if ft_status == Device_status.FT_OK.value:
                for i in range(numDevs.value):
                    print("Dev %d:" % i)
                    print(" Flags=0x{}".format(devInfo[i].flags))
                    print(" Type=0x{}".format(devInfo[i].type))
                    print(" ID=0x{}".format(devInfo[i].id))
                    print(" LocId=0x{}".format(devInfo[i].locId))
                    print(" SerialNumber={}".format(devInfo[i].serial_number))
                    print(" Description={}".format(devInfo[i].description))
                    print(" ft_handle=0x{}".format(devInfo[i].ft_handle))
            else:
                return 1
            ft_status = self.lib_ftd2xx.FT_Open(1, byref(self.ftdiHandle))
            print(ft_status)
            if ft_status != Device_status.FT_OK.value:
                raise ValueError("Can't open FT2232H device!")
                return 1
            else:
                print("Successfully open FT2232H device!")
        if self.SPI_Initial(self.ftdiHandle):
            ReadByte = 0
            for i in range(MemSize):
                self.data_out_buffer.data[i] = i
            ft_status = self.lib_ftd2xx.FT_GetQueueStatus(self.ftdiHandle, byref(self.num_bytes_read))
            if ft_status != Device_status.FT_OK.value and self.num_input_buffer.value > 0:
                self.lib_ftd2xx.FT_Read(self.ftdiHandle, self.input_buffer.data, self.num_input_buffer, byref(self.num_bytes_read))

    def set_dummy_rd(self, dummy_rd):
        self.ft2232_read_dly(dummy_rd)

    def set_dummy_wr(self, dummy_wr):
        self.ft2232_write_dly(dummy_wr)

    def read_inc(self):
        b_data = self.ft2232_read_inc()
        return b_data

    def write_inc(self, value):
        self.ft2232_write_inc(value)

    def read_con(self, addr, length):
        if length > 65536:
            raise ValueError('Data is too large to write, must be less than 65536.')
        data = []
        count = math.ceil(length/512)
        for n in range(count):
            if length/512 > 1:
                bdata = self.ft2232_read_con(addr+n*(512*4), 512)
            else:
                bdata = self.ft2232_read_con(addr + n * (512 * 4), length)
            data = data+bdata
        return data

    def write_con(self, addr, data_list):
        if len(data_list) > 65536:
            raise ValueError('Data is too large to write, must be less than 65536.')
        max_len = 512
        w_data_list = self.split_list(data_list, max_len)
        for n in range(len(w_data_list)):
            self.ft2232_write_con(addr+n*(512*4), w_data_list[n])

    def spi_sleep(self, sec):
        time.sleep(sec)
        with open(self.reg_config_all_file_path, 'a+') as fid:
            fid.write('delay {}s\n'.format(str(sec)))
            fid.close()
        with open(self.reg_config_file_path, 'a+') as fid:
            fid.write('delay {}s\n'.format(str(sec)))
            fid.close()

if __name__ == "__main__":
    spi = SPI()
    spi.ft2232_init()
    for i in range(3):
        spi.set_dummy_wr(dummy_wr=0x8)
        spi.set_dummy_rd(dummy_rd=0x8)
    print(spi.read(0xA0000448))

目录

  1. Python 基于 FTDI FT2232H 实现 SPI 通信控制
  2. 核心功能
  3. 代码实现
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 大模型产品经理转行指南:必备素质、技能与学习路径
  • MaxKB4j 开源智能体搭建平台技术文档
  • 大模型是如何生成文字的?
  • FPGA 入门指南:从点亮第一颗 LED 开始
  • 智能体工作流导出与导入实战:以 12345 政务热线为例
  • 2026 上半年主流 AIGC 长文本写作工具评测与选型指南
  • 当 AI 普及后,个人如何构建核心竞争力与变现路径?
  • 18 种大模型指令调优方法详解
  • GitHub Copilot 在 VS Code 中的代理功能使用指南
  • AIGC 工具全解析:从文本生成到代码辅助的实战指南
  • 二分查找算法核心逻辑与实战题解
  • Python 自动化实战:pyautogui 鼠标键盘控制指南
  • 栈的压入弹出序列验证算法详解
  • OpenClaw 跨平台安装指南:Windows、macOS 与 Linux
  • 深入分析:RAG 技术的演进与 Agent 架构解析
  • 递归算法核心:二叉树遍历与结构判断实现
  • ROG-Map: 面向大场景的高分辨率 LiDAR 机器人中心占用栅格地图
  • Linux 多线程:线程创建、等待与终止详解
  • 在 IntelliJ IDEA 中使用飞算 AI 的实操记录
  • LLaMA-Factory 命令行工具常用操作指南

相关免费在线工具

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online