diff --git a/.gitignore b/.gitignore index 685facd..2543af5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bootloader/build/* lark1fq/build/* +ate/build/* test/build/* tools/*.exe tools/*.xls diff --git a/ate/CMakeLists.txt b/ate/CMakeLists.txt new file mode 100755 index 0000000..e9c2089 --- /dev/null +++ b/ate/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 3.10) +set(PROJ_NAME "lark1fq") +set(BIN_FILE ${PROJ_NAME}.bin) +set(ASM_FILE ${PROJ_NAME}.asm) +project(${PROJ_NAME} VERSION 0.1) + +# toolchain path +set(TOOLCHAIN "arm-none-eabi-") +set(CMAKE_C_COMPILER "${TOOLCHAIN}gcc") +set(CMAKE_ASM_COMPILER "${TOOLCHAIN}gcc") +set(CMAKE_OBJCOPY "${TOOLCHAIN}objcopy") +set(CMAKE_OBJDUMP "${TOOLCHAIN}objdump") +set(CMAKE_AR "${TOOLCHAIN}ar") +set(CMAKE_RANLIB "${TOOLCHAIN}ranlib") +set(LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/flash.ld") + +set(CMAKE_C_FLAGS " \ +-mcpu=cortex-m4 \ +-mthumb \ +-g3 \ +-O2 \ +-Wall \ +-nostartfiles \ +-mfloat-abi=hard \ +-mfpu=vfpv4-d16 \ +-ffunction-sections \ +-fdata-sections \ +") + +set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}") + +set(CMAKE_EXE_LINKER_FLAGS " \ +-ffunction-sections \ +-fdata-sections \ +-Wl,--gc-sections \ +-T${LINKER_SCRIPT} \ +-Wl,-Map=${PROJ_NAME}.map \ +--specs=nano.specs \ +-Wl,--print-memory-usage \ +-Wl,--print-output-format \ +") + +add_definitions(-DSTM32F40_41xxx) +add_definitions(-DUSE_STDPERIPH_DRIVER) + +enable_language(ASM) +add_executable(${PROJ_NAME}.elf main.c) +target_sources(${PROJ_NAME}.elf PUBLIC ${CMAKE_CURRENT_LIST_DIR}/start.S) + +add_subdirectory(../driver driver) +target_link_libraries(${PROJ_NAME}.elf driver) +target_include_directories(${PROJ_NAME}.elf PUBLIC ../driver/stddriver/inc) +target_include_directories(${PROJ_NAME}.elf PUBLIC ../driver/cmsis/inc) + +add_subdirectory(../component/fatfs component/fatfs) +target_link_libraries(${PROJ_NAME}.elf fatfs) + +add_subdirectory(src src) +target_link_libraries(${PROJ_NAME}.elf src) +target_include_directories(${PROJ_NAME}.elf PUBLIC src) + +target_link_libraries(${PROJ_NAME}.elf m) # math library + +add_custom_command(TARGET ${PROJ_NAME}.elf POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -Obinary $ ${BIN_FILE} + COMMAND ${CMAKE_OBJDUMP} -d -S $ >${ASM_FILE} + # COMMENT "Generate ${BIN_FILE}\r\n" + COMMAND size ${PROJ_NAME}.elf + COMMAND echo "Calculating SHA-256 checksum for ${BIN_FILE}:" + COMMAND sha256sum ${BIN_FILE} +) + +# get git tag +execute_process( + COMMAND git describe --abbrev=40 --tags --dirty --always + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE GIT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET +) +if(GIT_TAG) + set(PROJECT_SDK_VERSION ${GIT_TAG}) +else() + message(WARNING "No Valid version info found for SDK!") + set(PROJECT_SDK_VERSION "version-unknown-panic") +endif() +message(STATUS "Project SDK Version: ${PROJECT_SDK_VERSION}") diff --git a/ate/Makefile b/ate/Makefile new file mode 100644 index 0000000..6c57e27 --- /dev/null +++ b/ate/Makefile @@ -0,0 +1,18 @@ +CMAKE = cmake # use user cmake +cmake_generator = "Unix Makefiles" +RM = $(CMAKE) -E remove_directory +MAKEFLAGS += --no-print-directory + +TOOLCHAIN ?= arm-none-eabi- + +#cmake definition config +cmake_definition+= -DTOOLCHAIN=${TOOLCHAIN} + +build:Makefile + $(CMAKE) -S . -B build -G $(cmake_generator) $(cmake_definition) + $(MAKE) -C build -j + +clean:: + $(RM) build + +.PHONY:build clean diff --git a/ate/flash.ld b/ate/flash.ld new file mode 100755 index 0000000..0022282 --- /dev/null +++ b/ate/flash.ld @@ -0,0 +1,80 @@ +ENTRY(Reset_Handler) + +StackSize = 0x4000; /* 16KB */ + +MEMORY +{ + FLASH (rx) :ORIGIN = 0x08020000, LENGTH = 384K + RAM (xrw) :ORIGIN = 0x20000000, LENGTH = 112K + CCM (rw) :ORIGIN = 0x10000000, LENGTH = 64K - StackSize +} + +_stack_top = ORIGIN(CCM) + LENGTH(CCM) + StackSize; + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >FLASH + + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + . = ALIGN(4); + } >FLASH + + .rodata : + { + . = ALIGN(4); + *(.rodata) + *(.rodata*) + . = ALIGN(4); + } >FLASH + + _data_load = LOADADDR(.data); + .data : + { + . = ALIGN(4); + _data_run = .; + *(.data) + *(.data.*) + . = ALIGN(4); + _data_run_end = .; + } >RAM AT>FLASH + + _data_ccm_load = LOADADDR(.data_ccm); + .data_ccm : + { + . = ALIGN(4); + _data_ccm_run = .; + *(.data_ccm) + *(.data_ccm*) + . = ALIGN(4); + _data_ccm_run_end = .; + } >CCM AT>FLASH + + .bss (NOLOAD) : + { + . = ALIGN(4); + _bss_run = .; + *(.bss) + *(.bss.*) + . = ALIGN(4); + _bss_run_end = .; + } >RAM + + .bss_ccm (NOLOAD) : + { + . = ALIGN(4); + _bss_ccm_run = .; + *(.bss_ccm) + *(.bss_ccm.*) + . = ALIGN(4); + _bss_ccm_run_end = .; + } >CCM +} diff --git a/ate/main.c b/ate/main.c new file mode 100755 index 0000000..0539946 --- /dev/null +++ b/ate/main.c @@ -0,0 +1,55 @@ +#include "led.h" +#include "button.h" +#include "heat.h" +#include "ltc1867.h" +#include "modbus.h" +#include "ltc2640.h" +#include "calc.h" +#include "sd.h" +#include "stm32f4xx_rcc.h" + +uint32_t system_tick_cnt; + +void system_tick_init(void) +{ + RCC_ClocksTypeDef rcc_clocks; + + system_tick_cnt = 0; + RCC_GetClocksFreq(&rcc_clocks); + SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); + SysTick_Config(rcc_clocks.HCLK_Frequency / 1000); +} + +void system_init(void) +{ + led_init(LED1 | LED2); + button_init(); + heat_init(); + ltc1867_init(); + modbus_init(); + system_tick_init(); + ltc2640_init(); +} + +int main(void) +{ + system_init(); + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); + SCB->VTOR = 0x08020000; + __enable_irq(); + while (1) { + modbus_loop(); + led_loop(); + button_loop(); + heat_loop(); + ltc2640_loop(); + calc_loop(); + sd_loop(); + } + return 0; +} + +void SysTick_Handler(void) +{ + system_tick_cnt++; +} diff --git a/ate/script/ate.py b/ate/script/ate.py new file mode 100644 index 0000000..e3e8b82 --- /dev/null +++ b/ate/script/ate.py @@ -0,0 +1,576 @@ +import tkinter as tk +from tkinter import ttk, messagebox +import serial +import serial.tools.list_ports +import threading +import time +from datetime import datetime +import crcmod + +class ATEApplication: + def __init__(self, root): + self.root = root + self.root.title("LARK-1FQ ATE设备监控") + self.root.geometry("680x480") + + # 串口相关变量 + self.serial_port = None + self.is_connected = False + self.read_thread = None + self.stop_thread = False + self.receive_buffer = bytearray() # 接收缓冲区 + + # 创建CRC计算函数 + self.crc16_func = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000) + + # 数据存储 + self.frequency_values = [0, 0, 0, 0] # ch0-ch3 频率值 + self.peak_values = [0, 0, 0, 0] # ch0-ch3 峰峰值 + self.key_status = 0 # 按键状态 + self.sd_status = 0 # SD卡状态 + + # 上下限设置 + self.freq_limits = [ + {"min": 7, "max": 9}, # ch0 + {"min": 7, "max": 9}, # ch1 + {"min": 7, "max": 9}, # ch2 + {"min": 7, "max": 9} # ch3 + ] + + self.peak_limits = [ + {"min": 2000, "max": 4000}, # ch0 + {"min": 2000, "max": 4000}, # ch1 + {"min": 2000, "max": 4000}, # ch2 + {"min": 2000, "max": 4000} # ch3 + ] + + self.create_widgets() + self.refresh_ports() + + # 设置关闭事件 + self.root.protocol("WM_DELETE_WINDOW", self.on_closing) + + def create_widgets(self): + # 1. 串口相关界面 + serial_frame = ttk.LabelFrame(self.root, text="串口设置", padding=10) + serial_frame.pack(fill="x", padx=10, pady=5) + + # 串口号选择 + ttk.Label(serial_frame, text="串口号:").grid(row=0, column=0, padx=5) + self.port_var = tk.StringVar() + self.port_combobox = ttk.Combobox(serial_frame, textvariable=self.port_var, width=15) + self.port_combobox.grid(row=0, column=1, padx=5) + + self.refresh_btn = ttk.Button(serial_frame, text="刷新", command=self.refresh_ports) + self.refresh_btn.grid(row=0, column=2, padx=5) + + # 波特率选择 + ttk.Label(serial_frame, text="波特率:").grid(row=0, column=3, padx=5) + self.baud_var = tk.StringVar(value="19200") + baud_combobox = ttk.Combobox(serial_frame, textvariable=self.baud_var, + values=["9600", "19200", "38400", "57600", "115200"], width=10) + baud_combobox.grid(row=0, column=4, padx=5) + + # 打开关闭按钮 + self.open_btn = ttk.Button(serial_frame, text="打开串口", command=self.open_serial) + self.open_btn.grid(row=0, column=5, padx=5) + + self.close_btn = ttk.Button(serial_frame, text="关闭串口", command=self.close_serial, state="disabled") + self.close_btn.grid(row=0, column=6, padx=5) + + # 调试信息显示 + self.debug_var = tk.StringVar(value="等待连接...") + debug_label = ttk.Label(serial_frame, textvariable=self.debug_var, foreground="blue") + debug_label.grid(row=1, column=0, columnspan=7, pady=5) + + # 2. 数值比较界面 + value_frame = ttk.LabelFrame(self.root, text="数值比较", padding=10) + value_frame.pack(fill="both", expand=True, padx=10, pady=5) + + # 频率部分(左边) + freq_frame = ttk.LabelFrame(value_frame, text="频率 (Hz)") + freq_frame.pack(side="left", fill="both", expand=True, padx=5) + + self.freq_widgets = [] + for i in range(4): + ch_frame = ttk.Frame(freq_frame) + ch_frame.pack(fill="x", pady=2) + + ttk.Label(ch_frame, text=f"CH{i}:").pack(side="left") + + # 最小值输入 + min_frame = ttk.Frame(ch_frame) + min_frame.pack(side="left", padx=2) + ttk.Label(min_frame, text="min:").pack() + min_var = tk.StringVar(value="7") + min_entry = tk.Entry(min_frame, textvariable=min_var, width=5, bg="white") + min_entry.pack() + min_entry.bind('', lambda e, ch=i: self.update_freq_limit(ch)) + + # 当前值显示 + value_label = tk.Label(ch_frame, text="0.0", width=8, relief="sunken", bg="white") + value_label.pack(side="left", padx=5) + + # 最大值输入 + max_frame = ttk.Frame(ch_frame) + max_frame.pack(side="left", padx=2) + ttk.Label(max_frame, text="max:").pack() + max_var = tk.StringVar(value="9") + max_entry = tk.Entry(max_frame, textvariable=max_var, width=5, bg="white") + max_entry.pack() + max_entry.bind('', lambda e, ch=i: self.update_freq_limit(ch)) + + self.freq_widgets.append({ + "min_var": min_var, + "max_var": max_var, + "min_entry": min_entry, + "max_entry": max_entry, + "value_label": value_label + }) + + # 峰峰值部分(右边) + peak_frame = ttk.LabelFrame(value_frame, text="峰峰值 (mV)") + peak_frame.pack(side="right", fill="both", expand=True, padx=5) + + self.peak_widgets = [] + for i in range(4): + ch_frame = ttk.Frame(peak_frame) + ch_frame.pack(fill="x", pady=2) + + ttk.Label(ch_frame, text=f"CH{i}:").pack(side="left") + + # 最小值输入 + min_frame = ttk.Frame(ch_frame) + min_frame.pack(side="left", padx=2) + ttk.Label(min_frame, text="min:").pack() + min_var = tk.StringVar(value="2000") + min_entry = tk.Entry(min_frame, textvariable=min_var, width=5, bg="white") + min_entry.pack() + min_entry.bind('', lambda e, ch=i: self.update_peak_limit(ch)) + + # 当前值显示 + value_label = tk.Label(ch_frame, text="0", width=8, relief="sunken", bg="white") + value_label.pack(side="left", padx=5) + + # 最大值输入 + max_frame = ttk.Frame(ch_frame) + max_frame.pack(side="left", padx=2) + ttk.Label(max_frame, text="max:").pack() + max_var = tk.StringVar(value="4000") + max_entry = tk.Entry(max_frame, textvariable=max_var, width=5, bg="white") + max_entry.pack() + max_entry.bind('', lambda e, ch=i: self.update_peak_limit(ch)) + + self.peak_widgets.append({ + "min_var": min_var, + "max_var": max_var, + "min_entry": min_entry, + "max_entry": max_entry, + "value_label": value_label + }) + + # 3. 状态显示界面 + status_frame = ttk.LabelFrame(self.root, text="状态显示", padding=10) + status_frame.pack(fill="x", padx=10, pady=5) + + # 通讯状态 + comm_frame = ttk.Frame(status_frame) + comm_frame.pack(side="left", expand=True) + ttk.Label(comm_frame, text="通讯状态:").pack() + self.comm_status = tk.Label(comm_frame, text="●", font=("Arial", 20), fg="red") + self.comm_status.pack() + + # SD卡状态 + sd_frame = ttk.Frame(status_frame) + sd_frame.pack(side="left", expand=True) + ttk.Label(sd_frame, text="SD卡状态:").pack() + self.sd_status_label = tk.Label(sd_frame, text="●", font=("Arial", 20), fg="red") + self.sd_status_label.pack() + + # 按键状态 + key_frame = ttk.Frame(status_frame) + key_frame.pack(side="left", expand=True) + ttk.Label(key_frame, text="按键状态:").pack() + self.key_status_label = tk.Label(key_frame, text="●", font=("Arial", 20), fg="red") + self.key_status_label.pack() + + def refresh_ports(self): + """刷新可用串口列表""" + ports = serial.tools.list_ports.comports() + port_list = [port.device for port in ports] + self.port_combobox['values'] = port_list + if port_list and not self.port_var.get(): + self.port_var.set(port_list[0]) + + def open_serial(self): + """打开串口""" + port = self.port_var.get() + baudrate = self.baud_var.get() + + if not port: + messagebox.showerror("错误", "请选择串口号") + return + + try: + self.serial_port = serial.Serial( + port=port, + baudrate=int(baudrate), + bytesize=serial.EIGHTBITS, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + timeout=0.1 + ) + + # 清空缓冲区 + self.clear_serial_buffer() + self.receive_buffer = bytearray() + + self.is_connected = True + self.open_btn.config(state="disabled") + self.close_btn.config(state="normal") + self.refresh_btn.config(state="disabled") + + # 启动读取线程 + self.stop_thread = False + self.read_thread = threading.Thread(target=self.serial_read_loop) + self.read_thread.daemon = True + self.read_thread.start() + + self.update_debug_info("串口打开成功,开始发送查询命令...") + messagebox.showinfo("成功", "串口打开成功") + + except Exception as e: + messagebox.showerror("错误", f"打开串口失败: {str(e)}") + + def close_serial(self): + """关闭串口""" + self.stop_thread = True + self.is_connected = False + + if self.serial_port and self.serial_port.is_open: + self.serial_port.close() + + self.open_btn.config(state="normal") + self.close_btn.config(state="disabled") + self.refresh_btn.config(state="normal") + self.comm_status.config(fg="red") + self.update_debug_info("串口已关闭") + + def clear_serial_buffer(self): + """清空串口缓冲区""" + if self.serial_port and self.serial_port.is_open: + try: + self.serial_port.reset_input_buffer() + self.serial_port.reset_output_buffer() + self.receive_buffer.clear() + self.update_debug_info("串口缓冲区已清空") + except Exception as e: + self.update_debug_info(f"清空缓冲区错误: {e}") + + def update_debug_info(self, message): + """更新调试信息""" + timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3] + debug_msg = f"[{timestamp}] {message}" + self.debug_var.set(debug_msg) + print(debug_msg) + + def calculate_crc(self, data): + """计算CRC并返回对调后的两个字节""" + if not data: + return bytes.fromhex('0000') + + # 计算CRC + crc_value = self.crc16_func(data) + + # 转换为两个字节并对调 + crc_bytes = crc_value.to_bytes(2, byteorder='big') + crc_swapped = bytes([crc_bytes[1], crc_bytes[0]]) + + return crc_swapped + + def send_and_receive_command(self): + """发送命令并接收响应""" + if not (self.serial_port and self.serial_port.is_open): + return + + try: + # 清空接收缓冲区 + self.clear_serial_buffer() + + # 发送查询命令 + full_command = bytes.fromhex('5A04123400097991') + self.serial_port.write(full_command) + self.update_debug_info(f"发送命令: {full_command.hex().upper()}") + + # 等待100ms让设备准备响应 + time.sleep(0.1) + + # 读取响应数据 + if self.serial_port.in_waiting: + data = self.serial_port.read(self.serial_port.in_waiting) + if data: + self.update_debug_info(f"收到 {len(data)} 字节响应数据") + self.process_received_data(data) + else: + self.update_debug_info("未收到响应数据") + self.root.after(0, lambda: self.comm_status.config(fg="red")) + else: + self.update_debug_info("无响应数据可读") + self.root.after(0, lambda: self.comm_status.config(fg="red")) + + except Exception as e: + self.update_debug_info(f"发送接收命令错误: {e}") + self.root.after(0, lambda: self.comm_status.config(fg="red")) + + def serial_read_loop(self): + """串口读取循环""" + last_send_time = 0 + send_interval = 0.2 # 200ms发送一次 + + while self.is_connected and not self.stop_thread: + current_time = time.time() + + # 发送并接收命令 + if current_time - last_send_time >= send_interval: + self.send_and_receive_command() + last_send_time = current_time + + time.sleep(0.01) + + def process_received_data(self, data): + """处理接收到的数据""" + hex_data = data.hex().upper() + self.update_debug_info(f"原始响应数据: {hex_data}") + + # 检查数据长度 + if len(data) < 23: + self.update_debug_info(f"数据长度不足: {len(data)}字节,期望至少23字节") + return + + # 查找帧头 + frame_start = -1 + for i in range(len(data) - 2): + if data[i] == 0x5A and data[i+1] == 0x04 and data[i+2] == 0x12: + frame_start = i + break + + if frame_start == -1: + self.update_debug_info("未找到帧头 5A0412") + return + + self.update_debug_info(f"找到帧头,位置: {frame_start}") + + # 提取完整帧(从帧头开始的23字节) + if len(data) - frame_start >= 23: + frame_data = data[frame_start:frame_start+23] + self.process_received_frame(frame_data) + else: + self.update_debug_info("帧数据不完整") + + def process_received_frame(self, data): + """处理接收到的完整数据帧(23字节)""" + hex_data = data.hex().upper() + self.update_debug_info(f"处理数据帧: {hex_data}") + + # CRC校验 - 前21字节计算CRC,最后2字节是CRC + if not self.check_crc(data): + self.update_debug_info("CRC校验失败") + self.root.after(0, lambda: self.comm_status.config(fg="red")) + return + + # 解析数据 + try: + # 解析峰峰值 (4个通道,每个2字节) + peak_values = [] + for i in range(4): + start_idx = 3 + i * 2 # 跳过帧头5A0412 (3字节) + peak_value = (data[start_idx] << 8) | data[start_idx + 1] + peak_values.append(peak_value) + + # 解析频率 (4个通道,每个2字节,需要除以10) + freq_values = [] + for i in range(4): + start_idx = 11 + i * 2 # 峰峰值后是频率 + freq_value = (data[start_idx] << 8) | data[start_idx + 1] + freq_values.append(freq_value / 10.0) + + # 解析状态 + key_status = data[19] # 按键状态 + sd_status = data[20] # SD卡状态 + + self.update_debug_info(f"解析成功: 峰峰值{peak_values}, 频率{freq_values}, 按键{key_status}, SD卡{sd_status}") + + # 更新界面 + self.root.after(0, self.update_display, peak_values, freq_values, key_status, sd_status) + + # 通讯成功,更新状态 + self.root.after(0, lambda: self.comm_status.config(fg="green")) + + except Exception as e: + self.update_debug_info(f"解析数据错误: {e}") + self.root.after(0, lambda: self.comm_status.config(fg="red")) + + def check_crc(self, data): + """CRC校验 - 前21字节计算CRC,最后2字节是CRC(需要对调)""" + try: + if len(data) < 23: + return False + + # 分离数据(前21字节)和CRC(最后2字节) + data_part = data[:21] # 前21字节是数据 + crc_received = data[21:23] # 最后2字节是CRC + + # 计算期望的CRC值(对调后的) + expected_crc = self.calculate_crc(data_part) + + # 比较CRC + result = crc_received == expected_crc + if not result: + self.update_debug_info(f"CRC不匹配: 收到{crc_received.hex().upper()}, 期望{expected_crc.hex().upper()}") + return result + + except Exception as e: + self.update_debug_info(f"CRC校验错误: {e}") + return False + + def update_display(self, peak_values, freq_values, key_status, sd_status): + """更新显示""" + # 更新峰峰值 + for i in range(4): + value = peak_values[i] + self.peak_values[i] = value + widget = self.peak_widgets[i] + widget["value_label"].config(text=str(value)) + + # 检查范围并设置颜色 + in_range = self.peak_limits[i]["min"] <= value <= self.peak_limits[i]["max"] + color = "green" if in_range else "red" + widget["value_label"].config(bg=color) + + # 如果越界,设置上下限输入框颜色 + min_color = "red" if value < self.peak_limits[i]["min"] else "white" + max_color = "red" if value > self.peak_limits[i]["max"] else "white" + widget["min_entry"].config(bg=min_color) + widget["max_entry"].config(bg=max_color) + + # 更新频率 + for i in range(4): + value = freq_values[i] + self.frequency_values[i] = value + widget = self.freq_widgets[i] + widget["value_label"].config(text=f"{value:.1f}") + + # 检查范围并设置颜色 + in_range = self.freq_limits[i]["min"] <= value <= self.freq_limits[i]["max"] + color = "green" if in_range else "red" + widget["value_label"].config(bg=color) + + # 如果越界,设置上下限输入框颜色 + min_color = "red" if value < self.freq_limits[i]["min"] else "white" + max_color = "red" if value > self.freq_limits[i]["max"] else "white" + widget["min_entry"].config(bg=min_color) + widget["max_entry"].config(bg=max_color) + + # 更新状态 + self.key_status = key_status + self.sd_status = sd_status + + # 按键状态:0=未按下,1=按下 + key_color = "green" if key_status == 1 else "red" + self.key_status_label.config(fg=key_color) + + # SD卡状态:5=成功,其他=失败 + sd_color = "green" if sd_status == 5 else "red" + self.sd_status_label.config(fg=sd_color) + + self.update_debug_info("界面更新完成") + + def update_freq_limit(self, channel): + """更新频率上下限""" + try: + min_val = float(self.freq_widgets[channel]["min_var"].get()) + max_val = float(self.freq_widgets[channel]["max_var"].get()) + + # 验证最小值不大于最大值 + if min_val > max_val: + messagebox.showerror("错误", "最小值不能大于最大值") + return + + self.freq_limits[channel]["min"] = min_val + self.freq_limits[channel]["max"] = max_val + + # 立即检查当前值并更新显示 + self.check_freq_value(channel) + + except ValueError: + messagebox.showerror("错误", "请输入有效的数字") + + def update_peak_limit(self, channel): + """更新峰峰值上下限""" + try: + min_val = float(self.peak_widgets[channel]["min_var"].get()) + max_val = float(self.peak_widgets[channel]["max_var"].get()) + + # 验证最小值不大于最大值 + if min_val > max_val: + messagebox.showerror("错误", "最小值不能大于最大值") + return + + self.peak_limits[channel]["min"] = min_val + self.peak_limits[channel]["max"] = max_val + + # 立即检查当前值并更新显示 + self.check_peak_value(channel) + + except ValueError: + messagebox.showerror("错误", "请输入有效的数字") + + def check_freq_value(self, channel): + """检查指定通道的频率值是否在范围内""" + value = self.frequency_values[channel] + widget = self.freq_widgets[channel] + + # 检查范围并设置颜色 + in_range = self.freq_limits[channel]["min"] <= value <= self.freq_limits[channel]["max"] + color = "green" if in_range else "red" + widget["value_label"].config(bg=color) + + # 如果越界,设置上下限输入框颜色 + min_color = "red" if value < self.freq_limits[channel]["min"] else "white" + max_color = "red" if value > self.freq_limits[channel]["max"] else "white" + widget["min_entry"].config(bg=min_color) + widget["max_entry"].config(bg=max_color) + + def check_peak_value(self, channel): + """检查指定通道的峰峰值是否在范围内""" + value = self.peak_values[channel] + widget = self.peak_widgets[channel] + + # 检查范围并设置颜色 + in_range = self.peak_limits[channel]["min"] <= value <= self.peak_limits[channel]["max"] + color = "green" if in_range else "red" + widget["value_label"].config(bg=color) + + # 如果越界,设置上下限输入框颜色 + min_color = "red" if value < self.peak_limits[channel]["min"] else "white" + max_color = "red" if value > self.peak_limits[channel]["max"] else "white" + widget["min_entry"].config(bg=min_color) + widget["max_entry"].config(bg=max_color) + + def check_current_values(self): + """检查当前值是否在范围内""" + for i in range(4): + self.check_freq_value(i) + self.check_peak_value(i) + + def on_closing(self): + """程序关闭时的清理工作""" + self.stop_thread = True + if self.serial_port and self.serial_port.is_open: + self.serial_port.close() + self.root.destroy() + +if __name__ == "__main__": + root = tk.Tk() + app = ATEApplication(root) + root.mainloop() \ No newline at end of file diff --git a/ate/src/CMakeLists.txt b/ate/src/CMakeLists.txt new file mode 100755 index 0000000..2c62141 --- /dev/null +++ b/ate/src/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories(.) +include_directories(../../driver/sdcard) +include_directories(../../driver/stddriver/inc) +include_directories(../../driver/cmsis/inc) +include_directories(../../component/fatfs/inc) + +file(GLOB FILELIST +device.c +led.c +button.c +heat.c +ltc1867.c +ltc2640.c +rs485.c +modbus.c +calc.c +sd.c +) + +add_library(src STATIC ${FILELIST}) +target_link_libraries(src driver) +target_link_libraries(src fatfs) diff --git a/ate/src/button.c b/ate/src/button.c new file mode 100755 index 0000000..ac12b61 --- /dev/null +++ b/ate/src/button.c @@ -0,0 +1,39 @@ +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" +#include "button.h" +#include "device.h" + +void button_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure = { + .GPIO_Pin = PIN_BUTTON, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_PuPd = GPIO_PuPd_UP, + }; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + GPIO_Init(PORT_BUTTON, &GPIO_InitStructure); +} + +int button_is_pressed(void) +{ + if (GPIO_ReadInputDataBit(PORT_BUTTON, PIN_BUTTON)) { + return 0; + } else { + return 1; + } +} + +void button_loop(void) +{ + static uint32_t ms = 0; + + if (system_tick_cnt < (ms + 100)) { + return; + } + ms = system_tick_cnt; + + device_data.button = button_is_pressed() ? 1 : 0; +} diff --git a/ate/src/button.h b/ate/src/button.h new file mode 100755 index 0000000..b852512 --- /dev/null +++ b/ate/src/button.h @@ -0,0 +1,23 @@ +#ifndef __BUTTON_H__ +#define __BUTTON_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define PORT_BUTTON (GPIOB) +#define PIN_BUTTON (GPIO_Pin_14) + +extern uint32_t system_tick_cnt; + +void button_init(void); +int button_is_pressed(void); +void button_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __BUTTON_H__ */ diff --git a/ate/src/calc.c b/ate/src/calc.c new file mode 100755 index 0000000..7a74d72 --- /dev/null +++ b/ate/src/calc.c @@ -0,0 +1,54 @@ +#include "calc.h" +#include "device.h" +#include "ltc1867.h" + +uint16_t calc_freq(uint32_t pre, uint32_t now) +{ + uint32_t freq; + + if (now > pre) { + freq = now - pre; + } else { + freq = pre - now; + } + freq = (LEDIR_FREQ * SAMPLES_PER_PERIOD * 10 + freq / 2) / freq; + + return (uint16_t)freq; +} + +uint16_t calc_peak(int ch, uint32_t pre, uint32_t now) +{ + uint16_t min, max, val; + + min = 65535; + max = 0; + for (uint32_t i = data_ltc1867.sample_pre[ch]; i < data_ltc1867.sample_now[ch]; i++) { + val = data_ltc1867_raw[ch][i % LTC1867_RAW_BUFF_SIZE]; + if (min > val) { + min = val; + } + if (max < val) { + max = val; + } + } + return (max - min + 8) / 16; +} + +void calc_loop(void) +{ + static uint32_t sample_cnt = 0; + static uint32_t pre[LTC1867_CH_CNT] = {0, 0, 0, 0}; + + if (sample_cnt == data_ltc1867.sample_cnt) { + return; + } + sample_cnt = data_ltc1867.sample_cnt; + + for (int i = 0; i < LTC1867_CH_CNT; i++) { + if (pre[i] != data_ltc1867.sample_pre[i]) { + pre[i] = data_ltc1867.sample_pre[i]; + device_data.freq[i] = calc_freq(data_ltc1867.sample_pre[i], data_ltc1867.sample_now[i]); + device_data.peak[i] = calc_peak(i, data_ltc1867.sample_pre[i], data_ltc1867.sample_now[i]); + } + } +} diff --git a/ate/src/calc.h b/ate/src/calc.h new file mode 100755 index 0000000..7d16789 --- /dev/null +++ b/ate/src/calc.h @@ -0,0 +1,17 @@ +#ifndef __CALC_H__ +#define __CALC_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +uint16_t calc_freq(uint32_t pre, uint32_t now); +void calc_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __CALC_H__ */ diff --git a/ate/src/config.h b/ate/src/config.h new file mode 100755 index 0000000..1436abe --- /dev/null +++ b/ate/src/config.h @@ -0,0 +1,15 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#define LEDIR_FREQ (8) +#define SAMPLES_PER_PERIOD (64) + +#ifdef __cplusplus +} +#endif + +#endif /* __CONFIG_H__ */ diff --git a/ate/src/device.c b/ate/src/device.c new file mode 100755 index 0000000..b237880 --- /dev/null +++ b/ate/src/device.c @@ -0,0 +1,29 @@ +#include "device.h" + +#define BITMAP_GAS_ADDR (0x080A0000) +#define BITMAP_MAIN_ADDR (BITMAP_GAS_ADDR + 20 * 1024 * 4) + +#define OFFSET_DATA (0x0000 * 2) + +struct device_data_s device_data __attribute__((section(".bss_ccm"))); + +const uint8_t * const modbus_map_ro[] = { + [OFFSET_DATA + 0] = (uint8_t *)&(device_data.peak[0]) + 1, + [OFFSET_DATA + 1] = (uint8_t *)&(device_data.peak[0]) + 0, + [OFFSET_DATA + 2] = (uint8_t *)&(device_data.peak[1]) + 1, + [OFFSET_DATA + 3] = (uint8_t *)&(device_data.peak[1]) + 0, + [OFFSET_DATA + 4] = (uint8_t *)&(device_data.peak[2]) + 1, + [OFFSET_DATA + 5] = (uint8_t *)&(device_data.peak[2]) + 0, + [OFFSET_DATA + 6] = (uint8_t *)&(device_data.peak[3]) + 1, + [OFFSET_DATA + 7] = (uint8_t *)&(device_data.peak[3]) + 0, + [OFFSET_DATA + 8] = (uint8_t *)&(device_data.freq[0]) + 1, + [OFFSET_DATA + 9] = (uint8_t *)&(device_data.freq[0]) + 0, + [OFFSET_DATA + 10] = (uint8_t *)&(device_data.freq[1]) + 1, + [OFFSET_DATA + 11] = (uint8_t *)&(device_data.freq[1]) + 0, + [OFFSET_DATA + 12] = (uint8_t *)&(device_data.freq[2]) + 1, + [OFFSET_DATA + 13] = (uint8_t *)&(device_data.freq[2]) + 0, + [OFFSET_DATA + 14] = (uint8_t *)&(device_data.freq[3]) + 1, + [OFFSET_DATA + 15] = (uint8_t *)&(device_data.freq[3]) + 0, + [OFFSET_DATA + 16] = (uint8_t *)&(device_data.button) + 0, + [OFFSET_DATA + 17] = (uint8_t *)&(device_data.sd) + 0, +}; diff --git a/ate/src/device.h b/ate/src/device.h new file mode 100755 index 0000000..a284a84 --- /dev/null +++ b/ate/src/device.h @@ -0,0 +1,25 @@ +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +/******************* device data *******************/ +struct device_data_s { + uint16_t peak[4]; + uint16_t freq[4]; + uint8_t button; + uint8_t sd; +}; + +extern const uint8_t * const modbus_map_ro[]; +extern struct device_data_s device_data; + +#ifdef __cplusplus +} +#endif + +#endif /* __DEVICE_H__ */ diff --git a/ate/src/heat.c b/ate/src/heat.c new file mode 100755 index 0000000..79c28ea --- /dev/null +++ b/ate/src/heat.c @@ -0,0 +1,45 @@ +#include "heat.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" + +void heat_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure = { + .GPIO_Pin = PIN_HEAT, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + GPIO_Init(PORT_HEAT, &GPIO_InitStructure); + heat_off(); +} + +void heat_on(void) +{ + GPIO_SetBits(PORT_HEAT, PIN_HEAT); +} + +void heat_off(void) +{ + GPIO_ResetBits(PORT_HEAT, PIN_HEAT); +} + +void heat_toggle(void) +{ + GPIO_ToggleBits(PORT_HEAT, PIN_HEAT); +} + +void heat_loop(void) +{ + static uint32_t ms = 0; + + if (system_tick_cnt < (ms + 62)) { + return; + } + ms = system_tick_cnt; + + heat_toggle(); +} diff --git a/ate/src/heat.h b/ate/src/heat.h new file mode 100755 index 0000000..bb938fb --- /dev/null +++ b/ate/src/heat.h @@ -0,0 +1,25 @@ +#ifndef __HEAT_H__ +#define __HEAT_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define PORT_HEAT (GPIOB) +#define PIN_HEAT (GPIO_Pin_1) + +extern uint32_t system_tick_cnt; + +void heat_init(void); +void heat_on(void); +void heat_off(void); +void heat_toggle(void); +void heat_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __HEAT_H__ */ diff --git a/ate/src/led.c b/ate/src/led.c new file mode 100755 index 0000000..2645b88 --- /dev/null +++ b/ate/src/led.c @@ -0,0 +1,48 @@ +#include "led.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" + +void led_init(uint16_t led) +{ + GPIO_InitTypeDef GPIO_InitStructure = { + .GPIO_Pin = led, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + GPIO_Init(PORT_LED, &GPIO_InitStructure); + led_off(led); +} + +void led_off(uint16_t led) +{ + GPIO_SetBits(PORT_LED, led); +} + +void led_on(uint16_t led) +{ + GPIO_ResetBits(PORT_LED, led); +} + +void led_loop(void) +{ + static uint32_t ms = 0; + static uint32_t led_cnt = 0; + + if (system_tick_cnt < (ms + 200)) { + return; + } + ms = system_tick_cnt; + + led_cnt = led_cnt & 3; + switch (led_cnt) { + case 0: led_off(LED1 | LED2); break; + case 1: led_off(LED1); led_on(LED2);break; + case 2: led_on(LED1); led_off(LED2); break; + case 3: led_on(LED1 | LED2); break; + } + led_cnt++; +} diff --git a/ate/src/led.h b/ate/src/led.h new file mode 100755 index 0000000..974260a --- /dev/null +++ b/ate/src/led.h @@ -0,0 +1,25 @@ +#ifndef __LED_H__ +#define __LED_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define PORT_LED (GPIOC) +#define LED1 (GPIO_Pin_4) +#define LED2 (GPIO_Pin_5) + +extern uint32_t system_tick_cnt; + +void led_init(uint16_t led); +void led_off(uint16_t led); +void led_on(uint16_t led); +void led_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LED_H__ */ diff --git a/ate/src/ltc1867.c b/ate/src/ltc1867.c new file mode 100755 index 0000000..04aaf47 --- /dev/null +++ b/ate/src/ltc1867.c @@ -0,0 +1,195 @@ +#include "ltc1867.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_tim.h" +#include "stm32f4xx_spi.h" + +uint16_t data_ltc1867_raw[LTC1867_CH_CNT][LTC1867_RAW_BUFF_SIZE] __attribute__((section(".bss_ccm"))); +struct data_ltc1867_s data_ltc1867 __attribute__((section(".bss_ccm"))); +__attribute__((section(".data_ccm"))) uint16_t ltc1867_spi_data[LTC1867_CH_CNT] = {0xC400, 0x9400, 0xD400, 0x8400}; /* order: ch1, ch2, ch3, ch0 */ + +void ltc1867_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + SPI_InitTypeDef SPI_InitStructure; + + /* TIM2 32bit for sample */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + // NVIC_SetPriority(PendSV_IRQn, 1); /* priority is just lower than sample, for write cali data to flash */ + /* Time base configuration */ + TIM_TimeBaseStructure.TIM_Period = TIMER_PERIOD_SAMPLE; + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); + /* Prescaler configuration */ + TIM_PrescalerConfig(TIM2, 0, TIM_PSCReloadMode_Immediate); + /* TIM2 Interrupts enable */ + TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); + /* TIM2 enable counter */ + TIM_Cmd(TIM2, ENABLE); + + /* TIM3 16bit for ADC conversion */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); + /* Time base configuration */ + TIM_TimeBaseStructure.TIM_Period = TIMER_PERIOD_DELAY; + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); + /* Prescaler configuration */ + TIM_PrescalerConfig(TIM3, 0, TIM_PSCReloadMode_Immediate); + /* TIM3 disable counter, start when ltc1867 need delay */ + TIM_Cmd(TIM3, DISABLE); + + /* LEDIR pin configure */ + GPIO_InitStructure.GPIO_Pin = PIN_LEDIR; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + GPIO_Init(PORT_LEDIR, &GPIO_InitStructure); + ltc1867_ledir_off(); + + /* LTC1867 conv pin configure */ + GPIO_InitStructure.GPIO_Pin = PIN_CONV; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + GPIO_Init(PORT_LTC1867, &GPIO_InitStructure); + /* config SPI for LTC1867 communication */ + GPIO_PinAFConfig(PORT_SPI, GPIO_PinSource5, GPIO_AF_SPI1); + GPIO_PinAFConfig(PORT_SPI, GPIO_PinSource6, GPIO_AF_SPI1); + GPIO_PinAFConfig(PORT_SPI, GPIO_PinSource7, GPIO_AF_SPI1); + GPIO_InitStructure.GPIO_Pin = PIN_SPI_SCK | PIN_SPI_SDI | PIN_SPI_SDO; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_SPI, &GPIO_InitStructure); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + SPI_I2S_DeInit(SPI1); + SPI_InitStructure.SPI_Mode = SPI_Mode_Master; + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; + SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; + SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + SPI_InitStructure.SPI_CRCPolynomial = 7; + SPI_Init(SPI1, &SPI_InitStructure); + SPI_Cmd(SPI1, ENABLE); + ltc1867_spi_select(); + ltc1867_transfer(ltc1867_spi_data[LTC1867_CH_CNT - 1]); + + data_ltc1867.ledir_cnt = 0; /* index of led count, for togglr IR led */ + data_ltc1867.sample_cnt = 0; /* index for search point of 32768 */ + for (uint8_t i = 0; i < LTC1867_CH_CNT; i++) { + data_ltc1867.sample_pre[i] = 0; + data_ltc1867.sample_now[i] = 0; + } +} + +void ltc1867_ledir_on(void) +{ + GPIO_SetBits(PORT_LEDIR, PIN_LEDIR); +} + +void ltc1867_ledir_off(void) +{ + GPIO_ResetBits(PORT_LEDIR, PIN_LEDIR); +} + +void ltc1867_ledir_toggle(void) +{ + GPIO_ToggleBits(PORT_LEDIR, PIN_LEDIR); +} + +void ltc1867_delay(void) +{ + FlagStatus sts; + + TIM_SetCounter(TIM3, 0); + TIM_ClearFlag(TIM3, TIM_FLAG_Update); + TIM_Cmd(TIM3, ENABLE); + while (1) { + sts = TIM_GetFlagStatus(TIM3, TIM_FLAG_Update); + if (sts != RESET) { + break; + } + } + TIM_Cmd(TIM3, DISABLE); +} + +void ltc1867_conv(void) +{ + GPIO_SetBits(PORT_LTC1867, PIN_CONV); +} + +void ltc1867_spi_select(void) +{ + GPIO_ResetBits(PORT_LTC1867, PIN_SPI_CS); +} + +uint16_t ltc1867_transfer(uint16_t data_send) +{ + FlagStatus flag; + + while (1) { + flag = SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE); + if (flag != RESET) { + break; + } + } + SPI_I2S_SendData(SPI1, data_send); + while (1) { + flag = SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE); + if (flag != RESET) { + break; + } + } + return SPI_I2S_ReceiveData(SPI1); +} + +void TIM2_IRQHandler(void) +{ + static uint16_t pre_val[LTC1867_CH_CNT]; + static uint16_t val[LTC1867_CH_CNT] = {65535, 65535, 65535, 65535}; + + TIM_ClearITPendingBit(TIM2, TIM_IT_Update); + + /* for control led IR */ + data_ltc1867.ledir_cnt++; + if (data_ltc1867.ledir_cnt == (SAMPLES_PER_PERIOD / 2)) { + ltc1867_ledir_on(); + } else if (data_ltc1867.ledir_cnt >= SAMPLES_PER_PERIOD) { + ltc1867_ledir_off(); + data_ltc1867.ledir_cnt = 0; + } + + /* sample 4 channel adc data */ + for (uint8_t i = 0; i < LTC1867_CH_CNT; i++) { + ltc1867_conv(); /* this point start convert */ + ltc1867_delay(); /* delay 3.5us for convert time, reference for LTC1867 datasheet */ + ltc1867_spi_select(); /* convert complete, make convert pin low for reading sample data by SPI */ + pre_val[i] = val[i]; + val[i] = ltc1867_transfer(ltc1867_spi_data[i]); /* read convert data and send next channel information */ + data_ltc1867_raw[i][data_ltc1867.sample_cnt % LTC1867_RAW_BUFF_SIZE] = val[i]; + if (pre_val[i] < 32768 && val[i] >= 32768) { + data_ltc1867.sample_pre[i] = data_ltc1867.sample_now[i]; + data_ltc1867.sample_now[i] = data_ltc1867.sample_cnt; + } + } + data_ltc1867.sample_cnt++; +} diff --git a/ate/src/ltc1867.h b/ate/src/ltc1867.h new file mode 100755 index 0000000..4446a92 --- /dev/null +++ b/ate/src/ltc1867.h @@ -0,0 +1,52 @@ +#ifndef __LTC1867_H__ +#define __LTC1867_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" +#include "config.h" + +#define TIMER_SRC_FREQ (84 * 1000 * 1000) +#define TIMER_PERIOD_SAMPLE (TIMER_SRC_FREQ / LEDIR_FREQ / SAMPLES_PER_PERIOD - 1) +#define TIMER_PERIOD_DELAY (TIMER_SRC_FREQ / 1000 / 1000 * 35 / 10 - 1) /* 3.5us */ + +#define LTC1867_CH_CNT (4) + +#define LTC1867_RAW_BUFF_SIZE (SAMPLES_PER_PERIOD * LEDIR_FREQ) + +#define PORT_LEDIR (GPIOB) +#define PIN_LEDIR (GPIO_Pin_0) +#define PORT_LTC1867 (GPIOA) +#define PIN_CONV (GPIO_Pin_4) +#define PORT_SPI (GPIOA) +#define PIN_SPI_CS (GPIO_Pin_4) +#define PIN_SPI_SCK (GPIO_Pin_5) +#define PIN_SPI_SDO (GPIO_Pin_6) +#define PIN_SPI_SDI (GPIO_Pin_7) + +struct data_ltc1867_s { + uint16_t ledir_cnt; /* index of led count, for togglr IR led */ + uint32_t sample_cnt; /* index of sample */ + uint32_t sample_pre[4]; /* index of pre sample rasing edge */ + uint32_t sample_now[4]; /* index of now sample rasing edge */ +}; + +extern struct data_ltc1867_s data_ltc1867; +extern uint16_t data_ltc1867_raw[LTC1867_CH_CNT][LTC1867_RAW_BUFF_SIZE]; + +void ltc1867_init(void); +void ltc1867_ledir_on(void); +void ltc1867_ledir_off(void); +void ltc1867_ledir_toggle(void); +void ltc1867_delay(void); +void ltc1867_conv(void); +void ltc1867_spi_select(void); +uint16_t ltc1867_transfer(uint16_t data_send); + +#ifdef __cplusplus +} +#endif + +#endif /* __LTC1867_H__ */ diff --git a/ate/src/ltc2640.c b/ate/src/ltc2640.c new file mode 100755 index 0000000..5eb6540 --- /dev/null +++ b/ate/src/ltc2640.c @@ -0,0 +1,110 @@ +#include "ltc2640.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_spi.h" +#include "stm32f4xx_dma.h" +#include "device.h" + +uint8_t data_ltc2640_output[LTC2640_OUTPUT_LEN]; +uint16_t data_ltc2640[] = { + VOLTAGE_200MV, + VOLTAGE_300MV, + VOLTAGE_400MV, + VOLTAGE_1000MV, + VOLTAGE_1200MV, + VOLTAGE_1500MV, + VOLTAGE_1800MV, + VOLTAGE_2000MV, + VOLTAGE_2400MV, + VOLTAGE_2500MV, +}; + +void ltc2640_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + SPI_InitTypeDef SPI_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); + + /* config ltc2640 pin */ + GPIO_InitStructure.GPIO_Pin = LTC2640_PIN_CS; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = LTC2640_PIN_SCK | LTC2640_PIN_SDI; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOB, &GPIO_InitStructure); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI3); + /* config ltc2640 clr pin */ + GPIO_InitStructure.GPIO_Pin = LTC2640_PIN_CLR; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_Init(GPIOB, &GPIO_InitStructure); + GPIO_SetBits(GPIOB, LTC2640_PIN_CLR); + + /* config SPI function */ + SPI_I2S_DeInit(SPI3); + SPI_InitStructure.SPI_Mode = SPI_Mode_Master; + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; + SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; + SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + SPI_InitStructure.SPI_CRCPolynomial = 7; + SPI_Init(SPI3, &SPI_InitStructure); + SPI_Cmd(SPI3, ENABLE); + SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); + + /* Configure DMA controller to manage SPI request */ + DMA_InitStructure.DMA_BufferSize = LTC2640_OUTPUT_LEN; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(&(SPI3->DR)); + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_Priority = DMA_Priority_Low; + DMA_InitStructure.DMA_Channel = DMA_Channel_0; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)data_ltc2640_output; + DMA_Init(DMA1_Stream5, &DMA_InitStructure); + ltc2640_send_data(0); +} + +void ltc2640_send_data(uint16_t data) +{ + data_ltc2640_output[0] = 0x30; + data_ltc2640_output[1] = (uint8_t)((data >> 4) & 0xFF); + data_ltc2640_output[2] = (uint8_t)((data << 4) & 0xFF); + DMA_ClearFlag(DMA1_Stream5, DMA_FLAG_FEIF5 | DMA_FLAG_DMEIF5 | DMA_FLAG_TEIF5 | DMA_FLAG_HTIF5 | DMA_FLAG_TCIF5); + DMA_SetCurrDataCounter(DMA1_Stream5, LTC2640_OUTPUT_LEN); + DMA_Cmd(DMA1_Stream5, ENABLE); +} + +void ltc2640_loop(void) +{ + static uint32_t ms = 0; + static uint32_t cnt = 0; + + if (system_tick_cnt < (ms + 100)) { + return; + } + GPIO_SetBits(GPIOA, LTC2640_PIN_CS); + ms = system_tick_cnt; + cnt = cnt % (sizeof(data_ltc2640) / sizeof(data_ltc2640[0])); + GPIO_ResetBits(GPIOA, LTC2640_PIN_CS); + ltc2640_send_data(data_ltc2640[cnt]); + cnt++; +} diff --git a/ate/src/ltc2640.h b/ate/src/ltc2640.h new file mode 100755 index 0000000..f347bf5 --- /dev/null +++ b/ate/src/ltc2640.h @@ -0,0 +1,38 @@ +#ifndef __LTC2640_H__ +#define __LTC2640_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define LTC2640_PIN_CLR (GPIO_Pin_7) +#define LTC2640_PIN_CS (GPIO_Pin_15) +#define LTC2640_PIN_SCK (GPIO_Pin_3) +#define LTC2640_PIN_SDI (GPIO_Pin_5) + +#define LTC2640_OUTPUT_LEN (3) + +#define VOLTAGE_200MV (328) +#define VOLTAGE_300MV (492) +#define VOLTAGE_400MV (655) +#define VOLTAGE_1000MV (1638) +#define VOLTAGE_1200MV (1966) +#define VOLTAGE_1500MV (2458) +#define VOLTAGE_1800MV (2949) +#define VOLTAGE_2000MV (3277) +#define VOLTAGE_2400MV (3932) +#define VOLTAGE_2500MV (4095) + +extern uint32_t system_tick_cnt; + +void ltc2640_init(void); +void ltc2640_send_data(uint16_t data); +void ltc2640_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LTC2640_H__ */ diff --git a/ate/src/modbus.c b/ate/src/modbus.c new file mode 100755 index 0000000..d5659bb --- /dev/null +++ b/ate/src/modbus.c @@ -0,0 +1,185 @@ +#include "device.h" +#include "rs485.h" +#include "modbus.h" + +const uint8_t crc_tabl[] = { //CRC low Value Table + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, +}; + +const uint8_t crc_tabh[] = { //CRC high Value Table + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, + 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, + 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, + 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, + 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, + 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, + 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, + 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, + 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, + 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, + 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, + 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, + 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, + 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, + 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, + 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, + 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, + 0x41, 0x81, 0x80, 0x40, +}; + +/* polynomial: x16+x15+x2+x1 */ +void crc16_8005_calc(uint8_t * p, uint16_t len, struct crc16_result_s *ret) +{ + struct crc16_result_s crc = {0xFF, 0xFF}; + uint8_t i, index; + + for (i = 0; i < len; i++) { + index = crc.crcl ^ p[i]; + crc.crcl = crc.crch ^ crc_tabl[index]; + crc.crch = crc_tabh[index]; + } + ret->crcl = crc.crcl; + ret->crch = crc.crch; +} + +void modbus_init(void) +{ + rs485_init(); +} + +uint16_t modbus_data_big2little16(uint8_t *buff) +{ + uint16_t val; + + val = (uint16_t)(buff[0]); + val <<= 8; + val |= (uint16_t)(buff[1]); + return val; +} + +uint32_t modbus_data_big2little32(uint8_t *buff) +{ + uint32_t val; + + val = (uint32_t)(buff[0]); + val <<= 8; + val |= (uint32_t)(buff[1]); + val <<= 8; + val |= (uint32_t)(buff[2]); + val <<= 8; + val |= (uint32_t)(buff[3]); + return val; +} + +/* pr: point of rx buffer + pt: point of tx buffer + err_type: reference for MODBUS_ERROR_CODE_XXX + return: length of tx data need send */ +uint16_t modbus_error_process(uint8_t *pr, uint8_t *pt, uint8_t err_type) +{ + struct crc16_result_s crc; + + pt[0] = pr[0]; + pt[1] = pr[1] + 0x80; + pt[2] = err_type; + crc16_8005_calc(pt, 3, &crc); + pt[3] = crc.crcl; + pt[4] = crc.crch; + return 5; +} + +/* pr: point of rx buffer + pt: point of tx buffer + len: length of rx data in buffer + return: length of tx data need send */ +uint16_t modbus_func_read_input(uint8_t *pr, uint8_t *pt, uint16_t len) +{ + uint16_t cnt, addr_s, i; + struct crc16_result_s crc; + + /* modbus register count */ + cnt = modbus_data_big2little16(pr + 4); + if (cnt != MODBUS_LENGTH_RO) { + /* modbus register count error */ + return modbus_error_process(pr, pt, MODBUS_ERROR_CODE_VALUE); + } + addr_s = modbus_data_big2little16(pr + 2); + if (addr_s != MODBUS_ADDR_RO_S) { + /* modbus register address error */ + return modbus_error_process(pr, pt, MODBUS_ERROR_CODE_ADDR); + } + pt[0] = pr[0]; + pt[1] = pr[1]; + pt[2] = (uint8_t)(cnt * 2); + for (i = 0; i < cnt * 2; i++) { + pt[3 + i] = *(modbus_map_ro[i]); + } + i += 3; + crc16_8005_calc(pt, i, &crc); + pt[i++] = crc.crcl; + pt[i++] = crc.crch; + + return i; +} + +void modbus_loop(void) +{ + static uint32_t frame_cnt = 0; + struct crc16_result_s crc; + + /* no new complete frame */ + if (rs485_data.frame_cnt == frame_cnt) { + return; + } + /* one new frame occur */ + frame_cnt = rs485_data.frame_cnt; + /* step 1: calc CRC */ + crc16_8005_calc(rs485_data.buff_rx, rs485_data.rx_len - 2, &crc); + if (crc.crcl != rs485_data.buff_rx[rs485_data.rx_len - 2] || \ + crc.crch != rs485_data.buff_rx[rs485_data.rx_len - 1]) { + /* CRC calc error */ + rs485_data.rx_len = 0; + rs485_mode_rx(); + rs485_rx_start(); + return; + } + + /* step 2: process data according function code */ + if (rs485_data.buff_rx[1] == MODBUS_FUNCTION_CODE_READ_INPUT) { + rs485_data.tx_len = modbus_func_read_input(rs485_data.buff_rx, rs485_data.buff_tx, rs485_data.rx_len); + } else { + rs485_data.tx_len = modbus_error_process(rs485_data.buff_rx, rs485_data.buff_tx, MODBUS_ERROR_CODE_FUNCTION); + } + if (rs485_data.tx_len == 0) { + rs485_data.rx_len = 0; + rs485_mode_rx(); + rs485_rx_start(); + } else { + rs485_send_data(rs485_data.tx_len); + } +} diff --git a/ate/src/modbus.h b/ate/src/modbus.h new file mode 100755 index 0000000..3c8bb09 --- /dev/null +++ b/ate/src/modbus.h @@ -0,0 +1,37 @@ +#ifndef __MODBUS_H__ +#define __MODBUS_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define MODBUS_FUNCTION_CODE_READ_INPUT (0x04) +#define MODBUS_FUNCTION_CODE_WRITE_SINGLE (0x06) +#define MODBUS_FUNCTION_CODE_WRITE_MULTI (0x10) + +#define MODBUS_ERROR_CODE_FUNCTION (0x01) +#define MODBUS_ERROR_CODE_ADDR (0x02) +#define MODBUS_ERROR_CODE_VALUE (0x03) +#define MODBUS_ERROR_CODE_EXECUTE (0x04) + +#define MODBUS_ADDR_RO_S (0x1234) +#define MODBUS_LENGTH_RO (9) + +struct crc16_result_s { + uint8_t crch; + uint8_t crcl; +}; + +void crc16_8005_calc(uint8_t * p, uint16_t len, struct crc16_result_s *ret); +void modbus_init(void); +uint16_t modbus_data_big2little16(uint8_t *buff); +uint32_t modbus_data_big2little32(uint8_t *buff); +void modbus_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MODBUS_H__ */ diff --git a/ate/src/rs485.c b/ate/src/rs485.c new file mode 100755 index 0000000..881ceaa --- /dev/null +++ b/ate/src/rs485.c @@ -0,0 +1,208 @@ +#include "rs485.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_tim.h" +#include "stm32f4xx_usart.h" +#include "stm32f4xx_dma.h" + +struct rs485_data_s rs485_data; +uint8_t rs485_buff_tx[RS485_BUFF_TX_LEN] __attribute__((aligned(16))); +uint8_t rs485_buff_rx[RS485_BUFF_RX_LEN]; + +void rs485_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + USART_InitTypeDef USART_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + /* init struct data */ + rs485_data.baudrate = RS485_DEFAULT_BAUDRATE; + rs485_data.parity = RS485_DEFAULT_PARITY; + rs485_data.stopbits = RS485_DEFAULT_STOPBITS; + rs485_data.addr = 0x5A; + rs485_data.rx_len = 0; + rs485_data.tx_len = 0; + rs485_data.buff_rx = rs485_buff_rx; + rs485_data.buff_tx = rs485_buff_tx; + rs485_data.frame_cnt = 0; + + /* config modbus direction pin */ + GPIO_InitStructure.GPIO_Pin = RS485_PIN_DIR, + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT, + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP, + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz, + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL, + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + GPIO_Init(RS485_PORT, &GPIO_InitStructure); + rs485_mode_rx(); + + /* config rs485 uart pin */ + GPIO_PinAFConfig(RS485_PORT, GPIO_PinSource9, GPIO_AF_USART1); + GPIO_PinAFConfig(RS485_PORT, GPIO_PinSource10, GPIO_AF_USART1); + GPIO_InitStructure.GPIO_Pin = RS485_PIN_TX | RS485_PIN_RX; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_Init(RS485_PORT, &GPIO_InitStructure); + /* config rs485 uart function */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + USART_DeInit(USART1); + USART_OverSampling8Cmd(USART1, ENABLE); + USART_InitStructure.USART_BaudRate = rs485_data.baudrate; + /* When using Parity the word length must be configured to 9 bits */ + if (rs485_data.parity == RS485_PARITY_ODD) { + USART_InitStructure.USART_WordLength = USART_WordLength_9b; + USART_InitStructure.USART_Parity = USART_Parity_Odd; + } else if (rs485_data.parity == RS485_PARITY_EVEN) { + USART_InitStructure.USART_WordLength = USART_WordLength_9b; + USART_InitStructure.USART_Parity = USART_Parity_Even; + } else { + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_Parity = USART_Parity_No; + } + if (rs485_data.stopbits == 2) { + USART_InitStructure.USART_StopBits = USART_StopBits_2; + } else { + USART_InitStructure.USART_StopBits = USART_StopBits_1; + } + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_Init(USART1, &USART_InitStructure); + USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); + USART_Cmd(USART1, ENABLE); + /* Configure DMA controller to manage USART TX request */ + DMA_InitStructure.DMA_BufferSize = RS485_BUFF_TX_LEN; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(&(USART1->DR)); + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_Channel = DMA_Channel_4; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)rs485_buff_tx; + DMA_Init(DMA2_Stream7, &DMA_InitStructure); + /* Configure interrupt for USART1 RX */ + NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); + USART_ITConfig(USART1, USART_IT_TC, ENABLE); + + /* config TIM4 for modbus recv timeout, 3.5 frame time */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); + if (rs485_data.baudrate >= 19200) { + TIM_TimeBaseStructure.TIM_Period = 1750; + } else { + TIM_TimeBaseStructure.TIM_Period = 1000 * 1000 * 35 / rs485_data.baudrate; + } + TIM_TimeBaseStructure.TIM_Prescaler = 84 - 1; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); + /* Prescaler configuration */ + TIM_PrescalerConfig(TIM4, 84 - 1, TIM_PSCReloadMode_Immediate); + /* TIM4 disable counter, start after reciving every uart data */ + TIM_Cmd(TIM4, DISABLE); + TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); + NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +} + +void rs485_timer_restart(void) +{ + TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); + TIM_SetCounter(TIM4, 0); + TIM_ClearITPendingBit(TIM4, TIM_IT_Update); + TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); + TIM_Cmd(TIM4, ENABLE); +} + +void rs485_timer_stop(void) +{ + TIM_Cmd(TIM4, DISABLE); + TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); + TIM_ClearITPendingBit(TIM4, TIM_IT_Update); +} + +void rs485_mode_tx(void) +{ + GPIO_SetBits(RS485_PORT, RS485_PIN_DIR); +} + +void rs485_mode_rx(void) +{ + GPIO_ResetBits(RS485_PORT, RS485_PIN_DIR); +} + +void rs485_rx_start(void) +{ + /* clear PE, FE, NE, ORE and IDLE flags, reference USART_ClearFlag function */ + USART_GetITStatus(USART1, USART_IT_RXNE); + USART_ReceiveData(USART1); + USART_ClearFlag(USART1, USART_FLAG_RXNE); + /* enable USART receive interrupt */ + USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); +} + +void rs485_rx_stop(void) +{ + USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); + USART_ClearITPendingBit(USART1, USART_IT_RXNE); +} + +void rs485_send_data(uint16_t len) +{ + rs485_mode_tx(); + DMA_SetCurrDataCounter(DMA2_Stream7, len); + USART_ClearITPendingBit(USART1, USART_IT_TC); + DMA_Cmd(DMA2_Stream7, ENABLE); +} + +void USART1_IRQHandler(void) +{ + if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { + rs485_timer_restart(); + if (rs485_data.rx_len < RS485_BUFF_RX_LEN) { + rs485_buff_rx[rs485_data.rx_len++] = USART_ReceiveData(USART1); + } else { + /* exception, has recevered too much data, drop */ + rs485_data.rx_len = 0; + } + } + /* one tx frame complete */ + if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) { + USART_ClearITPendingBit(USART1, USART_IT_TC); + DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7); + rs485_data.rx_len = 0; + rs485_mode_rx(); + rs485_rx_start(); + } +} + +void TIM4_IRQHandler(void) +{ + rs485_timer_stop(); + if (rs485_data.buff_rx[0] == rs485_data.addr && rs485_data.rx_len > 3) { + /* one completed frame, need processing */ + rs485_rx_stop(); + rs485_data.frame_cnt++; + } else { + /* address not match, drop */ + rs485_data.rx_len = 0; + } +} diff --git a/ate/src/rs485.h b/ate/src/rs485.h new file mode 100755 index 0000000..1e044a9 --- /dev/null +++ b/ate/src/rs485.h @@ -0,0 +1,53 @@ +#ifndef __RS485_H__ +#define __RS485_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" + +#define RS485_PORT (GPIOA) +#define RS485_PIN_DIR (GPIO_Pin_8) +#define RS485_PIN_TX (GPIO_Pin_9) +#define RS485_PIN_RX (GPIO_Pin_10) + +#define RS485_PARITY_NONE (0) +#define RS485_PARITY_ODD (1) +#define RS485_PARITY_EVEN (2) + +#define RS485_DEFAULT_BAUDRATE (19200) +#define RS485_DEFAULT_PARITY (RS485_PARITY_NONE) +#define RS485_DEFAULT_STOPBITS (1) + +#define RS485_BUFF_TX_LEN (1024) +#define RS485_BUFF_RX_LEN (1024) + +struct rs485_data_s { + uint32_t baudrate; + uint8_t parity; + uint8_t stopbits; + uint8_t addr; + uint16_t rx_len; + uint16_t tx_len; + uint8_t *buff_rx; + uint8_t *buff_tx; + uint32_t frame_cnt; +}; + +extern struct rs485_data_s rs485_data; + +void rs485_init(void); +void rs485_timer_restart(void); +void rs485_timer_stop(void); +void rs485_mode_tx(void); +void rs485_mode_rx(void); +void rs485_rx_start(void); +void rs485_rx_stop(void); +void rs485_send_data(uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* __RS485_H__ */ diff --git a/ate/src/sd.c b/ate/src/sd.c new file mode 100755 index 0000000..f1be5cd --- /dev/null +++ b/ate/src/sd.c @@ -0,0 +1,76 @@ +#include "ff.h" +#include "sd.h" +#include "sdio_sd.h" +#include "device.h" + +#define RETRY_MAX (3) + +FATFS fs; +TCHAR file_name[FILE_NAME_LEN]; + +uint8_t sd_detect(void) +{ + SD_Error sd_err; + FRESULT ret; + uint32_t retry; + DIR dir; + TCHAR name[FILE_NAME_LEN]; + + retry = RETRY_MAX; + while (retry--) { + sd_err = SD_Init(); + if (sd_err == SD_OK) { + break; + } else if (retry == 0) { + SD_DeInit(); + return SD_STS_ERR_INIT; + } + } + + retry = RETRY_MAX; + while (retry--) { + ret = f_mount(0, &fs); + if (ret == FR_OK) { + break; + } else { + SD_DeInit(); + return SD_STS_ERR_MOUNT; + } + } + + retry = RETRY_MAX; + while (retry--) { + ret = f_getcwd(name, sizeof(name)); + if (ret == FR_OK) { + break; + } else { + SD_DeInit(); + return SD_STS_ERR_GETCWD; + } + } + + retry = RETRY_MAX; + while (retry--) { + ret = f_opendir(&dir, name); + if (ret == FR_OK) { + break; + } else { + SD_DeInit(); + return SD_STS_ERR_OPENDIR; + } + } + + return SD_STS_OK; +} + +void sd_loop(void) +{ + static uint32_t ms = 0; + + if (system_tick_cnt < (ms + 500)) { + return; + } + ms = system_tick_cnt; + + device_data.sd = sd_detect(); +} diff --git a/ate/src/sd.h b/ate/src/sd.h new file mode 100755 index 0000000..88bf99b --- /dev/null +++ b/ate/src/sd.h @@ -0,0 +1,29 @@ +#ifndef __SD_H__ +#define __SD_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stm32f4xx.h" +#include "ff.h" + +#define SD_STS_NULL (0) +#define SD_STS_ERR_INIT (1) +#define SD_STS_ERR_MOUNT (2) +#define SD_STS_ERR_GETCWD (3) +#define SD_STS_ERR_OPENDIR (4) +#define SD_STS_OK (5) + +#define FILE_NAME_LEN (13) + +extern uint32_t system_tick_cnt; + +uint8_t sd_detect(void); +void sd_loop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SD_H__ */ diff --git a/ate/start.S b/ate/start.S new file mode 100755 index 0000000..f5ebad9 --- /dev/null +++ b/ate/start.S @@ -0,0 +1,370 @@ +.syntax unified +.cpu cortex-m4 +.thumb + +.global g_pfnVectors +.global Default_Handler +.global Reset_Handler + +.section .text.Reset_Handler +.weak Reset_Handler +.type Reset_Handler, %function +Reset_Handler: + cpsid i /* disable irq */ + ldr r0, =_stack_top + msr msp, r0 + /* load data section */ + ldr r0, =_data_load + ldr r1, =_data_run + ldr r2, =_data_run_end + cmp r1, r2 + bhs 2f +1: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blo 1b +2: + /* clear bss section */ + ldr r0, =0 + ldr r1, =_bss_run + ldr r2, =_bss_run_end + cmp r1, r2 + bhs 2f +1: + str r0, [r1], #4 + cmp r1, r2 + blo 1b +2: + /* load data_ccm section */ + ldr r0, =_data_ccm_load + ldr r1, =_data_ccm_run + ldr r2, =_data_ccm_run_end + cmp r1, r2 + bhs 2f +1: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r1, r2 + blo 1b +2: + /* clear bss_ccm section */ + ldr r0, =0 + ldr r1, =_bss_ccm_run + ldr r2, =_bss_ccm_run_end + cmp r1, r2 + bhs 2f +1: + str r0, [r1], #4 + cmp r1, r2 + blo 1b +2: + bl SystemInit + bl main + b . +.size Reset_Handler, .-Reset_Handler + +.section .text.Default_Handler,"ax",%progbits +Default_Handler: + MRS r0, msp + STMFD r0!, {r4 - r11} + STMFD r0!, {lr} + MSR msp, r0 + + PUSH {lr} + BL coredump + POP {lr} + + POP {lr} + POP {r4 - r11} + + BX lr +.size Default_Handler, .-Default_Handler + +.section .isr_vector,"a",%progbits +.type g_pfnVectors, %object +.size g_pfnVectors, .-g_pfnVectors +g_pfnVectors: + .word _stack_top + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FSMC_IRQHandler /* FSMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word CRYP_IRQHandler /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + /* External Interrupts */ + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + .weak FSMC_IRQHandler + .thumb_set FSMC_IRQHandler,Default_Handler + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + .weak CRYP_IRQHandler + .thumb_set CRYP_IRQHandler,Default_Handler + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler