From b49c9ab0c6a57712a24ce400362a876f42a66368 Mon Sep 17 00:00:00 2001 From: hm-thinkbook14p Date: Mon, 11 May 2026 19:55:43 +0800 Subject: [PATCH] =?UTF-8?q?Initial=20commit:=20PY32MD530H28U7TR=E6=AD=A5?= =?UTF-8?q?=E8=BF=9B=E7=94=B5=E6=9C=BA=E6=8E=A7=E5=88=B6=E5=99=A8=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完整实现了以下模块: - 系统数据总线(sys_data_bus)模块间通信 - UART/USART/LPUART驱动 + RS485半双工 - I2C驱动(AS5600角度传感器 + AT24C02 EEPROM) - Modbus RTU从站协议 - 步进电机微步进控制(正弦/余弦换相+S曲线加减速) - 到位开关驱动(DI_MIN/DI_MAX) - PGA+ADC电流检测 - 系统监控任务(内存/串口/传感器/任务状态) - LED/Key外设驱动 - 基于CMake + arm-none-eabi-gcc构建系统 --- .gitignore | 30 ++ CMakeLists.txt | 62 +++ app/main.c | 209 ++++++++ app/main.h | 6 + app/stepper/stepper_control.c | 562 +++++++++++++++++++++ app/stepper/stepper_control.h | 43 ++ app/tasks/monitor_task.c | 228 +++++++++ app/tasks/monitor_task.h | 11 + app/tasks/work_task.c | 31 ++ app/tasks/work_task.h | 11 + bsp/common_types.h | 32 ++ bsp/device/as5600/as5600_driver.c | 72 +++ bsp/device/as5600/as5600_driver.h | 19 + bsp/device/eeprom/eeprom_driver.c | 64 +++ bsp/device/eeprom/eeprom_driver.h | 18 + bsp/device/key/key_driver.c | 51 ++ bsp/device/key/key_driver.h | 16 + bsp/device/led/led_driver.c | 41 ++ bsp/device/led/led_driver.h | 17 + bsp/device/limit_switch/limit_switch.c | 209 ++++++++ bsp/device/limit_switch/limit_switch.h | 28 ++ bsp/hardware_init.c | 49 ++ bsp/hardware_init.h | 9 + bsp/modbus/modbus_slave.c | 280 +++++++++++ bsp/modbus/modbus_slave.h | 40 ++ cmake/arm-none-eabi-toolchain.cmake | 14 + config/config.h | 45 ++ drv/adc/adc_driver.c | 54 +++ drv/adc/adc_driver.h | 23 + drv/adc/pga_driver.c | 77 +++ drv/adc/pga_driver.h | 33 ++ drv/gpio/gpio_driver.c | 63 +++ drv/gpio/gpio_driver.h | 41 ++ drv/i2c/i2c_driver.c | 155 ++++++ drv/i2c/i2c_driver.h | 20 + drv/log/log_driver.c | 43 ++ drv/log/log_driver.h | 15 + drv/system/sys_data_bus.c | 54 +++ drv/system/sys_data_bus.h | 40 ++ drv/system/system_driver.c | 44 ++ drv/system/system_driver.h | 12 + drv/timer/timer_driver.c | 163 +++++++ drv/timer/timer_driver.h | 27 ++ drv/uart/uart_driver.c | 337 +++++++++++++ drv/uart/uart_driver.h | 38 ++ libs/CMSIS/cmsis_compiler.h | 52 ++ libs/CMSIS/cmsis_gcc.h | 161 +++++++ libs/CMSIS/cmsis_version.h | 11 + libs/CMSIS/core_cm0plus.h | 240 +++++++++ libs/device/py32md530.h | 644 +++++++++++++++++++++++++ libs/device/py32md530.ld | 77 +++ libs/device/startup_py32md530.s | 261 ++++++++++ libs/device/system_py32md530.c | 68 +++ libs/device/system_py32md530.h | 19 + tools/flash.sh | 42 ++ 55 files changed, 5011 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 app/main.c create mode 100644 app/main.h create mode 100644 app/stepper/stepper_control.c create mode 100644 app/stepper/stepper_control.h create mode 100644 app/tasks/monitor_task.c create mode 100644 app/tasks/monitor_task.h create mode 100644 app/tasks/work_task.c create mode 100644 app/tasks/work_task.h create mode 100644 bsp/common_types.h create mode 100644 bsp/device/as5600/as5600_driver.c create mode 100644 bsp/device/as5600/as5600_driver.h create mode 100644 bsp/device/eeprom/eeprom_driver.c create mode 100644 bsp/device/eeprom/eeprom_driver.h create mode 100644 bsp/device/key/key_driver.c create mode 100644 bsp/device/key/key_driver.h create mode 100644 bsp/device/led/led_driver.c create mode 100644 bsp/device/led/led_driver.h create mode 100644 bsp/device/limit_switch/limit_switch.c create mode 100644 bsp/device/limit_switch/limit_switch.h create mode 100644 bsp/hardware_init.c create mode 100644 bsp/hardware_init.h create mode 100644 bsp/modbus/modbus_slave.c create mode 100644 bsp/modbus/modbus_slave.h create mode 100644 cmake/arm-none-eabi-toolchain.cmake create mode 100644 config/config.h create mode 100644 drv/adc/adc_driver.c create mode 100644 drv/adc/adc_driver.h create mode 100644 drv/adc/pga_driver.c create mode 100644 drv/adc/pga_driver.h create mode 100644 drv/gpio/gpio_driver.c create mode 100644 drv/gpio/gpio_driver.h create mode 100644 drv/i2c/i2c_driver.c create mode 100644 drv/i2c/i2c_driver.h create mode 100644 drv/log/log_driver.c create mode 100644 drv/log/log_driver.h create mode 100644 drv/system/sys_data_bus.c create mode 100644 drv/system/sys_data_bus.h create mode 100644 drv/system/system_driver.c create mode 100644 drv/system/system_driver.h create mode 100644 drv/timer/timer_driver.c create mode 100644 drv/timer/timer_driver.h create mode 100644 drv/uart/uart_driver.c create mode 100644 drv/uart/uart_driver.h create mode 100644 libs/CMSIS/cmsis_compiler.h create mode 100644 libs/CMSIS/cmsis_gcc.h create mode 100644 libs/CMSIS/cmsis_version.h create mode 100644 libs/CMSIS/core_cm0plus.h create mode 100644 libs/device/py32md530.h create mode 100644 libs/device/py32md530.ld create mode 100644 libs/device/startup_py32md530.s create mode 100644 libs/device/system_py32md530.c create mode 100644 libs/device/system_py32md530.h create mode 100644 tools/flash.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd872f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Build output +build/ +*.o +*.d +*.elf +*.hex +*.bin +*.map + +# IDE files +.idea/ +.vscode/ +.trae/ +*.swp +*.swo +*~ + +# OS files +Thumbs.db +.DS_Store + +# Toolchain files +tools/gcc/ +tools/stlink/ +tools/openocd/ +tools/jlink/ +tools/cmake/ +tools/python/ +tools/makefile/ +tools/ninja/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..febf80d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.10) + +project(StepMotorCtrl C ASM) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_ASM_COMPILER_OPTIONS "") + +SET(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/libs/device/py32md530.ld) + +set(CMAKE_C_FLAGS "-mcpu=cortex-m0plus -mthumb -Wall -Wextra -Wpedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -O0 -g -MMD -MP" CACHE STRING "" FORCE) +set(CMAKE_ASM_FLAGS "-mcpu=cortex-m0plus -mthumb -x assembler-with-cpp" CACHE STRING "" FORCE) + +set(CMAKE_EXE_LINKER_FLAGS "-mcpu=cortex-m0plus -mthumb -T${LINKER_SCRIPT} -Wl,--gc-sections -Wl,--print-memory-usage -u _printf_float -specs=nano.specs -specs=nosys.specs" CACHE STRING "" FORCE) + +include_directories( + ${CMAKE_SOURCE_DIR}/libs + ${CMAKE_SOURCE_DIR}/libs/CMSIS + ${CMAKE_SOURCE_DIR}/libs/device + ${CMAKE_SOURCE_DIR}/config + ${CMAKE_SOURCE_DIR}/bsp + ${CMAKE_SOURCE_DIR}/bsp/device/led + ${CMAKE_SOURCE_DIR}/bsp/device/key + ${CMAKE_SOURCE_DIR}/bsp/device/eeprom + ${CMAKE_SOURCE_DIR}/bsp/device/limit_switch + ${CMAKE_SOURCE_DIR}/bsp/device/as5600 + ${CMAKE_SOURCE_DIR}/bsp/modbus + ${CMAKE_SOURCE_DIR}/drv/system + ${CMAKE_SOURCE_DIR}/drv/timer + ${CMAKE_SOURCE_DIR}/drv/uart + ${CMAKE_SOURCE_DIR}/drv/i2c + ${CMAKE_SOURCE_DIR}/drv/adc + ${CMAKE_SOURCE_DIR}/drv/gpio + ${CMAKE_SOURCE_DIR}/drv/log + ${CMAKE_SOURCE_DIR}/app + ${CMAKE_SOURCE_DIR}/app/tasks + ${CMAKE_SOURCE_DIR}/app/stepper +) + +file(GLOB_RECURSE SOURCES + ${CMAKE_SOURCE_DIR}/app/*.c + ${CMAKE_SOURCE_DIR}/bsp/*.c + ${CMAKE_SOURCE_DIR}/bsp/device/*/*.c + ${CMAKE_SOURCE_DIR}/bsp/modbus/*.c + ${CMAKE_SOURCE_DIR}/drv/*/*.c + ${CMAKE_SOURCE_DIR}/libs/device/*.c + ${CMAKE_SOURCE_DIR}/libs/device/*.s +) + +add_executable(${PROJECT_NAME} ${SOURCES}) +set(ELF_FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.elf) +set(HEX_FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.hex) +set(BIN_FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.bin) +add_custom_command(OUTPUT ${HEX_FILE} ${BIN_FILE} + COMMAND ${CMAKE_OBJCOPY} -O ihex ${ELF_FILE} ${HEX_FILE} + COMMAND ${CMAKE_OBJCOPY} -O binary ${ELF_FILE} ${BIN_FILE} + DEPENDS ${PROJECT_NAME} + COMMENT "Generating hex and bin files..." +) +add_custom_target(hex ALL DEPENDS ${HEX_FILE} ${BIN_FILE}) diff --git a/app/main.c b/app/main.c new file mode 100644 index 0000000..f423f4f --- /dev/null +++ b/app/main.c @@ -0,0 +1,209 @@ +#include "main.h" +#include "config.h" +#include "common_types.h" +#include "hardware_init.h" +#include "system_driver.h" +#include "gpio_driver.h" +#include "led_driver.h" +#include "key_driver.h" +#include "eeprom_driver.h" +#include "uart_driver.h" +#include "adc_driver.h" +#include "timer_driver.h" +#include "log_driver.h" +#include "sys_data_bus.h" +#if LIMIT_SWITCH_ENABLED +#include "limit_switch.h" +#endif +#if PGA_ENABLED +#include "pga_driver.h" +#endif +#include "as5600_driver.h" +#include "modbus_slave.h" +#include "stepper_control.h" +#include "tasks/work_task.h" +#include "tasks/monitor_task.h" +#include + +static void gpio_pin_init(void) +{ + gpio_config_t cfg; + + cfg.speed = GPIO_SPEED_HIGH; + cfg.pupd = GPIO_PUPD_NONE; + + cfg.mode = GPIO_MODE_AF; + cfg.af_num = 1; + + cfg.port = GPIOA; + cfg.pin = 9; + gpio_init(&cfg); + cfg.port = GPIOA; + cfg.pin = 10; + gpio_init(&cfg); + + cfg.port = GPIOA; + cfg.pin = 0; + gpio_init(&cfg); + cfg.port = GPIOA; + cfg.pin = 1; + gpio_init(&cfg); + + cfg.port = GPIOA; + cfg.pin = 4; + gpio_init(&cfg); + cfg.port = GPIOA; + cfg.pin = 2; + gpio_init(&cfg); + + cfg.port = GPIOA; + cfg.pin = 12; + gpio_init(&cfg); + cfg.port = GPIOA; + cfg.pin = 11; + gpio_init(&cfg); + + cfg.af_num = 2; + cfg.port = GPIOA; + cfg.pin = 7; + gpio_init(&cfg); + cfg.port = GPIOB; + cfg.pin = 0; + gpio_init(&cfg); + cfg.port = GPIOB; + cfg.pin = 1; + gpio_init(&cfg); + cfg.port = GPIOF; + cfg.pin = 3; + gpio_init(&cfg); + cfg.port = GPIOF; + cfg.pin = 1; + gpio_init(&cfg); + cfg.port = GPIOF; + cfg.pin = 0; + gpio_init(&cfg); + + cfg.mode = GPIO_MODE_OUTPUT; + cfg.speed = GPIO_SPEED_LOW; + cfg.af_num = 0; + cfg.port = GPIOA; + cfg.pin = 3; + gpio_init(&cfg); + + cfg.mode = GPIO_MODE_INPUT; + cfg.pupd = GPIO_PUPD_PULLUP; + + cfg.port = GPIOB; + cfg.pin = 5; + gpio_init(&cfg); + cfg.port = GPIOB; + cfg.pin = 6; + gpio_init(&cfg); + cfg.port = GPIOB; + cfg.pin = 7; + gpio_init(&cfg); + cfg.port = GPIOB; + cfg.pin = 8; + gpio_init(&cfg); + + cfg.mode = GPIO_MODE_ANALOG; + cfg.pupd = GPIO_PUPD_NONE; + + cfg.port = GPIOA; + cfg.pin = 15; + gpio_init(&cfg); + cfg.port = GPIOB; + cfg.pin = 3; + gpio_init(&cfg); +} + +static void uart_config_all(void) +{ + uart_config_t cfg; + + cfg.baudrate = 115200; + cfg.data_bits = 8; + cfg.stop_bits = 1; + cfg.parity = 0; + + uart_init(UART_ID_USART1, &cfg); + uart_init(UART_ID_UART1, &cfg); + + { + uart_config_t lpuart_cfg; + + lpuart_cfg.baudrate = 9600; + lpuart_cfg.data_bits = 8; + lpuart_cfg.stop_bits = 1; + lpuart_cfg.parity = 0; + + uart_init(UART_ID_LPUART1, &lpuart_cfg); + } +} + +static void limit_switch_setup(void) +{ +#if LIMIT_SWITCH_ENABLED + limit_switch_init(); + limit_switch_register_callback(LIMIT_SW_MAX, NULL); + limit_switch_register_callback(LIMIT_SW_MIN, NULL); +#endif +} + +static void pga_setup(void) +{ +#if PGA_ENABLED + pga_config_t pga_cfg; + + pga_cfg.gain = PGA_GAIN_8; + pga_cfg.shunt_resistor = PGA_SHUNT_RESISTOR; + pga_cfg.vref = PGA_VREF; + + pga_init(&pga_cfg); +#endif +} + +int main(void) +{ + hardware_init(); + + gpio_pin_init(); + + system_driver_init(); + + sys_data_bus_init(); + + log_init(); + + led_init(); + key_init(); + eeprom_init(); + + uart_config_all(); + + adc_init(); + pga_setup(); + + limit_switch_setup(); + + as5600_init(); + + modbus_slave_init(MODBUS_SLAVE_ADDR); + + stepper_init(); + + work_task_init(); + monitor_task_init(); + + uart_set_rs485_dir(UART_ID_USART1, 0); + + log_out("INFO: System initialized\n"); + + while (1) { + work_task_run(); + monitor_task_run(); + + modbus_slave_poll(); + stepper_run(); + } +} diff --git a/app/main.h b/app/main.h new file mode 100644 index 0000000..685e6ec --- /dev/null +++ b/app/main.h @@ -0,0 +1,6 @@ +#ifndef MAIN_H__ +#define MAIN_H__ + +void main_loop(void); + +#endif diff --git a/app/stepper/stepper_control.c b/app/stepper/stepper_control.c new file mode 100644 index 0000000..86ca58e --- /dev/null +++ b/app/stepper/stepper_control.c @@ -0,0 +1,562 @@ +#include "stepper_control.h" +#include "timer_driver.h" +#include "sys_data_bus.h" +#include "limit_switch.h" +#include "system_driver.h" +#include "config.h" +#include + +#define STEPPER_UPDATE_INTERVAL 10 +#define STEPPER_CALIB_SPEED 80 +#define STEPPER_TOTAL_STEPS_DEFAULT 2000 +#define STEPPER_CALIB_TIMEOUT_MS 10000 + +#define ANGLE_TABLE_SIZE 64 +#define ANGLE_RESOLUTION 1024 +#define ANGLE_PER_STEP (ANGLE_RESOLUTION / 4) + +static const uint16_t sine_table[ANGLE_TABLE_SIZE] = { + 1800, 1976, 2151, 2323, 2489, 2649, 2800, 2942, + 3073, 3191, 3297, 3387, 3463, 3522, 3565, 3591, + 3600, 3591, 3565, 3522, 3463, 3387, 3297, 3191, + 3073, 2942, 2800, 2649, 2489, 2323, 2151, 1976, + 1800, 1624, 1449, 1277, 1111, 951, 800, 658, + 527, 409, 303, 213, 137, 78, 35, 9, + 0, 9, 35, 78, 137, 213, 303, 409, + 527, 658, 800, 951, 1111, 1277, 1449, 1624, +}; + +static volatile int32_t current_position; +static int32_t target_position; +static int32_t start_position; +static float current_speed; +static float accel_distance; +static float decel_distance; +static float total_distance; +static uint8_t running; +static uint8_t calibrated; +static uint8_t di_max_installed; +static int32_t calibrated_steps; +static int32_t origin_steps; +static int32_t max_steps; +static stepper_state_t state; +static uint32_t last_update_tick; +static uint32_t calib_start_tick; +static uint8_t calib_found_min; +static uint8_t calib_found_max; +static int32_t calib_min_position; +static int32_t calib_max_position; +static uint16_t last_hold_duty_a; +static uint16_t last_hold_duty_b; + +static float s_curve_factor(float progress) +{ + if (progress <= 0.0f) return 0.0f; + if (progress >= 1.0f) return 1.0f; + return progress * progress * (3.0f - 2.0f * progress); +} + +static uint16_t stepper_lookup_sine(uint16_t index, uint8_t frac) +{ + uint16_t s0 = sine_table[index]; + uint16_t s1 = sine_table[(index + 1) & (ANGLE_TABLE_SIZE - 1)]; + return s0 + (((s1 - s0) * frac) >> 4); +} + +static void stepper_update_phases(void) +{ + uint16_t angle = (uint16_t)((current_position * ANGLE_PER_STEP) & (ANGLE_RESOLUTION - 1)); + uint8_t idx_a = angle >> 4; + uint8_t frac = (uint8_t)(angle & 0x0F); + uint8_t idx_b = (idx_a + 16) & (ANGLE_TABLE_SIZE - 1); + + uint16_t duty_a = stepper_lookup_sine(idx_a, frac); + uint16_t duty_b = stepper_lookup_sine(idx_b, frac); + + timer_pwm_set_duty(TIMER_CHANNEL_1, duty_a); + timer_pwm_set_duty(TIMER_CHANNEL_2, duty_b); + + last_hold_duty_a = duty_a; + last_hold_duty_b = duty_b; +} + +static void stepper_set_hold(void) +{ + uint16_t hold_a = (uint16_t)(((uint32_t)last_hold_duty_a * STEPPER_HOLD_CURRENT) / 100); + uint16_t hold_b = (uint16_t)(((uint32_t)last_hold_duty_b * STEPPER_HOLD_CURRENT) / 100); + timer_pwm_set_duty(TIMER_CHANNEL_1, hold_a); + timer_pwm_set_duty(TIMER_CHANNEL_2, hold_b); +} + +static void stepper_phases_off(void) +{ + timer_pwm_set_duty(TIMER_CHANNEL_1, STEPPER_PWM_CENTER); + timer_pwm_set_duty(TIMER_CHANNEL_2, STEPPER_PWM_CENTER); +} + +static void set_speed_to_data_bus(float speed) +{ + sys_data_bus_value_t val; + val.f = speed; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_SPEED, val); +} + +static void set_position_to_data_bus(int32_t pos) +{ + sys_data_bus_value_t val; + val.i = pos; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_POSITION, val); +} + +static void set_state_to_data_bus(stepper_state_t s) +{ + sys_data_bus_value_t val; + val.u = (uint32_t)s; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_STATE, val); +} + +static void stepper_apply_limit(void) +{ + if (limit_switch_get_state(LIMIT_SW_MIN) == LIMIT_SW_STATE_TRIGGERED) { + if (current_position < origin_steps) { + current_position = origin_steps; + set_position_to_data_bus(current_position); + } + } + + if (limit_switch_get_state(LIMIT_SW_MAX) == LIMIT_SW_STATE_TRIGGERED) { + if (current_position > max_steps) { + current_position = max_steps; + set_position_to_data_bus(current_position); + } + } +} + +ret_code_t stepper_init(void) +{ + current_position = 0; + target_position = 0; + start_position = 0; + current_speed = 0.0f; + running = 0; + calibrated = 0; + state = STEPPER_STATE_IDLE; + last_update_tick = system_get_tick(); + last_hold_duty_a = STEPPER_PWM_CENTER; + last_hold_duty_b = STEPPER_PWM_CENTER; + + { + sys_data_bus_value_t val; + + val.u = 0; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_CURRENT, val); + + val.i = 0; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_POSITION, val); + sys_data_bus_write(SYS_DATA_BUS_MOTOR_TARGET, val); + + val.f = 0.0f; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_SPEED, val); + + val.u = STEPPER_STATE_IDLE; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_STATE, val); + + val.i = STEPPER_TOTAL_STEPS_DEFAULT; + sys_data_bus_write(SYS_DATA_BUS_MAX_STEPS, val); + + val.i = 0; + sys_data_bus_write(SYS_DATA_BUS_ORIGIN_STEPS, val); + sys_data_bus_write(SYS_DATA_BUS_CALIBRATED_STEPS, val); + + val.u = 0; + sys_data_bus_write(SYS_DATA_BUS_IS_CALIBRATED, val); + sys_data_bus_write(SYS_DATA_BUS_IS_DI_MAX_INSTALLED, val); + } + + origin_steps = 0; + max_steps = STEPPER_TOTAL_STEPS_DEFAULT; + calibrated_steps = STEPPER_TOTAL_STEPS_DEFAULT; + di_max_installed = 1; + + timer_stepper_pwm_init(20000, STEPPER_PWM_RESOLUTION); + + return RET_OK; +} + +ret_code_t stepper_deinit(void) +{ + running = 0; + state = STEPPER_STATE_IDLE; + stepper_phases_off(); + timer_pwm_stop(); + return RET_OK; +} + +ret_code_t stepper_move_to(int32_t target) +{ + sys_data_bus_value_t val; + + if (state == STEPPER_STATE_CALIBRATING) { + return RET_BUSY; + } + + if (target < origin_steps) { + target = origin_steps; + } + if (target > max_steps) { + target = max_steps; + } + + target_position = target; + + val.i = target; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_TARGET, val); + + start_position = current_position; + total_distance = (float)(target_position - current_position); + + if (total_distance == 0.0f) { + stepper_set_hold(); + return RET_OK; + } + + current_speed = (float)STEPPER_SPEED_START; + running = 1; + state = STEPPER_STATE_ACCEL; + + set_state_to_data_bus(state); + + { + float total_abs = total_distance; + if (total_abs < 0.0f) total_abs = -total_abs; + + accel_distance = (float)STEPPER_ACCEL_STEPS; + decel_distance = (float)STEPPER_DECEL_STEPS; + + if (accel_distance + decel_distance > total_abs) { + float ratio = total_abs / (accel_distance + decel_distance); + accel_distance *= ratio; + decel_distance *= ratio; + } + } + + stepper_update_phases(); + + return RET_OK; +} + +ret_code_t stepper_move_rel(int32_t steps) +{ + return stepper_move_to(current_position + steps); +} + +ret_code_t stepper_stop(void) +{ + if (running) { + state = STEPPER_STATE_DECEL; + set_state_to_data_bus(state); + } + return RET_OK; +} + +ret_code_t stepper_emergency_stop(void) +{ + running = 0; + current_speed = 0.0f; + state = STEPPER_STATE_STOPPED; + stepper_set_hold(); + set_speed_to_data_bus(0.0f); + set_state_to_data_bus(state); + return RET_OK; +} + +ret_code_t stepper_calibrate(void) +{ + if (state == STEPPER_STATE_CALIBRATING) { + return RET_BUSY; + } + + calib_found_min = 0; + calib_found_max = 0; + calib_min_position = 0; + calib_max_position = 0; + calib_start_tick = system_get_tick(); + + current_position = 0; + state = STEPPER_STATE_CALIBRATING; + running = 1; + + stepper_update_phases(); + + { + sys_data_bus_value_t val; + val.u = 0; + sys_data_bus_write(SYS_DATA_BUS_IS_CALIBRATED, val); + } + + return RET_OK; +} + +static void stepper_run_calibrate(void) +{ + uint32_t now = system_get_tick(); + + if ((now - calib_start_tick) > STEPPER_CALIB_TIMEOUT_MS) { + state = STEPPER_STATE_STOPPED; + running = 0; + stepper_set_hold(); + return; + } + + if (!calib_found_min) { + if (limit_switch_get_state(LIMIT_SW_MIN) == LIMIT_SW_STATE_TRIGGERED) { + calib_found_min = 1; + calib_min_position = current_position; + origin_steps = current_position; + current_position = 0; + + { + sys_data_bus_value_t val; + val.i = current_position; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_POSITION, val); + sys_data_bus_write(SYS_DATA_BUS_ORIGIN_STEPS, val); + } + } else { + current_position -= 1; + set_position_to_data_bus(current_position); + stepper_update_phases(); + system_delay_ms(5); + } + return; + } + + if (!calib_found_max) { + { + sys_data_bus_value_t di_max_val; + di_max_val = sys_data_bus_read(SYS_DATA_BUS_DI_MAX_STATE); + if (di_max_val.u != 0) { + di_max_installed = 1; + } + } + + if (di_max_installed && limit_switch_get_state(LIMIT_SW_MAX) == LIMIT_SW_STATE_TRIGGERED) { + calib_found_max = 1; + calib_max_position = current_position; + max_steps = current_position; + calibrated_steps = max_steps - origin_steps; + + { + sys_data_bus_value_t val; + val.i = max_steps; + sys_data_bus_write(SYS_DATA_BUS_MAX_STEPS, val); + } + } else if (!di_max_installed) { + if (current_position >= calibrated_steps) { + calib_found_max = 1; + max_steps = calibrated_steps; + + { + sys_data_bus_value_t val; + val.i = max_steps; + sys_data_bus_write(SYS_DATA_BUS_MAX_STEPS, val); + } + } + } + + if (!calib_found_max) { + current_position += 1; + set_position_to_data_bus(current_position); + stepper_update_phases(); + system_delay_ms(5); + } + return; + } + + { + sys_data_bus_value_t val; + calibrated = 1; + val.u = 1; + sys_data_bus_write(SYS_DATA_BUS_IS_CALIBRATED, val); + + val.i = calibrated_steps; + sys_data_bus_write(SYS_DATA_BUS_CALIBRATED_STEPS, val); + + val.u = di_max_installed ? 1 : 0; + sys_data_bus_write(SYS_DATA_BUS_IS_DI_MAX_INSTALLED, val); + } + + stepper_phases_off(); + running = 0; + state = STEPPER_STATE_IDLE; + set_state_to_data_bus(state); +} + +static void stepper_run_move(void) +{ + uint32_t now; + uint32_t dt_ms; + float dt; + float abs_remaining; + float abs_traveled; + float speed_range; + + now = system_get_tick(); + dt_ms = now - last_update_tick; + + if (dt_ms < STEPPER_UPDATE_INTERVAL) { + return; + } + + if (dt_ms > 50) { + dt_ms = STEPPER_UPDATE_INTERVAL; + } + + last_update_tick = now; + dt = (float)dt_ms / 1000.0f; + + abs_traveled = (float)(current_position - start_position); + if (abs_traveled < 0.0f) abs_traveled = -abs_traveled; + + abs_remaining = total_distance - (float)(current_position - start_position); + if (abs_remaining < 0.0f) abs_remaining = 0.0f; + + stepper_apply_limit(); + + if (limit_switch_get_state(LIMIT_SW_MIN) == LIMIT_SW_STATE_TRIGGERED || + limit_switch_get_state(LIMIT_SW_MAX) == LIMIT_SW_STATE_TRIGGERED) { + if (state != STEPPER_STATE_DECEL) { + state = STEPPER_STATE_DECEL; + set_state_to_data_bus(state); + } + } + + speed_range = (float)(STEPPER_SPEED_MAX - STEPPER_SPEED_START); + + switch (state) { + case STEPPER_STATE_ACCEL: { + float accel_end = accel_distance; + + if (abs_traveled >= accel_end) { + state = STEPPER_STATE_CONSTANT; + current_speed = (float)STEPPER_SPEED_MAX; + set_state_to_data_bus(state); + } else { + float progress = abs_traveled / accel_end; + float sf = s_curve_factor(progress); + current_speed = (float)STEPPER_SPEED_START + speed_range * sf; + } + break; + } + + case STEPPER_STATE_CONSTANT: { + float decel_start = total_distance - decel_distance; + + if (total_distance > 0.0f && abs_traveled >= decel_start) { + state = STEPPER_STATE_DECEL; + set_state_to_data_bus(state); + } else if (total_distance < 0.0f && abs_traveled >= -decel_start) { + state = STEPPER_STATE_DECEL; + set_state_to_data_bus(state); + } else { + current_speed = (float)STEPPER_SPEED_MAX; + } + break; + } + + case STEPPER_STATE_DECEL: { + float decel_remaining; + + if (total_distance > 0.0f) { + decel_remaining = total_distance - abs_traveled; + } else { + decel_remaining = -total_distance - abs_traveled; + } + + if (decel_remaining <= 0.5f) { + current_position = target_position; + current_speed = 0.0f; + state = STEPPER_STATE_STOPPED; + running = 0; + set_position_to_data_bus(current_position); + set_speed_to_data_bus(0.0f); + stepper_update_phases(); + stepper_set_hold(); + set_state_to_data_bus(state); + return; + } + + { + float decel_prog = 1.0f - (decel_remaining / decel_distance); + if (decel_prog < 0.0f) decel_prog = 0.0f; + if (decel_prog > 1.0f) decel_prog = 1.0f; + + float sf = s_curve_factor(decel_prog); + current_speed = (float)STEPPER_SPEED_MAX - speed_range * sf; + if (current_speed < (float)STEPPER_SPEED_START) { + current_speed = (float)STEPPER_SPEED_START; + } + } + break; + } + + default: + return; + } + + { + float speed_step = current_speed * dt; + + if (total_distance > 0.0f) { + current_position += (int32_t)speed_step; + if (current_position > target_position) { + current_position = target_position; + } + } else { + current_position -= (int32_t)speed_step; + if (current_position < target_position) { + current_position = target_position; + } + } + + if (current_position > max_steps) { + current_position = max_steps; + } + if (current_position < origin_steps) { + current_position = origin_steps; + } + } + + stepper_update_phases(); + + set_position_to_data_bus(current_position); + set_speed_to_data_bus(current_speed); +} + +void stepper_run(void) +{ + if (!running) { + return; + } + + if (state == STEPPER_STATE_CALIBRATING) { + stepper_run_calibrate(); + return; + } + + stepper_run_move(); +} + +int32_t stepper_get_position(void) +{ + return current_position; +} + +int32_t stepper_get_target(void) +{ + return target_position; +} + +stepper_state_t stepper_get_state(void) +{ + return state; +} diff --git a/app/stepper/stepper_control.h b/app/stepper/stepper_control.h new file mode 100644 index 0000000..a09b5f8 --- /dev/null +++ b/app/stepper/stepper_control.h @@ -0,0 +1,43 @@ +#ifndef STEPPER_CONTROL_H__ +#define STEPPER_CONTROL_H__ + +#include "common_types.h" +#include + +#define STEPPER_SPEED_START 50 +#define STEPPER_SPEED_MAX 500 +#define STEPPER_ACCEL_STEPS 200 +#define STEPPER_DECEL_STEPS 200 + +#define STEPPER_PWM_RESOLUTION 3600 +#define STEPPER_PWM_CENTER 1800 +#define STEPPER_HOLD_CURRENT 50 + +typedef enum { + STEPPER_STATE_IDLE = 0, + STEPPER_STATE_ACCEL, + STEPPER_STATE_CONSTANT, + STEPPER_STATE_DECEL, + STEPPER_STATE_STOPPED, + STEPPER_STATE_CALIBRATING, +} stepper_state_t; + +typedef enum { + STEPPER_DIR_POSITIVE = 0, + STEPPER_DIR_NEGATIVE = 1, +} stepper_dir_t; + +ret_code_t stepper_init(void); +ret_code_t stepper_deinit(void); +ret_code_t stepper_move_to(int32_t target); +ret_code_t stepper_move_rel(int32_t steps); +ret_code_t stepper_stop(void); +ret_code_t stepper_emergency_stop(void); +ret_code_t stepper_calibrate(void); +void stepper_run(void); + +int32_t stepper_get_position(void); +int32_t stepper_get_target(void); +stepper_state_t stepper_get_state(void); + +#endif diff --git a/app/tasks/monitor_task.c b/app/tasks/monitor_task.c new file mode 100644 index 0000000..bf870c6 --- /dev/null +++ b/app/tasks/monitor_task.c @@ -0,0 +1,228 @@ +#include "monitor_task.h" +#include "system_driver.h" +#include "uart_driver.h" +#include "log_driver.h" +#include "sys_data_bus.h" +#include "as5600_driver.h" +#include "limit_switch.h" +#include "eeprom_driver.h" +#include "stepper_control.h" +#include "work_task.h" +#include "config.h" +#include + +#define MONITOR_INTERVAL_MS 5000 + +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern uint32_t _estack; + +static uint32_t last_run_tick; +static uint32_t run_count; +static uint32_t last_report_tick; + +static const char* ret_code_str(ret_code_t code) +{ + switch (code) { + case RET_OK: return "OK"; + case RET_ERROR: return "ERROR"; + case RET_BUSY: return "BUSY"; + case RET_TIMEOUT: return "TIMEOUT"; + case RET_INVALID_PARAM: return "INV_PARAM"; + case RET_NOMEM: return "NOMEM"; + case RET_NOT_SUPPORTED: return "UNSUPPORTED"; + default: return "UNKNOWN"; + } +} + +static const char* stepper_state_str(int32_t state_val) +{ + switch (state_val) { + case 0: return "IDLE"; + case 1: return "ACCEL"; + case 2: return "CONST"; + case 3: return "DECEL"; + case 4: return "STOPPED"; + case 5: return "CALIB"; + default: return "?"; + } +} + +static const char* limit_switch_state_str(void) +{ + uint8_t di_min, di_max; + sys_data_bus_value_t val; + + val = sys_data_bus_read(SYS_DATA_BUS_DI_MIN_STATE); + di_min = (uint8_t)val.u; + val = sys_data_bus_read(SYS_DATA_BUS_DI_MAX_STATE); + di_max = (uint8_t)val.u; + + if (di_min && di_max) return "MIN+MAX"; + if (di_min) return "MIN"; + if (di_max) return "MAX"; + return "NONE"; +} + +static void report_memory(void) +{ + uint32_t flash_used; + uint32_t ram_used; + uint32_t ram_free; + uint32_t data_size; + uint32_t bss_size; + uint32_t stack_used; + + data_size = (uint32_t)&_edata - (uint32_t)&_sdata; + bss_size = (uint32_t)&_ebss - (uint32_t)&_sbss; + flash_used = (uint32_t)&_sidata + data_size - 0x08000000; + ram_used = (uint32_t)&_ebss - 0x20000000; + ram_free = 0x20002000 - (uint32_t)&_ebss; + + { + uint32_t sp_val; + __asm volatile ("mrs %0, msp" : "=r" (sp_val)); + if (sp_val > (uint32_t)&_ebss) { + stack_used = _estack - sp_val; + } else { + stack_used = _estack - (uint32_t)&_ebss; + } + } + + log_out("--- Memory ---\n"); + log_out(" Flash: %lu B / 64 KB (%lu%%)\n", flash_used, flash_used * 100 / 65536); + log_out(" RAM: %lu B / 8 KB (%lu%%)\n", ram_used, ram_used * 100 / 8192); + log_out(" RAM Free: %lu B | Stack: ~%lu B\n", ram_free, stack_used); + log_out(" .data: %lu B | .bss: %lu B\n", data_size, bss_size); +} + +static void report_uart(void) +{ + uint32_t i; + const char* names[UART_ID_COUNT] = { "USART1(RS485)", "UART1(DEBUG)", "LPUART1" }; + + log_out("--- UART ---\n"); + for (i = 0; i < UART_ID_COUNT; i++) { + const uart_stats_t *stats = uart_get_stats((uart_id_t)i); + if (stats) { + log_out(" %s: TX=%lu RX=%lu OVF=%lu\n", + names[i], stats->tx_bytes, stats->rx_bytes, stats->overflow_errors); + } + } +} + +static void report_sensors(void) +{ + sys_data_bus_value_t val; + float angle; + uint16_t raw; + float current; + uint8_t eeprom_ok; + ret_code_t eeprom_err; + + log_out("--- Sensors ---\n"); + + val = sys_data_bus_read(SYS_DATA_BUS_AS5600_ANGLE); + angle = val.f; + val = sys_data_bus_read(SYS_DATA_BUS_AS5600_RAW); + raw = (uint16_t)val.u; + log_out(" AS5600: raw=%u angle=%.1f deg\n", raw, (double)angle); + + val = sys_data_bus_read(SYS_DATA_BUS_MOTOR_CURRENT); + current = val.f; + log_out(" Motor Current: %.3f A\n", (double)current); + + log_out(" Limit Switches: %s\n", limit_switch_state_str()); + + log_out("--- EEPROM ---\n"); + eeprom_ok = eeprom_is_initialized(); + eeprom_err = eeprom_get_last_error(); + log_out(" Init: %s | Last Error: %s\n", + eeprom_ok ? "YES" : "NO", ret_code_str(eeprom_err)); +} + +static void report_tasks(void) +{ + uint32_t now; + uint32_t work_tick, monitor_tick; + uint32_t work_count, monitor_count; + int32_t motor_state, motor_pos, motor_target; + float motor_speed; + sys_data_bus_value_t val; + uint32_t work_age, monitor_age; + + now = system_get_tick(); + work_tick = work_task_get_last_run_tick(); + monitor_tick = monitor_task_get_last_run_tick(); + work_count = work_task_get_run_count(); + monitor_count = monitor_task_get_run_count(); + + if (now >= work_tick) { + work_age = now - work_tick; + } else { + work_age = 0; + } + if (now >= monitor_tick) { + monitor_age = now - monitor_tick; + } else { + monitor_age = 0; + } + + log_out("--- Tasks ---\n"); + log_out(" work_task: last_run=%lu ms ago count=%lu\n", work_age, work_count); + log_out(" monitor_task: last_run=%lu ms ago count=%lu\n", monitor_age, monitor_count); + + val = sys_data_bus_read(SYS_DATA_BUS_MOTOR_STATE); + motor_state = val.i; + val = sys_data_bus_read(SYS_DATA_BUS_MOTOR_POSITION); + motor_pos = val.i; + val = sys_data_bus_read(SYS_DATA_BUS_MOTOR_TARGET); + motor_target = val.i; + val = sys_data_bus_read(SYS_DATA_BUS_MOTOR_SPEED); + motor_speed = val.f; + log_out(" Stepper: state=%s pos=%ld target=%ld speed=%.0f\n", + stepper_state_str(motor_state), motor_pos, motor_target, (double)motor_speed); + + val = sys_data_bus_read(SYS_DATA_BUS_IS_CALIBRATED); + log_out(" Calibrated: %s\n", val.u ? "YES" : "NO"); +} + +void monitor_task_init(void) +{ + last_run_tick = 0; + run_count = 0; + last_report_tick = 0; +} + +void monitor_task_run(void) +{ + uint32_t now; + + last_run_tick = system_get_tick(); + run_count++; + + now = last_run_tick; + if (now - last_report_tick >= MONITOR_INTERVAL_MS) { + last_report_tick = now; + + log_out("\n========== System Monitor [%lu ms] ==========\n", now); + report_memory(); + report_uart(); + report_sensors(); + report_tasks(); + log_out("=============================================\n\n"); + } +} + +uint32_t monitor_task_get_last_run_tick(void) +{ + return last_run_tick; +} + +uint32_t monitor_task_get_run_count(void) +{ + return run_count; +} diff --git a/app/tasks/monitor_task.h b/app/tasks/monitor_task.h new file mode 100644 index 0000000..fcb89fa --- /dev/null +++ b/app/tasks/monitor_task.h @@ -0,0 +1,11 @@ +#ifndef MONITOR_TASK_H__ +#define MONITOR_TASK_H__ + +#include + +void monitor_task_init(void); +void monitor_task_run(void); +uint32_t monitor_task_get_last_run_tick(void); +uint32_t monitor_task_get_run_count(void); + +#endif diff --git a/app/tasks/work_task.c b/app/tasks/work_task.c new file mode 100644 index 0000000..521b1d7 --- /dev/null +++ b/app/tasks/work_task.c @@ -0,0 +1,31 @@ +#include "work_task.h" +#include "system_driver.h" +#include "led_driver.h" +#include "config.h" + +static uint32_t last_run_tick; +static uint32_t run_count; + +void work_task_init(void) +{ + last_run_tick = 0; + run_count = 0; +} + +void work_task_run(void) +{ + last_run_tick = system_get_tick(); + run_count++; + + led_blink(500); +} + +uint32_t work_task_get_last_run_tick(void) +{ + return last_run_tick; +} + +uint32_t work_task_get_run_count(void) +{ + return run_count; +} diff --git a/app/tasks/work_task.h b/app/tasks/work_task.h new file mode 100644 index 0000000..218b312 --- /dev/null +++ b/app/tasks/work_task.h @@ -0,0 +1,11 @@ +#ifndef WORK_TASK_H__ +#define WORK_TASK_H__ + +#include + +void work_task_init(void); +void work_task_run(void); +uint32_t work_task_get_last_run_tick(void); +uint32_t work_task_get_run_count(void); + +#endif diff --git a/bsp/common_types.h b/bsp/common_types.h new file mode 100644 index 0000000..6c8fd6a --- /dev/null +++ b/bsp/common_types.h @@ -0,0 +1,32 @@ +#ifndef COMMON_TYPES_H__ +#define COMMON_TYPES_H__ + +#include + +typedef enum { + RET_OK = 0, + RET_ERROR = -1, + RET_BUSY = -2, + RET_TIMEOUT = -3, + RET_INVALID_PARAM = -4, + RET_NOMEM = -5, + RET_NOT_SUPPORTED = -6, +} ret_code_t; + +typedef enum { + DEVICE_STATE_UNINIT = 0, + DEVICE_STATE_INIT = 1, + DEVICE_STATE_STARTED = 2, + DEVICE_STATE_STOPPED = 3, + DEVICE_STATE_ERROR = 4, +} device_state_t; + +typedef struct { + void *handle; + uint32_t flags; + device_state_t state; + ret_code_t (*init)(void); + ret_code_t (*deinit)(void); +} device_driver_t; + +#endif diff --git a/bsp/device/as5600/as5600_driver.c b/bsp/device/as5600/as5600_driver.c new file mode 100644 index 0000000..016134e --- /dev/null +++ b/bsp/device/as5600/as5600_driver.c @@ -0,0 +1,72 @@ +#include "as5600_driver.h" +#include "i2c_driver.h" +#include "sys_data_bus.h" +#include "config.h" + +static uint8_t as5600_initialized = 0; + +ret_code_t as5600_init(void) +{ + ret_code_t ret; + + if (!I2C1_ENABLED) { + return RET_NOT_SUPPORTED; + } + + ret = i2c_check_device(AS5600_I2C_ADDR); + if (ret != RET_OK) { + as5600_initialized = 0; + return RET_ERROR; + } + + as5600_initialized = 1; + return RET_OK; +} + +ret_code_t as5600_deinit(void) +{ + as5600_initialized = 0; + return RET_OK; +} + +uint16_t as5600_read_raw(void) +{ + uint8_t buf[2]; + + if (!as5600_initialized) { + return 0; + } + + if (i2c_mem_read(AS5600_I2C_ADDR, AS5600_ANGLE_H_REG, 1, buf, 2) != RET_OK) { + return 0; + } + + return (uint16_t)(((uint16_t)buf[0] << 8) | (uint16_t)buf[1]) & 0x0FFF; +} + +float as5600_read_angle(void) +{ + uint16_t raw; + float angle; + + raw = as5600_read_raw(); + + angle = (float)raw * AS5600_ANGLE_MAX_DEG / (float)AS5600_RAW_MAX; + + { + sys_data_bus_value_t val; + + val.u = (uint32_t)raw; + sys_data_bus_write(SYS_DATA_BUS_AS5600_RAW, val); + + val.f = angle; + sys_data_bus_write(SYS_DATA_BUS_AS5600_ANGLE, val); + } + + return angle; +} + +ret_code_t as5600_check_device(void) +{ + return i2c_check_device(AS5600_I2C_ADDR); +} diff --git a/bsp/device/as5600/as5600_driver.h b/bsp/device/as5600/as5600_driver.h new file mode 100644 index 0000000..21a37c9 --- /dev/null +++ b/bsp/device/as5600/as5600_driver.h @@ -0,0 +1,19 @@ +#ifndef AS5600_DRIVER_H__ +#define AS5600_DRIVER_H__ + +#include "common_types.h" +#include + +#define AS5600_I2C_ADDR 0x36 +#define AS5600_ANGLE_H_REG 0x0C +#define AS5600_ANGLE_L_REG 0x0D +#define AS5600_RAW_MAX 4096 +#define AS5600_ANGLE_MAX_DEG 360.0f + +ret_code_t as5600_init(void); +ret_code_t as5600_deinit(void); +uint16_t as5600_read_raw(void); +float as5600_read_angle(void); +ret_code_t as5600_check_device(void); + +#endif diff --git a/bsp/device/eeprom/eeprom_driver.c b/bsp/device/eeprom/eeprom_driver.c new file mode 100644 index 0000000..b480091 --- /dev/null +++ b/bsp/device/eeprom/eeprom_driver.c @@ -0,0 +1,64 @@ +#include "eeprom_driver.h" +#include "i2c_driver.h" +#include "config.h" + +static uint8_t eeprom_initialized; +static uint8_t eeprom_init_attempted; +static ret_code_t eeprom_last_error; + +ret_code_t eeprom_init(void) +{ + ret_code_t ret; + uint32_t speed = I2C1_SPEED; + + eeprom_init_attempted = 1; + ret = i2c_init(speed); + if (ret == RET_OK) { + eeprom_initialized = 1; + } + eeprom_last_error = ret; + return ret; +} + +ret_code_t eeprom_write(uint16_t addr, const uint8_t *data, uint32_t len) +{ + ret_code_t ret; + + if (addr + len > EEPROM_TOTAL_SIZE) { + eeprom_last_error = RET_INVALID_PARAM; + return RET_INVALID_PARAM; + } + + ret = i2c_mem_write(EEPROM_DEV_ADDR >> 1, addr, 1, data, len); + eeprom_last_error = ret; + return ret; +} + +ret_code_t eeprom_read(uint16_t addr, uint8_t *data, uint32_t len) +{ + ret_code_t ret; + + if (addr + len > EEPROM_TOTAL_SIZE) { + eeprom_last_error = RET_INVALID_PARAM; + return RET_INVALID_PARAM; + } + + ret = i2c_mem_read(EEPROM_DEV_ADDR >> 1, addr, 1, data, len); + eeprom_last_error = ret; + return ret; +} + +ret_code_t eeprom_get_last_error(void) +{ + return eeprom_last_error; +} + +uint8_t eeprom_is_initialized(void) +{ + return eeprom_initialized; +} + +void eeprom_reset_status(void) +{ + eeprom_last_error = RET_OK; +} diff --git a/bsp/device/eeprom/eeprom_driver.h b/bsp/device/eeprom/eeprom_driver.h new file mode 100644 index 0000000..69563e7 --- /dev/null +++ b/bsp/device/eeprom/eeprom_driver.h @@ -0,0 +1,18 @@ +#ifndef EEPROM_DRIVER_H__ +#define EEPROM_DRIVER_H__ + +#include "common_types.h" +#include + +#define EEPROM_DEV_ADDR 0xA0 +#define EEPROM_PAGE_SIZE 8 +#define EEPROM_TOTAL_SIZE 2048 + +ret_code_t eeprom_init(void); +ret_code_t eeprom_write(uint16_t addr, const uint8_t *data, uint32_t len); +ret_code_t eeprom_read(uint16_t addr, uint8_t *data, uint32_t len); +ret_code_t eeprom_get_last_error(void); +uint8_t eeprom_is_initialized(void); +void eeprom_reset_status(void); + +#endif diff --git a/bsp/device/key/key_driver.c b/bsp/device/key/key_driver.c new file mode 100644 index 0000000..01f11c7 --- /dev/null +++ b/bsp/device/key/key_driver.c @@ -0,0 +1,51 @@ +#include "key_driver.h" +#include "gpio_driver.h" +#include "config.h" + +static gpio_config_t di_max_cfg = { + .port = DI_MAX_PORT, + .pin = DI_MAX_PIN, + .mode = GPIO_MODE_INPUT, + .pupd = GPIO_PUPD_PULLUP, + .speed = GPIO_SPEED_LOW, + .af_num = 0, +}; + +static gpio_config_t di_min_cfg = { + .port = DI_MIN_PORT, + .pin = DI_MIN_PIN, + .mode = GPIO_MODE_INPUT, + .pupd = GPIO_PUPD_PULLUP, + .speed = GPIO_SPEED_LOW, + .af_num = 0, +}; + +ret_code_t key_init(void) +{ + ret_code_t ret; + + ret = gpio_init(&di_max_cfg); + if (ret != RET_OK) return ret; + + ret = gpio_init(&di_min_cfg); + return ret; +} + +uint8_t key_get_state(key_id_t key) +{ + switch (key) { + case KEY_DI_MAX: + return gpio_get_level(DI_MAX_PORT, DI_MAX_PIN); + case KEY_DI_MIN: + return gpio_get_level(DI_MIN_PORT, DI_MIN_PIN); + default: + return 0; + } +} + +ret_code_t key_register_callback(key_id_t key, void (*callback)(uint8_t state)) +{ + (void)key; + (void)callback; + return RET_NOT_SUPPORTED; +} diff --git a/bsp/device/key/key_driver.h b/bsp/device/key/key_driver.h new file mode 100644 index 0000000..33ca85a --- /dev/null +++ b/bsp/device/key/key_driver.h @@ -0,0 +1,16 @@ +#ifndef KEY_DRIVER_H__ +#define KEY_DRIVER_H__ + +#include "common_types.h" +#include + +typedef enum { + KEY_DI_MAX = 0, + KEY_DI_MIN = 1, +} key_id_t; + +ret_code_t key_init(void); +uint8_t key_get_state(key_id_t key); +ret_code_t key_register_callback(key_id_t key, void (*callback)(uint8_t state)); + +#endif diff --git a/bsp/device/led/led_driver.c b/bsp/device/led/led_driver.c new file mode 100644 index 0000000..3e530a5 --- /dev/null +++ b/bsp/device/led/led_driver.c @@ -0,0 +1,41 @@ +#include "led_driver.h" +#include "gpio_driver.h" +#include "system_driver.h" +#include "config.h" + +static gpio_config_t led_cfg = { + .port = LED_PORT, + .pin = LED_PIN, + .mode = GPIO_MODE_OUTPUT, + .pupd = GPIO_PUPD_NONE, + .speed = GPIO_SPEED_LOW, + .af_num = 0, +}; + +ret_code_t led_init(void) +{ + return gpio_init(&led_cfg); +} + +ret_code_t led_set(led_state_t state) +{ + switch (state) { + case LED_ON: + return gpio_set_level(LED_PORT, LED_PIN, 0); + case LED_OFF: + return gpio_set_level(LED_PORT, LED_PIN, 1); + case LED_TOGGLE: + return gpio_toggle(LED_PORT, LED_PIN); + default: + return RET_INVALID_PARAM; + } +} + +ret_code_t led_blink(uint32_t interval_ms) +{ + led_set(LED_ON); + system_delay_ms(interval_ms); + led_set(LED_OFF); + system_delay_ms(interval_ms); + return RET_OK; +} diff --git a/bsp/device/led/led_driver.h b/bsp/device/led/led_driver.h new file mode 100644 index 0000000..e334bfb --- /dev/null +++ b/bsp/device/led/led_driver.h @@ -0,0 +1,17 @@ +#ifndef LED_DRIVER_H__ +#define LED_DRIVER_H__ + +#include "common_types.h" +#include + +typedef enum { + LED_OFF = 0, + LED_ON = 1, + LED_TOGGLE = 2, +} led_state_t; + +ret_code_t led_init(void); +ret_code_t led_set(led_state_t state); +ret_code_t led_blink(uint32_t interval_ms); + +#endif diff --git a/bsp/device/limit_switch/limit_switch.c b/bsp/device/limit_switch/limit_switch.c new file mode 100644 index 0000000..435fdab --- /dev/null +++ b/bsp/device/limit_switch/limit_switch.c @@ -0,0 +1,209 @@ +#include "limit_switch.h" +#include "gpio_driver.h" +#include "py32md530.h" +#include "system_driver.h" +#include "sys_data_bus.h" +#include "config.h" +#include + +static limit_switch_callback_t sw_callbacks[2]; +static uint8_t sw_triggered[2]; +static uint8_t sw_initialized = 0; + +void EXTI4_15_IRQHandler(void) +{ + if (EXTI->PR & (1UL << 8)) { + EXTI->PR = (1UL << 8); + + TIM1->BDTR &= ~TIM_BDTR_MOE_Msk; + TIM1->CR1 &= ~TIM_CR1_CEN_Msk; + + sw_triggered[LIMIT_SW_MAX] = 1; + + { + sys_data_bus_value_t val; + val.u = 1; + sys_data_bus_write(SYS_DATA_BUS_DI_MAX_STATE, val); + } + + if (sw_callbacks[LIMIT_SW_MAX]) { + sw_callbacks[LIMIT_SW_MAX](LIMIT_SW_MAX, LIMIT_SW_STATE_TRIGGERED); + } + } +} + +void EXTI2_3_IRQHandler(void) +{ + if (EXTI->PR & (1UL << 2)) { + EXTI->PR = (1UL << 2); + + TIM1->BDTR &= ~TIM_BDTR_MOE_Msk; + TIM1->CR1 &= ~TIM_CR1_CEN_Msk; + + sw_triggered[LIMIT_SW_MIN] = 1; + + { + sys_data_bus_value_t val; + val.u = 1; + sys_data_bus_write(SYS_DATA_BUS_DI_MIN_STATE, val); + } + + if (sw_callbacks[LIMIT_SW_MIN]) { + sw_callbacks[LIMIT_SW_MIN](LIMIT_SW_MIN, LIMIT_SW_STATE_TRIGGERED); + } + } +} + +static ret_code_t gpio_config(void) +{ + gpio_config_t cfg; + + cfg.mode = GPIO_MODE_INPUT; + cfg.speed = GPIO_SPEED_LOW; + cfg.af_num = 0; + + cfg.port = DI_MAX_PORT; + cfg.pin = DI_MAX_PIN; + cfg.pupd = GPIO_PUPD_PULLDOWN; + gpio_init(&cfg); + + cfg.port = DI_MIN_PORT; + cfg.pin = DI_MIN_PIN; + cfg.pupd = GPIO_PUPD_PULLDOWN; + gpio_init(&cfg); + + return RET_OK; +} + +static ret_code_t exti_config(void) +{ + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + + SYSCFG->EXTICR[0] &= ~(0xFUL << 8); + SYSCFG->EXTICR[0] |= (0x1UL << 8); + + EXTI->RTSR |= (1UL << 2); + + EXTI->IMR |= (1UL << 2); + + SYSCFG->EXTICR[2] &= ~(0xFUL << 0); + + EXTI->RTSR |= (1UL << 8); + + EXTI->IMR |= (1UL << 8); + + NVIC_SetPriority(EXTI2_3_IRQn, 0x10); + NVIC_EnableIRQ(EXTI2_3_IRQn); + NVIC_SetPriority(EXTI4_15_IRQn, 0x10); + NVIC_EnableIRQ(EXTI4_15_IRQn); + + return RET_OK; +} + +ret_code_t limit_switch_init(void) +{ + ret_code_t ret; + + sw_callbacks[LIMIT_SW_MAX] = NULL; + sw_callbacks[LIMIT_SW_MIN] = NULL; + sw_triggered[LIMIT_SW_MAX] = 0; + sw_triggered[LIMIT_SW_MIN] = 0; + + ret = gpio_config(); + if (ret != RET_OK) return ret; + + ret = exti_config(); + if (ret != RET_OK) return ret; + + sw_initialized = 1; + + return RET_OK; +} + +ret_code_t limit_switch_deinit(void) +{ + NVIC_DisableIRQ(EXTI2_3_IRQn); + NVIC_DisableIRQ(EXTI4_15_IRQn); + + EXTI->IMR &= ~(1UL << 2); + EXTI->IMR &= ~(1UL << 8); + + sw_initialized = 0; + return RET_OK; +} + +limit_switch_state_t limit_switch_get_state(limit_switch_id_t id) +{ + uint8_t level; + uint32_t tick_start; + uint8_t stable_count; + + if (!sw_initialized) { + return LIMIT_SW_STATE_NORMAL; + } + + switch (id) { + case LIMIT_SW_MAX: + level = gpio_get_level(DI_MAX_PORT, DI_MAX_PIN); + tick_start = system_get_tick(); + stable_count = 0; + + while ((system_get_tick() - tick_start) < LIMIT_SW_DEBOUNCE_MS) { + if (gpio_get_level(DI_MAX_PORT, DI_MAX_PIN) == level) { + stable_count++; + } else { + level = gpio_get_level(DI_MAX_PORT, DI_MAX_PIN); + stable_count = 0; + } + } + + return (level != 0) ? LIMIT_SW_STATE_TRIGGERED : LIMIT_SW_STATE_NORMAL; + + case LIMIT_SW_MIN: + level = gpio_get_level(DI_MIN_PORT, DI_MIN_PIN); + tick_start = system_get_tick(); + stable_count = 0; + + while ((system_get_tick() - tick_start) < LIMIT_SW_DEBOUNCE_MS) { + if (gpio_get_level(DI_MIN_PORT, DI_MIN_PIN) == level) { + stable_count++; + } else { + level = gpio_get_level(DI_MIN_PORT, DI_MIN_PIN); + stable_count = 0; + } + } + + return (level != 0) ? LIMIT_SW_STATE_TRIGGERED : LIMIT_SW_STATE_NORMAL; + + default: + return LIMIT_SW_STATE_NORMAL; + } +} + +uint8_t limit_switch_is_triggered(limit_switch_id_t id) +{ + if (id > LIMIT_SW_MIN) return 0; + return sw_triggered[id]; +} + +ret_code_t limit_switch_register_callback(limit_switch_id_t id, limit_switch_callback_t callback) +{ + if (id > LIMIT_SW_MIN) { + return RET_INVALID_PARAM; + } + + sw_callbacks[id] = callback; + return RET_OK; +} + +ret_code_t limit_switch_set_interrupt(uint8_t enable) +{ + if (enable) { + EXTI->IMR |= (1UL << 2); + EXTI->IMR |= (1UL << 8); + } else { + EXTI->IMR &= ~(1UL << 2); + EXTI->IMR &= ~(1UL << 8); + } + return RET_OK; +} diff --git a/bsp/device/limit_switch/limit_switch.h b/bsp/device/limit_switch/limit_switch.h new file mode 100644 index 0000000..cdd2887 --- /dev/null +++ b/bsp/device/limit_switch/limit_switch.h @@ -0,0 +1,28 @@ +#ifndef LIMIT_SWITCH_H__ +#define LIMIT_SWITCH_H__ + +#include "common_types.h" +#include + +#define LIMIT_SW_DEBOUNCE_MS 10 + +typedef enum { + LIMIT_SW_MAX = 0, + LIMIT_SW_MIN = 1, +} limit_switch_id_t; + +typedef enum { + LIMIT_SW_STATE_NORMAL = 0, + LIMIT_SW_STATE_TRIGGERED = 1, +} limit_switch_state_t; + +typedef void (*limit_switch_callback_t)(limit_switch_id_t id, limit_switch_state_t state); + +ret_code_t limit_switch_init(void); +ret_code_t limit_switch_deinit(void); +limit_switch_state_t limit_switch_get_state(limit_switch_id_t id); +uint8_t limit_switch_is_triggered(limit_switch_id_t id); +ret_code_t limit_switch_register_callback(limit_switch_id_t id, limit_switch_callback_t callback); +ret_code_t limit_switch_set_interrupt(uint8_t enable); + +#endif diff --git a/bsp/hardware_init.c b/bsp/hardware_init.c new file mode 100644 index 0000000..6137815 --- /dev/null +++ b/bsp/hardware_init.c @@ -0,0 +1,49 @@ +#include "hardware_init.h" +#include "py32md530.h" +#include "system_py32md530.h" +#include "config.h" + +ret_code_t hardware_init(void) +{ + SystemInit(); + + RCC->AHBENR |= RCC_AHBENR_GPIOAEN + | RCC_AHBENR_GPIOBEN + | RCC_AHBENR_GPIOCEN + | RCC_AHBENR_GPIOFEN; + + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN + | RCC_APB2ENR_USART1EN + | RCC_APB2ENR_TIM1EN; + + RCC->APB1ENR |= RCC_APB1ENR_UART1EN + | RCC_APB1ENR_LPUART1EN + | RCC_APB1ENR_I2C1EN + | RCC_APB1ENR_TIM3EN + | RCC_APB1ENR_TIM14EN; + + RCC->AHBENR |= RCC_AHBENR_DMAEN; + + return RET_OK; +} + +ret_code_t hardware_deinit(void) +{ + RCC->AHBENR &= ~(RCC_AHBENR_GPIOAEN + | RCC_AHBENR_GPIOBEN + | RCC_AHBENR_GPIOCEN + | RCC_AHBENR_GPIOFEN + | RCC_AHBENR_DMAEN); + + RCC->APB2ENR &= ~(RCC_APB2ENR_SYSCFGEN + | RCC_APB2ENR_USART1EN + | RCC_APB2ENR_TIM1EN); + + RCC->APB1ENR &= ~(RCC_APB1ENR_UART1EN + | RCC_APB1ENR_LPUART1EN + | RCC_APB1ENR_I2C1EN + | RCC_APB1ENR_TIM3EN + | RCC_APB1ENR_TIM14EN); + + return RET_OK; +} diff --git a/bsp/hardware_init.h b/bsp/hardware_init.h new file mode 100644 index 0000000..fd0ee88 --- /dev/null +++ b/bsp/hardware_init.h @@ -0,0 +1,9 @@ +#ifndef HARDWARE_INIT_H__ +#define HARDWARE_INIT_H__ + +#include "common_types.h" + +ret_code_t hardware_init(void); +ret_code_t hardware_deinit(void); + +#endif diff --git a/bsp/modbus/modbus_slave.c b/bsp/modbus/modbus_slave.c new file mode 100644 index 0000000..8465626 --- /dev/null +++ b/bsp/modbus/modbus_slave.c @@ -0,0 +1,280 @@ +#include "modbus_slave.h" +#include "uart_driver.h" +#include "system_driver.h" +#include "sys_data_bus.h" +#include "config.h" +#include + +#define MODBUS_RX_TIMEOUT_MS 5 +#define MODBUS_TX_GUARD_US 2 + +#define MODBUS_EXCEPTION_ILLEGAL_FUNCTION 0x01 +#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDR 0x02 +#define MODBUS_EXCEPTION_ILLEGAL_DATA_VAL 0x03 + +#define MODBUS_ADDR_BROADCAST 0x00 + +#define REG_BUS_DATA_START 0x0000 +#define REG_BUS_DATA_END 0x001F +#define REG_BUS_DATA_HIGH_START 0x0020 +#define REG_BUS_DATA_HIGH_END 0x003F +#define REG_FLAG_LOW 0x0040 +#define REG_FLAG_HIGH 0x0041 + +static uint8_t slave_address; +static modbus_state_t state; +static uint8_t rx_buf[MODBUS_BUF_SIZE]; +static uint16_t rx_len; +static uint32_t rx_tick_start; +static uint8_t initialized; + +static uint16_t modbus_crc16_calc(const uint8_t *data, uint16_t len) +{ + uint16_t crc = 0xFFFF; + uint16_t i, j; + + for (i = 0; i < len; i++) { + crc ^= data[i]; + for (j = 0; j < 8; j++) { + if (crc & 0x0001) { + crc = (crc >> 1) ^ 0xA001; + } else { + crc = crc >> 1; + } + } + } + return crc; +} + +uint16_t modbus_crc16(const uint8_t *data, uint16_t len) +{ + return modbus_crc16_calc(data, len); +} + +static void modbus_send_response(const uint8_t *data, uint16_t len) +{ + uart_send(UART_ID_USART1, data, len); +} + +static void modbus_send_exception(uint8_t func_code, uint8_t exception) +{ + uint8_t resp[5]; + uint16_t crc; + + resp[0] = slave_address; + resp[1] = func_code | 0x80; + resp[2] = exception; + + crc = modbus_crc16_calc(resp, 3); + resp[3] = (uint8_t)(crc & 0xFF); + resp[4] = (uint8_t)((crc >> 8) & 0xFF); + + modbus_send_response(resp, 5); +} + +static void modbus_handle_read_holding(uint16_t reg_addr, uint16_t reg_count) +{ + uint8_t resp[MODBUS_BUF_SIZE]; + uint16_t crc; + uint16_t i; + uint16_t resp_len; + sys_data_bus_value_t bus_val; + uint32_t flags; + + if (reg_count < 1 || reg_count > 125) { + modbus_send_exception(MODBUS_FUNC_READ_HOLDING, MODBUS_EXCEPTION_ILLEGAL_DATA_VAL); + return; + } + + if ((reg_addr >= REG_BUS_DATA_START && (reg_addr + reg_count - 1) <= REG_BUS_DATA_END) || + (reg_addr >= REG_BUS_DATA_HIGH_START && (reg_addr + reg_count - 1) <= REG_BUS_DATA_HIGH_END) || + (reg_addr >= REG_FLAG_LOW && (reg_addr + reg_count - 1) <= REG_FLAG_HIGH)) { + + resp[0] = slave_address; + resp[1] = MODBUS_FUNC_READ_HOLDING; + resp[2] = (uint8_t)(reg_count * 2); + + for (i = 0; i < reg_count; i++) { + uint16_t addr = reg_addr + i; + uint16_t reg_val = 0; + + if (addr <= REG_BUS_DATA_END) { + bus_val = sys_data_bus_read((sys_data_bus_id_t)addr); + reg_val = (uint16_t)(bus_val.u & 0xFFFF); + } else if (addr >= REG_BUS_DATA_HIGH_START && addr <= REG_BUS_DATA_HIGH_END) { + bus_val = sys_data_bus_read((sys_data_bus_id_t)(addr - REG_BUS_DATA_HIGH_START)); + reg_val = (uint16_t)((bus_val.u >> 16) & 0xFFFF); + } else if (addr == REG_FLAG_LOW) { + flags = 0; + reg_val = (uint16_t)(flags & 0xFFFF); + } else if (addr == REG_FLAG_HIGH) { + flags = 0; + reg_val = (uint16_t)((flags >> 16) & 0xFFFF); + } + + resp[3 + i * 2] = (uint8_t)((reg_val >> 8) & 0xFF); + resp[4 + i * 2] = (uint8_t)(reg_val & 0xFF); + } + + resp_len = 3 + reg_count * 2; + crc = modbus_crc16_calc(resp, resp_len); + resp[resp_len] = (uint8_t)(crc & 0xFF); + resp[resp_len + 1] = (uint8_t)((crc >> 8) & 0xFF); + + modbus_send_response(resp, resp_len + 2); + } else { + modbus_send_exception(MODBUS_FUNC_READ_HOLDING, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDR); + } +} + +static void modbus_handle_write_single_reg(uint16_t reg_addr, uint16_t reg_value) +{ + uint8_t resp[8]; + uint16_t crc; + + if (reg_addr <= REG_BUS_DATA_END) { + sys_data_bus_value_t val; + sys_data_bus_value_t current; + + current = sys_data_bus_read((sys_data_bus_id_t)reg_addr); + val.u = (current.u & 0xFFFF0000) | reg_value; + sys_data_bus_write((sys_data_bus_id_t)reg_addr, val); + } else if (reg_addr >= REG_BUS_DATA_HIGH_START && reg_addr <= REG_BUS_DATA_HIGH_END) { + sys_data_bus_value_t val; + sys_data_bus_value_t current; + uint8_t idx = (uint8_t)(reg_addr - REG_BUS_DATA_HIGH_START); + + current = sys_data_bus_read((sys_data_bus_id_t)idx); + val.u = (current.u & 0x0000FFFF) | ((uint32_t)reg_value << 16); + sys_data_bus_write((sys_data_bus_id_t)idx, val); + } else { + modbus_send_exception(MODBUS_FUNC_WRITE_SINGLE_REG, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDR); + return; + } + + resp[0] = slave_address; + resp[1] = MODBUS_FUNC_WRITE_SINGLE_REG; + resp[2] = (uint8_t)((reg_addr >> 8) & 0xFF); + resp[3] = (uint8_t)(reg_addr & 0xFF); + resp[4] = (uint8_t)((reg_value >> 8) & 0xFF); + resp[5] = (uint8_t)(reg_value & 0xFF); + + crc = modbus_crc16_calc(resp, 6); + resp[6] = (uint8_t)(crc & 0xFF); + resp[7] = (uint8_t)((crc >> 8) & 0xFF); + + modbus_send_response(resp, 8); +} + +static void modbus_process_frame(void) +{ + uint16_t crc_recv, crc_calc; + + if (rx_len < 4) { + state = MODBUS_IDLE; + return; + } + + if (rx_buf[0] != slave_address && rx_buf[0] != MODBUS_ADDR_BROADCAST) { + state = MODBUS_IDLE; + return; + } + + crc_recv = (uint16_t)rx_buf[rx_len - 1] << 8 | rx_buf[rx_len - 2]; + crc_calc = modbus_crc16_calc(rx_buf, rx_len - 2); + + if (crc_recv != crc_calc) { + state = MODBUS_IDLE; + return; + } + + { + uint8_t func = rx_buf[1]; + uint16_t reg_addr; + uint16_t reg_count; + + switch (func) { + case MODBUS_FUNC_READ_HOLDING: + if (rx_len < 8) { + break; + } + reg_addr = (uint16_t)rx_buf[2] << 8 | rx_buf[3]; + reg_count = (uint16_t)rx_buf[4] << 8 | rx_buf[5]; + modbus_handle_read_holding(reg_addr, reg_count); + break; + + case MODBUS_FUNC_WRITE_SINGLE_REG: + if (rx_len < 8) { + break; + } + reg_addr = (uint16_t)rx_buf[2] << 8 | rx_buf[3]; + reg_count = (uint16_t)rx_buf[4] << 8 | rx_buf[5]; + modbus_handle_write_single_reg(reg_addr, reg_count); + break; + + default: + modbus_send_exception(func, MODBUS_EXCEPTION_ILLEGAL_FUNCTION); + break; + } + } + + state = MODBUS_IDLE; +} + +ret_code_t modbus_slave_init(uint8_t slave_addr) +{ + slave_address = slave_addr; + state = MODBUS_IDLE; + rx_len = 0; + rx_tick_start = 0; + initialized = 1; + + return RET_OK; +} + +ret_code_t modbus_slave_deinit(void) +{ + initialized = 0; + state = MODBUS_IDLE; + return RET_OK; +} + +void modbus_slave_poll(void) +{ + uint32_t available; + uint8_t byte; + uint32_t now; + + if (!initialized) { + return; + } + + available = uart_available(UART_ID_USART1); + + if (available > 0) { + if (state == MODBUS_IDLE) { + state = MODBUS_RX_IN_PROGRESS; + rx_len = 0; + } + + while (available > 0 && rx_len < MODBUS_BUF_SIZE) { + if (uart_receive(UART_ID_USART1, &byte, 1, 0) == RET_OK) { + rx_buf[rx_len++] = byte; + } + available--; + } + + rx_tick_start = system_get_tick(); + } + + if (state == MODBUS_RX_IN_PROGRESS && rx_len > 0) { + now = system_get_tick(); + if ((now - rx_tick_start) >= MODBUS_RX_TIMEOUT_MS) { + state = MODBUS_RX_COMPLETE; + } + } + + if (state == MODBUS_RX_COMPLETE) { + modbus_process_frame(); + } +} diff --git a/bsp/modbus/modbus_slave.h b/bsp/modbus/modbus_slave.h new file mode 100644 index 0000000..6cbe7cd --- /dev/null +++ b/bsp/modbus/modbus_slave.h @@ -0,0 +1,40 @@ +#ifndef MODBUS_SLAVE_H__ +#define MODBUS_SLAVE_H__ + +#include "common_types.h" +#include + +#define MODBUS_SLAVE_ADDR 0x01 +#define MODBUS_MASTER_ADDR 0xF0 +#define MODBUS_BUF_SIZE 256 + +#define MODBUS_FUNC_READ_COILS 0x01 +#define MODBUS_FUNC_READ_HOLDING 0x03 +#define MODBUS_FUNC_WRITE_SINGLE_COIL 0x05 +#define MODBUS_FUNC_WRITE_SINGLE_REG 0x06 +#define MODBUS_FUNC_WRITE_MULTIPLE_REGS 0x10 + +typedef enum { + MODBUS_IDLE = 0, + MODBUS_RX_IN_PROGRESS, + MODBUS_RX_COMPLETE, + MODBUS_TX_IN_PROGRESS, +} modbus_state_t; + +typedef struct { + uint8_t slave_addr; + uint8_t func_code; + uint16_t reg_addr; + uint16_t reg_count; + uint8_t byte_count; + uint16_t reg_value; + uint8_t data[MODBUS_BUF_SIZE]; + uint16_t data_len; +} modbus_frame_t; + +ret_code_t modbus_slave_init(uint8_t slave_addr); +ret_code_t modbus_slave_deinit(void); +void modbus_slave_poll(void); +uint16_t modbus_crc16(const uint8_t *data, uint16_t len); + +#endif diff --git a/cmake/arm-none-eabi-toolchain.cmake b/cmake/arm-none-eabi-toolchain.cmake new file mode 100644 index 0000000..7ed3b71 --- /dev/null +++ b/cmake/arm-none-eabi-toolchain.cmake @@ -0,0 +1,14 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR cortex-m0plus) + +set(CMAKE_C_COMPILER arm-none-eabi-gcc) +set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) + +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +set(CMAKE_C_COMPILER_WORKS 1) +set(CMAKE_C_COMPILER_FORCED 1) + +set(CMAKE_CROSSCOMPILING TRUE) diff --git a/config/config.h b/config/config.h new file mode 100644 index 0000000..34dad80 --- /dev/null +++ b/config/config.h @@ -0,0 +1,45 @@ +#ifndef CONFIG_H__ +#define CONFIG_H__ + +#define DEBUG_ENABLED 1 + +#define F_CPU 72000000UL +#define SYSTICK_RELOAD_VAL (F_CPU / 1000) + +#define USART1_RS485_ENABLED 1 +#define USART1_RS485_DIR_PORT GPIOA +#define USART1_RS485_DIR_PIN 3 + +#define USART1_ENABLED 1 +#define LPUART1_ENABLED 1 + +#define I2C1_ENABLED 1 +#define I2C1_SPEED 100000 + +#define ADC1_ENABLED 1 + +#define TIM1_PWM_ENABLED 1 +#define TIM1_PWM_FREQ 20000 + +#define LED_ENABLED 1 +#define KEY_ENABLED 1 +#define EEPROM_ENABLED 1 + +#define LIMIT_SWITCH_ENABLED 1 +#define PGA_ENABLED 1 + +#define DI_MAX_PORT GPIOA +#define DI_MAX_PIN 8 +#define DI_MIN_PORT GPIOB +#define DI_MIN_PIN 2 + +#define ID_PORT GPIOB +#define ID_PIN_1 5 +#define ID_PIN_2 6 +#define ID_PIN_3 7 +#define ID_PIN_4 8 + +#define LED_PORT GPIOA +#define LED_PIN 6 + +#endif diff --git a/drv/adc/adc_driver.c b/drv/adc/adc_driver.c new file mode 100644 index 0000000..2bff12a --- /dev/null +++ b/drv/adc/adc_driver.c @@ -0,0 +1,54 @@ +#include "adc_driver.h" +#include "py32md530.h" +#include "config.h" + +ret_code_t adc_init(void) +{ + RCC->APB2ENR |= RCC_APB2ENR_ADCEN; + + ADC1->CR &= ~ADC_CR_ADEN_Msk; + + ADC1->CFGR1 = ADC_CFGR1_RES_1; + + ADC1->CHSMPR2 = (0x7 << 0); + + ADC1->SMPR1 = 0x07; + + ADC1->ISR &= ~ADC_ISR_ADRDY_Msk; + ADC1->CR |= ADC_CR_ADEN_Msk; + while (!(ADC1->ISR & ADC_ISR_ADRDY_Msk)); + + return RET_OK; +} + +ret_code_t adc_deinit(void) +{ + ADC1->CR |= ADC_CR_ADDIS_Msk; + while (ADC1->CR & ADC_CR_ADEN_Msk); + + RCC->APB2ENR &= ~RCC_APB2ENR_ADCEN; + return RET_OK; +} + +uint16_t adc_read_channel(adc_channel_t ch) +{ + ADC1->CHDR1 = (uint32_t)ch; + + ADC1->ISR &= ~ADC_ISR_EOC_Msk; + + ADC1->CR |= ADC_CR_ADSTART_Msk; + + while (!(ADC1->ISR & ADC_ISR_EOC_Msk)); + + return (uint16_t)(ADC1->CHDR1 & 0x0FFF); +} + +ret_code_t adc_start_dma(uint16_t *buffer, uint32_t len) +{ + ADC1->CFGR1 |= ADC_CFGR1_DMAEN_Msk + | ADC_CFGR1_DMACFG_Msk; + + ADC1->CR |= ADC_CR_ADSTART_Msk; + + return RET_OK; +} diff --git a/drv/adc/adc_driver.h b/drv/adc/adc_driver.h new file mode 100644 index 0000000..3f5111e --- /dev/null +++ b/drv/adc/adc_driver.h @@ -0,0 +1,23 @@ +#ifndef ADC_DRIVER_H__ +#define ADC_DRIVER_H__ + +#include "common_types.h" +#include + +typedef enum { + ADC_CH_0 = 0, + ADC_CH_1 = 1, + ADC_CH_2 = 2, + ADC_CH_3 = 3, + ADC_CH_4 = 4, + ADC_CH_5 = 5, + ADC_CH_6 = 6, + ADC_CH_7 = 7, +} adc_channel_t; + +ret_code_t adc_init(void); +ret_code_t adc_deinit(void); +uint16_t adc_read_channel(adc_channel_t ch); +ret_code_t adc_start_dma(uint16_t *buffer, uint32_t len); + +#endif diff --git a/drv/adc/pga_driver.c b/drv/adc/pga_driver.c new file mode 100644 index 0000000..5bce92d --- /dev/null +++ b/drv/adc/pga_driver.c @@ -0,0 +1,77 @@ +#include "pga_driver.h" +#include "adc_driver.h" +#include "py32md530.h" +#include "config.h" +#include "sys_data_bus.h" +#include + +static uint8_t pga_gain = PGA_GAIN_1; +static float pga_shunt = PGA_SHUNT_RESISTOR; +static float pga_vref = PGA_VREF; +static uint8_t pga_initialized = 0; + +ret_code_t pga_init(const pga_config_t *config) +{ + if (config == NULL) { + return RET_INVALID_PARAM; + } + + pga_gain = config->gain; + pga_shunt = config->shunt_resistor; + pga_vref = config->vref; + + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + + COMP->CR &= ~COMP_CR_EN_Msk; + + COMP->CR = COMP_CR_EN_Msk + | COMP_CR_PGA_MODE_Msk + | ((uint32_t)pga_gain << COMP_CR_PGA_GAIN_Pos); + + while (!(COMP->CSR & COMP_CSR_OUT_Msk)); + + pga_initialized = 1; + + return RET_OK; +} + +ret_code_t pga_deinit(void) +{ + COMP->CR &= ~COMP_CR_EN_Msk; + pga_initialized = 0; + return RET_OK; +} + +uint16_t pga_read_raw(void) +{ + if (!pga_initialized) { + return 0; + } + + return adc_read_channel(PGA_ADC_CH); +} + +float pga_read_current(void) +{ + uint16_t raw; + float voltage; + float current; + + if (!pga_initialized) { + return 0.0f; + } + + raw = adc_read_channel(PGA_ADC_CH); + + voltage = (float)raw * pga_vref / PGA_ADC_RESOLUTION; + + current = voltage / ((float)pga_gain * pga_shunt); + + { + sys_data_bus_value_t val; + val.f = current; + sys_data_bus_write(SYS_DATA_BUS_MOTOR_CURRENT, val); + } + + return current; +} diff --git a/drv/adc/pga_driver.h b/drv/adc/pga_driver.h new file mode 100644 index 0000000..8b382e6 --- /dev/null +++ b/drv/adc/pga_driver.h @@ -0,0 +1,33 @@ +#ifndef PGA_DRIVER_H__ +#define PGA_DRIVER_H__ + +#include "common_types.h" +#include "sys_data_bus.h" +#include + +#define PGA_ADC_CH ADC_CH_0 + +#define PGA_GAIN_1 0x00 +#define PGA_GAIN_2 0x01 +#define PGA_GAIN_4 0x02 +#define PGA_GAIN_8 0x03 +#define PGA_GAIN_16 0x04 +#define PGA_GAIN_32 0x05 +#define PGA_GAIN_64 0x06 + +#define PGA_SHUNT_RESISTOR 0.001f +#define PGA_VREF 3.3f +#define PGA_ADC_RESOLUTION 4096.0f + +typedef struct { + uint8_t gain; + float shunt_resistor; + float vref; +} pga_config_t; + +ret_code_t pga_init(const pga_config_t *config); +ret_code_t pga_deinit(void); +float pga_read_current(void); +uint16_t pga_read_raw(void); + +#endif diff --git a/drv/gpio/gpio_driver.c b/drv/gpio/gpio_driver.c new file mode 100644 index 0000000..e3a2f23 --- /dev/null +++ b/drv/gpio/gpio_driver.c @@ -0,0 +1,63 @@ +#include "gpio_driver.h" +#include "config.h" + +ret_code_t gpio_init(const gpio_config_t *config) +{ + uint32_t moder_mask, moder_val; + uint32_t pupd_mask, pupd_val; + uint32_t ospeedr_mask, ospeedr_val; + uint32_t afr_mask, afr_val; + uint32_t pin_2bit = config->pin * 2; + uint32_t pin_4bit = config->pin * 4; + + moder_mask = ~(0x3UL << pin_2bit); + moder_val = ((uint32_t)config->mode) << pin_2bit; + config->port->MODER = (config->port->MODER & moder_mask) | moder_val; + + ospeedr_mask = ~(0x3UL << pin_2bit); + ospeedr_val = ((uint32_t)config->speed) << pin_2bit; + config->port->OSPEEDR = (config->port->OSPEEDR & ospeedr_mask) | ospeedr_val; + + pupd_mask = ~(0x3UL << pin_2bit); + pupd_val = ((uint32_t)config->pupd) << pin_2bit; + config->port->PUPDR = (config->port->PUPDR & pupd_mask) | pupd_val; + + if (config->mode == GPIO_MODE_AF) { + if (config->pin < 8) { + afr_mask = ~(0xFUL << pin_4bit); + afr_val = ((uint32_t)config->af_num) << pin_4bit; + config->port->AFRL = (config->port->AFRL & afr_mask) | afr_val; + } else { + afr_mask = ~(0xFUL << (pin_4bit - 32)); + afr_val = ((uint32_t)config->af_num) << (pin_4bit - 32); + config->port->AFRH = (config->port->AFRH & afr_mask) | afr_val; + } + } + + return RET_OK; +} + +ret_code_t gpio_set_level(GPIO_TypeDef *port, uint32_t pin, uint8_t level) +{ + if (level) { + port->BSRR = (1UL << pin); + } else { + port->BRR = (1UL << pin); + } + return RET_OK; +} + +uint8_t gpio_get_level(GPIO_TypeDef *port, uint32_t pin) +{ + return (port->IDR >> pin) & 0x01; +} + +ret_code_t gpio_toggle(GPIO_TypeDef *port, uint32_t pin) +{ + if (port->ODR & (1UL << pin)) { + port->BRR = (1UL << pin); + } else { + port->BSRR = (1UL << pin); + } + return RET_OK; +} diff --git a/drv/gpio/gpio_driver.h b/drv/gpio/gpio_driver.h new file mode 100644 index 0000000..8b59dfe --- /dev/null +++ b/drv/gpio/gpio_driver.h @@ -0,0 +1,41 @@ +#ifndef GPIO_DRIVER_H__ +#define GPIO_DRIVER_H__ + +#include "common_types.h" +#include "py32md530.h" +#include + +typedef enum { + GPIO_MODE_INPUT = 0x00, + GPIO_MODE_OUTPUT = 0x01, + GPIO_MODE_AF = 0x02, + GPIO_MODE_ANALOG = 0x03, +} gpio_mode_t; + +typedef enum { + GPIO_PUPD_NONE = 0x00, + GPIO_PUPD_PULLUP = 0x01, + GPIO_PUPD_PULLDOWN = 0x02, +} gpio_pupd_t; + +typedef enum { + GPIO_SPEED_LOW = 0x00, + GPIO_SPEED_MEDIUM = 0x01, + GPIO_SPEED_HIGH = 0x03, +} gpio_speed_t; + +typedef struct { + GPIO_TypeDef *port; + uint32_t pin; + gpio_mode_t mode; + gpio_pupd_t pupd; + gpio_speed_t speed; + uint8_t af_num; +} gpio_config_t; + +ret_code_t gpio_init(const gpio_config_t *config); +ret_code_t gpio_set_level(GPIO_TypeDef *port, uint32_t pin, uint8_t level); +uint8_t gpio_get_level(GPIO_TypeDef *port, uint32_t pin); +ret_code_t gpio_toggle(GPIO_TypeDef *port, uint32_t pin); + +#endif diff --git a/drv/i2c/i2c_driver.c b/drv/i2c/i2c_driver.c new file mode 100644 index 0000000..1344837 --- /dev/null +++ b/drv/i2c/i2c_driver.c @@ -0,0 +1,155 @@ +#include "i2c_driver.h" +#include "py32md530.h" +#include "system_py32md530.h" +#include "config.h" + +#define I2C_TIMEOUT 10000 + +static void i2c_wait_flag(uint32_t flag) +{ + uint32_t timeout = I2C_TIMEOUT; + while (!(I2C1->ISR & flag)) { + if (--timeout == 0) break; + } +} + +ret_code_t i2c_init(uint32_t speed) +{ + uint32_t timing; + + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; + + I2C1->CR1 &= ~I2C_CR1_PE_Msk; + + timing = (SystemCoreClock / speed) - 1; + if (timing > 0x3F) timing = 0x3F; + I2C1->TIMINGR = timing; + + I2C1->CR1 = I2C_CR1_PE_Msk; + + return RET_OK; +} + +ret_code_t i2c_deinit(void) +{ + I2C1->CR1 &= ~I2C_CR1_PE_Msk; + RCC->APB1ENR &= ~RCC_APB1ENR_I2C1EN; + return RET_OK; +} + +ret_code_t i2c_master_write(uint8_t dev_addr, const uint8_t *data, uint32_t len) +{ + uint32_t i; + + I2C1->CR2 = (dev_addr << 1) + | (len << 16) + | (1UL << 13); + + I2C1->CR2 |= (1UL << 14); + + i2c_wait_flag(I2C_ISR_TXIS_Msk); + + for (i = 0; i < len; i++) { + I2C1->TXDR = data[i]; + if (i < len - 1) { + i2c_wait_flag(I2C_ISR_TXIS_Msk); + } + } + + i2c_wait_flag(I2C_ISR_STOPF_Msk); + I2C1->ICR |= I2C_ISR_STOPF_Msk; + + return RET_OK; +} + +ret_code_t i2c_master_read(uint8_t dev_addr, uint8_t *data, uint32_t len) +{ + uint32_t i; + + I2C1->CR2 = (dev_addr << 1) + | (len << 16) + | (1UL << 13); + + I2C1->CR2 |= (1UL << 14); + + for (i = 0; i < len; i++) { + i2c_wait_flag(I2C_ISR_RXNE_Msk); + data[i] = (uint8_t)I2C1->RXDR; + } + + i2c_wait_flag(I2C_ISR_STOPF_Msk); + I2C1->ICR |= I2C_ISR_STOPF_Msk; + + return RET_OK; +} + +ret_code_t i2c_mem_write(uint8_t dev_addr, uint16_t mem_addr, uint8_t mem_addr_size, const uint8_t *data, uint32_t len) +{ + uint8_t buf[len + 2]; + uint32_t i; + + if (mem_addr_size == 1) { + buf[0] = (uint8_t)(mem_addr & 0xFF); + } else { + buf[0] = (uint8_t)((mem_addr >> 8) & 0xFF); + buf[1] = (uint8_t)(mem_addr & 0xFF); + } + + for (i = 0; i < len; i++) { + buf[mem_addr_size + i] = data[i]; + } + + return i2c_master_write(dev_addr, buf, len + mem_addr_size); +} + +ret_code_t i2c_mem_read(uint8_t dev_addr, uint16_t mem_addr, uint8_t mem_addr_size, uint8_t *data, uint32_t len) +{ + uint8_t addr_buf[2]; + + if (mem_addr_size == 1) { + addr_buf[0] = (uint8_t)(mem_addr & 0xFF); + } else { + addr_buf[0] = (uint8_t)((mem_addr >> 8) & 0xFF); + addr_buf[1] = (uint8_t)(mem_addr & 0xFF); + } + + I2C1->CR2 = (dev_addr << 1) + | (mem_addr_size << 16) + | (1UL << 13); + + I2C1->CR2 |= (1UL << 14); + + if (mem_addr_size == 1) { + i2c_wait_flag(I2C_ISR_TXIS_Msk); + I2C1->TXDR = addr_buf[0]; + } else { + i2c_wait_flag(I2C_ISR_TXIS_Msk); + I2C1->TXDR = addr_buf[0]; + i2c_wait_flag(I2C_ISR_TXIS_Msk); + I2C1->TXDR = addr_buf[1]; + } + + i2c_wait_flag(I2C_ISR_STOPF_Msk); + I2C1->ICR |= I2C_ISR_STOPF_Msk; + + return i2c_master_read(dev_addr, data, len); +} + +ret_code_t i2c_check_device(uint8_t dev_addr) +{ + I2C1->CR2 = (dev_addr << 1) + | (0 << 16) + | (1UL << 13); + + I2C1->CR2 |= (1UL << 14); + + i2c_wait_flag(I2C_ISR_STOPF_Msk); + I2C1->ICR |= I2C_ISR_STOPF_Msk; + + if (I2C1->ISR & I2C_ISR_NACKF_Msk) { + I2C1->ICR |= I2C_ISR_NACKF_Msk; + return RET_ERROR; + } + + return RET_OK; +} diff --git a/drv/i2c/i2c_driver.h b/drv/i2c/i2c_driver.h new file mode 100644 index 0000000..ce6a3f6 --- /dev/null +++ b/drv/i2c/i2c_driver.h @@ -0,0 +1,20 @@ +#ifndef I2C_DRIVER_H__ +#define I2C_DRIVER_H__ + +#include "common_types.h" +#include + +typedef enum { + I2C_SPEED_STANDARD = 100000, + I2C_SPEED_FAST = 400000, +} i2c_speed_t; + +ret_code_t i2c_init(uint32_t speed); +ret_code_t i2c_deinit(void); +ret_code_t i2c_master_write(uint8_t dev_addr, const uint8_t *data, uint32_t len); +ret_code_t i2c_master_read(uint8_t dev_addr, uint8_t *data, uint32_t len); +ret_code_t i2c_mem_write(uint8_t dev_addr, uint16_t mem_addr, uint8_t mem_addr_size, const uint8_t *data, uint32_t len); +ret_code_t i2c_mem_read(uint8_t dev_addr, uint16_t mem_addr, uint8_t mem_addr_size, uint8_t *data, uint32_t len); +ret_code_t i2c_check_device(uint8_t dev_addr); + +#endif diff --git a/drv/log/log_driver.c b/drv/log/log_driver.c new file mode 100644 index 0000000..933baa9 --- /dev/null +++ b/drv/log/log_driver.c @@ -0,0 +1,43 @@ +#include "log_driver.h" +#include "uart_driver.h" +#include +#include +#include + +#define LOG_BUF_SIZE 128 + +int _write(int file, char *ptr, int len) +{ + (void)file; + + if (ptr == NULL || len <= 0) { + return 0; + } + + uart_send(UART_ID_UART1, (const uint8_t *)ptr, (uint32_t)len); + + return len; +} + +ret_code_t log_init(void) +{ + return RET_OK; +} + +void log_out(const char *fmt, ...) +{ + char buf[LOG_BUF_SIZE]; + va_list args; + int len; + + va_start(args, fmt); + len = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (len > 0) { + if ((uint32_t)len >= sizeof(buf)) { + len = (int)sizeof(buf) - 1; + } + uart_send(UART_ID_UART1, (const uint8_t *)buf, (uint32_t)len); + } +} diff --git a/drv/log/log_driver.h b/drv/log/log_driver.h new file mode 100644 index 0000000..a9a068e --- /dev/null +++ b/drv/log/log_driver.h @@ -0,0 +1,15 @@ +#ifndef LOG_DRIVER_H__ +#define LOG_DRIVER_H__ + +#include "common_types.h" +#include + +#define LOG_LEVEL_DEBUG 0 +#define LOG_LEVEL_INFO 1 +#define LOG_LEVEL_WARN 2 +#define LOG_LEVEL_ERROR 3 + +ret_code_t log_init(void); +void log_out(const char *fmt, ...); + +#endif diff --git a/drv/system/sys_data_bus.c b/drv/system/sys_data_bus.c new file mode 100644 index 0000000..ba2a5c7 --- /dev/null +++ b/drv/system/sys_data_bus.c @@ -0,0 +1,54 @@ +#include "sys_data_bus.h" + +static sys_data_bus_value_t data_pool[SYS_DATA_BUS_ID_MAX]; +static uint32_t flag_bits; + +ret_code_t sys_data_bus_init(void) +{ + uint32_t i; + + for (i = 0; i < SYS_DATA_BUS_ID_MAX; i++) { + data_pool[i].u = 0; + } + + flag_bits = 0; + + return RET_OK; +} + +void sys_data_bus_write(sys_data_bus_id_t id, sys_data_bus_value_t value) +{ + if (id >= SYS_DATA_BUS_ID_MAX) { + return; + } + + data_pool[id] = value; +} + +sys_data_bus_value_t sys_data_bus_read(sys_data_bus_id_t id) +{ + if (id >= SYS_DATA_BUS_ID_MAX) { + sys_data_bus_value_t zero = {.u = 0}; + return zero; + } + + return data_pool[id]; +} + +void sys_data_bus_set_flag(uint8_t bit) +{ + if (bit >= 32) return; + flag_bits |= (1UL << bit); +} + +void sys_data_bus_clear_flag(uint8_t bit) +{ + if (bit >= 32) return; + flag_bits &= ~(1UL << bit); +} + +uint8_t sys_data_bus_get_flag(uint8_t bit) +{ + if (bit >= 32) return 0; + return (flag_bits >> bit) & 1; +} diff --git a/drv/system/sys_data_bus.h b/drv/system/sys_data_bus.h new file mode 100644 index 0000000..6c2870a --- /dev/null +++ b/drv/system/sys_data_bus.h @@ -0,0 +1,40 @@ +#ifndef SYS_DATA_BUS_H__ +#define SYS_DATA_BUS_H__ + +#include "common_types.h" +#include + +#define SYS_DATA_BUS_ID_MAX 32 + +typedef enum { + SYS_DATA_BUS_MOTOR_CURRENT = 0, + SYS_DATA_BUS_MOTOR_POSITION, + SYS_DATA_BUS_MOTOR_TARGET, + SYS_DATA_BUS_MOTOR_SPEED, + SYS_DATA_BUS_MOTOR_STATE, + SYS_DATA_BUS_AS5600_ANGLE, + SYS_DATA_BUS_AS5600_RAW, + SYS_DATA_BUS_DI_MAX_STATE, + SYS_DATA_BUS_DI_MIN_STATE, + SYS_DATA_BUS_CALIBRATED_STEPS, + SYS_DATA_BUS_ORIGIN_STEPS, + SYS_DATA_BUS_MAX_STEPS, + SYS_DATA_BUS_IS_CALIBRATED, + SYS_DATA_BUS_IS_DI_MAX_INSTALLED, + SYS_DATA_BUS_MODBUS_SLAVE_ADDR, +} sys_data_bus_id_t; + +typedef union { + float f; + int32_t i; + uint32_t u; +} sys_data_bus_value_t; + +ret_code_t sys_data_bus_init(void); +void sys_data_bus_write(sys_data_bus_id_t id, sys_data_bus_value_t value); +sys_data_bus_value_t sys_data_bus_read(sys_data_bus_id_t id); +void sys_data_bus_set_flag(uint8_t bit); +void sys_data_bus_clear_flag(uint8_t bit); +uint8_t sys_data_bus_get_flag(uint8_t bit); + +#endif diff --git a/drv/system/system_driver.c b/drv/system/system_driver.c new file mode 100644 index 0000000..082ed00 --- /dev/null +++ b/drv/system/system_driver.c @@ -0,0 +1,44 @@ +#include "system_driver.h" +#include "py32md530.h" +#include "system_py32md530.h" +#include "config.h" + +static volatile uint32_t sys_tick_count = 0; + +void SysTick_Handler(void) +{ + sys_tick_count++; +} + +ret_code_t system_driver_init(void) +{ + SystemCoreClockUpdate(); + + SysTick_Config(SYSTICK_RELOAD_VAL); + + NVIC_SetPriority(SysTick_IRQn, 0x0F); + + return RET_OK; +} + +void system_delay_ms(uint32_t ms) +{ + uint32_t start = sys_tick_count; + while ((sys_tick_count - start) < ms); +} + +void system_delay_us(uint32_t us) +{ + uint32_t count = 0; + uint32_t fcpu = SystemCoreClock; + uint32_t cycles = (fcpu / 1000000) * us / 3; + + while (count < cycles) { + count++; + } +} + +uint32_t system_get_tick(void) +{ + return sys_tick_count; +} diff --git a/drv/system/system_driver.h b/drv/system/system_driver.h new file mode 100644 index 0000000..bac22c7 --- /dev/null +++ b/drv/system/system_driver.h @@ -0,0 +1,12 @@ +#ifndef SYSTEM_DRIVER_H__ +#define SYSTEM_DRIVER_H__ + +#include "common_types.h" +#include + +ret_code_t system_driver_init(void); +void system_delay_ms(uint32_t ms); +void system_delay_us(uint32_t us); +uint32_t system_get_tick(void); + +#endif diff --git a/drv/timer/timer_driver.c b/drv/timer/timer_driver.c new file mode 100644 index 0000000..effe5ca --- /dev/null +++ b/drv/timer/timer_driver.c @@ -0,0 +1,163 @@ +#include "timer_driver.h" +#include "py32md530.h" +#include "system_py32md530.h" +#include "config.h" + +ret_code_t timer_pwm_init(uint32_t freq_hz) +{ + uint32_t prescaler, period; + + RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; + + TIM1->CR1 &= ~TIM_CR1_CEN; + TIM1->SR = 0; + TIM1->BDTR |= TIM_BDTR_MOE_Msk; + TIM1->BDTR &= ~TIM_BDTR_BKE_Msk; + + prescaler = (SystemCoreClock / 1000000) - 1; + + period = (1000000 / freq_hz) - 1; + + TIM1->PSC = prescaler; + TIM1->ARR = period; + + TIM1->CCMR1 = (0x6 << 4) + | (0x6 << 12); + + TIM1->CCMR2 = (0x6 << 4); + + TIM1->CCER |= TIM_CCER_CC1E_Msk + | TIM_CCER_CC2E_Msk + | TIM_CCER_CC3E_Msk; + + TIM1->CCER |= TIM_CCER_CC1NE_Msk + | TIM_CCER_CC2NE_Msk + | TIM_CCER_CC3NE_Msk; + + TIM1->BDTR |= TIM_BDTR_MOE_Msk; + + TIM1->EGR |= TIM_EGR_UG_Msk; + + TIM1->CR1 |= TIM_CR1_ARPE_Msk; + TIM1->CR1 |= TIM_CR1_CEN_Msk; + + return RET_OK; +} + +ret_code_t timer_stepper_pwm_init(uint32_t freq_hz, uint16_t resolution) +{ + if (resolution == 0) return RET_INVALID_PARAM; + + RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; + + TIM1->CR1 &= ~TIM_CR1_CEN; + TIM1->SR = 0; + + TIM1->PSC = 0; + + TIM1->ARR = resolution - 1; + + TIM1->CCMR1 = (0x6 << 4) + | (0x6 << 12); + + TIM1->CCMR2 = 0; + + TIM1->CCER |= TIM_CCER_CC1E_Msk + | TIM_CCER_CC2E_Msk; + + TIM1->CCER |= TIM_CCER_CC1NE_Msk + | TIM_CCER_CC2NE_Msk; + + TIM1->CCER &= ~(TIM_CCER_CC3E_Msk | TIM_CCER_CC3NE_Msk); + + TIM1->BDTR |= TIM_BDTR_MOE_Msk; + + TIM1->EGR |= TIM_EGR_UG_Msk; + + TIM1->CR1 |= TIM_CR1_ARPE_Msk; + TIM1->CR1 |= TIM_CR1_CEN_Msk; + + (void)freq_hz; + return RET_OK; +} + +ret_code_t timer_pwm_set_duty(timer_channel_t ch, uint16_t duty) +{ + switch (ch) { + case TIMER_CHANNEL_1: + TIM1->CCR1 = duty; + break; + case TIMER_CHANNEL_2: + TIM1->CCR2 = duty; + break; + case TIMER_CHANNEL_3: + TIM1->CCR3 = duty; + break; + default: + return RET_INVALID_PARAM; + } + return RET_OK; +} + +ret_code_t timer_pwm_set_compare(timer_channel_t ch, uint16_t compare) +{ + return timer_pwm_set_duty(ch, compare); +} + +ret_code_t timer_pwm_start(void) +{ + TIM1->CR1 |= TIM_CR1_CEN_Msk; + TIM1->BDTR |= TIM_BDTR_MOE_Msk; + return RET_OK; +} + +ret_code_t timer_pwm_stop(void) +{ + TIM1->BDTR &= ~TIM_BDTR_MOE_Msk; + TIM1->CR1 &= ~TIM_CR1_CEN_Msk; + return RET_OK; +} + +ret_code_t timer_pwm_deinit(void) +{ + TIM1->CR1 &= ~TIM_CR1_CEN_Msk; + TIM1->BDTR = 0; + TIM1->CCER = 0; + TIM1->SR = 0; + + RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN; + return RET_OK; +} + +ret_code_t timer_encoder_init(void) +{ + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + + TIM3->CR1 &= ~TIM_CR1_CEN; + TIM3->SR = 0; + + TIM3->PSC = 0; + TIM3->ARR = 0xFFFF; + + TIM3->SMCR = (0x3 << 0); + + TIM3->CCMR1 = (0x01 << 0) + | (0x01 << 8); + + TIM3->CCER = 0; + + TIM3->EGR |= TIM_EGR_UG_Msk; + TIM3->CR1 |= TIM_CR1_CEN_Msk; + + return RET_OK; +} + +uint16_t timer_encoder_get_count(void) +{ + return (uint16_t)TIM3->CNT; +} + +void timer_encoder_clear_count(void) +{ + TIM3->CNT = 0; +} diff --git a/drv/timer/timer_driver.h b/drv/timer/timer_driver.h new file mode 100644 index 0000000..7a1ec73 --- /dev/null +++ b/drv/timer/timer_driver.h @@ -0,0 +1,27 @@ +#ifndef TIMER_DRIVER_H__ +#define TIMER_DRIVER_H__ + +#include "common_types.h" +#include + +typedef enum { + TIMER_CHANNEL_1 = 0, + TIMER_CHANNEL_2 = 1, + TIMER_CHANNEL_3 = 2, + TIMER_CHANNEL_4 = 3, +} timer_channel_t; + +ret_code_t timer_pwm_init(uint32_t freq_hz); +ret_code_t timer_pwm_set_duty(timer_channel_t ch, uint16_t duty); +ret_code_t timer_pwm_set_compare(timer_channel_t ch, uint16_t compare); +ret_code_t timer_pwm_start(void); +ret_code_t timer_pwm_stop(void); +ret_code_t timer_pwm_deinit(void); + +ret_code_t timer_stepper_pwm_init(uint32_t freq_hz, uint16_t resolution); + +ret_code_t timer_encoder_init(void); +uint16_t timer_encoder_get_count(void); +void timer_encoder_clear_count(void); + +#endif diff --git a/drv/uart/uart_driver.c b/drv/uart/uart_driver.c new file mode 100644 index 0000000..19d84f9 --- /dev/null +++ b/drv/uart/uart_driver.c @@ -0,0 +1,337 @@ +#include "uart_driver.h" +#include "py32md530.h" +#include "system_py32md530.h" +#include "system_driver.h" +#include "config.h" +#include + +#define UART_FIFO_SIZE 256 + +typedef struct { + uint8_t buffer[UART_FIFO_SIZE]; + volatile uint32_t head; + volatile uint32_t tail; + uint8_t initialized; +} uart_fifo_t; + +static uart_fifo_t uart_fifos[UART_ID_COUNT]; +static uart_stats_t uart_statistics[UART_ID_COUNT]; + +static void uart_fifo_init(uart_fifo_t *fifo) +{ + fifo->head = 0; + fifo->tail = 0; + fifo->initialized = 1; +} + +static void uart_stats_init(void) +{ + uint32_t i; + for (i = 0; i < UART_ID_COUNT; i++) { + uart_statistics[i].tx_bytes = 0; + uart_statistics[i].rx_bytes = 0; + uart_statistics[i].overflow_errors = 0; + } +} + +static void uart_fifo_push(uart_fifo_t *fifo, uint8_t data) +{ + uint32_t next = (fifo->head + 1) % UART_FIFO_SIZE; + if (next != fifo->tail) { + fifo->buffer[fifo->head] = data; + fifo->head = next; + } +} + +static uint32_t uart_fifo_pop(uart_fifo_t *fifo, uint8_t *data) +{ + if (fifo->tail == fifo->head) { + return 0; + } + *data = fifo->buffer[fifo->tail]; + fifo->tail = (fifo->tail + 1) % UART_FIFO_SIZE; + return 1; +} + +static uint32_t uart_fifo_count(uart_fifo_t *fifo) +{ + return (fifo->head - fifo->tail) % UART_FIFO_SIZE; +} + +void USART1_IRQHandler(void) +{ + if (USART1->SR & USART_SR_RXNE_Msk) { + uint8_t data = (uint8_t)(USART1->DR & 0xFF); + uart_statistics[UART_ID_USART1].rx_bytes++; + { + uint32_t next = (uart_fifos[UART_ID_USART1].head + 1) % UART_FIFO_SIZE; + if (next == uart_fifos[UART_ID_USART1].tail) { + uart_statistics[UART_ID_USART1].overflow_errors++; + } + } + uart_fifo_push(&uart_fifos[UART_ID_USART1], data); + } + if (USART1->SR & USART_SR_TC_Msk) { + USART1->SR &= ~USART_SR_TC_Msk; + } +} + +void UART1_IRQHandler(void) +{ + if (UART1->SR & USART_SR_RXNE_Msk) { + uint8_t data = (uint8_t)(UART1->DR & 0xFF); + uart_statistics[UART_ID_UART1].rx_bytes++; + { + uint32_t next = (uart_fifos[UART_ID_UART1].head + 1) % UART_FIFO_SIZE; + if (next == uart_fifos[UART_ID_UART1].tail) { + uart_statistics[UART_ID_UART1].overflow_errors++; + } + } + uart_fifo_push(&uart_fifos[UART_ID_UART1], data); + } + if (UART1->SR & USART_SR_TC_Msk) { + UART1->SR &= ~USART_SR_TC_Msk; + } +} + +void LPUART1_IRQHandler(void) +{ + if (LPUART1->ISR & (1UL << 5)) { + uint8_t data = (uint8_t)(LPUART1->DR & 0xFF); + uart_statistics[UART_ID_LPUART1].rx_bytes++; + { + uint32_t next = (uart_fifos[UART_ID_LPUART1].head + 1) % UART_FIFO_SIZE; + if (next == uart_fifos[UART_ID_LPUART1].tail) { + uart_statistics[UART_ID_LPUART1].overflow_errors++; + } + } + uart_fifo_push(&uart_fifos[UART_ID_LPUART1], data); + } +} + +static ret_code_t usart1_init(const uart_config_t *config) +{ + uint32_t brr; + + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + + USART1->CR1 &= ~USART_CR1_UE_Msk; + + brr = (SystemCoreClock + config->baudrate / 2) / config->baudrate; + USART1->BRR = brr; + + USART1->CR1 = USART_CR1_UE_Msk + | USART_CR1_TE_Msk + | USART_CR1_RE_Msk + | USART_CR1_RXNEIE_Msk; + + USART1->CR3 = USART_CR3_DMAR_Msk + | USART_CR3_DMAT_Msk; + + NVIC_SetPriority(USART1_IRQn, 0x08); + NVIC_EnableIRQ(USART1_IRQn); + + uart_stats_init(); + uart_fifo_init(&uart_fifos[UART_ID_USART1]); + + return RET_OK; +} + +static ret_code_t uart1_init(const uart_config_t *config) +{ + uint32_t brr; + + RCC->APB1ENR |= RCC_APB1ENR_UART1EN; + + UART1->CR1 &= ~USART_CR1_UE_Msk; + + brr = (SystemCoreClock + config->baudrate / 2) / config->baudrate; + UART1->BRR = brr; + + UART1->CR1 = USART_CR1_UE_Msk + | USART_CR1_TE_Msk + | USART_CR1_RE_Msk + | USART_CR1_RXNEIE_Msk; + + UART1->CR3 = USART_CR3_DMAR_Msk + | USART_CR3_DMAT_Msk; + + NVIC_SetPriority(UART1_IRQn, 0x08); + NVIC_EnableIRQ(UART1_IRQn); + + uart_fifo_init(&uart_fifos[UART_ID_UART1]); + + return RET_OK; +} + +static ret_code_t lpuart1_init(const uart_config_t *config) +{ + RCC->APB1ENR |= RCC_APB1ENR_LPUART1EN; + + LPUART1->CR1 &= ~(1UL << 0); + + LPUART1->BRR = (256 * SystemCoreClock + config->baudrate / 2) / config->baudrate; + + LPUART1->CR1 = (1UL << 0) + | (1UL << 2) + | (1UL << 3) + | (1UL << 5); + + NVIC_SetPriority(LPUART1_IRQn, 0x08); + NVIC_EnableIRQ(LPUART1_IRQn); + + uart_fifo_init(&uart_fifos[UART_ID_LPUART1]); + + return RET_OK; +} + +ret_code_t uart_init(uart_id_t id, const uart_config_t *config) +{ + if (id >= UART_ID_COUNT || config == NULL) { + return RET_INVALID_PARAM; + } + + switch (id) { + case UART_ID_USART1: + return usart1_init(config); + case UART_ID_UART1: + return uart1_init(config); + case UART_ID_LPUART1: + return lpuart1_init(config); + default: + return RET_ERROR; + } +} + +ret_code_t uart_deinit(uart_id_t id) +{ + switch (id) { + case UART_ID_USART1: + NVIC_DisableIRQ(USART1_IRQn); + USART1->CR1 = 0; + RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN; + break; + case UART_ID_UART1: + NVIC_DisableIRQ(UART1_IRQn); + UART1->CR1 = 0; + RCC->APB1ENR &= ~RCC_APB1ENR_UART1EN; + break; + case UART_ID_LPUART1: + NVIC_DisableIRQ(LPUART1_IRQn); + LPUART1->CR1 = 0; + RCC->APB1ENR &= ~RCC_APB1ENR_LPUART1EN; + break; + default: + return RET_INVALID_PARAM; + } + return RET_OK; +} + +ret_code_t uart_send(uart_id_t id, const uint8_t *data, uint32_t len) +{ + uint32_t i; + + if (id == UART_ID_USART1) { + uart_set_rs485_dir(UART_ID_USART1, 1); + } + + for (i = 0; i < len; i++) { + switch (id) { + case UART_ID_USART1: + while (!(USART1->SR & USART_SR_TXE_Msk)); + USART1->DR = data[i]; + while (!(USART1->SR & USART_SR_TC_Msk)); + uart_statistics[UART_ID_USART1].tx_bytes++; + break; + case UART_ID_UART1: + while (!(UART1->SR & USART_SR_TXE_Msk)); + UART1->DR = data[i]; + while (!(UART1->SR & USART_SR_TC_Msk)); + uart_statistics[UART_ID_UART1].tx_bytes++; + break; + case UART_ID_LPUART1: + while (!(LPUART1->ISR & (1UL << 0))); + LPUART1->DR = data[i]; + uart_statistics[UART_ID_LPUART1].tx_bytes++; + break; + default: + return RET_INVALID_PARAM; + } + } + + if (id == UART_ID_USART1) { + volatile uint32_t delay = (SystemCoreClock / 1000000) * 2; + while (delay--); + uart_set_rs485_dir(UART_ID_USART1, 0); + } + return RET_OK; +} + +ret_code_t uart_receive(uart_id_t id, uint8_t *data, uint32_t len, uint32_t timeout) +{ + uint32_t i; + uint32_t tick_start = 0; + + if (timeout > 0) { + tick_start = system_get_tick(); + } + + for (i = 0; i < len; i++) { + while (uart_fifo_count(&uart_fifos[id]) == 0) { + if (timeout > 0) { + if ((system_get_tick() - tick_start) >= timeout) { + return RET_TIMEOUT; + } + } + } + uart_fifo_pop(&uart_fifos[id], &data[i]); + } + return RET_OK; +} + +ret_code_t uart_send_dma(uart_id_t id, const uint8_t *data, uint32_t len) +{ + return uart_send(id, data, len); +} + +ret_code_t uart_receive_dma(uart_id_t id, uint8_t *data, uint32_t len) +{ + return uart_receive(id, data, len, 0); +} + +uint32_t uart_available(uart_id_t id) +{ + return uart_fifo_count(&uart_fifos[id]); +} + +ret_code_t uart_set_rs485_dir(uart_id_t id, uint8_t tx_mode) +{ + if (id != UART_ID_USART1) { + return RET_NOT_SUPPORTED; + } + + if (tx_mode) { + USART1_RS485_DIR_PORT->BSRR = (1UL << USART1_RS485_DIR_PIN); + } else { + USART1_RS485_DIR_PORT->BRR = (1UL << USART1_RS485_DIR_PIN); + } + return RET_OK; +} + +const uart_stats_t* uart_get_stats(uart_id_t id) +{ + if (id >= UART_ID_COUNT) { + return NULL; + } + return &uart_statistics[id]; +} + +void uart_reset_stats(uart_id_t id) +{ + if (id >= UART_ID_COUNT) { + return; + } + uart_statistics[id].tx_bytes = 0; + uart_statistics[id].rx_bytes = 0; + uart_statistics[id].overflow_errors = 0; +} diff --git a/drv/uart/uart_driver.h b/drv/uart/uart_driver.h new file mode 100644 index 0000000..b7735fd --- /dev/null +++ b/drv/uart/uart_driver.h @@ -0,0 +1,38 @@ +#ifndef UART_DRIVER_H__ +#define UART_DRIVER_H__ + +#include "common_types.h" +#include + +typedef enum { + UART_ID_USART1 = 0, + UART_ID_UART1, + UART_ID_LPUART1, + UART_ID_COUNT, +} uart_id_t; + +typedef struct { + uint32_t tx_bytes; + uint32_t rx_bytes; + uint32_t overflow_errors; +} uart_stats_t; + +typedef struct { + uint32_t baudrate; + uint8_t data_bits; + uint8_t stop_bits; + uint8_t parity; +} uart_config_t; + +ret_code_t uart_init(uart_id_t id, const uart_config_t *config); +ret_code_t uart_deinit(uart_id_t id); +ret_code_t uart_send(uart_id_t id, const uint8_t *data, uint32_t len); +ret_code_t uart_receive(uart_id_t id, uint8_t *data, uint32_t len, uint32_t timeout); +ret_code_t uart_send_dma(uart_id_t id, const uint8_t *data, uint32_t len); +ret_code_t uart_receive_dma(uart_id_t id, uint8_t *data, uint32_t len); +uint32_t uart_available(uart_id_t id); +ret_code_t uart_set_rs485_dir(uart_id_t id, uint8_t tx_mode); +const uart_stats_t* uart_get_stats(uart_id_t id); +void uart_reset_stats(uart_id_t id); + +#endif diff --git a/libs/CMSIS/cmsis_compiler.h b/libs/CMSIS/cmsis_compiler.h new file mode 100644 index 0000000..c6f73bc --- /dev/null +++ b/libs/CMSIS/cmsis_compiler.h @@ -0,0 +1,52 @@ +#ifndef __CMSIS_COMPILER_H__ +#define __CMSIS_COMPILER_H__ + +#include + +#define __I volatile const +#define __O volatile +#define __IO volatile + +#define __IM volatile const +#define __OM volatile +#define __IOM volatile + +#define __CLZ __builtin_clz + +#ifndef __ASM +#define __ASM __asm +#endif + +#ifndef __INLINE +#define __INLINE inline +#endif + +#ifndef __STATIC_INLINE +#define __STATIC_INLINE static inline +#endif + +#ifndef __NO_RETURN +#define __NO_RETURN __attribute__((__noreturn__)) +#endif + +#ifndef __USED +#define __USED __attribute__((used)) +#endif + +#ifndef __WEAK +#define __WEAK __attribute__((weak)) +#endif + +#ifndef __UNALIGNED_UINT32 +#define __UNALIGNED_UINT32(x) (*((volatile uint32_t *)(x))) +#endif + +#ifndef __PACKED +#define __PACKED __attribute__((packed)) +#endif + +#ifndef __ALIGNED +#define __ALIGNED(x) __attribute__((aligned(x))) +#endif + +#endif diff --git a/libs/CMSIS/cmsis_gcc.h b/libs/CMSIS/cmsis_gcc.h new file mode 100644 index 0000000..40ce01a --- /dev/null +++ b/libs/CMSIS/cmsis_gcc.h @@ -0,0 +1,161 @@ +#ifndef __CMSIS_GCC_H__ +#define __CMSIS_GCC_H__ + +#include + +#define __DMB() __asm volatile ("dmb" ::: "memory") +#define __DSB() __asm volatile ("dsb" ::: "memory") +#define __ISB() __asm volatile ("isb" ::: "memory") +#define __NOP() __asm volatile ("nop") +#define __WFI() __asm volatile ("wfi") +#define __WFE() __asm volatile ("wfe") +#define __SEV() __asm volatile ("sev") + +__STATIC_INLINE uint32_t __get_PSP(void) +{ + uint32_t result; + __ASM volatile ("MRS %0, psp" : "=r" (result)); + return result; +} + +__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack)); +} + +__STATIC_INLINE uint32_t __get_MSP(void) +{ + uint32_t result; + __ASM volatile ("MRS %0, msp" : "=r" (result)); + return result; +} + +__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack)); +} + +__STATIC_INLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + __ASM volatile ("MRS %0, primask" : "=r" (result)); + return result; +} + +__STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask)); +} + +__STATIC_INLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" ::: "memory"); +} + +__STATIC_INLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" ::: "memory"); +} + +__STATIC_INLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + __ASM volatile ("MRS %0, control" : "=r" (result)); + return result; +} + +__STATIC_INLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control)); +} + +__STATIC_INLINE void __BKPT(uint32_t value) +{ + __ASM volatile ("bkpt %0" : : "i" (value)); +} + +__STATIC_INLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value)); + return result; +} + +__STATIC_INLINE uint32_t __REV(uint32_t value) +{ + uint32_t result; + __ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value)); + return result; +} + +__STATIC_INLINE uint32_t __REV16(uint32_t value) +{ + uint32_t result; + __ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value)); + return result; +} + +__STATIC_INLINE int32_t __REVSH(int32_t value) +{ + int32_t result; + __ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value)); + return result; +} + +__STATIC_INLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + __ASM volatile ("rrx %0, %1" : "=r" (result) : "r" (value)); + return result; +} + +__STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + uint32_t result; + __ASM volatile ("ror %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2)); + return result; +} + +__STATIC_INLINE uint32_t __LDREXB(uint8_t *addr) +{ + uint32_t result; + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr)); + return result; +} + +__STATIC_INLINE uint32_t __LDREXH(uint16_t *addr) +{ + uint32_t result; + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr)); + return result; +} + +__STATIC_INLINE uint32_t __LDREXW(uint32_t *addr) +{ + uint32_t result; + __ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr)); + return result; +} + +__STATIC_INLINE uint32_t __STREXB(uint8_t value, uint8_t *addr) +{ + uint32_t result; + __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value)); + return result; +} + +__STATIC_INLINE uint32_t __STREXH(uint16_t value, uint16_t *addr) +{ + uint32_t result; + __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value)); + return result; +} + +__STATIC_INLINE uint32_t __STREXW(uint32_t value, uint32_t *addr) +{ + uint32_t result; + __ASM volatile ("strex %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value)); + return result; +} + +#endif diff --git a/libs/CMSIS/cmsis_version.h b/libs/CMSIS/cmsis_version.h new file mode 100644 index 0000000..d366617 --- /dev/null +++ b/libs/CMSIS/cmsis_version.h @@ -0,0 +1,11 @@ +#ifndef __CMSIS_VERSION_H__ +#define __CMSIS_VERSION_H__ + +#define __CMSIS_VERSION_MAIN (5U) +#define __CMSIS_VERSION_SUB (1U) +#define __CMSIS_VERSION_PATCH (0U) +#define __CMSIS_VERSION ((__CMSIS_VERSION_MAIN << 16U) | \ + (__CMSIS_VERSION_SUB << 8U) | \ + (__CMSIS_VERSION_PATCH)) + +#endif diff --git a/libs/CMSIS/core_cm0plus.h b/libs/CMSIS/core_cm0plus.h new file mode 100644 index 0000000..bd583ff --- /dev/null +++ b/libs/CMSIS/core_cm0plus.h @@ -0,0 +1,240 @@ +#ifndef __CORE_CM0PLUS_H__ +#define __CORE_CM0PLUS_H__ + +#include +#include "cmsis_version.h" +#include "cmsis_compiler.h" +#include "cmsis_gcc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define __CM0PLUS_REV 0x0000U +#define __MPU_PRESENT 0U +#define __VTOR_PRESENT 1U +#define __NVIC_PRIO_BITS 2U +#define __Vendor_SysTickConfig 0U + +typedef struct { + __IOM uint32_t ISER[1U]; + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; + uint32_t RESERVED1[31U]; + __IOM uint32_t ISPR[1U]; + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IPR[8U]; +} NVIC_Type; + +typedef struct { + __IM uint32_t CPUID; + __IOM uint32_t ICSR; + uint32_t RESERVED0; + __IOM uint32_t AIRCR; + __IOM uint32_t SCR; + __IOM uint32_t CCR; + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; + __IOM uint32_t SHCSR; +} SCB_Type; + +typedef struct { + __IOM uint32_t CTRL; + __IOM uint32_t LOAD; + __IOM uint32_t VAL; + __IM uint32_t CALIB; +} SysTick_Type; + +#define SCB_ACTLR_SPLISCIE_Pos 0U +#define SCB_ACTLR_SPLISCIE_Msk (1UL << SCB_ACTLR_SPLISCIE_Pos) + +#define SCB_ACTLR_DISOOFP_Pos 1U +#define SCB_ACTLR_DISOOFP_Msk (1UL << SCB_ACTLR_DISOOFP_Pos) + +#define SCB_ACTLR_DISFPCA_Pos 2U +#define SCB_ACTLR_DISFPCA_Msk (1UL << SCB_ACTLR_DISFPCA_Pos) + +#define SCB_CPUID_REVISION_Pos 20U +#define SCB_CPUID_REVISION_Msk (0xFU << SCB_CPUID_REVISION_Pos) +#define SCB_CPUID_PARTNO_Pos 4U +#define SCB_CPUID_PARTNO_Msk (0xFFFU << SCB_CPUID_PARTNO_Pos) +#define SCB_CPUID_CONSTANT_Pos 0U +#define SCB_CPUID_CONSTANT_Msk (0xFU << SCB_CPUID_CONSTANT_Pos) + +#define SCB_ICSR_NMIPENDSET_Pos 31U +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) +#define SCB_ICSR_PENDSVSET_Pos 28U +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) +#define SCB_ICSR_PENDSVCLR_Pos 27U +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) +#define SCB_ICSR_PENDSTSET_Pos 26U +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) +#define SCB_ICSR_PENDSTCLR_Pos 25U +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) +#define SCB_ICSR_ISRPREEMPT_Pos 23U +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) +#define SCB_ICSR_ISRPENDING_Pos 22U +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) +#define SCB_ICSR_VECTPENDING_Pos 12U +#define SCB_ICSR_VECTPENDING_Msk (0x3FFUL << SCB_ICSR_VECTPENDING_Pos) +#define SCB_ICSR_VECTACTIVE_Pos 0U +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL << SCB_ICSR_VECTACTIVE_Pos) + +#define SCB_AIRCR_VECTKEY_Pos 16U +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) +#define SCB_AIRCR_SYSRESETREQ_Pos 2U +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) +#define SCB_AIRCR_ENDIANESS_Pos 0U +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) + +#define SCB_SCR_SEVONPEND_Pos 4U +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) +#define SCB_SCR_SLEEPDEEP_Pos 2U +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) +#define SCB_SCR_SLEEPONEXIT_Pos 1U +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) + +#define SCB_CCR_STKALIGN_Pos 9U +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) +#define SCB_CCR_UNALIGN_TRP_Pos 3U +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) + +#define SCB_SHCSR_SVCALLPENDED_Pos 15U +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) + +#define SysTick_CTRL_COUNTFLAG_Pos 16U +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) +#define SysTick_CTRL_CLKSOURCE_Pos 2U +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) +#define SysTick_CTRL_TICKINT_Pos 1U +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) +#define SysTick_CTRL_ENABLE_Pos 0U +#define SysTick_CTRL_ENABLE_Msk (1UL << SysTick_CTRL_ENABLE_Pos) + +#define SysTick_LOAD_RELOAD_Pos 0U +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos) + +#define SysTick_VAL_CURRENT_Pos 0U +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos) + +#define SysTick_CALIB_TENMS_Pos 0U +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL << SysTick_CALIB_TENMS_Pos) +#define SysTick_CALIB_SKEW_Pos 30U +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) +#define SysTick_CALIB_NOREF_Pos 31U +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) + +#define SHP_START_ADDR 0xE000ED18U +#define VTOR_ADDR 0xE000ED08U + +#define NVIC_BASE 0xE000E100U +#define SCB_BASE 0xE000ED00U +#define SysTick_BASE 0xE000E010U + +#define NVIC ((NVIC_Type *)NVIC_BASE) +#define SCB ((SCB_Type *)SCB_BASE) +#define SysTick ((SysTick_Type *)SysTick_BASE) + +#define NonMaskableInt_IRQn (-14) +#define HardFault_IRQn (-13) +#define SVCall_IRQn (-5) +#define PendSV_IRQn (-2) +#define SysTick_IRQn (-1) + +typedef int32_t IRQn_Type; + +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->IPR[(uint32_t)IRQn] = (uint32_t)(priority << (8U - __NVIC_PRIO_BITS)); + } + else + { + SCB->SHP[(uint32_t)((int32_t)(IRQn) & 0xFUL) - 4UL] = (uint32_t)(priority << (8U - __NVIC_PRIO_BITS)); + } +} + +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return 1UL; + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); + NVIC_SetPriority(SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); + SysTick->VAL = 0UL; + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; + return 0UL; +} + +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return ((uint32_t)(NVIC->IPR[(uint32_t)IRQn] >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return ((uint32_t)(SCB->SHP[(uint32_t)((int32_t)(IRQn) & 0xFUL) - 4UL] >> (8U - __NVIC_PRIO_BITS))); + } +} + +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[0U] = (uint32_t)(1UL << ((uint32_t)(int32_t)IRQn) & 0x1FUL); +} + +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[0U] = (uint32_t)(1UL << ((uint32_t)(int32_t)IRQn) & 0x1FUL); +} + +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return ((uint32_t)((NVIC->ISPR[0U] >> ((uint32_t)(int32_t)IRQn)) & 1UL)); +} + +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[0U] = (uint32_t)(1UL << ((uint32_t)(int32_t)IRQn) & 0x1FUL); +} + +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[0U] = (uint32_t)(1UL << ((uint32_t)(int32_t)IRQn) & 0x1FUL); +} + +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); + SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_ENDIANESS_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); + for (;;) { __NOP(); } +} + +__STATIC_INLINE uint32_t SCB_GetVTOR(void) +{ + return (*(volatile uint32_t *)VTOR_ADDR); +} + +__STATIC_INLINE void SCB_SetVTOR(uint32_t offset) +{ + *(volatile uint32_t *)VTOR_ADDR = offset; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/device/py32md530.h b/libs/device/py32md530.h new file mode 100644 index 0000000..0852298 --- /dev/null +++ b/libs/device/py32md530.h @@ -0,0 +1,644 @@ +#ifndef __PY32MD530_H__ +#define __PY32MD530_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "core_cm0plus.h" + +#define __PY32MD530_H_VERSION 0x0100U + +#define FLASH_BASE 0x08000000UL +#define SRAM_BASE 0x20000000UL +#define PERIPH_BASE 0x40000000UL + +#define APB1PERIPH_BASE PERIPH_BASE +#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000UL) +#define AHB1PERIPH_BASE (PERIPH_BASE + 0x20000UL) +#define AHB2PERIPH_BASE (PERIPH_BASE + 0x200000UL) + +#define GPIOA_BASE (AHB2PERIPH_BASE + 0x00000000UL) +#define GPIOB_BASE (AHB2PERIPH_BASE + 0x00000400UL) +#define GPIOC_BASE (AHB2PERIPH_BASE + 0x00000800UL) +#define GPIOD_BASE (AHB2PERIPH_BASE + 0x00000C00UL) +#define GPIOF_BASE (AHB2PERIPH_BASE + 0x00001400UL) + +#define RCC_BASE (AHB1PERIPH_BASE + 0x00001000UL) + +#define USART1_BASE (APB2PERIPH_BASE + 0x3800UL) +#define UART1_BASE (APB1PERIPH_BASE + 0x4400UL) +#define LPUART1_BASE (APB1PERIPH_BASE + 0x4800UL) + +#define I2C1_BASE (APB1PERIPH_BASE + 0x5400UL) +#define SPI1_BASE (APB2PERIPH_BASE + 0x3000UL) + +#define TIM1_BASE (APB2PERIPH_BASE + 0x2C00UL) +#define TIM3_BASE (APB1PERIPH_BASE + 0x0400UL) +#define TIM14_BASE (APB1PERIPH_BASE + 0x2000UL) +#define TIM16_BASE (APB1PERIPH_BASE + 0x2800UL) +#define TIM17_BASE (APB1PERIPH_BASE + 0x2C00UL) +#define LPTIM_BASE (APB1PERIPH_BASE + 0x7C00UL) + +#define ADC1_BASE (APB2PERIPH_BASE + 0x2400UL) + +#define DMA1_BASE (AHB1PERIPH_BASE + 0x00000UL) + +#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00UL) +#define IWDG_BASE (APB1PERIPH_BASE + 0x3000UL) +#define RTC_BASE (APB1PERIPH_BASE + 0x2800UL) +#define SYSCFG_BASE (APB2PERIPH_BASE + 0x0000UL) +#define EXTI_BASE (APB2PERIPH_BASE + 0x0400UL) +#define COMP_BASE (APB2PERIPH_BASE + 0x0200UL) + +#define FLASH_SIZE 0x00010000UL +#define SRAM_SIZE 0x00002000UL + +typedef struct { + __IOM uint32_t MODER; + __IOM uint32_t OTYPER; + __IOM uint32_t OSPEEDR; + __IOM uint32_t PUPDR; + __IM uint32_t IDR; + __IOM uint32_t ODR; + __IOM uint32_t BSRR; + __IOM uint32_t LCKR; + __IOM uint32_t AFRL; + __IOM uint32_t AFRH; + __IOM uint32_t BRR; +} GPIO_TypeDef; + +typedef struct { + __IOM uint32_t CR; + __IOM uint32_t CFGR; + __IOM uint32_t CIR; + __IOM uint32_t APB2RSTR; + __IOM uint32_t APB1RSTR; + __IOM uint32_t AHBENR; + __IOM uint32_t APB2ENR; + __IOM uint32_t APB1ENR; + __IOM uint32_t BDCR; + __IOM uint32_t CSR; + __IOM uint32_t AHBRSTR; + __IOM uint32_t CFGR2; + __IOM uint32_t CFGR3; +} RCC_TypeDef; + +typedef struct { + __IOM uint32_t SR; + __IOM uint32_t DR; + __IOM uint32_t BRR; + __IOM uint32_t CR1; + __IOM uint32_t CR2; + __IOM uint32_t CR3; + __IOM uint32_t GTPR; +} USART_TypeDef; + +typedef struct { + __IOM uint32_t ISR; + __IOM uint32_t DR; + __IOM uint32_t BRR; + __IOM uint32_t CR1; + __IOM uint32_t CR2; + __IOM uint32_t CR3; + __IOM uint32_t CR4; +} LPUART_TypeDef; + +typedef struct { + __IOM uint32_t CR1; + __IOM uint32_t CR2; + __IOM uint32_t OAR1; + __IOM uint32_t OAR2; + __IOM uint32_t TIMINGR; + __IOM uint32_t TIMEOUTR; + __IOM uint32_t ISR; + __IOM uint32_t ICR; + __IOM uint32_t PECR; + __IOM uint32_t RXDR; + __IOM uint32_t TXDR; +} I2C_TypeDef; + +typedef struct { + __IOM uint32_t CR1; + __IOM uint32_t CR2; + __IOM uint32_t SMCR; + __IOM uint32_t DIER; + __IOM uint32_t SR; + __IOM uint32_t EGR; + __IOM uint32_t CCMR1; + __IOM uint32_t CCMR2; + __IOM uint32_t CCER; + __IOM uint32_t CNT; + __IOM uint32_t PSC; + __IOM uint32_t ARR; + uint32_t RESERVED0; + __IOM uint32_t CCR1; + __IOM uint32_t CCR2; + __IOM uint32_t CCR3; + __IOM uint32_t CCR4; + uint32_t RESERVED1; + __IOM uint32_t DCR; + __IOM uint32_t DMAR; + __IOM uint32_t OR1; + __IOM uint32_t OR2; +} TIM_TypeDef; + +typedef struct { + __IOM uint32_t CR1; + __IOM uint32_t CR2; + __IOM uint32_t CFGR; + __IOM uint32_t SMCR; + __IOM uint32_t DIER; + __IOM uint32_t SR; + __IOM uint32_t EGR; + __IOM uint32_t CCMR1; + __IOM uint32_t CCMR2; + __IOM uint32_t CCER; + __IOM uint32_t CNT; + __IOM uint32_t PSC; + __IOM uint32_t ARR; + __IOM uint32_t RCR; + __IOM uint32_t CCR1; + __IOM uint32_t CCR2; + __IOM uint32_t CCR3; + __IOM uint32_t CCR4; + __IOM uint32_t BDTR; + __IOM uint32_t DCR; + __IOM uint32_t DMAR; + __IOM uint32_t OR1; + __IOM uint32_t CCMR3; + __IOM uint32_t CCR5; + __IOM uint32_t CCR6; + __IOM uint32_t OR2; + __IOM uint32_t OR3; +} TIM1_TypeDef; + +typedef struct { + __IOM uint32_t ISR; + __IOM uint32_t IER; + __IOM uint32_t CR; + __IOM uint32_t CFGR1; + __IOM uint32_t CFGR2; + __IOM uint32_t SMPR1; + __IOM uint32_t SMPR2; + __IOM uint32_t TR1; + __IOM uint32_t TR2; + __IOM uint32_t CHSMPR1; + __IOM uint32_t CHSMPR2; + __IOM uint32_t CHDR1; + __IOM uint32_t CHDR2; + __IOM uint32_t CHDR3; + __IOM uint32_t CHDR4; + __IOM uint32_t CHDR5; + __IOM uint32_t CHDR6; + __IOM uint32_t CHDR7; +} ADC_TypeDef; + +typedef struct { + __IOM uint32_t CCR; + __IOM uint32_t CNDTR; + __IOM uint32_t CPAR; + __IOM uint32_t CMAR; +} DMA_Channel_TypeDef; + +typedef struct { + __IOM uint32_t ISR; + __IOM uint32_t IFCR; +} DMA_TypeDef; + +typedef struct { + __IOM uint32_t CR; + __IOM uint32_t CFGR; + __IOM uint32_t CFG2; + __IOM uint32_t EXTICR[4]; + __IOM uint32_t CFG3; +} SYSCFG_TypeDef; + +typedef struct { + __IOM uint32_t IMR; + __IOM uint32_t EMR; + __IOM uint32_t RTSR; + __IOM uint32_t FTSR; + __IOM uint32_t SWIER; + __IOM uint32_t PR; +} EXTI_TypeDef; + +typedef struct { + __IOM uint32_t KR; + __IOM uint32_t PR; + __IOM uint32_t RLR; + __IOM uint32_t SR; +} IWDG_TypeDef; + +typedef struct { + __IOM uint32_t CR; + __IOM uint32_t CFR; + __IOM uint32_t SR; +} WWDG_TypeDef; + +typedef struct { + __IOM uint32_t TR; + __IOM uint32_t DR; + __IOM uint32_t CR; + __IOM uint32_t ISR; + __IOM uint32_t PRER; + __IOM uint32_t WUTR; + __IOM uint32_t ALRMAR; + __IOM uint32_t ALRMBR; + __IOM uint32_t WPR; + __IOM uint32_t SSR; + __IOM uint32_t SHIFTR; + __IOM uint32_t TSTR; + __IOM uint32_t TSDR; + __IOM uint32_t TSSSR; + __IOM uint32_t CALR; + __IOM uint32_t TAMPCR; + __IOM uint32_t ALRMASSR; + __IOM uint32_t ALRMBSSR; + __IOM uint32_t OR; +} RTC_TypeDef; + +typedef struct { + __IOM uint32_t CR1; + __IOM uint32_t CR2; + __IOM uint32_t CFGR1; + __IOM uint32_t CFGR2; + __IOM uint32_t BRR; + __IOM uint32_t RESERVED0; + __IOM uint32_t DIER; + __IOM uint32_t SR; + __IOM uint32_t ICFR; + __IOM uint32_t IER; +} SPI_TypeDef; + +typedef struct { + __IOM uint32_t CR; + __IOM uint32_t CSR; +} COMP_TypeDef; + +#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE) +#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE) +#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE) +#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE) +#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE) +#define RCC ((RCC_TypeDef *)RCC_BASE) +#define USART1 ((USART_TypeDef *)USART1_BASE) +#define UART1 ((USART_TypeDef *)UART1_BASE) +#define LPUART1 ((LPUART_TypeDef *)LPUART1_BASE) +#define I2C1 ((I2C_TypeDef *)I2C1_BASE) +#define SPI1 ((SPI_TypeDef *)SPI1_BASE) +#define TIM1 ((TIM1_TypeDef *)TIM1_BASE) +#define TIM3 ((TIM_TypeDef *)TIM3_BASE) +#define TIM14 ((TIM_TypeDef *)TIM14_BASE) +#define TIM16 ((TIM_TypeDef *)TIM16_BASE) +#define TIM17 ((TIM_TypeDef *)TIM17_BASE) +#define LPTIM ((TIM_TypeDef *)LPTIM_BASE) +#define ADC1 ((ADC_TypeDef *)ADC1_BASE) +#define DMA1_Channel1 ((DMA_Channel_TypeDef *)(DMA1_BASE + 0x08)) +#define DMA1_Channel2 ((DMA_Channel_TypeDef *)(DMA1_BASE + 0x1C)) +#define DMA1_Channel3 ((DMA_Channel_TypeDef *)(DMA1_BASE + 0x30)) +#define DMA1 ((DMA_TypeDef *)DMA1_BASE) +#define SYSCFG ((SYSCFG_TypeDef *)SYSCFG_BASE) +#define EXTI ((EXTI_TypeDef *)EXTI_BASE) +#define COMP ((COMP_TypeDef *)COMP_BASE) +#define IWDG ((IWDG_TypeDef *)IWDG_BASE) +#define WWDG ((WWDG_TypeDef *)WWDG_BASE) +#define RTC ((RTC_TypeDef *)RTC_BASE) + +#define GPIO_MODER_MODE0_Pos 0U +#define GPIO_MODER_MODE0_Msk (0x3UL << GPIO_MODER_MODE0_Pos) +#define GPIO_MODER_MODE0_0 (0x1UL << GPIO_MODER_MODE0_Pos) +#define GPIO_MODER_MODE0_1 (0x2UL << GPIO_MODER_MODE0_Pos) + +#define GPIO_OTYPER_OT0_Pos 0U +#define GPIO_OTYPER_OT0_Msk (0x1UL << GPIO_OTYPER_OT0_Pos) +#define GPIO_OTYPER_OT0_0 (0x1UL << GPIO_OTYPER_OT0_Pos) + +#define GPIO_OSPEEDR_OSPEED0_Pos 0U +#define GPIO_OSPEEDR_OSPEED0_Msk (0x3UL << GPIO_OSPEEDR_OSPEED0_Pos) +#define GPIO_OSPEEDR_OSPEED0_0 (0x1UL << GPIO_OSPEEDR_OSPEED0_Pos) +#define GPIO_OSPEEDR_OSPEED0_1 (0x2UL << GPIO_OSPEEDR_OSPEED0_Pos) + +#define GPIO_PUPDR_PUPD0_Pos 0U +#define GPIO_PUPDR_PUPD0_Msk (0x3UL << GPIO_PUPDR_PUPD0_Pos) +#define GPIO_PUPDR_PUPD0_0 (0x1UL << GPIO_PUPDR_PUPD0_Pos) +#define GPIO_PUPDR_PUPD0_1 (0x2UL << GPIO_PUPDR_PUPD0_Pos) + +#define GPIO_BSRR_BS0_Pos 0U +#define GPIO_BSRR_BS0_Msk (0x1UL << GPIO_BSRR_BS0_Pos) +#define GPIO_BSRR_BR0_Pos 16U +#define GPIO_BSRR_BR0_Msk (0x1UL << GPIO_BSRR_BR0_Pos) + +#define RCC_AHBENR_GPIOAEN_Pos 17U +#define RCC_AHBENR_GPIOAEN_Msk (0x1UL << RCC_AHBENR_GPIOAEN_Pos) +#define RCC_AHBENR_GPIOAEN RCC_AHBENR_GPIOAEN_Msk +#define RCC_AHBENR_GPIOBEN_Pos 18U +#define RCC_AHBENR_GPIOBEN_Msk (0x1UL << RCC_AHBENR_GPIOBEN_Pos) +#define RCC_AHBENR_GPIOBEN RCC_AHBENR_GPIOBEN_Msk +#define RCC_AHBENR_GPIOCEN_Pos 19U +#define RCC_AHBENR_GPIOCEN_Msk (0x1UL << RCC_AHBENR_GPIOCEN_Pos) +#define RCC_AHBENR_GPIOCEN RCC_AHBENR_GPIOCEN_Msk +#define RCC_AHBENR_GPIOFEN_Pos 22U +#define RCC_AHBENR_GPIOFEN_Msk (0x1UL << RCC_AHBENR_GPIOFEN_Pos) +#define RCC_AHBENR_GPIOFEN RCC_AHBENR_GPIOFEN_Msk +#define RCC_AHBENR_DMAEN_Pos 0U +#define RCC_AHBENR_DMAEN_Msk (0x1UL << RCC_AHBENR_DMAEN_Pos) +#define RCC_AHBENR_DMAEN RCC_AHBENR_DMAEN_Msk + +#define RCC_APB2ENR_USART1EN_Pos 14U +#define RCC_APB2ENR_USART1EN_Msk (0x1UL << RCC_APB2ENR_USART1EN_Pos) +#define RCC_APB2ENR_USART1EN RCC_APB2ENR_USART1EN_Msk +#define RCC_APB2ENR_SPI1EN_Pos 12U +#define RCC_APB2ENR_SPI1EN_Msk (0x1UL << RCC_APB2ENR_SPI1EN_Pos) +#define RCC_APB2ENR_TIM1EN_Pos 11U +#define RCC_APB2ENR_TIM1EN_Msk (0x1UL << RCC_APB2ENR_TIM1EN_Pos) +#define RCC_APB2ENR_TIM1EN RCC_APB2ENR_TIM1EN_Msk +#define RCC_APB2ENR_SYSCFGEN_Pos 0U +#define RCC_APB2ENR_SYSCFGEN_Msk (0x1UL << RCC_APB2ENR_SYSCFGEN_Pos) +#define RCC_APB2ENR_SYSCFGEN RCC_APB2ENR_SYSCFGEN_Msk +#define RCC_APB2ENR_ADCEN_Pos 9U +#define RCC_APB2ENR_ADCEN_Msk (0x1UL << RCC_APB2ENR_ADCEN_Pos) +#define RCC_APB2ENR_ADCEN RCC_APB2ENR_ADCEN_Msk + +#define RCC_APB1ENR_TIM3EN_Pos 1U +#define RCC_APB1ENR_TIM3EN_Msk (0x1UL << RCC_APB1ENR_TIM3EN_Pos) +#define RCC_APB1ENR_TIM3EN RCC_APB1ENR_TIM3EN_Msk +#define RCC_APB1ENR_TIM14EN_Pos 8U +#define RCC_APB1ENR_TIM14EN_Msk (0x1UL << RCC_APB1ENR_TIM14EN_Pos) +#define RCC_APB1ENR_TIM14EN RCC_APB1ENR_TIM14EN_Msk +#define RCC_APB1ENR_UART1EN_Pos 18U +#define RCC_APB1ENR_UART1EN_Msk (0x1UL << RCC_APB1ENR_UART1EN_Pos) +#define RCC_APB1ENR_UART1EN RCC_APB1ENR_UART1EN_Msk +#define RCC_APB1ENR_LPUART1EN_Pos 19U +#define RCC_APB1ENR_LPUART1EN_Msk (0x1UL << RCC_APB1ENR_LPUART1EN_Pos) +#define RCC_APB1ENR_LPUART1EN RCC_APB1ENR_LPUART1EN_Msk +#define RCC_APB1ENR_I2C1EN_Pos 21U +#define RCC_APB1ENR_I2C1EN_Msk (0x1UL << RCC_APB1ENR_I2C1EN_Pos) +#define RCC_APB1ENR_I2C1EN RCC_APB1ENR_I2C1EN_Msk +#define RCC_APB1ENR_LPTIMEN_Pos 31U +#define RCC_APB1ENR_LPTIMEN_Msk (0x1UL << RCC_APB1ENR_LPTIMEN_Pos) +#define RCC_APB1ENR_PWREN_Pos 28U +#define RCC_APB1ENR_PWREN_Msk (0x1UL << RCC_APB1ENR_PWREN_Pos) +#define RCC_APB1ENR_PWREN RCC_APB1ENR_PWREN_Msk + +/* RCC CR register bit definitions */ +#define RCC_CR_HSION_Pos 0U +#define RCC_CR_HSION_Msk (0x1UL << RCC_CR_HSION_Pos) +#define RCC_CR_HSION RCC_CR_HSION_Msk +#define RCC_CR_HSIRDY_Pos 1U +#define RCC_CR_HSIRDY_Msk (0x1UL << RCC_CR_HSIRDY_Pos) +#define RCC_CR_HSIRDY RCC_CR_HSIRDY_Msk +#define RCC_CR_HSITRIM_Pos 3U +#define RCC_CR_HSITRIM_Msk (0x1FUL << RCC_CR_HSITRIM_Pos) +#define RCC_CR_HSICAL_Pos 8U +#define RCC_CR_HSICAL_Msk (0xFFUL << RCC_CR_HSICAL_Pos) +#define RCC_CR_HSEON_Pos 16U +#define RCC_CR_HSEON_Msk (0x1UL << RCC_CR_HSEON_Pos) +#define RCC_CR_HSERDY_Pos 17U +#define RCC_CR_HSERDY_Msk (0x1UL << RCC_CR_HSERDY_Pos) +#define RCC_CR_PLLON_Pos 24U +#define RCC_CR_PLLON_Msk (0x1UL << RCC_CR_PLLON_Pos) +#define RCC_CR_PLLON RCC_CR_PLLON_Msk +#define RCC_CR_PLLRDY_Pos 25U +#define RCC_CR_PLLRDY_Msk (0x1UL << RCC_CR_PLLRDY_Pos) +#define RCC_CR_PLLRDY RCC_CR_PLLRDY_Msk + +/* RCC CFGR register bit definitions */ +#define RCC_CFGR_SW_Pos 0U +#define RCC_CFGR_SW_Msk (0x3UL << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SW RCC_CFGR_SW_Msk +#define RCC_CFGR_SW_0 (0x1UL << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SW_1 (0x2UL << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SW_HSI (0x0UL << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SW_HSE (0x1UL << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SW_PLL (0x2UL << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SWS_Pos 2U +#define RCC_CFGR_SWS_Msk (0x3UL << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_SWS RCC_CFGR_SWS_Msk +#define RCC_CFGR_SWS_0 (0x1UL << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_SWS_1 (0x2UL << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_SWS_HSI (0x0UL << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_SWS_HSE (0x1UL << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_SWS_PLL (0x2UL << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_HPRE_Pos 4U +#define RCC_CFGR_HPRE_Msk (0xFUL << RCC_CFGR_HPRE_Pos) +#define RCC_CFGR_PPRE_Pos 8U +#define RCC_CFGR_PPRE_Msk (0x7UL << RCC_CFGR_PPRE_Pos) +#define RCC_CFGR_PLLSRC_Pos 16U +#define RCC_CFGR_PLLSRC_Msk (0x1UL << RCC_CFGR_PLLSRC_Pos) +#define RCC_CFGR_PLLSRC RCC_CFGR_PLLSRC_Msk +#define RCC_CFGR_PLLXTPRE_Pos 17U +#define RCC_CFGR_PLLXTPRE_Msk (0x1UL << RCC_CFGR_PLLXTPRE_Pos) + +/* RCC CFGR2 register bit definitions */ +#define RCC_CFGR2_PLLMUL_Pos 0U +#define RCC_CFGR2_PLLMUL_Msk (0xFUL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL RCC_CFGR2_PLLMUL_Msk +#define RCC_CFGR2_PLLMUL2 (0x0UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL3 (0x1UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL4 (0x2UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL5 (0x3UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL6 (0x4UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL7 (0x5UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL8 (0x6UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL9 (0x7UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL10 (0x8UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL11 (0x9UL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL12 (0xAUL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL13 (0xBUL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL14 (0xCUL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL15 (0xDUL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PLLMUL16 (0xEUL << RCC_CFGR2_PLLMUL_Pos) +#define RCC_CFGR2_PREDIV_Pos 4U +#define RCC_CFGR2_PREDIV_Msk (0x1UL << RCC_CFGR2_PREDIV_Pos) + +#define RCC_APB2RST_TIM1RST_Pos 11U +#define RCC_APB2RST_TIM1RST_Msk (0x1UL << RCC_APB2RST_TIM1RST_Pos) +#define RCC_APB2RST_USART1RST_Pos 14U +#define RCC_APB2RST_USART1RST_Msk (0x1UL << RCC_APB2RST_USART1RST_Pos) +#define RCC_APB2RST_ADCRST_Pos 9U +#define RCC_APB2RST_ADCRST_Msk (0x1UL << RCC_APB2RST_ADCRST_Pos) + +#define RCC_APB1RST_UART1RST_Pos 18U +#define RCC_APB1RST_UART1RST_Msk (0x1UL << RCC_APB1RST_UART1RST_Pos) +#define RCC_APB1RST_LPUART1RST_Pos 19U +#define RCC_APB1RST_LPUART1RST_Msk (0x1UL << RCC_APB1RST_LPUART1RST_Pos) +#define RCC_APB1RST_I2C1RST_Pos 21U +#define RCC_APB1RST_I2C1RST_Msk (0x1UL << RCC_APB1RST_I2C1RST_Pos) +#define RCC_APB1RST_TIM3RST_Pos 1U +#define RCC_APB1RST_TIM3RST_Msk (0x1UL << RCC_APB1RST_TIM3RST_Pos) + +/* USART registers bit definitions */ +#define USART_CR1_UE_Pos 0U +#define USART_CR1_UE_Msk (0x1UL << USART_CR1_UE_Pos) +#define USART_CR1_RE_Pos 2U +#define USART_CR1_RE_Msk (0x1UL << USART_CR1_RE_Pos) +#define USART_CR1_TE_Pos 3U +#define USART_CR1_TE_Msk (0x1UL << USART_CR1_TE_Pos) +#define USART_CR1_RXNEIE_Pos 5U +#define USART_CR1_RXNEIE_Msk (0x1UL << USART_CR1_RXNEIE_Pos) +#define USART_CR1_TCIE_Pos 6U +#define USART_CR1_TCIE_Msk (0x1UL << USART_CR1_TCIE_Pos) +#define USART_CR1_TXNEIE_Pos 7U +#define USART_CR1_TXNEIE_Msk (0x1UL << USART_CR1_TXNEIE_Pos) + +#define USART_CR1_M_Pos 12U +#define USART_CR1_M_Msk (0x1UL << USART_CR1_M_Pos) +#define USART_CR1_M0_Pos 12U +#define USART_CR1_M0_Msk (0x1UL << USART_CR1_M0_Pos) +#define USART_CR1_M1_Pos 28U +#define USART_CR1_M1_Msk (0x1UL << USART_CR1_M1_Pos) +#define USART_CR1_OVER8_Pos 15U +#define USART_CR1_OVER8_Msk (0x1UL << USART_CR1_OVER8_Pos) + +#define USART_CR3_DMAR_Pos 6U +#define USART_CR3_DMAR_Msk (0x1UL << USART_CR3_DMAR_Pos) +#define USART_CR3_DMAT_Pos 7U +#define USART_CR3_DMAT_Msk (0x1UL << USART_CR3_DMAT_Pos) + +#define USART_SR_RXNE_Pos 5U +#define USART_SR_RXNE_Msk (0x1UL << USART_SR_RXNE_Pos) +#define USART_SR_TC_Pos 6U +#define USART_SR_TC_Msk (0x1UL << USART_SR_TC_Pos) +#define USART_SR_TXE_Pos 7U +#define USART_SR_TXE_Msk (0x1UL << USART_SR_TXE_Pos) + +/* I2C registers bit definitions */ +#define I2C_CR1_PE_Pos 0U +#define I2C_CR1_PE_Msk (0x1UL << I2C_CR1_PE_Pos) + +#define I2C_ISR_TXIS_Pos 1U +#define I2C_ISR_TXIS_Msk (0x1UL << I2C_ISR_TXIS_Pos) +#define I2C_ISR_RXNE_Pos 2U +#define I2C_ISR_RXNE_Msk (0x1UL << I2C_ISR_RXNE_Pos) +#define I2C_ISR_STOPF_Pos 5U +#define I2C_ISR_STOPF_Msk (0x1UL << I2C_ISR_STOPF_Pos) +#define I2C_ISR_NACKF_Pos 4U +#define I2C_ISR_NACKF_Msk (0x1UL << I2C_ISR_NACKF_Pos) + +/* ADC registers bit definitions */ +#define ADC_CR_ADEN_Pos 0U +#define ADC_CR_ADEN_Msk (0x1UL << ADC_CR_ADEN_Pos) +#define ADC_CR_ADDIS_Pos 1U +#define ADC_CR_ADDIS_Msk (0x1UL << ADC_CR_ADDIS_Pos) +#define ADC_CR_ADSTART_Pos 2U +#define ADC_CR_ADSTART_Msk (0x1UL << ADC_CR_ADSTART_Pos) + +#define ADC_CFGR1_RES_Pos 3U +#define ADC_CFGR1_RES_Msk (0x3UL << ADC_CFGR1_RES_Pos) +#define ADC_CFGR1_RES_1 (0x2UL << ADC_CFGR1_RES_Pos) +#define ADC_CFGR1_DMAEN_Pos 8U +#define ADC_CFGR1_DMAEN_Msk (0x1UL << ADC_CFGR1_DMAEN_Pos) +#define ADC_CFGR1_DMACFG_Pos 9U +#define ADC_CFGR1_DMACFG_Msk (0x1UL << ADC_CFGR1_DMACFG_Pos) + +#define ADC_ISR_ADRDY_Pos 0U +#define ADC_ISR_ADRDY_Msk (0x1UL << ADC_ISR_ADRDY_Pos) +#define ADC_ISR_EOC_Pos 2U +#define ADC_ISR_EOC_Msk (0x1UL << ADC_ISR_EOC_Pos) + +/* COMP (PGA) registers bit definitions */ +#define COMP_CR_EN_Pos 0U +#define COMP_CR_EN_Msk (0x1UL << COMP_CR_EN_Pos) +#define COMP_CR_PGA_MODE_Pos 4U +#define COMP_CR_PGA_MODE_Msk (0x1UL << COMP_CR_PGA_MODE_Pos) +#define COMP_CR_PGA_GAIN_Pos 5U +#define COMP_CR_PGA_GAIN_Msk (0x7UL << COMP_CR_PGA_GAIN_Pos) +#define COMP_CSR_OUT_Pos 0U +#define COMP_CSR_OUT_Msk (0x1UL << COMP_CSR_OUT_Pos) + +/* TIM registers bit definitions */ +#define TIM_CR1_CEN_Pos 0U +#define TIM_CR1_CEN_Msk (0x1UL << TIM_CR1_CEN_Pos) +#define TIM_CR1_CEN TIM_CR1_CEN_Msk +#define TIM_CR1_OPM_Pos 3U +#define TIM_CR1_OPM_Msk (0x1UL << TIM_CR1_OPM_Pos) +#define TIM_CR1_ARPE_Pos 7U +#define TIM_CR1_ARPE_Msk (0x1UL << TIM_CR1_ARPE_Pos) + +#define TIM_DIER_UIE_Pos 0U +#define TIM_DIER_UIE_Msk (0x1UL << TIM_DIER_UIE_Pos) +#define TIM_DIER_CC1IE_Pos 1U +#define TIM_DIER_CC1IE_Msk (0x1UL << TIM_DIER_CC1IE_Pos) +#define TIM_DIER_CC2IE_Pos 2U +#define TIM_DIER_CC2IE_Msk (0x1UL << TIM_DIER_CC2IE_Pos) +#define TIM_DIER_CC3IE_Pos 3U +#define TIM_DIER_CC3IE_Msk (0x1UL << TIM_DIER_CC3IE_Pos) +#define TIM_DIER_CC4IE_Pos 4U +#define TIM_DIER_CC4IE_Msk (0x1UL << TIM_DIER_CC4IE_Pos) + +#define TIM_SR_UIF_Pos 0U +#define TIM_SR_UIF_Msk (0x1UL << TIM_SR_UIF_Pos) +#define TIM_SR_CC1IF_Pos 1U +#define TIM_SR_CC1IF_Msk (0x1UL << TIM_SR_CC1IF_Pos) +#define TIM_SR_CC2IF_Pos 2U +#define TIM_SR_CC2IF_Msk (0x1UL << TIM_SR_CC2IF_Pos) +#define TIM_SR_CC3IF_Pos 3U +#define TIM_SR_CC3IF_Msk (0x1UL << TIM_SR_CC3IF_Pos) +#define TIM_SR_CC4IF_Pos 4U +#define TIM_SR_CC4IF_Msk (0x1UL << TIM_SR_CC4IF_Pos) + +#define TIM_EGR_UG_Pos 0U +#define TIM_EGR_UG_Msk (0x1UL << TIM_EGR_UG_Pos) + +#define TIM_CCER_CC1E_Pos 0U +#define TIM_CCER_CC1E_Msk (0x1UL << TIM_CCER_CC1E_Pos) +#define TIM_CCER_CC1NE_Pos 2U +#define TIM_CCER_CC1NE_Msk (0x1UL << TIM_CCER_CC1NE_Pos) +#define TIM_CCER_CC2E_Pos 4U +#define TIM_CCER_CC2E_Msk (0x1UL << TIM_CCER_CC2E_Pos) +#define TIM_CCER_CC2NE_Pos 6U +#define TIM_CCER_CC2NE_Msk (0x1UL << TIM_CCER_CC2NE_Pos) +#define TIM_CCER_CC3E_Pos 8U +#define TIM_CCER_CC3E_Msk (0x1UL << TIM_CCER_CC3E_Pos) +#define TIM_CCER_CC3NE_Pos 10U +#define TIM_CCER_CC3NE_Msk (0x1UL << TIM_CCER_CC3NE_Pos) +#define TIM_CCER_CC4E_Pos 12U +#define TIM_CCER_CC4E_Msk (0x1UL << TIM_CCER_CC4E_Pos) + +#define TIM_BDTR_BKE_Pos 12U +#define TIM_BDTR_BKE_Msk (0x1UL << TIM_BDTR_BKE_Pos) +#define TIM_BDTR_BKP_Pos 13U +#define TIM_BDTR_BKP_Msk (0x1UL << TIM_BDTR_BKP_Pos) +#define TIM_BDTR_AOE_Pos 14U +#define TIM_BDTR_AOE_Msk (0x1UL << TIM_BDTR_AOE_Pos) +#define TIM_BDTR_MOE_Pos 15U +#define TIM_BDTR_MOE_Msk (0x1UL << TIM_BDTR_MOE_Pos) +#define TIM_BDTR_DTG_Pos 0U +#define TIM_BDTR_DTG_Msk (0xFFUL << TIM_BDTR_DTG_Pos) + +/* Interrupt numbers */ +enum IRQn { + WWDG_IRQn = 0, + PVD_IRQn = 1, + RTC_IRQn = 2, + FLASH_IRQn = 3, + RCC_IRQn = 4, + EXTI0_1_IRQn = 5, + EXTI2_3_IRQn = 6, + EXTI4_15_IRQn = 7, + DMA1_Ch1_IRQn = 9, + DMA1_Ch2_3_IRQn = 10, + DMA1_Ch4_5_IRQn = 11, + ADC1_IRQn = 12, + TIM1_BRK_IRQn = 13, + TIM1_UP_IRQn = 14, + TIM1_TRG_LVL_IRQn = 15, + TIM1_CC_IRQn = 16, + TIM3_IRQn = 17, + TIM14_IRQn = 19, + TIM16_IRQn = 21, + TIM17_IRQn = 22, + I2C1_IRQn = 23, + SPI1_IRQn = 24, + USART1_IRQn = 25, + UART1_IRQn = 28, + LPUART1_IRQn = 29, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/device/py32md530.ld b/libs/device/py32md530.ld new file mode 100644 index 0000000..cb2a6f3 --- /dev/null +++ b/libs/device/py32md530.ld @@ -0,0 +1,77 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > FLASH + + .text : + { + . = ALIGN(4); + *(.text) + *(.text*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + + KEEP(*(.init)) + KEEP(*(.fini)) + + . = ALIGN(4); + _etext = .; + } > FLASH + + .ARM.exidx : + { + *(.ARM.exidx*) + . = ALIGN(4); + } > FLASH + + .rodata : + { + . = ALIGN(4); + *(.rodata) + *(.rodata*) + . = ALIGN(4); + } > FLASH + + _sidata = .; + + .data : AT(_sidata) + { + . = ALIGN(4); + _sdata = .; + *(.data) + *(.data*) + . = ALIGN(4); + _edata = .; + } > RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + __bss_start = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + __bss_end = _ebss; + } > RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } + + _end = .; + PROVIDE(end = .); +} diff --git a/libs/device/startup_py32md530.s b/libs/device/startup_py32md530.s new file mode 100644 index 0000000..a42d209 --- /dev/null +++ b/libs/device/startup_py32md530.s @@ -0,0 +1,261 @@ +.syntax unified +.cpu cortex-m0plus +.fpu softvfp +.thumb + +.global g_pfnVectors +.global Default_Handler + +.word _sidata +.word _sdata +.word _edata +.word _sbss +.word _ebss + +.equ BootRAM, 0xF108F85F + +.macro def_irq_handler handler_name +.weak \handler_name +.set \handler_name, Default_Handler +.endm + +.section .text.Default_Handler,"ax",%progbits +Default_Handler: + b Default_Handler + +.section .text.Reset_Handler,"ax",%progbits +.global Reset_Handler +Reset_Handler: + ldr r0, =_estack + mov sp, r0 + + ldr r1, =_sbss + ldr r2, =_ebss + movs r3, #0 + b FillZeroLoop + +FillZero: + str r3, [r1] + adds r1, r1, #4 + +FillZeroLoop: + cmp r1, r2 + bcc FillZero + + ldr r0, =_sidata + ldr r1, =_sdata + ldr r2, =_edata + b CopyDataLoop + +CopyData: + ldr r3, [r0] + str r3, [r1] + adds r0, r0, #4 + adds r1, r1, #4 + +CopyDataLoop: + cmp r1, r2 + bcc CopyData + + bl SystemInit + bl main + +LoopForever: + b LoopForever + +def_irq_handler NMI_Handler +def_irq_handler HardFault_Handler +def_irq_handler SVCall_Handler +def_irq_handler PendSV_Handler +def_irq_handler SysTick_Handler + +def_irq_handler WWDG_IRQHandler +def_irq_handler RCC_IRQHandler +def_irq_handler EXTI0_1_IRQHandler +def_irq_handler EXTI2_3_IRQHandler +def_irq_handler EXTI4_15_IRQHandler +def_irq_handler DMA1_Ch1_IRQHandler +def_irq_handler DMA1_Ch2_3_IRQHandler +def_irq_handler DMA1_Ch4_5_IRQHandler +def_irq_handler ADC1_IRQHandler +def_irq_handler TIM1_BRK_IRQHandler +def_irq_handler TIM1_UP_IRQHandler +def_irq_handler TIM1_TRG_LVL_IRQHandler +def_irq_handler TIM1_CC_IRQHandler +def_irq_handler TIM3_IRQHandler +def_irq_handler TIM14_IRQHandler +def_irq_handler TIM16_IRQHandler +def_irq_handler TIM17_IRQHandler +def_irq_handler I2C1_IRQHandler +def_irq_handler SPI1_IRQHandler +def_irq_handler USART1_IRQHandler +def_irq_handler UART1_IRQHandler +def_irq_handler LPUART1_IRQHandler + +.section .isr_vector,"a",%progbits +.type g_pfnVectors, %object +.size g_pfnVectors, .-g_pfnVectors + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word SVCall_Handler + .word 0 + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + .word WWDG_IRQHandler + .word RCC_IRQHandler + .word EXTI0_1_IRQHandler + .word EXTI2_3_IRQHandler + .word EXTI4_15_IRQHandler + .word 0 + .word 0 + .word DMA1_Ch1_IRQHandler + .word DMA1_Ch2_3_IRQHandler + .word DMA1_Ch4_5_IRQHandler + .word ADC1_IRQHandler + .word TIM1_BRK_IRQHandler + .word TIM1_UP_IRQHandler + .word TIM1_TRG_LVL_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM3_IRQHandler + .word 0 + .word TIM14_IRQHandler + .word 0 + .word TIM16_IRQHandler + .word TIM17_IRQHandler + .word I2C1_IRQHandler + .word SPI1_IRQHandler + .word USART1_IRQHandler + .word 0 + .word 0 + .word UART1_IRQHandler + .word LPUART1_IRQHandler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 diff --git a/libs/device/system_py32md530.c b/libs/device/system_py32md530.c new file mode 100644 index 0000000..3cafc98 --- /dev/null +++ b/libs/device/system_py32md530.c @@ -0,0 +1,68 @@ +#include "system_py32md530.h" +#include "py32md530.h" + +uint32_t SystemCoreClock = 8000000UL; + +static void HSI_Setup(void) +{ + RCC->CR |= ((uint32_t)RCC_CR_HSION); + while ((RCC->CR & RCC_CR_HSIRDY) == 0); +} + +static void PLL_Setup(void) +{ + RCC->CFGR &= ~RCC_CFGR_PLLSRC; + RCC->CFGR |= RCC_CFGR_PLLSRC; + + RCC->CFGR2 &= ~RCC_CFGR2_PLLMUL; + RCC->CFGR2 |= RCC_CFGR2_PLLMUL9; + + RCC->CR |= RCC_CR_PLLON; + while ((RCC->CR & RCC_CR_PLLRDY) == 0); +} + +static void Flash_Setup(void) +{ + #define FLASH_ACR_LATENCY_Pos 0 + #define FLASH_ACR_LATENCY_Msk (0x1UL << FLASH_ACR_LATENCY_Pos) + #define FLASH_ACR_PRFTBE_Pos 4 + #define FLASH_ACR_PRFTBE_Msk (0x1UL << FLASH_ACR_PRFTBE_Pos) + + uint32_t acr = *((uint32_t *)0x40022000); + acr |= FLASH_ACR_LATENCY_Msk; + acr |= FLASH_ACR_PRFTBE_Msk; + *((uint32_t *)0x40022000) = acr; +} + +void SystemInit(void) +{ + HSI_Setup(); + PLL_Setup(); + Flash_Setup(); + + RCC->CFGR &= ~RCC_CFGR_SW; + RCC->CFGR |= RCC_CFGR_SW_PLL; + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); + + SystemCoreClock = 72000000UL; + + RCC->APB1ENR |= RCC_APB1ENR_PWREN; +} + +void SystemCoreClockUpdate(void) +{ + uint32_t tmp; + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case RCC_CFGR_SWS_HSI: + SystemCoreClock = 8000000UL; + break; + case RCC_CFGR_SWS_PLL: + SystemCoreClock = 72000000UL; + break; + default: + SystemCoreClock = 8000000UL; + break; + } +} diff --git a/libs/device/system_py32md530.h b/libs/device/system_py32md530.h new file mode 100644 index 0000000..3883f8a --- /dev/null +++ b/libs/device/system_py32md530.h @@ -0,0 +1,19 @@ +#ifndef SYSTEM_PY32MD530_H__ +#define SYSTEM_PY32MD530_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern uint32_t SystemCoreClock; + +void SystemInit(void); +void SystemCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/flash.sh b/tools/flash.sh new file mode 100644 index 0000000..cbaf445 --- /dev/null +++ b/tools/flash.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +BUILD_DIR="${PROJECT_DIR}/build" +ELF_FILE="${BUILD_DIR}/StepMotorCtrl.elf" + +if [ ! -f "${ELF_FILE}" ]; then + echo "Error: ${ELF_FILE} not found. Please build the project first." + echo "Run: cd build && cmake .. && make" + exit 1 +fi + +OPENOCD_SCRIPTS="${HOME}/openocd/scripts" +OPENOCD_INTERFACE="interface/stlink.cfg" +OPENOCD_TARGET="target/py32md5xx.cfg" + +if [ -f "/usr/local/share/openocd/scripts/${OPENOCD_TARGET}" ]; then + OPENOCD_SCRIPTS="/usr/local/share/openocd/scripts" +fi + +if command -v openocd &> /dev/null; then + echo "Flashing ${ELF_FILE} with OpenOCD..." + openocd -s "${OPENOCD_SCRIPTS}" \ + -f "${OPENOCD_INTERFACE}" \ + -f "${OPENOCD_TARGET}" \ + -c "program ${ELF_FILE} verify reset exit" +elif command -v st-flash &> /dev/null; then + echo "Flashing with st-flash..." + BIN_FILE="${BUILD_DIR}/StepMotorCtrl.bin" + if [ -f "${BIN_FILE}" ]; then + st-flash write ${BIN_FILE} 0x08000000 + else + echo "Error: ${BIN_FILE} not found." + exit 1 + fi +else + echo "Error: Neither OpenOCD nor st-flash found." + echo "Please install tools or use ST-Link Utility to flash." + exit 1 +fi + +echo "Flash complete."