From eddd8c2584ca2e9f9a67306f0dfe134fdaf6b1ef Mon Sep 17 00:00:00 2001 From: penglei <1624952103@qq.com> Date: Sat, 6 Dec 2025 18:14:03 +0800 Subject: [PATCH] =?utf8?q?=E4=BC=98=E5=8C=96SPI=E4=BC=A0=E8=BE=93=EF=BC=8C?= =?utf8?q?=E5=A2=9E=E5=8A=A0cat1=20=E6=97=B6=E9=97=B4=E5=90=8C=E6=AD=A5?= =?utf8?q?=E5=AE=9A=E6=97=B6=E5=99=A8=E6=8E=A7=E5=88=B6=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- cat1modem/src/LeiNiao/spi_write_test.py | 504 ++++++++++++------ .../chips/brandy/pm/include/pm_definition.h | 3 +- code/sdk/middleware/chips/brandy/pm/pm.c | 3 +- .../4g/cat1Service/Service/cat1_server.c | 16 + .../4g/cat1Service/include/cat1_server.h | 10 + code/sdk/zhihui/utils/custom_spi.c | 356 ++++--------- 6 files changed, 473 insertions(+), 419 deletions(-) diff --git a/cat1modem/src/LeiNiao/spi_write_test.py b/cat1modem/src/LeiNiao/spi_write_test.py index 9afa1151c..d5695a0f2 100644 --- a/cat1modem/src/LeiNiao/spi_write_test.py +++ b/cat1modem/src/LeiNiao/spi_write_test.py @@ -1,84 +1,106 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -SPI 写操作测试模块(保留原始时序版) -核心:严格保留原有延时/时序 + 适配datasize参数 + 解决内存/赋值报错 +SPI 写操作测试模块 +连续写2MB递增数据,仅当收到外部中断时发送数据块,用于测试SPI传输完整性和数据丢失检测 """ import log + +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +clog = log.getLogger("spiwritetest") + import utime from machine import SPI from machine import Pin from machine import ExtInt -# 设置日志输出级别 -log.basicConfig(level=log.INFO) -clog = log.getLogger("spiwritetest") +# SPI配置说明: +# spi - 通道选择[0,1],int类型 +# mode - SPI 的工作模式,int类型: +# 0: CPOL=0, CPHA=0 +# 1: CPOL=0, CPHA=1 +# 2: CPOL=1, CPHA=0 +# 3: CPOL=1, CPHA=1 +# clk - 时钟频率: +# 0: 100kHz +# 1: 200kHz +# 8: 1.625MHz +# 9: 3.25MHz +# 12: 26MHz -# 测试参数(完全保留原始值) -TEST_DATA_SIZE = 2 * 1024 * 1024 # 2MB总数据量 -PACKET_TOTAL_SIZE = 1024 # 每包总长度严格1024字节 -HEADER_SIZE = 1 # 1字节序号头 -DATA_BODY_SIZE = PACKET_TOTAL_SIZE - HEADER_SIZE # 1023字节数据体 -SPI_CHANNEL = 2 # SPI通道2 -SPI_MODE = 0 # Mode 0 -SPI_CLK = 8 # 1.625MHz +# 测试参数 +TEST_DATA_SIZE = 18 * 1024 * 1024 # 2MB +CHUNK_SIZE = 1024 # 每次发送1KB +SPI_CHANNEL = 2 # SPI通道2(对应MCU端SPI1) +SPI_MODE = 0 # Mode 0 +SPI_CLK = 12 # 1.625MHz(可根据需要调整:8=1.625MHz, 9=3.25MHz, 12=26MHz) -# 全局中断标志位(保留原始) +# 全局中断标志位:标记是否收到中断(仅中断回调可置位,主逻辑复位) interrupt_triggered = False -INTERRUPT_TIMEOUT = 60 # 中断等待超时时间(秒) +# 中断等待超时时间(单位:秒),避免无限等待 +INTERRUPT_TIMEOUT = 60 -# SPI接收缓存(保留原始) -recv_buf = bytearray(1) # 通用接收缓存 -slave_feedback_buf = bytearray(1) # 从机反馈缓存(仅1字节:需要重发的序号) -# 中断回调函数(完全保留原始逻辑) +# 中断回调函数:收到中断时置位标志位 def ExtIntfun(args): global interrupt_triggered + # clog.info('### interrupt {} ###'.format(args)) # args[0]:gpio号 args[1]:上升沿或下降沿 if args[1] == 0: interrupt_triggered = True - clog.info("interrupt_triggered = True (need read slave data)") + clog.info("interrupt_triggered = True") + # pm.autosleep(0) + # pm.wakelock_lock(lpm_fd) + # elif args[1] == 1: + # clog.info("enable autosleep") + # pm.wakelock_unlock(lpm_fd) + # pm.autosleep(1) + # clog.info("recvDataPin={}".format(recvDataPin.read())) -# 初始化外部中断(保留原始时序/配置) +# 初始化外部中断(GPIO3,上升/下降沿触发,无上下拉) extint = ExtInt(ExtInt.GPIO3, ExtInt.IRQ_RISING_FALLING, ExtInt.PULL_DISABLE, ExtIntfun) extint.enable() clog.info("External interrupt initialized: GPIO3, RISING_FALLING edge") -# 唤醒MCU引脚(完全保留原始配置/时序) +# 创建gpio对象(唤醒MCU的引脚,GPIO4,输出模式,初始高电平) gpioWakeBT = Pin(Pin.GPIO4, Pin.OUT, Pin.PULL_DISABLE, 1) +# 设置输入输出模式 gpioWakeBT.set_dir(Pin.OUT) + +# 设置引脚电平 gpioWakeBT.write(1) class SpiWriteTest: - """SPI写操作测试类(严格保留原始时序)""" + """ + SPI写操作测试类 + 生成递增数据并通过SPI发送,用于测试数据完整性 + """ - def __init__(self, total_data_size=TEST_DATA_SIZE, packet_size=PACKET_TOTAL_SIZE, + def __init__(self, data_size=TEST_DATA_SIZE, chunk_size=CHUNK_SIZE, spi_channel=SPI_CHANNEL, spi_mode=SPI_MODE, spi_clk=SPI_CLK): - self.total_data_size = total_data_size - self.packet_size = packet_size - self.header_size = HEADER_SIZE - self.data_body_size = DATA_BODY_SIZE + """ + 初始化SPI写测试 + + Args: + data_size: 要发送的数据总大小(字节),默认2MB + chunk_size: 每次发送的数据块大小(字节),默认1KB + spi_channel: SPI通道,默认2(对应MCU端SPI1) + spi_mode: SPI模式,默认0 + spi_clk: SPI时钟频率,默认8(1.625MHz) + """ + self.data_size = TEST_DATA_SIZE + self.chunk_size = chunk_size self.spi_channel = spi_channel self.spi_mode = spi_mode - self.spi_clk = spi_clk + self.spi_clk = SPI_CLK self.spi_obj = None - - # 包缓存区:key=序号, value=完整包数据(1024字节) - self.packet_cache = {} - self.retrans_count = 0 # 总重传次数 - - # 发送控制(保留原始) - self.current_seq = 0 - self.current_data_start = 0 - self.packet_count = 0 - self.total_sent_bytes = 0 - + self.current_value = 0 # 当前数据值(从0开始递增) + def __init_spi(self): - """初始化SPI对象(保留原始逻辑)""" + """初始化SPI对象""" try: self.spi_obj = SPI(self.spi_channel, self.spi_mode, self.spi_clk) - if hasattr(self.spi_obj, 'set_full_duplex'): - self.spi_obj.set_full_duplex(True) clog.info("SPI initialized: channel={}, mode={}, clk={}".format( self.spi_channel, self.spi_mode, self.spi_clk)) return True @@ -86,172 +108,328 @@ class SpiWriteTest: clog.error("Failed to initialize SPI: {}".format(e)) return False - def __generate_data_body(self, start_value): - """生成1023字节数据体(保留原始逻辑,解决赋值报错)""" - # 改为直接构建bytes,避免bytearray赋值 - data_body_list = [] + def __generate_chunk(self, start_value, chunk_size): + """ + 生成递增数据块 + + Args: + start_value: 起始值(字节值,0-255) + chunk_size: 数据块大小(字节) + + Returns: + bytearray: 递增数据块 + """ + chunk = bytearray(chunk_size) value = start_value - for i in range(self.data_body_size): - data_body_list.append(value & 0xFF) - value = (value + 1) % 256 - return bytes(data_body_list) - - def __build_packet(self, seq, start_value): - """构建1024字节完整包并缓存(保留原始逻辑)""" - # 1字节序号头 - header = bytes([seq & 0xFF]) - # 1023字节数据体 - data_body = self.__generate_data_body(start_value) - # 拼接成1024字节总包 - packet = header + data_body - # 缓存包(保留原始缓存逻辑) - self.packet_cache[seq] = packet - return packet + for i in range(chunk_size): + chunk[i] = value & 0xFF # 只取低8位 + value = (value + 1) % 256 # 递增,超过255后回到0 + return chunk - def __send_packet(self, packet, seq): - """发送指定包(仅修复datasize参数,严格保留原始时序)""" - try: - # 严格保留原始时序:write(0)→2ms→write(1)→10ms - gpioWakeBT.write(0) - utime.sleep_ms(2) - gpioWakeBT.write(1) - utime.sleep_ms(10) + def __send_chunk(self, chunk): + """ + 通过SPI发送数据块 + + Args: + chunk: 要发送的数据块(bytearray或bytes) + Returns: + bool: 发送是否成功 + """ + gpioWakeBT.write(0) + # clog.info("gpioWakeBT.write(0)") + utime.sleep_ms(2) + gpioWakeBT.write(1) + utime.sleep_ms(2) + try: if self.spi_obj is None: + clog.error("SPI object is None, cannot send chunk") + return False + + chunk_len = len(chunk) + if hasattr(self.spi_obj, 'write'): + + # write(data, datasize) - datasize 参数必需 + clog.debug("Calling SPI.write() with {} bytes".format(chunk_len)) + self.spi_obj.write(chunk, chunk_len) + clog.debug("SPI.write() completed successfully") + # elif hasattr(self.spi_obj, 'write_read'): + # # write_read(read_buf, write_data, datasize, timeout) + # # 或者 write_read(read_buf, write_data, datasize) + # read_buf = bytearray(chunk_len) + # try: + # # 尝试带timeout的调用 + # self.spi_obj.write_read(read_buf, chunk, chunk_len, 5) + # except TypeError: + # # 尝试不带timeout的调用 + # self.spi_obj.write_read(read_buf, chunk, chunk_len) + else: + clog.error("SPI object does not have write or write_read method") return False - - # 核心修复:显式传入datasize参数,保留原始发送逻辑 - self.spi_obj.write(packet, len(packet)) - clog.info("reply seq {} (1024 bytes total)".format(seq)) return True except Exception as e: - clog.error("send seq {} fail: {}".format(seq, e)) + clog.error("Error sending chunk via SPI: {}".format(e)) + import sys + clog.error("Exception type: {}, details: {}".format(type(e).__name__, str(e))) return False - def __read_slave_feedback(self): - """中断触发时读取从机反馈(保留原始时序/逻辑)""" - global slave_feedback_buf, interrupt_triggered - try: - if self.spi_obj is None: - return - - # 保留原始读取逻辑,补充datasize参数 - self.spi_obj.read(slave_feedback_buf, len(slave_feedback_buf)) - retrans_seq = slave_feedback_buf[0] - - # 保留原始重发逻辑 - if retrans_seq in self.packet_cache: - self.retrans_count += 1 - clog.warning("Slave send NACK, need retransmit seq {}".format(retrans_seq)) - # 严格保留原始重发时序/逻辑 - self.__send_packet(self.packet_cache[retrans_seq], retrans_seq) - else: - clog.warning("seq {} not in cache, skip retrans".format(retrans_seq)) - - interrupt_triggered = False - except Exception as e: - clog.error("Read slave feedback failed: {}".format(e)) - interrupt_triggered = False - def close(self): - """关闭SPI(保留原始逻辑)""" + """关闭SPI对象,释放资源""" if self.spi_obj is not None: try: if hasattr(self.spi_obj, 'close'): self.spi_obj.close() + clog.info("SPI object closed via close() method") elif hasattr(self.spi_obj, 'deinit'): self.spi_obj.deinit() + clog.info("SPI object closed via deinit() method") + else: + clog.warning("SPI object does not have close() or deinit() method") except Exception as e: - clog.error("Close SPI failed: {}".format(e)) + clog.error("Error closing SPI object: {}".format(e)) finally: self.spi_obj = None - + + def __wait_for_interrupt(self, timeout_seconds=INTERRUPT_TIMEOUT): + """ + 等待中断信号 + + Args: + timeout_seconds: 超时时间(秒),默认使用全局 INTERRUPT_TIMEOUT + + Returns: + bool: 是否收到中断(True表示收到,False表示超时) + """ + global interrupt_triggered + + # 先检查是否已经有中断信号(可能在调用此函数之前就已经触发了) + if interrupt_triggered: + clog.info("Interrupt signal already present, consuming it immediately") + interrupt_triggered = False # 消费掉这个中断信号 + return True + + # 重置中断标志,准备等待新的中断 + interrupt_triggered = False + + # 等待中断,带超时机制 + start_wait_time = utime.time() + check_count = 0 + while not interrupt_triggered: + elapsed = utime.time() - start_wait_time + if elapsed >= timeout_seconds: + clog.warning("Interrupt wait timeout after {:.2f} seconds (checked {} times)".format( + elapsed, check_count)) + return False + try: + utime.sleep_ms(5) # 每10ms检查一次,减少CPU占用 + except Exception as e: + clog.error("Error in utime.sleep_ms: {}".format(e)) + return False + check_count += 1 + # 每1秒打印一次等待状态 + if check_count % 100 == 0: + clog.info("Still waiting for interrupt... (elapsed: {:.2f}s)".format(elapsed)) + + clog.info("Interrupt received after {:.2f} seconds (checked {} times)".format( + utime.time() - start_wait_time, check_count)) + # 重置标志,为下次等待做准备 + interrupt_triggered = False + return True + def run_test(self): - """运行测试(严格保留原始时序/逻辑,仅修复报错)""" + """ + 运行SPI写测试 + 首次发送不等待中断,后续每次发送前等待中断信号 + + Returns: + tuple: (success: bool, send_time: float, total_bytes: int, data_pattern_info: dict) + success: 测试是否成功 + send_time: 发送耗时(秒) + total_bytes: 发送的总字节数 + data_pattern_info: 数据模式信息(用于MCU端验证) + """ global interrupt_triggered + try: + # 初始化SPI if not self.__init_spi(): return False, 0.0, 0, {} - # 保留原始日志 - clog.info("=== SPI Write Test Start (1024B/packet: 1B seq + 1023B data) ===") - clog.info("Total data size: {} bytes ({:.2f} MB)".format( - self.total_data_size, self.total_data_size / 1024 / 1024)) - clog.info("Packet size: {} bytes (1B seq header + 1023B data body)".format(self.packet_size)) + clog.info("Starting SPI write test") + clog.info("Test parameters:") + clog.info(" Total data size: {} bytes ({:.2f} MB)".format( + self.data_size, self.data_size / 1024.0 / 1024.0)) + clog.info(" Chunk size: {} bytes".format(self.chunk_size)) + clog.info(" SPI channel: {}, mode: {}, clk: {}".format( + self.spi_channel, self.spi_mode, self.spi_clk)) + clog.info(" Delay between chunks: 5ms (to reduce SPI pressure)") + clog.info(" Data pattern: Incremental bytes (0, 1, 2, ..., 255, 0, 1, ...)") + # 记录开始时间 start_time = utime.time() - # 保留原始发送逻辑 - while self.total_sent_bytes < self.total_data_size: - clog.info("Sending packet {} (seq {})".format(self.packet_count, self.current_seq)) + # 发送数据 + total_sent = 0 + chunk_count = 0 + current_byte_value = 0 # 当前字节值(0-255循环) + + # 计算需要发送的块数 + total_chunks = (self.data_size + self.chunk_size - 1) // self.chunk_size + + clog.info("Starting to send {} chunks...".format(total_chunks)) + + while total_sent < self.data_size: + # 计算剩余数据量 + remaining_bytes = self.data_size - total_sent + remaining_chunks = (remaining_bytes + self.chunk_size - 1) // self.chunk_size - # 构建当前包(保留原始逻辑) - packet = self.__build_packet(self.current_seq, self.current_data_start) - # 缓存上一包(保留原始逻辑) - self.packet_cache[self.current_seq] = packet + # 首次发送不等待中断,后续每次发送前等待中断 + # if chunk_count == 0: + # # 首次发送,不等待中断 + # clog.info("Sending first chunk (chunk_count=0) without waiting for interrupt") + # else: + # # 后续发送,等待中断信号 + # clog.info("Waiting for interrupt before sending chunk {} (remaining: {} bytes, {} chunks)...".format( + # chunk_count, remaining_bytes, remaining_chunks)) + # if not self.__wait_for_interrupt(): + # clog.error("Interrupt wait timeout at chunk {} (sent: {} bytes, remaining: {} bytes)".format( + # chunk_count, total_sent, remaining_bytes)) + # self.close() + # return False, 0.0, total_sent, {} + # clog.info("Interrupt received, sending chunk {}".format(chunk_count)) - # 发送包(保留原始时序/逻辑) - send_ok = self.__send_packet(packet, self.current_seq) + # 计算本次发送的块大小(最后一块可能小于chunk_size) + remaining = self.data_size - total_sent + current_chunk_size = min(self.chunk_size, remaining) - # 保留原始中断处理逻辑 - if interrupt_triggered: - clog.info("Interrupt triggered, read slave feedback...") - self.__read_slave_feedback() # 读取从机,为主机提供CLK - interrupt_triggered = False # 重置中断标志 + # 生成递增数据块 + chunk = self.__generate_chunk(current_byte_value, current_chunk_size) - if not send_ok: - clog.error("Send packet {} (seq {}) failed".format(self.packet_count, self.current_seq)) - self.close() - return False, 0.0, self.total_sent_bytes, {} + # 更新当前字节值(为下一块准备) + current_byte_value = (current_byte_value + current_chunk_size) % 256 - # 保留原始统计更新逻辑 - self.total_sent_bytes += self.packet_size # 按1024字节/包统计 - self.current_data_start = (self.current_data_start + self.data_body_size) % 256 # 数据体起始值递增 - self.current_seq = (self.current_seq + 1) % 256 # 序号循环 - self.packet_count += 1 + # 通过SPI发送数据块 + if not self.__send_chunk(chunk): + clog.error("Failed to send chunk {} at offset {}".format( + chunk_count, total_sent)) + self.close() + return False, 0.0, total_sent, {} - # 保留原始进度打印逻辑 - if self.packet_count % 64 == 0: - progress = (self.total_sent_bytes / self.total_data_size) * 100 - clog.info("Progress: {:.2f}% | Packets sent: {} | Total bytes: {} | Retrans: {} times".format( - progress, self.packet_count, self.total_sent_bytes, self.retrans_count)) + total_sent += current_chunk_size + chunk_count += 1 - # 保留原始延时 + # 每次发送后延迟5ms,减少SPI压力,避免FIFO溢出 utime.sleep_ms(5) + + # 每发送64KB打印一次进度 + if total_sent % (64 * 1024) < self.chunk_size: + progress = (total_sent / self.data_size) * 100 + clog.info("SPI TX Progress: {:.2f}% ({}/{}) bytes, chunks: {}".format( + progress, total_sent, self.data_size, chunk_count)) - # 保留原始测试完成逻辑 + # 记录结束时间并计算耗时 end_time = utime.time() send_time = end_time - start_time - speed_kbps = (self.total_sent_bytes * 8) / send_time / 1024 if send_time > 0 else 0 - clog.info("=== Test Completed ===") - clog.info("Total packets sent: {} ({} bytes total)".format( - self.packet_count, self.total_sent_bytes)) - clog.info("Send time: {:.3f}s | Speed: {:.2f} Kbps".format(send_time, speed_kbps)) - clog.info("Total retrans times: {}".format(self.retrans_count)) + # 计算传输速度 + speed_kbps = (total_sent * 8.0) / send_time / 1024.0 # Kbps + speed_mbps = speed_kbps / 1024.0 # Mbps - self.close() - return True, send_time, self.total_sent_bytes, { - "packet_size": self.packet_size, - "header_size": self.header_size, - "data_body_size": self.data_body_size, - "retrans_count": self.retrans_count + # 数据模式信息(用于MCU端验证) + data_pattern_info = { + 'total_bytes': total_sent, + 'chunk_size': self.chunk_size, + 'pattern': 'incremental', # 递增模式 + 'start_value': 0, # 起始值为0 + 'cycle': 256, # 每256字节循环一次(0-255) + 'description': 'Data values increment from 0 to 255, then cycle back to 0' } - + + if speed_mbps >= 1.0: + clog.info("SPI write test completed: {} bytes in {:.3f}s, Speed: {:.2f} Mbps ({:.2f} Kbps)".format( + total_sent, send_time, speed_mbps, speed_kbps)) + else: + clog.info("SPI write test completed: {} bytes in {:.3f}s, Speed: {:.2f} Kbps".format( + total_sent, send_time, speed_kbps)) + + clog.info("Data pattern info:") + clog.info(" Pattern: Incremental bytes (0, 1, 2, ..., 255, 0, 1, ...)") + clog.info(" Start value: 0") + clog.info(" Cycle: Every 256 bytes") + clog.info(" Total chunks: {}".format(chunk_count)) + clog.info(" Expected byte at offset N: (N % 256)") + + # 关闭SPI + self.close() + + return True, send_time, total_sent, data_pattern_info + except Exception as e: - clog.error("Test failed: {}".format(e)) + clog.error("Error in SPI write test: {}".format(e)) self.close() return False, 0.0, 0, {} + + def get_expected_byte_at_offset(self, offset): + """ + 获取指定偏移位置的期望字节值(用于MCU端验证) + + Args: + offset: 字节偏移位置(0开始) + + Returns: + int: 期望的字节值(0-255) + """ + return offset % 256 -# 便捷运行函数(保留原始) -def run_spi_write_test(): - test = SpiWriteTest() - success, send_time, total_bytes, info = test.run_test() + +def run_spi_write_test(data_size=TEST_DATA_SIZE, chunk_size=CHUNK_SIZE, + spi_channel=SPI_CHANNEL, spi_mode=SPI_MODE, spi_clk=SPI_CLK): + """ + 运行SPI写测试的便捷函数 + + Args: + data_size: 要发送的数据总大小(字节),默认2MB + chunk_size: 每次发送的数据块大小(字节),默认1KB + spi_channel: SPI通道,默认2(对应MCU端SPI1) + spi_mode: SPI模式,默认0 + spi_clk: SPI时钟频率,默认8(1.625MHz) + + Returns: + tuple: (success: bool, send_time: float, total_bytes: int) + """ + test = SpiWriteTest(data_size, chunk_size, spi_channel, spi_mode, spi_clk) + try: + success, send_time, total_bytes, pattern_info = test.run_test() + if success: + clog.info("SPI write test PASSED") + else: + clog.error("SPI write test FAILED") + return success, send_time, total_bytes + finally: + test.close() + + +# 自动运行测试(如果直接执行此脚本) +if __name__ == '__main__': + # 运行2MB递增数据测试 + success, send_time, total_bytes = run_spi_write_test( + data_size=2 * 1024 * 1024, # 2MB + chunk_size=1024, # 1KB chunks + spi_channel=2, # SPI通道2(对应MCU端SPI1) + spi_mode=0, # Mode 0 + spi_clk=8 # 1.625MHz(可根据需要调整) + ) + if success: - clog.info("Test PASSED | Total bytes sent: {}".format(total_bytes)) + clog.info("Test completed successfully!") + clog.info("Total bytes sent: {} ({:.2f} MB)".format( + total_bytes, total_bytes / 1024.0 / 1024.0)) + clog.info("Send time: {:.3f} seconds".format(send_time)) else: - clog.error("Test FAILED") - return success + clog.error("Test failed!") + +# 如果作为模块导入,不自动运行 +# 可以通过以下方式使用: +# from spi_write_test import run_spi_write_test +# success, send_time, total_bytes = run_spi_write_test() -if __name__ == '__main__': - run_spi_write_test() \ No newline at end of file diff --git a/code/sdk/middleware/chips/brandy/pm/include/pm_definition.h b/code/sdk/middleware/chips/brandy/pm/include/pm_definition.h index f32cd8944..09f369866 100644 --- a/code/sdk/middleware/chips/brandy/pm/include/pm_definition.h +++ b/code/sdk/middleware/chips/brandy/pm/include/pm_definition.h @@ -53,7 +53,8 @@ typedef enum { PM_ID_BUTTON_GPIO,//gpio按键 PM_ID_BP,//血压 PM_ID_4G_AI,//4g AI - PM_ID_GPS,//4g AI + PM_ID_GPS,//GPS + PM_ID_SPI,//SPI #ifdef SUPPORT_ALIPAY_SEC PM_ID_ALIPAY,//支付宝 #endif diff --git a/code/sdk/middleware/chips/brandy/pm/pm.c b/code/sdk/middleware/chips/brandy/pm/pm.c index 961967b86..36252e0d4 100644 --- a/code/sdk/middleware/chips/brandy/pm/pm.c +++ b/code/sdk/middleware/chips/brandy/pm/pm.c @@ -252,7 +252,8 @@ const char* pm_id_name_arr[] ={ "PM_ID_BUTTON_GPIO",//gpio按键 "PM_ID_BP",//血压 "PM_ID_4G_AI",//4g AI - "PM_ID_GPS",//4g AI + "PM_ID_GPS",//GPS + "PM_ID_SPI",//SPI #ifdef SUPPORT_ALIPAY_SEC "PM_ID_ALIPAY",//支付宝 #endif diff --git a/code/sdk/zhihui/4g/cat1Service/Service/cat1_server.c b/code/sdk/zhihui/4g/cat1Service/Service/cat1_server.c index 0fb083ece..505246179 100644 --- a/code/sdk/zhihui/4g/cat1Service/Service/cat1_server.c +++ b/code/sdk/zhihui/4g/cat1Service/Service/cat1_server.c @@ -1955,6 +1955,22 @@ errcode_t cat1_server_init(void) return ERRCODE_SUCC; } +//0关闭 1开启 +void cat_sync_timer_control(int cmd) +{ + if(g_timer_time_sync == NULL) + return; + + if(cmd == 0 && osTimerIsRunning(g_timer_time_sync)) + { + osTimerStop(g_timer_time_sync); + } + else if(cmd == 1 && !osTimerIsRunning(g_timer_time_sync)) + { + osTimerStart(g_timer_time_sync,5000); + } +} + #ifdef __cplusplus } diff --git a/code/sdk/zhihui/4g/cat1Service/include/cat1_server.h b/code/sdk/zhihui/4g/cat1Service/include/cat1_server.h index f3df815be..5d200a729 100644 --- a/code/sdk/zhihui/4g/cat1Service/include/cat1_server.h +++ b/code/sdk/zhihui/4g/cat1Service/include/cat1_server.h @@ -1,3 +1,11 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2025-10-27 15:10:13 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2025-12-06 18:09:30 + * @FilePath: /FD230/code/sdk/zhihui/4g/cat1Service/include/cat1_server.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ /* BSD Socket API Example This example code is in the Public Domain (or CC0 licensed, at your option.) @@ -47,6 +55,8 @@ uint8_t set_call_hungup_flag(uint8_t data); void cat1_call_hungup_timer(void); void cat1_start_tcp_ota_init(void); +void cat_sync_timer_control(int cmd); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/code/sdk/zhihui/utils/custom_spi.c b/code/sdk/zhihui/utils/custom_spi.c index dae20c4bb..4bc69a452 100644 --- a/code/sdk/zhihui/utils/custom_spi.c +++ b/code/sdk/zhihui/utils/custom_spi.c @@ -20,21 +20,18 @@ #include "spi.h" #include "custom_spi.h" #include "custom_utils.h" +#include "pm.h" -osSemaphoreId_t g_semaphore_spi_id = NULL; -static int total_cnt = 0; + +static osSemaphoreId_t g_semaphore_spi_id = NULL; +static app_task_definition_t taskcfg={0}; +static uint32_t total_cnt = 0; static uint8_t g_rx_buffer[1024] = {0}; -static uint8_t last_expect_seq = 1; // 初始期望递增序号(根据主设备实际起始值调整) -static const uint8_t retrans_cmd = 0x01; -#define PACKET_HEADER_OFFSET 0 -#define PACKET_TOTAL_SIZE 1024 -static uint8_t first_flag = 0; -static int discontinuous_cnt = 0; static uint32_t pkg_recv_cnt = 0; // 新增:接收包计数 -static int current_seq = 0; -static int expected_seq = 0; +static uint32_t total_byte_error_cnt = 0; + void custom_spi_read(void) { @@ -49,248 +46,75 @@ void custom_spi_read(void) if(ret == 0 && spi_data.rx_bytes == 1024) { - uint8_t current_seq = spi_data.rx_buff[0]; - printf("spi_data.rx_bytes : %d, spi_data.rx_data[0]:0x%02X,spi_data.rx_data[1023]:0x%02X\n", spi_data.rx_bytes, current_seq,spi_data.rx_buff[1023]); + total_cnt += spi_data.rx_bytes; + printf("total_cnt:%d\n",total_cnt); + // printf("spi_data.rx_buff[0]:0x%x,total_cnt:%d\n",spi_data.rx_buff[0],total_cnt); + // printf("spi_data.rx_bytes : %d, spi_data.rx_data[0]:0x%02X,spi_data.rx_data[1023]:0x%02X\n", + // spi_data.rx_bytes, current_seq, spi_data.rx_buff[1023]); - // 新增:包计数自增 + // 包计数自增(从第一个包开始计数) pkg_recv_cnt++; - - // 核心修改:仅在接收包数超过10个后,才执行连续性判定 - if (pkg_recv_cnt > 10) { - if (last_expect_seq != 0xFF) { // 非首次接收才判定 - uint8_t expected_seq = (last_expect_seq == 0x00) ? 0xFF : (last_expect_seq - 1); - if (current_seq != expected_seq) { - discontinuous_cnt++; - printf("不连续(跳变):当前0x%02X, 期望0x%02X | 累计不连续数:%d\n", - current_seq, expected_seq, discontinuous_cnt); - uapi_gpio_set_dir(S_AGPIO_L13, GPIO_DIRECTION_OUTPUT); - uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_HIGH); - uapi_tcxo_delay_ms(2); - uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_LOW); - uapi_tcxo_delay_ms(5); - uint8_t data = expected_seq; - spi_data.tx_buff = &data; - spi_data.tx_bytes = 1; - ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - printf("uapi_spi_slave_write ret : 0x%02X \n", ret); - } + + // --------------- 逐字节严格递增判断(无跳过,首个包就校验)--------------- + uint8_t byte_error_cnt = 0; // 单包内字节错误计数 + uint8_t prev_byte = spi_data.rx_buff[0]; // 初始化为第一个字节 + // printf("head\n"); + // 遍历1024字节(从第2个字节开始校验) + for (int i = 1; i < 1024; i++) + { + // if(i < 20) + // printf("(0x%02X)",spi_data.rx_buff[i]); + // if(i == 20) + // printf("\n"); + uint8_t curr_byte = spi_data.rx_buff[i]; + // 8位字节递增规则:0xFF后应为0x00,其余为前一字节+1 + uint8_t expected_byte = (prev_byte == 0xFF) ? 0x00 : (prev_byte + 1); + + // 校验当前字节是否等于期望的递增字节(无跳过) + if (curr_byte != expected_byte) + { + byte_error_cnt++; + // 打印错误详情(调试用,正式环境可注释) + printf("字节[%d]不连续:当前0x%02X, 期望0x%02X(前一字节0x%02X)\n", + i, curr_byte, expected_byte, prev_byte); } + + // 更新前一字节,用于下一轮校验 + prev_byte = curr_byte; + } + // printf("该包无错误\n"); + // 单包字节校验结果汇总(首个包就统计) + if (byte_error_cnt > 0) + { + printf("【包%d】字节递增错误数:%d | 累计字节错误数:%d\n", + pkg_recv_cnt, byte_error_cnt, total_byte_error_cnt += byte_error_cnt); } - - // 更新上一次接收的序号(用于下次判定) - last_expect_seq = current_seq; - - total_cnt += spi_data.rx_bytes; - printf("total_cnt : %d, 当前接收包数:%d\n", total_cnt, pkg_recv_cnt); - } - else - { - // 新增:包计数自增(失败/长度不符的包也计数,若仅统计成功包可移到上面if内) - pkg_recv_cnt++; - - uapi_gpio_set_dir(S_AGPIO_L13, GPIO_DIRECTION_OUTPUT); - uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_HIGH); - uapi_tcxo_delay_ms(2); - uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_LOW); - uapi_tcxo_delay_ms(5); - uint8_t data = expected_seq; - spi_data.tx_buff = &data; - spi_data.tx_bytes = 1; - ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - printf("uapi_spi_slave_write ret : 0x%02X \n", ret); - // printf("接收失败/长度不符,当前接收包数:%d\n", pkg_recv_cnt); } - // spi_xfer_data_t spi_data = {0}; - // errcode_t ret = ERRCODE_FAIL; - - // memset(g_rx_buffer, 0, sizeof(g_rx_buffer)); - // spi_data.rx_bytes = sizeof(g_rx_buffer); - // spi_data.rx_buff = g_rx_buffer; - - // ret = uapi_spi_slave_read(SPI_BUS_1, &spi_data, 50); - - // if(ret == 0 && spi_data.rx_bytes == 1024) - // { - // printf("spi_data.rx_bytes : %d,spi_data.rx_data[0]:0x%x\n",spi_data.rx_bytes,spi_data.rx_buff[0]); - // if(spi_data.rx_bytes == sizeof(g_rx_buffer)) - // total_cnt += spi_data.rx_bytes; - // printf("total_cnt : %d\n",total_cnt); - - - // // uapi_gpio_set_dir(S_AGPIO_L13, GPIO_DIRECTION_OUTPUT); - - // // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_HIGH); - // // uapi_tcxo_delay_ms(10); /* delay 10 ms */ - // // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_LOW); - // // if(spi_fp == NULL) - // // { - // // spi_fp = fopen("/user/data/spi_text.txt","w+"); - // // } - - // // if(spi_fp) - // // { - // // int ret = fwrite(spi_data.rx_buff,1,spi_data.rx_bytes,spi_fp); - // // printf("fwrite ret:%d\n",ret); - // // } - // } // else // { + // // 新增:包计数自增(失败/长度不符的包也计数,若仅统计成功包可移到上面if内) + // pkg_recv_cnt++; + // uapi_gpio_set_dir(S_AGPIO_L13, GPIO_DIRECTION_OUTPUT); - // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_HIGH); - // uapi_tcxo_delay_ms(2); /* delay 10 ms */ + // uapi_tcxo_delay_ms(2); // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_LOW); - - // uint8_t data = last_expect_seq; - // last_expect_seq++; + // uapi_tcxo_delay_ms(5); + // uint8_t data = expected_seq; // spi_data.tx_buff = &data; // spi_data.tx_bytes = 1; // ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - // printf("uapi_spi_slave_write ret : %x \n",ret); + // printf("uapi_spi_slave_write ret : 0x%02X \n", ret); + // // printf("接收失败/长度不符,当前接收包数:%d\n", pkg_recv_cnt); // } - // if(ret == 0 && spi_data.rx_bytes == 1024) - // { - // if(first_flag == 0) - // { - // first_flag = 1; - // last_expect_seq = spi_data.rx_buff[0]; - // } - // else if(last_expect_seq != spi_data.rx_buff[0] - 1) - // { - // printf("data error,last_expect_seq:0x%x,spi_data.rx_data[0]:0x%x\n",last_expect_seq,spi_data.rx_buff[0]); - // uint8_t data = last_expect_seq; - // last_expect_seq++; - // spi_data.tx_buff = &data; - // spi_data.tx_bytes = 1; - // ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - // printf("uapi_spi_slave_write ret : %x \n",ret); - // } - // else if(last_expect_seq == 0 && spi_data.rx_buff[0] == 0xff) - // { - // last_expect_seq = spi_data.rx_buff[0]; - // printf("spi_data.rx_bytes : %d,spi_data.rx_data[0]:0x%x\n",spi_data.rx_bytes,spi_data.rx_buff[0]); - // if(spi_data.rx_bytes == sizeof(g_rx_buffer)) - // total_cnt += spi_data.rx_bytes; - // printf("total_cnt : %d\n",total_cnt); - // } - // else - // { - // last_expect_seq = spi_data.rx_buff[0]; - // printf("spi_data.rx_bytes : %d,spi_data.rx_data[0]:0x%x\n",spi_data.rx_bytes,spi_data.rx_buff[0]); - // if(spi_data.rx_bytes == sizeof(g_rx_buffer)) - // total_cnt += spi_data.rx_bytes; - // printf("total_cnt : %d\n",total_cnt); - // } - - - - // uapi_gpio_set_dir(S_AGPIO_L13, GPIO_DIRECTION_OUTPUT); - - // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_HIGH); - // uapi_tcxo_delay_ms(10); /* delay 10 ms */ - // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_LOW); - // if(spi_fp == NULL) - // { - // spi_fp = fopen("/user/data/spi_text.txt","w+"); - // } - - // if(spi_fp) - // { - // int ret = fwrite(spi_data.rx_buff,1,spi_data.rx_bytes,spi_fp); - // printf("fwrite ret:%d\n",ret); - // } - // } - // else - // { - // uint8_t data = last_expect_seq; - // last_expect_seq++; - // spi_data.tx_buff = &data; - // spi_data.tx_bytes = 1; - // ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - // printf("uapi_spi_slave_write ret : %x \n",ret); - // } - // printf("\n=== SPI Read ===\n"); - // printf("uapi_spi_slave_read ret : 0x%x, rx bytes: %d\n", ret, spi_data.rx_bytes); - - // if (ret == 0 && spi_data.rx_bytes == PACKET_TOTAL_SIZE) - // { - // uint8_t current_seq = g_rx_buffer[PACKET_HEADER_OFFSET]; - // printf("Header seq: 0x%02X, Expect seq: 0x%02X\n", current_seq, last_expect_seq); - - // // 核心:判定序号是否为“递增连续”(仅允许递增,禁止递减) - // uint8_t is_continuous = 0; - // // 情况1:正常递增(如 0x7→0x8、0xFF→0x0) - // if (current_seq == last_expect_seq) - // { - // is_continuous = 1; - // } - // // 情况2:255→0 溢出递增(合法) - // else if (last_expect_seq == 0xFF && current_seq == 0x00) - // { - // is_continuous = 1; - // printf("Seq overflow (255→0) → continuous\n"); - // } - - // if (is_continuous) - // { - // // 序号合法:累加计数 + 更新下一个期望序号(递增) - // total_cnt += spi_data.rx_bytes; - // last_expect_seq++; // uint8_t自动溢出(255→0) - // printf("Seq OK! Total cnt: %d, Next expect: 0x%02X\n", total_cnt, last_expect_seq); - // } - // else - // { - // // 序号递减/跳变:触发重传,不更新计数 - // printf("Seq ERROR! Current:0x%02X, Expect:0x%02X → Send retrans cmd (0x01)\n", - // current_seq, last_expect_seq); - - // spi_data.tx_buff = (uint8_t*)&retrans_cmd; - // spi_data.tx_bytes = 1; - // errcode_t write_ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - // printf("Retrans cmd send ret: 0x%x\n", write_ret); - // return; // 不更新计数,等待主设备重发正确序号 - // } - // } - // else if (ret == 0) - // { - // printf("Rx packet incomplete! Expect:1024, Actual:%d\n", spi_data.rx_bytes); - // } - // else - // { - // // 读取失败:回传当前期望序号,便于主设备定位 - // printf("SPI Read FAIL (0x%x) → Write back expect seq:0x%02X\n", ret, last_expect_seq); - // spi_data.tx_buff = &last_expect_seq; - // spi_data.tx_bytes = 1; - // ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - // if (ret != 0) ret = uapi_spi_slave_write(SPI_BUS_1, &spi_data, 50); - // printf("Write back ret:0x%x, data:0x%02X\n", ret, last_expect_seq); - // last_expect_seq++; - // } - - - // uapi_gpio_set_dir(S_AGPIO_L13, GPIO_DIRECTION_OUTPUT); - - // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_HIGH); - // uapi_tcxo_delay_ms(2); /* delay 10 ms */ - // uapi_gpio_set_val(S_AGPIO_L13, GPIO_LEVEL_LOW); - - // if(ret == ERRCODE_SUCC) - // { - // printf("\nhead\n"); - // for(int i = 0; i < spi_data.rx_bytes ;i ++ ) - // { - // printf("byte[%d]:(%x),",i,spi_data.rx_buff[i]); - // } - // printf("\nend\n"); - // } } void custom_spi_service_task(void *arg) { - printf("SPI处理任务启动,开始等待中断...\r\n"); + printf("SPI处理任务启动,开始等待中断...\r\n"); // 任务循环:永久运行,处理每次中断 while (1) { @@ -309,21 +133,13 @@ void custom_spi_service_task(void *arg) } else if (ret == osErrorTimeout) { // 超时处理:打印日志,继续循环等待 - printf("SPI中断等待超时(%d秒),继续等待...\r\n", 60); + printf("SPI中断等待超时%d秒,继续等待...\r\n", 60); } else { // 信号量错误:退出循环,任务结束(可选重试逻辑) - printf("信号量获取失败(状态:%d),任务退出\r\n", ret); + printf("信号量获取失败 状态:%d,任务退出\r\n", ret); // break; } } - - // 任务退出前清理资源 - if (g_semaphore_spi_id != NULL) { - osSemaphoreDelete(g_semaphore_spi_id); - g_semaphore_spi_id = NULL; - } - printf("SPI处理任务退出\r\n"); - osThreadExit(); } void custom_spi_init(void) @@ -345,7 +161,7 @@ void custom_spi_init(void) attr.frame_format = SPI_CFG_FRAME_FORMAT_MOTOROLA_SPI; attr.spi_frame_format = (uint32_t)HAL_SPI_FRAME_FORMAT_STANDARD; // 标准SPI格式(非QUAD) attr.frame_size = (uint32_t)HAL_SPI_FRAME_SIZE_8; // 8位数据(与Python端匹配) - attr.tmod = HAL_SPI_TRANS_MODE_TXRX; // 只接收模式 + attr.tmod = HAL_SPI_TRANS_MODE_RX; // 只接收模式 attr.sste = SPI_CFG_SSTE_DISABLE; attr.ndf = 1; @@ -374,21 +190,20 @@ void custom_spi_init(void) ret = uapi_gpio_register_isr_func(S_MGPIO23, GPIO_INTERRUPT_FALLING_EDGE, custom_spi_rx_callback ); if (ret != ERRCODE_SUCC) { printf("uapi_gpio_register_isr_func failed: 0x%x\n", ret); - return; + goto FAILED; } g_semaphore_spi_id = osSemaphoreNew(1, 0, NULL); if(g_semaphore_spi_id == NULL) { printf("osSemaphoreNew failed\n"); - return; + goto FAILED; } - app_task_definition_t taskcfg={0}; // taskcfg.create_queue_handle = create_ppg_queue; taskcfg.attr.name="custom_spi_service"; - taskcfg.attr.priority = osPriorityNormal4; + taskcfg.attr.priority = osPriorityHigh; taskcfg.attr.stack_size = 0x2000; taskcfg.func = custom_spi_service_task; @@ -398,10 +213,19 @@ void custom_spi_init(void) if(ret != ERRCODE_SUCC) { printf("create custom_spi_service_task failed %d!\r\n",ret); - return; + goto FAILED; } + uint8_t cnt = pm_veto_get_id_cnt(PM_ID_SPI); + if (cnt == 0) + { + uapi_pm_add_sleep_veto(PM_ID_SPI); + } + + ret = uapi_pm_request_mode(PM_ID_SPI, PM_MODE_PERFORMACE); + printf("uapi_pm_request_mode ret : %X\n",ret); + return; // ret = osSemaphoreAcquire(g_semaphore_spi_id, 60 * 1000); // if (ret != 0) // { @@ -414,21 +238,37 @@ void custom_spi_init(void) // } // printf("SPI中断触发,初始化完成\r\n"); - +FAILED: + custom_spi_deinit(); } void custom_spi_deinit(void) { - discontinuous_cnt = 0; - last_expect_seq = 1; + pkg_recv_cnt = 0; + total_byte_error_cnt = 0; total_cnt = 0; - memset_s(g_rx_buffer,sizeof(g_rx_buffer),0,sizeof(g_rx_buffer)); - uapi_spi_deinit(SPI_BUS_1); + errcode_t ret = 0; + + if(taskcfg.task_handle) + { + ret = uapi_terminate_thread(taskcfg.task_handle); + if (ret != ERRCODE_SUCC) { + printf("uapi_terminate_thread failed: 0x%x\n", ret); + } + taskcfg.task_handle = NULL; + } + + uapi_pin_set_ie(S_MGPIO23,HAL_PIO_IE_DISABLE); - errcode_t ret = uapi_gpio_unregister_isr_func(S_MGPIO23); + + ret = uapi_gpio_unregister_isr_func(S_MGPIO23); if (ret != ERRCODE_SUCC) { printf("uapi_gpio_unregister_isr_func failed: 0x%x\n", ret); - return; + } + + ret = uapi_spi_deinit(SPI_BUS_1); + if (ret != ERRCODE_SUCC) { + printf("uapi_spi_deinit failed: 0x%x\n", ret); } if (g_semaphore_spi_id != NULL) @@ -436,6 +276,14 @@ void custom_spi_deinit(void) osSemaphoreDelete(g_semaphore_spi_id); g_semaphore_spi_id = NULL; } + + uapi_pm_request_mode(PM_ID_SPI, PM_MODE_NORMAL); + + uint8_t cnt = pm_veto_get_id_cnt(PM_ID_SPI); + if (cnt == 1) + { + uapi_pm_remove_sleep_veto(PM_ID_SPI); + } } -- 2.17.1