TCP可以正常使用
This commit is contained in:
@@ -7,12 +7,15 @@
|
||||
* 创建日期:2026-03-14
|
||||
* 修改记录:
|
||||
* 2026-03-14 王建锋 创建初始版本,按代码规范重构
|
||||
* 2026-07-18 王建锋 改造 write_send_buf / read_recv_buf 使用 SPI2 DMA 批量传输
|
||||
*/
|
||||
|
||||
/* 头文件包含区 - 先包含本模块头文件,再包含依赖头文件 */
|
||||
#include "ch395f.h"
|
||||
#include "spi.h"
|
||||
#include "usart.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* 私有宏定义区
|
||||
@@ -21,12 +24,24 @@
|
||||
#define CH395F_RESET_DELAY_MS 20U /* 复位后等待延时(ms) */
|
||||
#define CH395F_INIT_TIMEOUT_MS 500U /* 初始化超时时间(ms) */
|
||||
#define CH395F_SPI_BEGIN_DELAY_MS 1U /* SPI 事务开始延时(ms) */
|
||||
#define CH395F_DMA_BUF_SIZE 1500U /* DMA 缓冲区最大字节数 */
|
||||
|
||||
/*
|
||||
* 私有变量区 - DMA 传输相关
|
||||
*/
|
||||
static volatile uint8_t s_spi2_dma_done = 0U; /* DMA 传输完成标志 */
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t s_spi2_dma_tx_buf[CH395F_DMA_BUF_SIZE]; /* DMA 发送缓冲区 */
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t s_spi2_dma_rx_buf[CH395F_DMA_BUF_SIZE]; /* DMA 接收缓冲区 */
|
||||
|
||||
/*
|
||||
* 私有函数声明区
|
||||
*/
|
||||
static void ch395f_spi_begin(void);
|
||||
static void ch395f_spi_end(void);
|
||||
static void ch395f_spi_dma_transfer(uint16_t len);
|
||||
|
||||
/*
|
||||
* 私有函数实现区
|
||||
@@ -34,14 +49,14 @@ static void ch395f_spi_end(void);
|
||||
|
||||
/*
|
||||
* 函数功能:开始 SPI 事务(CS 拉高 -> 拉低)
|
||||
* 函数说明:手册要求 SPI 模式下字节间无需间隔
|
||||
* 函数说明:手册要求 SPI 模式下字节间无需间隔,
|
||||
* CS 拉高再拉低满足最小片选间隔要求
|
||||
*/
|
||||
static void ch395f_spi_begin(void)
|
||||
{
|
||||
/* CS 先拉高,确保空闲状态 */
|
||||
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(CH395F_SPI_BEGIN_DELAY_MS);
|
||||
/* CS 拉低,启动事务 */
|
||||
/* CS 拉低,启动事务(无需额外延时,SPI 时序由 SCK 频率决定) */
|
||||
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
@@ -54,6 +69,81 @@ static void ch395f_spi_end(void)
|
||||
HAL_GPIO_WritePin(CH395_SCS_GPIO_Port, CH395_SCS_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:DMA 全双工传输并等待完成
|
||||
* 入口参数:len - 传输字节数 uint16_t
|
||||
* 函数说明:发送 s_spi2_dma_tx_buf,接收到 s_spi2_dma_rx_buf,
|
||||
* 阻塞等待 DMA 完成回调置位标志
|
||||
*/
|
||||
static void ch395f_spi_dma_transfer(uint16_t len)
|
||||
{
|
||||
HAL_StatusTypeDef status;
|
||||
uint32_t tickstart;
|
||||
volatile uint32_t loop_cnt = 0U;
|
||||
|
||||
s_spi2_dma_done = 0U;
|
||||
status = HAL_SPI_TransmitReceive_DMA(&hspi2, s_spi2_dma_tx_buf, s_spi2_dma_rx_buf, len);
|
||||
if (status != HAL_OK)
|
||||
{
|
||||
printf("[DMA] HAL_SPI_TransmitReceive_DMA FAIL: %d, SPI_State=%d, SPI_Error=0x%lX, DMA_State=%d\r\n",
|
||||
(int)status,
|
||||
(int)hspi2.State,
|
||||
hspi2.ErrorCode,
|
||||
(int)hspi2.hdmarx->State);
|
||||
return;
|
||||
}
|
||||
|
||||
tickstart = HAL_GetTick();
|
||||
while (s_spi2_dma_done == 0U)
|
||||
{
|
||||
loop_cnt++;
|
||||
if ((HAL_GetTick() - tickstart) > 1000U)
|
||||
{
|
||||
printf("[DMA] TIMEOUT after 1s, len=%d, loop=%lu, SPI_State=%d, SPI_Error=0x%lX\r\n",
|
||||
(int)len, loop_cnt,
|
||||
(int)hspi2.State,
|
||||
hspi2.ErrorCode);
|
||||
printf("[DMA] DMA_RX: State=%d, Dir=%lu, CNT=%lu\r\n",
|
||||
(int)hspi2.hdmarx->State,
|
||||
hspi2.hdmarx->Init.Direction,
|
||||
__HAL_DMA_GET_COUNTER(hspi2.hdmarx));
|
||||
printf("[DMA] DMA_TX: State=%d, Dir=%lu, CNT=%lu\r\n",
|
||||
(int)hspi2.hdmatx->State,
|
||||
hspi2.hdmatx->Init.Direction,
|
||||
__HAL_DMA_GET_COUNTER(hspi2.hdmatx));
|
||||
printf("[DMA] SPI2_CR1=0x%lX, CR2=0x%lX, SR=0x%lX\r\n",
|
||||
SPI2->CR1, SPI2->CR2, SPI2->SR);
|
||||
/* 强制复位 SPI2 DMA 状态,避免死锁 */
|
||||
HAL_SPI_Abort(&hspi2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:SPI 收发完成回调
|
||||
* 函数说明:由 HAL SPI 驱动在 DMA TX+RX 完成后调用(HAL_SPI_TransmitReceive_DMA 触发此回调)
|
||||
*/
|
||||
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
|
||||
{
|
||||
if (hspi->Instance == SPI2)
|
||||
{
|
||||
s_spi2_dma_done = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:SPI 错误回调
|
||||
* 函数说明:由 HAL SPI 驱动在 DMA 传输出错时调用,释放等待
|
||||
*/
|
||||
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
|
||||
{
|
||||
if (hspi->Instance == SPI2)
|
||||
{
|
||||
s_spi2_dma_done = 1U;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 公共函数实现区
|
||||
*/
|
||||
@@ -164,6 +254,299 @@ uint8_t ch395f_get_version(void)
|
||||
return version;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取远端 IP 和端口
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* p_buf - 6 字节输出缓冲区(4字节IP + 2字节端口)
|
||||
* 限定条件:TCP Server 模式下连接建立后调用
|
||||
* 函数说明:IP 低字节在前,端口低字节在前
|
||||
*/
|
||||
void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
/* 检查输入参数合法性 */
|
||||
if (p_buf == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送获取远端 IP 和端口命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_GET_REMOT_IPP_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 读取 4 字节 IP 地址 */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p_buf[i] = ch395f_read_data();
|
||||
}
|
||||
|
||||
/* 读取 2 字节端口号 */
|
||||
for (i = 4; i < 6; i++)
|
||||
{
|
||||
p_buf[i] = ch395f_read_data();
|
||||
}
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 CH395 功能参数
|
||||
* 入口参数:para - 4 字节功能参数 uint32_t
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_fun_para(uint32_t para)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置功能参数命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_FUN_PARA);
|
||||
|
||||
/* 发送 4 字节参数(低字节在前) */
|
||||
ch395f_write_data((uint8_t)(para));
|
||||
ch395f_write_data((uint8_t)(para >> 8));
|
||||
ch395f_write_data((uint8_t)(para >> 16));
|
||||
ch395f_write_data((uint8_t)(para >> 24));
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 TCP MSS
|
||||
* 入口参数:mss - MSS 值 uint16_t 60~1460
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_tcp_mss(uint16_t mss)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置 TCP MSS 命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_TCP_MSS);
|
||||
|
||||
/* 发送 2 字节 MSS 值(低字节在前) */
|
||||
ch395f_write_data(mss & 0xFFU);
|
||||
ch395f_write_data((mss >> 8) & 0xFFU);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 Socket 接收缓冲区
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* start_block - 起始块地址 uint8_t
|
||||
* block_count - 块个数 uint8_t
|
||||
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
|
||||
*/
|
||||
void ch395f_set_recv_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置接收缓冲区命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_RECV_BUF);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 发送起始块地址 */
|
||||
ch395f_write_data(start_block);
|
||||
|
||||
/* 发送块个数 */
|
||||
ch395f_write_data(block_count);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 Socket 发送缓冲区
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* start_block - 起始块地址 uint8_t
|
||||
* block_count - 块个数 uint8_t
|
||||
* 限定条件:必须在 OPEN_SOCKET_SN 之前调用
|
||||
*/
|
||||
void ch395f_set_send_buf(uint8_t sock, uint8_t start_block, uint8_t block_count)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置发送缓冲区命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_SEND_BUF);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 发送起始块地址 */
|
||||
ch395f_write_data(start_block);
|
||||
|
||||
/* 发送块个数 */
|
||||
ch395f_write_data(block_count);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:清空 Socket 接收缓冲区
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 限定条件:Socket 已打开
|
||||
*/
|
||||
void ch395f_clear_recv_buf(uint8_t sock)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送清空接收缓冲区命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_CLEAR_RECV_BUF_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 TCP KeepAlive 空闲时间
|
||||
* 入口参数:time - 空闲时间(秒) uint32_t
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_keepalive_idle(uint32_t time)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置 KeepAlive 空闲时间命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_IDLE);
|
||||
|
||||
/* 发送 4 字节时间值(低字节在前) */
|
||||
ch395f_write_data((uint8_t)(time));
|
||||
ch395f_write_data((uint8_t)(time >> 8));
|
||||
ch395f_write_data((uint8_t)(time >> 16));
|
||||
ch395f_write_data((uint8_t)(time >> 24));
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 TCP KeepAlive 探测间隔
|
||||
* 入口参数:time - 间隔时间(秒) uint32_t
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_keepalive_intvl(uint32_t time)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置 KeepAlive 探测间隔命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_INTVL);
|
||||
|
||||
/* 发送 4 字节时间值(低字节在前) */
|
||||
ch395f_write_data((uint8_t)(time));
|
||||
ch395f_write_data((uint8_t)(time >> 8));
|
||||
ch395f_write_data((uint8_t)(time >> 16));
|
||||
ch395f_write_data((uint8_t)(time >> 24));
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 TCP KeepAlive 探测次数
|
||||
* 入口参数:cnt - 探测次数 uint8_t
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_keepalive_cnt(uint8_t cnt)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置 KeepAlive 探测次数命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_CNT);
|
||||
|
||||
/* 发送探测次数 */
|
||||
ch395f_write_data(cnt);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:启用/禁用指定 Socket 的 KeepAlive
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* enable - 1 启用,0 禁用 uint8_t
|
||||
* 限定条件:Socket 已打开
|
||||
*/
|
||||
void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置 KeepAlive 使能命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_KEEPALIVE_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 发送使能标志 */
|
||||
ch395f_write_data(enable);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 TCP 重传次数
|
||||
* 入口参数:cnt - 重传次数 uint8_t(0=使用默认值5)
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_retrans_count(uint8_t cnt)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置重传次数命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_RETRAN_COUNT);
|
||||
|
||||
/* 发送重传次数 */
|
||||
ch395f_write_data(cnt);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 TCP 重传周期
|
||||
* 入口参数:period - 重传周期(毫秒) uint16_t
|
||||
* 限定条件:必须在 ch395f_init() 之前调用
|
||||
*/
|
||||
void ch395f_set_retrans_period(uint16_t period)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送设置重传周期命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_SET_RETRAN_PERIOD);
|
||||
|
||||
/* 发送 2 字节周期值(低字节在前) */
|
||||
ch395f_write_data(period & 0xFFU);
|
||||
ch395f_write_data((period >> 8) & 0xFFU);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:软件复位 CH395
|
||||
* 返回值:CH395F_STATUS_OK
|
||||
@@ -211,55 +594,58 @@ uint8_t ch395f_get_cmd_status(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:轮询等待命令执行完成
|
||||
* 入口参数:timeout_ms - 超时时间(毫秒) uint32_t
|
||||
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 或 CH395F_CMD_RET_ABORT)
|
||||
* 限定条件:在发送长执行命令后调用
|
||||
* 函数说明:每 20ms 查询一次,直到命令完成或超时
|
||||
*/
|
||||
uint8_t ch395f_poll_cmd_status(uint32_t timeout_ms)
|
||||
{
|
||||
uint8_t status;
|
||||
uint32_t retry_count = 0U;
|
||||
uint32_t max_retries = (timeout_ms + 20U - 1U) / 20U;
|
||||
|
||||
while (1)
|
||||
{
|
||||
HAL_Delay(20U);
|
||||
status = ch395f_get_cmd_status();
|
||||
|
||||
if (status != CH395F_ERR_BUSY)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
if (++retry_count >= max_retries)
|
||||
{
|
||||
return CH395F_ERR_BUSY; /* 超时 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:初始化 CH395(包含 MAC、PHY、TCP/IP 协议栈)
|
||||
* 返回值:CH395F_STATUS_OK - 成功,CH395F_STATUS_TIMEOUT - 超时失败
|
||||
* 限定条件:芯片已通过 ch395f_reset() 复位
|
||||
* 函数说明:阻塞等待初始化完成或超时(典型 5ms,TE1)
|
||||
* 函数说明:阻塞等待初始化完成或超时(芯片需要约 200ms,这里等最多 4s)
|
||||
*/
|
||||
ch395f_status_t ch395f_init(void)
|
||||
{
|
||||
uint8_t status;
|
||||
uint32_t retry_count = 0U;
|
||||
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送初始化命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_INIT_CH395);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
|
||||
/* 轮询等待初始化完成 */
|
||||
while (1)
|
||||
{
|
||||
/* 每次轮询延时 1ms */
|
||||
HAL_Delay(1U);
|
||||
status = ch395f_poll_cmd_status(4000U);
|
||||
|
||||
/* 查询命令执行状态 */
|
||||
status = ch395f_get_cmd_status();
|
||||
|
||||
/* 状态非 BUSY 表示执行完毕 */
|
||||
if (status != CH395F_ERR_BUSY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* 超时判断 */
|
||||
if (++retry_count > CH395F_INIT_TIMEOUT_MS)
|
||||
{
|
||||
return CH395F_STATUS_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/* 返回最终执行结果 */
|
||||
if (status == CH395F_ERR_SUCCESS)
|
||||
{
|
||||
return CH395F_STATUS_OK;
|
||||
}
|
||||
|
||||
return CH395F_STATUS_ERROR;
|
||||
return (status == CH395F_ERR_BUSY) ? CH395F_STATUS_TIMEOUT : CH395F_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -673,114 +1059,95 @@ void ch395f_set_sour_port(uint8_t sock, uint16_t port)
|
||||
|
||||
/*
|
||||
* 函数功能:打开 Socket
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||
* 限定条件:协议类型、目标 IP、端口已设置
|
||||
*/
|
||||
void ch395f_open_socket(uint8_t sock)
|
||||
uint8_t ch395f_open_socket(uint8_t sock)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送打开 Socket 命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_OPEN_SOCKET_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
|
||||
return ch395f_poll_cmd_status(4000U);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:关闭 Socket
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||
* 限定条件:Socket 已打开
|
||||
*/
|
||||
void ch395f_close_socket(uint8_t sock)
|
||||
uint8_t ch395f_close_socket(uint8_t sock)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送关闭 Socket 命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_CLOSE_SOCKET_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
|
||||
return ch395f_poll_cmd_status(4000U);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:启动 TCP 监听模式
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||
* 限定条件:Socket 已打开且协议类型为 TCP
|
||||
*/
|
||||
void ch395f_tcp_listen(uint8_t sock)
|
||||
uint8_t ch395f_tcp_listen(uint8_t sock)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送 TCP 监听命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_TCP_LISTEN_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
|
||||
return ch395f_poll_cmd_status(4000U);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:启动 TCP 连接
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||
* 限定条件:Socket 已打开且协议类型为 TCP
|
||||
*/
|
||||
void ch395f_tcp_connect(uint8_t sock)
|
||||
uint8_t ch395f_tcp_connect(uint8_t sock)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送 TCP 连接命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_TCP_CONNECT_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
|
||||
return ch395f_poll_cmd_status(4000U);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:断开 TCP 连接
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* 返回值:命令执行状态码(CH395F_ERR_SUCCESS 表示成功) uint8_t
|
||||
* 限定条件:TCP 已建立连接
|
||||
*/
|
||||
void ch395f_tcp_disconnect(uint8_t sock)
|
||||
uint8_t ch395f_tcp_disconnect(uint8_t sock)
|
||||
{
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送 TCP 断开命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_TCP_DISCONNECT_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
ch395f_spi_end();
|
||||
|
||||
return ch395f_poll_cmd_status(4000U);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:向 Socket 发送缓冲区写入数据
|
||||
* 函数功能:向 Socket 发送缓冲区写入数据(DMA 批量传输)
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* p_data - 数据指针 uint8_t*
|
||||
* len - 数据长度 uint16_t
|
||||
* 限定条件:指针非空,长度大于 0,TCP 已连接或 UDP 已打开
|
||||
* 函数说明:将命令头和数据打包到 DMA 缓冲区,一次 SPI DMA 传输完成
|
||||
*/
|
||||
void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t total;
|
||||
|
||||
/* 检查输入参数合法性 */
|
||||
if (p_data == NULL)
|
||||
@@ -788,41 +1155,40 @@ void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
||||
return;
|
||||
}
|
||||
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送写入发送缓冲区命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_WRITE_SEND_BUF_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 发送数据长度低字节 */
|
||||
ch395f_write_data(len & 0xFFU);
|
||||
|
||||
/* 发送数据长度高字节 */
|
||||
ch395f_write_data((len >> 8) & 0xFFU);
|
||||
|
||||
/* 逐字节发送数据 */
|
||||
for (i = 0; i < len; i++)
|
||||
/* 计算总长度:1(cmd) + 1(sock) + 2(len) + data */
|
||||
total = 4U + len;
|
||||
if (total > CH395F_DMA_BUF_SIZE)
|
||||
{
|
||||
ch395f_write_data(p_data[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
/* 打包命令头到 DMA 发送缓冲区 */
|
||||
s_spi2_dma_tx_buf[0] = CH395F_CMD_WRITE_SEND_BUF_SN;
|
||||
s_spi2_dma_tx_buf[1] = sock;
|
||||
s_spi2_dma_tx_buf[2] = len & 0xFFU;
|
||||
s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU;
|
||||
|
||||
/* 拷贝用户数据到 DMA 发送缓冲区 */
|
||||
memcpy(&s_spi2_dma_tx_buf[4], p_data, len);
|
||||
|
||||
/* CS 拉低 -> DMA 批量传输 -> CS 拉高 */
|
||||
ch395f_spi_begin();
|
||||
ch395f_spi_dma_transfer(total);
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:从 Socket 接收缓冲区读取数据
|
||||
* 函数功能:从 Socket 接收缓冲区读取数据(DMA 批量传输)
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
* p_data - 输出缓冲区指针 uint8_t*
|
||||
* len - 待读取数据长度 uint16_t
|
||||
* 限定条件:指针非空,长度大于 0,接收缓冲区有数据
|
||||
* 函数说明:命令头打包到发送缓冲区(数据部分填 0xFF 作时钟),
|
||||
* 一次 SPI DMA 全双工传输,有效数据从接收缓冲区偏移 4 字节处拷出
|
||||
*/
|
||||
void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t total;
|
||||
|
||||
/* 检查输入参数合法性 */
|
||||
if (p_data == NULL)
|
||||
@@ -830,29 +1196,29 @@ void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len)
|
||||
return;
|
||||
}
|
||||
|
||||
/* 开始 SPI 事务 */
|
||||
ch395f_spi_begin();
|
||||
|
||||
/* 发送读取接收缓冲区命令 */
|
||||
ch395f_write_cmd(CH395F_CMD_READ_RECV_BUF_SN);
|
||||
|
||||
/* 发送 Socket 索引 */
|
||||
ch395f_write_data(sock);
|
||||
|
||||
/* 发送读取长度低字节 */
|
||||
ch395f_write_data(len & 0xFFU);
|
||||
|
||||
/* 发送读取长度高字节 */
|
||||
ch395f_write_data((len >> 8) & 0xFFU);
|
||||
|
||||
/* 逐字节读取数据 */
|
||||
for (i = 0; i < len; i++)
|
||||
/* 计算总长度:1(cmd) + 1(sock) + 2(len) + data */
|
||||
total = 4U + len;
|
||||
if (total > CH395F_DMA_BUF_SIZE)
|
||||
{
|
||||
p_data[i] = ch395f_read_data();
|
||||
return;
|
||||
}
|
||||
|
||||
/* 结束 SPI 事务 */
|
||||
/* 命令头打包到 DMA 发送缓冲区 */
|
||||
s_spi2_dma_tx_buf[0] = CH395F_CMD_READ_RECV_BUF_SN;
|
||||
s_spi2_dma_tx_buf[1] = sock;
|
||||
s_spi2_dma_tx_buf[2] = len & 0xFFU;
|
||||
s_spi2_dma_tx_buf[3] = (len >> 8) & 0xFFU;
|
||||
|
||||
/* 数据部分填充 0xFF(SPI 时钟驱动用) */
|
||||
memset(&s_spi2_dma_tx_buf[4], 0xFFU, len);
|
||||
|
||||
/* CS 拉低 -> DMA 全双工传输(发命令头 + 收数据) -> CS 拉高 */
|
||||
ch395f_spi_begin();
|
||||
ch395f_spi_dma_transfer(total);
|
||||
ch395f_spi_end();
|
||||
|
||||
/* 从 DMA 接收缓冲区偏移 4 字节处拷贝有效数据到用户缓冲区 */
|
||||
memcpy(p_data, &s_spi2_dma_rx_buf[4], len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -910,6 +1276,24 @@ uint8_t ch395f_get_glob_int_status(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取全局中断状态(2 字节版,支持 Socket 0~7)
|
||||
* 返回值:中断状态 uint16_t(低字节=Socket 0~3 + PHY/DHCP,高字节=Socket 4~7 + DHCPv6)
|
||||
* 限定条件:芯片已初始化
|
||||
*/
|
||||
uint16_t ch395f_get_glob_int_status_all(void)
|
||||
{
|
||||
uint16_t status;
|
||||
|
||||
ch395f_spi_begin();
|
||||
ch395f_write_cmd(CH395F_CMD_GET_GLOB_INT_STATUS_ALL);
|
||||
status = (uint16_t)ch395f_read_data();
|
||||
status |= ((uint16_t)ch395f_read_data() << 8U);
|
||||
ch395f_spi_end();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取 Socket 中断状态
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 3
|
||||
@@ -937,3 +1321,68 @@ uint8_t ch395f_get_sock_int_status(uint8_t sock)
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取 Socket 状态(2 字节输出)
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* status - 2 字节输出缓冲区 [0]=Socket状态, [1]=TCP状态
|
||||
* 限定条件:芯片已初始化
|
||||
*/
|
||||
void ch395f_get_socket_status(uint8_t sock, uint8_t *status)
|
||||
{
|
||||
ch395f_spi_begin();
|
||||
ch395f_write_cmd(CH395F_CMD_GET_SOCKET_STATUS_SN);
|
||||
ch395f_write_data(sock);
|
||||
status[0] = ch395f_read_data();
|
||||
status[1] = ch395f_read_data();
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 ARP 重传参数
|
||||
* 入口参数:period_100ms - ARP 重传周期(单位 100ms,0=默认值=10即1秒) uint8_t
|
||||
* cnt - ARP 重传次数(0=默认值=3) uint8_t
|
||||
* 限定条件:应在 ch395f_init() 之后调用
|
||||
* 函数说明:周期最大值约 25.5 秒,255 表示无限重传
|
||||
*/
|
||||
void ch395f_set_arp(uint8_t period_100ms, uint8_t cnt)
|
||||
{
|
||||
ch395f_spi_begin();
|
||||
ch395f_write_cmd(CH395F_CMD_SET_ARP);
|
||||
ch395f_write_data(period_100ms);
|
||||
ch395f_write_data(cnt);
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:设置 Socket TTL
|
||||
* 入口参数:sock - Socket 索引 uint8_t 0 - 7
|
||||
* ttl - TTL 值 uint8_t 最大 128
|
||||
* 限定条件:Socket 已打开,TCP Server 模式下不生效
|
||||
*/
|
||||
void ch395f_set_ttl(uint8_t sock, uint8_t ttl)
|
||||
{
|
||||
ch395f_spi_begin();
|
||||
ch395f_write_cmd(CH395F_CMD_SET_TTL);
|
||||
ch395f_write_data(sock);
|
||||
ch395f_write_data(ttl);
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取不可达信息(用于调试连接失败原因)
|
||||
* 出口参数:p_buf - 8 字节输出缓冲区(类型+协议码+端口+IP)
|
||||
* 限定条件:收到 GINT_STAT_UNREACH 中断后调用
|
||||
*/
|
||||
void ch395f_get_unreach_info(uint8_t *p_buf)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
ch395f_spi_begin();
|
||||
ch395f_write_cmd(CH395F_CMD_GET_UNREACH_IPPT);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
p_buf[i] = ch395f_read_data();
|
||||
}
|
||||
ch395f_spi_end();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user