CH347读写SPI Flash

news2024/11/27 4:01:18

CH347读写SPI Flash

前面耽搁了几天,今天终于把CH347 SPI接口调试好了。

CH347动态库中SPI接口函数如下:

typedef struct _SPI_CONFIG{
	UCHAR           iMode;                 // 0-3:SPI Mode0/1/2/3
	UCHAR           iClock;                // 0=60MHz, 1=30MHz, 2=15MHz, 3=7.5MHz, 4=3.75MHz, 5=1.875MHz, 6=937.5KHz,7=468.75KHz
	UCHAR			iByteOrder;            // 0=LSB first(LSB), 1=MSB first(MSB)
	USHORT          iSpiWriteReadInterval; // The SPI interface routinely reads and writes data command, the unit is uS
	UCHAR           iSpiOutDefaultData;    // SPI prints data by default when it reads data
	ULONG			iChipSelect;           // Piece of selected control, if bit 7 is 0, slice selection control is ignored, if bit 7 is 1, the parameter is valid: bit 1 bit 0 is 00/01 and CS1/CS2 pins are selected as low level active chip options respectively
	UCHAR           CS1Polarity;           // Bit 0: CS1 polarity control: 0: effective low level; 1: effective lhigh level;
	UCHAR           CS2Polarity;           // Bit 0: CS2 polarity control: 0: effective low level; 1: effective lhigh level;
	USHORT          iIsAutoDeativeCS;      // Whether to undo slice selection automatically after the operation is complete
	USHORT          iActiveDelay;          // Set the latency for read/write operations after slice selection,the unit is us
	ULONG           iDelayDeactive;        // Delay time for read and write operations after slice selection is unselected,the unit is us
}mSpiCfgS,*mPSpiCfgS;

/***************SPI********************/
// SPI Controller Initialization
BOOL	WINAPI	CH347SPI_Init(ULONG iIndex,mSpiCfgS *SpiCfg);

// Get SPI controller configuration information
BOOL    WINAPI  CH347SPI_GetCfg(ULONG iIndex,mSpiCfgS *SpiCfg);

// Before setting the chip selection status, call CH347SPI_Init to set CS
BOOL	WINAPI	CH347SPI_ChangeCS(ULONG			iIndex,         // Specify device number	
								  UCHAR         iStatus);       // 0=Cancel the piece to choose,1=Set piece selected

// Set SPI slice selection
BOOL	WINAPI	CH347SPI_SetChipSelect(ULONG			iIndex,            // Specify device number
									   USHORT           iEnableSelect,     // The lower octet is CS1 and the higher octet is CS2. A byte value of 1= sets CS, 0= ignores this CS setting
									   USHORT           iChipSelect,       // The lower octet is CS1 and the higher octet is CS2. A byte value of 1= sets CS, 0= ignores this CS setting
									   ULONG            iIsAutoDeativeCS,  // The lower 16 bits are CS1 and the higher 16 bits are CS2. Whether to undo slice selection automatically after the operation is complete
									   ULONG            iActiveDelay,      // The lower 16 bits are CS1 and the higher 16 bits are CS2. Set the latency of read/write operations after chip selection, the unit is us
									   ULONG            iDelayDeactive);   // The lower 16 bits are CS1 and the higher 16 bits are CS2. Delay time for read and write operations after slice selection the unit is us

//SPI4 write data
BOOL	WINAPI	CH347SPI_Write(ULONG			iIndex,          // Specify device number	
							   ULONG			iChipSelect,     // Slice selection control, when bit 7 is 0, slice selection control is ignored, and when bit 7 is 1, slice selection operation is performed
							   ULONG			iLength,         // Number of bytes of data to be transferred	
							   ULONG			iWriteStep,      // The length of a single block to be read
							   PVOID			ioBuffer);       // Point to a buffer to place the data to be written out from MOSI

//SPI4 read data. No need to write data first, the efficiency is higher than that of the CH347SPI_WriteRead
BOOL	WINAPI	CH347SPI_Read(ULONG			iIndex,           // Specify device number
							  ULONG			iChipSelect,      // Slice selection control, when bit 7 is 0, slice selection control is ignored, and when bit 7 is 1, slice selection operation is performed
							  ULONG         oLength,          // Number of bytes to send
							  PULONG		iLength,          // Number of bytes of data to be read in
							  PVOID			ioBuffer);        // Points to a buffer that place the data to be written out from DOUT, return the data read in from DIN

// Handle SPI data stream 4-wire interface
BOOL	WINAPI	CH347SPI_WriteRead(ULONG			iIndex,       // Specify the device number
								   ULONG			iChipSelect,  // Selection control, if the film selection control bit 7 is 0, ignore the film selection control bit 7 is 1 and operate the film selection
								   ULONG			iLength,      // Number of bytes of data to be transferred
								   PVOID			ioBuffer );   // Points to a buffer that place the data to be written out from DOUT, return the data read in from DIN

//place the data to be written from MOSI, return the data read in from MISO
BOOL	WINAPI	CH347StreamSPI4(ULONG			iIndex,       // Specify the device number
								ULONG			iChipSelect,  // Film selection control, if bit 7 is 0, slice selection control is ignored.If bit 7 is 1, the parameter is valid:Bit 1 bit 0 is 00/01/10. Select D0/D1/D2 pins as low level active chip options respectively
								ULONG			iLength,      // Number of bytes of data to be transferred
								PVOID			ioBuffer );   // Points to a buffer, places data to be written out from DOUT, and returns data to be read in from DIN

要实现SPI通信,至少要用到CH347SPI_Init(ULONG iIndex,mSpiCfgS *SpiCfg) CH347SPI_Write(ULONG iIndex, ULONG iChipSelect, ULONG iLength, ULONG iWriteStep, PVOID ioBuffer) CH347SPI_Read(ULONG iIndex, ULONG iChipSelect, ULONG oLength, PULONG iLength, PVOID ioBuffer)这3个函数。

对这3个函数进行封装:

class SPIConfig(ctypes.Structure):
    _fields_ = [
        ("iMode", ctypes.c_ubyte),                      # 0-3: SPI Mode0/1/2/3
        ("iClock", ctypes.c_ubyte),                     # 0=60MHz, 1=30MHz, 2=15MHz, 3=7.5MHz,
        ("iByteOrder", ctypes.c_ubyte),                 # 4=3.75MHz, 5=1.875MHz, 6=937.5KHz, 7=468.75KHz
        ("iSpiWriteReadInterval", ctypes.c_ushort),     # Regular interval for SPI read/write commands, in microseconds
        ("iSpiOutDefaultData", ctypes.c_ubyte),         # Default output data when reading from SPI
        ("iChipSelect", ctypes.c_ulong),                # Chip select control. Bit 7 as 0 ignores chip select control,
                                                        # Bit 7 as 1 makes the parameters valid:
                                                        # Bit 1 and Bit 0 as 00/01 selects CS1/CS2 pin as the active low chip select.
        ("CS1Polarity", ctypes.c_ubyte),                # Bit 0: CS1 polarity control, 0: active low, 1: active high
        ("CS2Polarity", ctypes.c_ubyte),                # Bit 0: CS2 polarity control, 0: active low, 1: active high
        ("iIsAutoDeativeCS", ctypes.c_ushort),          # Automatically de-assert chip select after the operation is completed
        ("iActiveDelay", ctypes.c_ushort),              # Delay time for executing read/write operations after chip select is set, in microseconds
        ("iDelayDeactive", ctypes.c_ulong)              # Delay time for executing read/write operations after chip select is de-asserted, in microseconds
    ]

def spi_init(self, device_index: int, spi_config: SPIConfig) -> bool:
	"""
	Initialize the SPI Controller.

	Args:
		device_index (int): The device number.
		spi_config (SPIConfig): The configuration for the SPI controller.

	Returns:
		bool: True if initialization is successful, False otherwise.
	"""
	result = self.ch347dll.CH347SPI_Init(device_index, ctypes.byref(spi_config))
	return result

def spi_write(self, device_index: int, chip_select: int, write_data: bytes, write_step: int = 512) -> bool:
	"""
	SPI write data.

	Args:
		device_index (int): Device number.
		chip_select (int): Chip selection control. When bit 7 is 0, chip selection control is ignored.
							When bit 7 is 1, chip selection operation is performed.
		write_data (bytes): Data to write.
		write_step (int, optional): The length of a single block to be read. Default is 512.

	Returns:
		bool: True if successful, False otherwise.
	"""
	write_length = len(write_data)
	write_buffer = ctypes.create_string_buffer(write_data)
	result = self.ch347dll.CH347SPI_Write(device_index, chip_select, write_length, write_step, write_buffer)
	return result

def spi_read(self, device_index: int, chip_select: int, write_data: bytes, read_length: int) -> bytes:
	"""
	SPI read data.

	Args:
		device_index (int): Device number.
		chip_select (int): Chip selection control. When bit 7 is 0, chip selection control is ignored.
						When bit 7 is 1, chip selection operation is performed.
		write_data (bytes): Data to write.
		read_length (int): Number of bytes to read.

	Returns:
		bytes: Data read in from the SPI stream if successful, None otherwise.
	"""
	write_length = len(write_data)

	# Create ctypes buffer for write data
	write_buffer = ctypes.create_string_buffer(write_data)

	# Create ctypes buffer for read data
	read_buffer = ctypes.create_string_buffer(read_length)

	# Create combined buffer for read and write data
	combined_buffer = ctypes.create_string_buffer(write_buffer.raw[:write_length] + read_buffer.raw)

	result = self.ch347dll.CH347SPI_Read(device_index, chip_select, write_length, ctypes.byref(ctypes.c_ulong(read_length)), combined_buffer)

	if result:
		# Extract the read data from the combined buffer
		read_data = combined_buffer[:read_length]
		return bytes(read_data)
	else:
		return None

连接CH347和SPI Flash模块:

连接CH347和SPI Flash模块

上图中,红色LED的是W25Q32FV SPI Flash模块,绿色LED的是MPU6050。

编写测试代码:

import ch347

dll_path = "ch347dlla64.dll"  # Replace with the actual path to the DLL
device_index = 0  # Set the device index according to your requirements

ch347_driver = ch347.CH347Driver(dll_path)

result = ch347_driver.open_device(device_index)
if result:
    print(f"Successfully opened device index: {device_index}")
else:
    print(f"Failed to close device index: {device_index}")

spi_config = ch347.SPIConfig(
    iMode = 0,
    iClock = 0,
    iByteOrder = 1,
    iSpiWriteReadInterval = 0,
    iSpiOutDefaultData = 0,
    iChipSelect = 0x80,
    CS1Polarity = 0,
    CS2Polarity = 0,
    iIsAutoDeative = 1,
    iActiveDelay = 0,
    iDelayDeactive = 0
)
result = ch347_driver.spi_init(device_index, spi_config)
if result:
    print("Success to init SPI.")
else:
    print("Failed to init SPI.")

# 读制造商数据
read_data = ch347_driver.spi_read(device_index, 0x80, b"\x90\x00\x00\x00", 2)
print(read_data)

# 读 0x000000 4个字节
read_data = ch347_driver.spi_read(device_index, 0x80, b"\x03\x00\x00\x00", 4)
print(read_data)

# 写 0x000000 2个字节 0x01 0x02
ch347_driver.spi_write(device_index, 0x80, b'\x06')
ch347_driver.spi_write(device_index, 0x80, b'\x02\x00\x00\x00\x01\x02')

# 读 0x000000 4个字节
read_data = ch347_driver.spi_read(device_index, 0x80, b"\x03\x00\x00\x00", 4)
print(read_data)

# Example usage of CH347CloseDevice
result = ch347_driver.close_device(device_index)
if result:
    print(f"Successfully closed device index: {device_index}")
else:
    print(f"Failed to close device index: {device_index}")

运行一下:

❯ python testSPI.py
Successfully opened device index: 0
Success to init SPI.
b'\xef\x15'
b'\xff\xff\xff\xff'
b'\x01\x02\xff\xff'
Successfully closed device index: 0

至此就可以读写SPI Flash了。

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1053037.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据分析方法:RFM模型

一、RFM基本原理 RFM是三个单词的缩写: 最近一次消费时间(Recency),取数的时候一般取最近一次消费记录到当前时间的间隔,比如:7天、30天、90天未到店消费;直观上,一个用户太久不到…

Windows 下安装及配置 MySQL 8.1 (图文教程)

目录 下载 MySQL安装 MySQL配置 MySQL修改密码配置环境变量 卸载 MySQL开源项目微服务商城项目前后端分离项目 下载 MySQL 访问 MySQL 下载地址:https://dev.mysql.com/downloads/mysql/ 下载 MySQL 时,你可以选择 ZIP 包或 MSI 安装: ZIP包…

智能合约漏洞,Dyna 事件分析

智能合约漏洞,Dyna 事件分析 1. 漏洞简介 https://twitter.com/BlockSecTeam/status/1628319536117153794 https://twitter.com/BeosinAlert/status/1628301635834486784 2. 相关地址或交易 攻击交易 1: https://bscscan.com/tx/0x7fa89d869fd1b89e…

【Java 进阶篇】MySQL 事务详解

在数据库管理中,事务是一组SQL语句的执行单元,它们被视为一个整体。事务的主要目标是保持数据库的一致性和完整性,即要么所有SQL语句都成功执行,要么所有SQL语句都不执行。在MySQL中,事务起到了非常重要的作用&#xf…

【C++】map、set,multiset和multimap的使用及底层原理【完整版】

目录 一、map和set的使用 1、序列式容器和关联式容器 2、set的使用讲解 3、map的使用讲解 二、multiset和multimap 1、multiset和multimap的使用 2、OJ题:前k个高频单词 一、map和set的使用 1、序列式容器和关联式容器 序列式容器:vector/list/s…

java遇到的问题

java遇到的问题 Tomcat与JDK版本问题 当使用Tomcat10的版本用于springmvc借用浏览器调试时,使用JDK8浏览器会报异常。 需要JDK17(可以配置多个JDK环境,切换使用)才可以使用,配置为JAVA_HOME路径,否则&a…

Linux系统编程系列之进程间通信-消息队列

一、什么是消息队列 消息队列是system-V三种IPC对象之一,是进程间通信的一种方式。 二、消息队列的特性 允许发送的数据携带类型(指定发送给谁),具有相同类型的数据在消息队列内部排队,读取的时候也要指定类型&#x…

STM32三种开发方式及标准库和HAL库的编程差异

三种开发方式 STM32基于标准库函数和HAL库编程差异_stm32库函数和hal库-CSDN博客本文目的是以串口通信来简要分析STM32使用标准库函数和HAL库函数编程的差异。目录(一)开发方式1.配置寄存器2.库函数3.HAL库(二)库函数与HAL库对比…

格点数据可视化(美国站点的日降雨数据)

获取美国站点的日降雨量的格点数据,并且可视化 导入模块 from datetime import datetime, timedelta from urllib.request import urlopenimport cartopy.crs as ccrs import cartopy.feature as cfeature import matplotlib.colors as mcolors import matplotli…

3D孪生场景搭建:模型区域摆放

前面介绍完了NSDT场景编辑器的线性绘制和阵列绘制,本章将讲述下编辑器的另一种绘制方式:区域绘制。 1、区域绘制功能简介 在场景中绘制资产时,除使用上述两个的方式外,NSDT 编辑器还支持使用区域绘制的方式进行绘制。先选取需要…

【C/C++笔试练习】——数组名和数组名、switch循环语句、数据在计算机中的存储顺序、字符串中找出连续最长的数字串、数组中出现次数超过一半的数字

文章目录 C/C笔试练习1.数组名和&数组名(1)数组名和&数组名的差异(2)理解数组名和指针偏移(3)理解数组名代表的含义(4)理解数组名代表的含义 2.switch循环语句(6…

FFmpeg 命令:从入门到精通 | ffplay 简单过滤器

FFmpeg 命令:从入门到精通 | ffplay 简单过滤器 FFmpeg 命令:从入门到精通 | ffplay 简单过滤器视频旋转视频反转视频旋转和反转音频变速播放视频变速播放音视频同时变速更多参考 FFmpeg 命令:从入门到精通 | ffplay 简单过滤器 本节介绍了简…

【CFD小工坊】浅水方程的离散及求解方法

【CFD小工坊】浅水方程的离散及求解方法 前言基于有限体积法的方程离散界面通量与源项计算干-湿网格的处理数值离散的稳定性条件参考文献 前言 我们模型的控制方程,即浅水方程组的表达式如下: ∂ U ∂ t ∂ E ( U ) ∂ x ∂ G ( U ) ∂ y S ( U ) U…

十五、异常(4)

本章概要 Java 标志异常 特例:RuntimeException 使用 finally 进行清理 finally 用来做什么?在 return 中使用 finally缺憾:异常丢失 Java 标准异常 Throwable 这个 Java 类被用来表示任何可以作为异常被抛出的类。Throwable 对象可分为两…

JUC——并发编程—第二部分

集合类不安全 list不安全 //报错 java.util.ConcurrentModificationException public class ListTest {public static void main(String[] args) {List<String> list new CopyOnWriteArrayList<>();//并发下Arrayist边读边写会不安全的/*** 解决方案&#xff1a…

国庆作业 9月30 消息队列实现进程间通信

01_write.c&#xff1a; #include <myhead.h> #define MAX 1024//x消息结构体 typedef struct {long msgtype; //消息类型char msg[MAX]; //消息正文 }Msg;#define SIZE sizeof(Msg)-sizeof(long) //正文大小int main(int argc, const char *argv[]) {//1:创建一个key…

机器学习之单层神经网络的训练:增量规则(Delta Rule)

文章目录 权重的调整单层神经网络使用delta规则的训练过程 神经网络以权值的形式存储信息,根据给定的信息来修改权值的系统方法称为学习规则。由于训练是神经网络系统地存储信息的唯一途径&#xff0c;因此学习规则是神经网络研究中的一个重要组成部分 权重的调整 &#xff08…

企业级磁盘阵列存储系统由硬到软全析

企业级磁盘阵列是由一组设备构成的存储系统,主要包括两种类型的设备,分别是控制器和扩展柜,其中控制器只有一台,扩展柜可以没有,也可以有多台。在EMC的Unity中分别称为DPE(Disk Processor Enclosure)和DAE(Disk Array Enclosure),在华为的OceanStor里面称为控制框和硬…

【网络模型】OSI七层网络模型、TCP/IP网络模型、键入网址到页面显示的过程、DNS是什么等重点知识汇总

目录 OSI 的七层模型 TCP/IP 网络模型 键入网址到网页显示发生了什么 你知道DNS是什么&#xff1f; OSI 的七层模型 简要概括 应用层&#xff1a;为用户的应用进程提供网络通信服务表示层&#xff1a;处理用户信息的表示问题&#xff0c;数据的编码&#xff0c;压缩和解压…