ch39f 驱动成功

This commit is contained in:
2026-07-15 20:14:54 +08:00
parent 9943b410f4
commit c8c7ec0992
21 changed files with 17994 additions and 32 deletions

495
Inc/ch395f.h Normal file
View File

@@ -0,0 +1,495 @@
/*
* 模块名称CH395F SPI Ethernet Protocol Stack Driver
* 模块功能CH395F 以太网协议栈芯片 SPI 驱动提供网络初始化、Socket 管理、
* 数据收发等功能。命令码参考 CH395 手册 v2.2 Table 5-1
* 适用平台STM32F4 系列SPI2 接口)
* 作者:王建锋
* 创建日期2026-06-06
* 修改记录:
* 2026-06-06 王建锋 创建初始版本,按代码规范重构
*/
#ifndef __CH395F_H
#define __CH395F_H
/*
* 头文件包含区 - 仅包含本模块必需的头文件
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/*
* 宏定义区 - SPI 命令码(来自 CH395 手册 v2.2 Table 5-1
*/
/* 无输入数据,无输出数据 */
#define CH395F_CMD_RESET_ALL 0x05U
#define CH395F_CMD_ENTER_SLEEP 0x03U
/* 无输入数据1 字节输出 */
#define CH395F_CMD_GET_IC_VER 0x01U
#define CH395F_CMD_GET_CMD_STATUS 0x2CU
#define CH395F_CMD_GET_GLOB_INT_STATUS 0x29U
#define CH395F_CMD_GET_GLOB_INT_STATUS_ALL 0x19U
#define CH395F_CMD_GET_PHY_STATUS 0x26U
#define CH395F_CMD_GET_DHCP_STATUS 0x42U
/* 无输入数据6 字节输出 */
#define CH395F_CMD_GET_MAC_ADDR 0x40U
/* 无输入数据20 字节输出 */
#define CH395F_CMD_GET_IP_INF 0x43U
/* 1 字节输入,无输出数据 */
#define CH395F_CMD_SET_PHY 0x20U
#define CH395F_CMD_PING_ENABLE 0x3FU
#define CH395F_CMD_DHCP_ENABLE 0x41U
#define CH395F_CMD_SET_RETRAN_COUNT 0x2AU
/* 1 字节输入1 字节输出 */
#define CH395F_CMD_CHECK_EXIST 0x06U
#define CH395F_CMD_SET_FUN_PARA 0x55U
/* 2 字节输入,无输出数据 */
#define CH395F_CMD_SET_TTL 0x51U
#define CH395F_CMD_SET_ARP 0x44U
/* 3 字节输入,无输出数据 */
#define CH395F_CMD_SET_BAUDRATE 0x02U
#define CH395F_CMD_SET_RETRAN_PERIOD 0x2BU
/* 4 字节输入,无输出数据 */
#define CH395F_CMD_SET_IP_ADDR 0x22U
#define CH395F_CMD_SET_GWIP_ADDR 0x23U
#define CH395F_CMD_SET_MASK_ADDR 0x24U
/* 6 字节输入,无输出数据 */
#define CH395F_CMD_SET_MAC_ADDR 0x21U
/* 初始化命令(仅写入,执行时间较长) */
#define CH395F_CMD_INIT_CH395 0x27U
/* Socket 命令 */
/* 1 字节输入socket 索引),无输出数据 */
#define CH395F_CMD_CLOSE_SOCKET_SN 0x3DU
#define CH395F_CMD_OPEN_SOCKET_SN 0x35U
#define CH395F_CMD_TCP_LISTEN_SN 0x36U
#define CH395F_CMD_TCP_CONNECT_SN 0x37U
#define CH395F_CMD_TCP_DISCONNECT_SN 0x38U
#define CH395F_CMD_CLEAR_RECV_BUF_SN 0x2EU
/* 1 字节输入1 字节输出socket 索引) */
#define CH395F_CMD_GET_INT_STATUS_SN 0x30U
#define CH395F_CMD_GET_SOCKET_STATUS_SN 0x2FU
/* 1 字节输入2 字节输出 */
#define CH395F_CMD_GET_RECV_LEN_SN 0x3BU
/* 2 字节输入,无输出数据 */
#define CH395F_CMD_SET_PROTO_TYPE_SN 0x34U
#define CH395F_CMD_SET_IPRAW_PRO_SN 0x3EU
/* 3 字节输入,无输出数据 */
#define CH395F_CMD_SET_DES_PORT_SN 0x32U
#define CH395F_CMD_SET_SOUR_PORT_SN 0x33U
/* 5 字节输入无输出数据socket + 4 字节 IP */
#define CH395F_CMD_SET_IP_ADDR_SN 0x31U
/* 1 字节输入6 字节输出socket 索引 -> 远程 IP + 端口) */
#define CH395F_CMD_GET_REMOT_IPP_SN 0x2DU
/* 3 字节输入 + 数据输出socket + 长度) */
#define CH395F_CMD_READ_RECV_BUF_SN 0x3CU
/* 3 字节输入 + 数据输入socket + 长度 + 数据) */
#define CH395F_CMD_WRITE_SEND_BUF_SN 0x39U
/* 其他命令 */
#define CH395F_CMD_SET_TCP_MSS 0x50U
#define CH395F_CMD_SET_RECV_BUF 0x52U
#define CH395F_CMD_SET_SEND_BUF 0x53U
#define CH395F_CMD_SET_KEEPALIVE_IDLE 0x56U
#define CH395F_CMD_SET_KEEPALIVE_INTVL 0x57U
#define CH395F_CMD_SET_KEEPALIVE_CNT 0x58U
#define CH395F_CMD_SET_KEEPALIVE_SN 0x59U
#define CH395F_CMD_EEPROM_ERASE 0xE9U
#define CH395F_CMD_EEPROM_WRITE 0xEAU
#define CH395F_CMD_EEPROM_READ 0xEBU
#define CH395F_CMD_READ_GPIO_REG 0xECH
#define CH395F_CMD_WRITE_GPIO_REG 0xEDU
/*
* CH395 错误码(来自手册 CH395INC.H 引用)
*/
#define CH395F_ERR_SUCCESS 0x00U
#define CH395F_ERR_BUSY 0x01U
#define CH395F_ERR_CMD 0x02U
#define CH395F_ERR_MAC 0x03U
#define CH395F_ERR_PHY 0x04U
#define CH395F_ERR_IP_CONFLI 0x05U
#define CH395F_ERR_SOCK 0x06U
#define CH395F_ERR_SOCK_BUSY 0x07U
#define CH395F_ERR_SOCK_CLOSED 0x08U
#define CH395F_ERR_SOCK_ERR 0x09U
#define CH395F_ERR_UNKNOW 0xFFU
/*
* PHY 状态码
*/
#define CH395F_PHY_DISCONN 0x01U /* PHY 断开连接 */
#define CH395F_PHY_10M_FULL 0x02U /* 10M 全双工 */
#define CH395F_PHY_10M_HALF 0x04U /* 10M 半双工 */
#define CH395F_PHY_100M_FULL 0x08U /* 100M 全双工 */
#define CH395F_PHY_100M_HALF 0x10U /* 100M 半双工 */
#define CH395F_PHY_AUTO_NEGOTIATE 0x20U /* 自动协商 */
/*
* 协议类型
*/
#define CH395F_PROTO_TYPE_IP_RAW 0x00U
#define CH395F_PROTO_TYPE_MAC_RAW 0x01U
#define CH395F_PROTO_TYPE_UDP 0x02U
#define CH395F_PROTO_TYPE_TCP 0x03U
/*
* Socket 状态
*/
#define CH395F_SOCKET_CLOSED 0x00U
#define CH395F_SOCKET_OPEN 0x05U
/*
* TCP 状态
*/
#define CH395F_TCP_CLOSED 0x00U
#define CH395F_TCP_LISTEN 0x01U
#define CH395F_TCP_SYN_SENT 0x02U
#define CH395F_TCP_SYN_RCVD 0x03U
#define CH395F_TCP_ESTABLISHED 0x04U
#define CH395F_TCP_FIN_WAIT_1 0x05U
#define CH395F_TCP_FIN_WAIT_2 0x06U
#define CH395F_TCP_CLOSE_WAIT 0x07U
#define CH395F_TCP_CLOSING 0x08U
#define CH395F_TCP_LAST_ACK 0x09U
#define CH395F_TCP_TIME_WAIT 0x0AU
/*
* 全局中断状态位
*/
#define CH395F_GINT_STAT_UNREACH 0x01U
#define CH395F_GINT_STAT_IP_CONFLI 0x02U
#define CH395F_GINT_STAT_PHY_CHANGE 0x04U
#define CH395F_GINT_STAT_DHCP 0x08U
#define CH395F_GINT_STAT_SOCK0 0x10U
#define CH395F_GINT_STAT_SOCK1 0x20U
#define CH395F_GINT_STAT_SOCK2 0x40U
#define CH395F_GINT_STAT_SOCK3 0x80U
/*
* Socket 中断状态位
*/
#define CH395F_SINT_STAT_CONNECT 0x01U
#define CH395F_SINT_STAT_DISCONNECT 0x02U
#define CH395F_SINT_STAT_SEND_OK 0x04U
#define CH395F_SINT_STAT_SENBUF_FREE 0x08U
#define CH395F_SINT_STAT_RECV_OK 0x10U
#define CH395F_SINT_STAT_DISCARD 0x20U
#define CH395F_SINT_STAT_SOCK_TIMEOUT 0x40U
/*
* 类型定义区 - 驱动返回码
*/
typedef enum {
CH395F_STATUS_OK = 0,
CH395F_STATUS_ERROR = -1,
CH395F_STATUS_TIMEOUT = -2,
CH395F_STATUS_NOT_DETECTED = -3
} ch395f_status_t;
/*
* 函数声明区 - SPI 基础事务层
*/
/*
* 函数功能:向 CH395 写入命令字节
* 入口参数cmd - 命令码 uint8_t 0x00 - 0xFF
* 返回值:命令码回显值 uint8_t
* 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用
* 函数说明SPI 模式下命令与数据之间无需间隔
*/
uint8_t ch395f_write_cmd(uint8_t cmd);
/*
* 函数功能:向 CH395 写入数据字节
* 入口参数data - 数据字节 uint8_t 0x00 - 0xFF
* 返回值:数据回显值 uint8_t
* 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用
*/
uint8_t ch395f_write_data(uint8_t data);
/*
* 函数功能:从 CH395 读取数据字节
* 返回值:接收到的数据字节 uint8_t
* 限定条件:需在 ch395f_spi_begin() 和 ch395f_spi_end() 之间调用
*/
uint8_t ch395f_read_data(void);
/*
* 函数声明区 - 芯片检测与版本
*/
/*
* 函数功能:检测 CH395 芯片是否存在且通信正常
* 返回值CH395F_STATUS_OK - 检测到芯片CH395F_STATUS_NOT_DETECTED - 未检测到
* 限定条件SPI2 已正确初始化
* 函数说明:发送 CMD_CHECK_EXIST (0x06) 及测试字节 0x57
* 芯片应返回按位取反值 0xA8
*/
ch395f_status_t ch395f_check_exist(void);
/*
* 函数功能:读取 CH395 芯片版本号
* 返回值版本字节bit5:0 为版本号uint8_t
* 限定条件:芯片已通过 ch395f_check_exist() 检测
*/
uint8_t ch395f_get_version(void);
/*
* 函数声明区 - 初始化
*/
/*
* 函数功能:软件复位 CH395
* 返回值CH395F_STATUS_OK
* 限定条件SPI2 已正确初始化
* 函数说明:复位耗时约 15msTE0函数内部已包含延时
*/
ch395f_status_t ch395f_reset(void);
/*
* 函数功能:查询命令执行状态
* 返回值状态字节CH395F_ERR_SUCCESS / CH395F_ERR_BUSY / ...uint8_t
* 限定条件:仅在长执行命令(如初始化)后调用
*/
uint8_t ch395f_get_cmd_status(void);
/*
* 函数功能:初始化 CH395包含 MAC、PHY、TCP/IP 协议栈)
* 返回值CH395F_STATUS_OK - 成功CH395F_STATUS_TIMEOUT - 超时失败
* 限定条件:芯片已通过 ch395f_reset() 复位
* 函数说明:阻塞等待初始化完成或超时(典型 5msTE1
*/
ch395f_status_t ch395f_init(void);
/*
* 函数声明区 - 网络参数配置
*/
/*
* 函数功能:设置 CH395 IP 地址(低字节在前)
* 入口参数p_ip - 4 字节 IP 地址指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
*/
void ch395f_set_ip_addr(uint8_t *p_ip);
/*
* 函数功能:设置网关 IP 地址(低字节在前)
* 入口参数p_gwip - 4 字节网关 IP 指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
*/
void ch395f_set_gwip_addr(uint8_t *p_gwip);
/*
* 函数功能:设置子网掩码(低字节在前)
* 入口参数p_mask - 4 字节子网掩码指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
*/
void ch395f_set_mask_addr(uint8_t *p_mask);
/*
* 函数功能:设置 MAC 地址(低字节在前,存储于 EEPROM
* 入口参数p_mac - 6 字节 MAC 地址指针 uint8_t*
* 限定条件:指针非空,芯片已初始化
* 函数说明:执行耗时约 30usTE5
*/
void ch395f_set_mac_addr(uint8_t *p_mac);
/*
* 函数功能:从 CH395 读取 MAC 地址
* 出口参数p_mac - 6 字节 MAC 地址缓冲区指针 uint8_t*
* 限定条件:指针非空
*/
void ch395f_get_mac_addr(uint8_t *p_mac);
/*
* 函数功能:读取 IP 信息IP + 掩码 + DNS共 20 字节)
* 出口参数p_buf - 20 字节缓冲区指针 uint8_t*
* 限定条件:指针非空
*/
void ch395f_get_ip_inf(uint8_t *p_buf);
/*
* 函数声明区 - PHY 管理
*/
/*
* 函数功能:获取 PHY 连接状态
* 返回值PHY 状态码CH395F_PHY_DISCONN、CH395F_PHY_10M_FULL 等uint8_t
* 限定条件:芯片已初始化
*/
uint8_t ch395f_get_phy_status(void);
/*
* 函数功能:设置 PHY 连接模式
* 入口参数phystat - 连接模式码 uint8_t 0x20 = 自动协商
* 限定条件:芯片已初始化
*/
void ch395f_set_phy(uint8_t phystat);
/*
* 函数声明区 - DHCP
*/
/*
* 函数功能:启用/禁用 DHCP
* 入口参数enable - 1 启用0 禁用 uint8_t
* 限定条件:芯片已初始化
*/
void ch395f_set_dhcp(uint8_t enable);
/*
* 函数功能:获取 DHCP 状态
* 返回值0 = 成功,非零 = 错误/超时 uint8_t
* 限定条件:芯片已初始化且 DHCP 已启用
*/
uint8_t ch395f_get_dhcp_status(void);
/*
* 函数声明区 - Socket 管理
*/
/*
* 函数功能:设置 Socket 协议类型
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* proto - 协议类型 uint8_t CH395F_PROTO_TYPE_xxx
* 限定条件Socket 未打开
*/
void ch395f_set_proto_type(uint8_t sock, uint8_t proto);
/*
* 函数功能:设置 Socket 目标 IP 地址
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* p_ip - 4 字节目标 IP 指针 uint8_t*
* 限定条件:指针非空
*/
void ch395f_set_des_ip(uint8_t sock, uint8_t *p_ip);
/*
* 函数功能:设置 Socket 目标端口(小端序)
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* port - 目标端口 uint16_t
* 限定条件:无
*/
void ch395f_set_des_port(uint8_t sock, uint16_t port);
/*
* 函数功能:设置 Socket 源端口(小端序)
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* port - 源端口 uint16_t
* 限定条件:无
*/
void ch395f_set_sour_port(uint8_t sock, uint16_t port);
/*
* 函数功能:打开 Socket
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 限定条件:协议类型、目标 IP、端口已设置
*/
void ch395f_open_socket(uint8_t sock);
/*
* 函数功能:关闭 Socket
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 限定条件Socket 已打开
*/
void ch395f_close_socket(uint8_t sock);
/*
* 函数功能:启动 TCP 监听模式
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 限定条件Socket 已打开且协议类型为 TCP
*/
void ch395f_tcp_listen(uint8_t sock);
/*
* 函数功能:启动 TCP 连接
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 限定条件Socket 已打开且协议类型为 TCP
*/
void ch395f_tcp_connect(uint8_t sock);
/*
* 函数功能:断开 TCP 连接
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 限定条件TCP 已建立连接
*/
void ch395f_tcp_disconnect(uint8_t sock);
/*
* 函数声明区 - Socket 数据传输
*/
/*
* 函数功能:向 Socket 发送缓冲区写入数据
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* p_data - 数据指针 uint8_t*
* len - 数据长度 uint16_t
* 限定条件:指针非空,长度大于 0TCP 已连接或 UDP 已打开
*/
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
/*
* 函数功能:从 Socket 接收缓冲区读取数据
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* p_data - 输出缓冲区指针 uint8_t*
* len - 待读取数据长度 uint16_t
* 限定条件:指针非空,长度大于 0接收缓冲区有数据
*/
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len);
/*
* 函数功能:获取 Socket 接收缓冲区数据长度
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 返回值:接收数据长度 uint16_t
* 限定条件Socket 已打开
*/
uint16_t ch395f_get_recv_len(uint8_t sock);
/*
* 函数声明区 - 中断状态
*/
/*
* 函数功能:获取全局中断状态
* 返回值:中断状态字节 uint8_t
* 限定条件:芯片已初始化
*/
uint8_t ch395f_get_glob_int_status(void);
/*
* 函数功能:获取 Socket 中断状态
* 入口参数sock - Socket 索引 uint8_t 0 - 3
* 返回值Socket 中断状态字节 uint8_t
* 限定条件:芯片已初始化
*/
uint8_t ch395f_get_sock_int_status(uint8_t sock);
#ifdef __cplusplus
}
#endif
#endif /* __CH395F_H */

View File

@@ -61,6 +61,26 @@ void Error_Handler(void);
#define LED1_GPIO_Port GPIOC
#define LED2_Pin GPIO_PIN_5
#define LED2_GPIO_Port GPIOC
#define LED3_Pin GPIO_PIN_1
#define LED3_GPIO_Port GPIOB
#define LED4_Pin GPIO_PIN_2
#define LED4_GPIO_Port GPIOB
#define LED5_Pin GPIO_PIN_11
#define LED5_GPIO_Port GPIOF
#define LED6_Pin GPIO_PIN_12
#define LED6_GPIO_Port GPIOF
#define CH395_SCS_Pin GPIO_PIN_12
#define CH395_SCS_GPIO_Port GPIOB
#define CH395F_SCK_Pin GPIO_PIN_13
#define CH395F_SCK_GPIO_Port GPIOB
#define CH395F_SDO_Pin GPIO_PIN_14
#define CH395F_SDO_GPIO_Port GPIOB
#define CH395F_SDOB15_Pin GPIO_PIN_15
#define CH395F_SDOB15_GPIO_Port GPIOB
#define ST_TX0_Pin GPIO_PIN_9
#define ST_TX0_GPIO_Port GPIOA
#define ST_RX0_Pin GPIO_PIN_10
#define ST_RX0_GPIO_Port GPIOA
/* USER CODE BEGIN Private defines */

52
Inc/spi.h Normal file
View File

@@ -0,0 +1,52 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file spi.h
* @brief This file contains all the function prototypes for
* the spi.c file
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SPI_H__
#define __SPI_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern SPI_HandleTypeDef hspi2;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_SPI2_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __SPI_H__ */

View File

@@ -62,9 +62,9 @@
/* #define HAL_SAI_MODULE_ENABLED */
/* #define HAL_SD_MODULE_ENABLED */
/* #define HAL_MMC_MODULE_ENABLED */
/* #define HAL_SPI_MODULE_ENABLED */
#define HAL_SPI_MODULE_ENABLED
/* #define HAL_TIM_MODULE_ENABLED */
/* #define HAL_UART_MODULE_ENABLED */
#define HAL_UART_MODULE_ENABLED
/* #define HAL_USART_MODULE_ENABLED */
/* #define HAL_IRDA_MODULE_ENABLED */
/* #define HAL_SMARTCARD_MODULE_ENABLED */

52
Inc/usart.h Normal file
View File

@@ -0,0 +1,52 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.h
* @brief This file contains all the function prototypes for
* the usart.c file
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_USART1_UART_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */