diff --git a/ttt.c b/ttt.c new file mode 100644 index 0000000..fec3e83 --- /dev/null +++ b/ttt.c @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2026 Wisetop. All Rights Reserved. + */ +/** @file main.c + * + * @version 0.0.1 + * @date 2026/04/22 + * @license + * @description + */ +#include "main.h" + +#include "hal_gpio.h" +#include "hal_tim.h" +#include "uart_cmd_srv.h" +//============================================================================= +// Constant Definition +//============================================================================= +#define EPWM_TARGET_FREQ_HZ (24000U) +#define EPWM_TIM_CLOCK_HZ (60000000U) +#define PWM_TABLE_SIZE (64U) + +// Example: 50Hz electrical frequency in Q0.32 phase accumulator domain. +#define PHASE_TARGET_FREQ_HZ (50U) + +#define PHASE_OFFSET_120_DEG_Q32 (0x55555555UL) +#define PHASE_OFFSET_240_DEG_Q32 (0xAAAAAAAAUL) + +//============================================================================= +// Macro Definition +//============================================================================= + +//============================================================================= +// Structure Definition +//============================================================================= + +//============================================================================= +// Global Data Definition +//============================================================================= +static const uint16_t pwm_table[PWM_TABLE_SIZE] + = { 1250, 1372, 1493, 1612, 1728, 1839, 1944, 2042, 2133, 2216, 2289, + 2352, 2404, 2446, 2475, 2493, 2499, 2493, 2475, 2446, 2404, 2352, + 2289, 2216, 2133, 2042, 1944, 1839, 1728, 1612, 1493, 1372, 1250, + 1127, 1006, 887, 771, 660, 555, 457, 366, 283, 210, 147, + 95, 53, 24, 6, 0, 6, 24, 53, 95, 147, 210, + 283, 366, 457, 555, 660, 771, 887, 1006, 1127 }; + +static volatile uint32_t phase_acc_base = 0U; +static uint32_t phase_acc_step = 0U; + +//============================================================================= +// Private Function Definition +//============================================================================= +static void epwm_set_3phase_duty_from_phase(uint32_t phase_q32) +{ + const uint16_t idx_a = (uint16_t)(phase_q32 >> 26U); + const uint16_t idx_b = (uint16_t)((phase_q32 + PHASE_OFFSET_120_DEG_Q32) >> 26U); + const uint16_t idx_c = (uint16_t)((phase_q32 + PHASE_OFFSET_240_DEG_Q32) >> 26U); + + EPWM->CCR1 = pwm_table[idx_a & (PWM_TABLE_SIZE - 1U)]; + EPWM->CCR2 = pwm_table[idx_b & (PWM_TABLE_SIZE - 1U)]; + EPWM->CCR3 = pwm_table[idx_c & (PWM_TABLE_SIZE - 1U)]; +} + +__INTERRUPT static void epwm_irq_handler(void) +{ + if ((EPWM->SR & 0x10000U) == 0x10000U) + { + phase_acc_base += phase_acc_step; + epwm_set_3phase_duty_from_phase(phase_acc_base); + TIM_ClearITPendingBit(EPWM, 0x10000U); // clear EPWM OVIF + } +} + +static uint16_t epwm_calc_prescaler(uint32_t tim_clk_hz, uint32_t pwm_freq_hz, + uint16_t period) +{ + const uint32_t denom = pwm_freq_hz * ((uint32_t)period + 1U); + uint32_t psc = (tim_clk_hz + (denom / 2U)) / denom; + + if (psc == 0U) + { + psc = 1U; + } + return (uint16_t)(psc - 1U); +} + +static uint16_t epwm_calc_max_period(uint32_t tim_clk_hz, uint32_t pwm_freq_hz) +{ + uint32_t period = (tim_clk_hz / pwm_freq_hz); + + if (period == 0U) + { + return 0U; + } + + period -= 1U; + if (period > 0xFFFFU) + { + period = 0xFFFFU; + } + return (uint16_t)period; +} + +static uint32_t phase_acc_calc_step(uint32_t target_freq_hz, + uint32_t update_freq_hz) +{ + return (uint32_t)(((uint64_t)target_freq_hz << 32) / update_freq_hz); +} + +static void epwm_init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = { 0 }; + TIM_OCInitTypeDef TIM_OCInitStruct = { 0 }; + TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStr = { 0 }; + sys_irq_attr_t irq_attr = { 0 }; + const uint16_t period = epwm_calc_max_period(EPWM_TIM_CLOCK_HZ, + EPWM_TARGET_FREQ_HZ); + const uint16_t prescaler = epwm_calc_prescaler(EPWM_TIM_CLOCK_HZ, + EPWM_TARGET_FREQ_HZ, period); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_00 | GPIO_Pin_01 | GPIO_Pin_02 + | GPIO_Pin_03 | GPIO_Pin_04 | GPIO_Pin_05; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStruct.GPIO_AF_Mode = GPIO_AF_6; + GPIO_Init(GPIOA, &GPIO_InitStruct); + + irq_attr.disable_vector = false; + irq_attr.trig_mode = SYS_IRQ_TRIGGER_LEVEL; + irq_attr.level = SYS_IRQ_LEVEL_H; + irq_attr.priority = SYS_IRQ_PRIORITY_MIDDEN; + sys_register_IRQ(EPWM_IRQn, epwm_irq_handler, &irq_attr); + + TIM_DeInit(EPWM); + + TIM_TimeBaseStructInit(&TIM_TimeBaseInitStr); + TIM_TimeBaseInitStr.TIM_Prescaler = prescaler; + TIM_TimeBaseInitStr.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInitStr.TIM_Period = period; + TIM_TimeBaseInitStr.TIM_ClockDivision = TIM_CKD_Div1; + TIM_TimeBaseInitStr.TIM_RepetitionCounter = 0; + TIM_TimeBaseInit(EPWM, &TIM_TimeBaseInitStr); + TIM_ARRPreloadConfig(EPWM, ENABLE); + + TIM_OCStructInit(&TIM_OCInitStruct); + TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; + TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; + TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; + TIM_OCInitStruct.TIM_Pulse = pwm_table[0]; + TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; + TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; + TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset; + TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; + + TIM_OC1Init(EPWM, &TIM_OCInitStruct); + TIM_OC2Init(EPWM, &TIM_OCInitStruct); + TIM_OC3Init(EPWM, &TIM_OCInitStruct); + + EPWM->CCMR1_OUTPUT_b.OC1PE = 1U; + EPWM->CCMR1_OUTPUT_b.OC2PE = 1U; + EPWM->CCMR2_OUTPUT_b.OC3PE = 1U; + + EPWM->DIER |= 0x0800U; // overflow interrupt enable + TIM_ClearITPendingBit(EPWM, 0x10000U); + + TIM_Cmd(EPWM, ENABLE); + TIM_CtrlPWMOutputs(EPWM, ENABLE); + epwm_set_3phase_duty_from_phase(phase_acc_base); + __enable_irq(); +} + +static void sysclk_init(void) +{ + SYSCFG_ClkInitTypeDef SysClkInit = { 0 }; + SysClkInit.ClkSource = SYSCFG_ClkSrc_HSI; + SYSCFG_SysClkConfig(&SysClkInit); + + sys_config_systick(SYS_TICK_1_MS); +} + +//============================================================================= +// Public Function Definition +//============================================================================= +int main(void) +{ + sysclk_init(); + phase_acc_step = phase_acc_calc_step(PHASE_TARGET_FREQ_HZ, EPWM_TARGET_FREQ_HZ); + epwm_init(); + + uart_init(); + uart_send_msg("%s\r\n", "uart ok"); + + while (1) + { + uart_cmd_process(); + } + return 0; +} diff --git a/uart.c b/uart.c new file mode 100644 index 0000000..a52eac8 --- /dev/null +++ b/uart.c @@ -0,0 +1,145 @@ +#include "uart_cmd_srv.h" + +#include +#include +#include + +#include "epwm_drv.h" + +static bool cmd_match_with_arg(const volatile char *buf, const char *prefix, const char **arg_out) +{ + size_t len = strlen(prefix); + for (size_t i = 0; i < len; i++) + { + if (buf[i] != prefix[i]) + return false; + } + if (buf[len] == ' ') + { + *arg_out = (const char *)&buf[len + 1]; + return true; + } + return false; +} + +static int32_t cmd_parse_int_list(const char *arg, int32_t *out, int32_t max_count) +{ + int32_t count = 0; + char *end = NULL; + const char *p = arg; + + while (*p != '\0' && count < max_count) + { + while (*p == ' ') + p++; + + if (*p == '\0') + break; + + out[count] = strtol(p, &end, 10); + if (end == p) + return -1; + + count++; + p = end; + } + + while (*p == ' ') + p++; + + if (*p != '\0') + return -1; + + return count; +} + +static bool cmd_parse_int_args(const char *arg, int32_t *out, int32_t expect_count, + const char *usage_msg) +{ + int32_t parsed = cmd_parse_int_list(arg, out, expect_count); + + if (parsed != expect_count) + { + uart_send_msg("%s", usage_msg); + return false; + } + return true; +} + +static void cmd_handle_val(const char *arg) +{ + int32_t values[8] = { 0 }; + int32_t parsed = cmd_parse_int_list(arg, values, 8); + + if (parsed <= 0) + { + uart_send_msg("ERR usage: val n1 n2 ...\r\n"); + return; + } + + for (int32_t i = 0; i < parsed; i++) + { + uart_send_msg("%d\r\n", values[i]); + } +} + +void uart_cmd_process(void) +{ + if (!uart_is_frame_ready()) + return; + + const char *arg = NULL; + char *cmd = (char *)g_uart_rx_buf; + + if (strcmp(cmd, "help") == 0) + { + uart_send_msg("Commands:\r\n"); + uart_send_msg(" help - show this help\r\n"); + uart_send_msg(" fw_ver - show firmware version\r\n"); + uart_send_msg(" pwm_en 1/0 - enable/disable PWM output\r\n"); + uart_send_msg(" epwm_set_duty d1 d2 d3 - set duty for 3 channels\r\n"); + uart_send_msg(" val n1 n2 ... - parse integer values\r\n"); + } + else if (strcmp(cmd, "fw_ver") == 0) + { + uart_send_msg("FW: " FW_VERSION "\r\n"); + } + else if (cmd_match_with_arg(cmd, "pwm_en", &arg)) + { + if (arg[0] == '1') + { + epwm_en(1); + uart_send_msg("OK pwm on\r\n"); + } + else if (arg[0] == '0') + { + epwm_en(0); + uart_send_msg("OK pwm off\r\n"); + } + else + { + uart_send_msg("ERR usage: pwm_en 1/0\r\n"); + } + } + else if (cmd_match_with_arg(cmd, "epwm_set_duty", &arg)) + { + int32_t values[3] = { 0 }; + if (cmd_parse_int_args(arg, values, 3, + "ERR usage: epwm_set_duty duty1 duty2 duty3\r\n")) + { + epwm_set_duty(values[0], values[1], values[2]); + uart_send_msg("OK epwm_set_duty: %d %d %d\r\n", values[0], values[1], values[2]); + } + } + else if (cmd_match_with_arg(cmd, "val", &arg)) + { + cmd_handle_val(arg); + } + else + { + uart_send_msg("ERR unknown cmd\r\n"); + } + + /* Reset for next command */ + uart_clear_rx_frame(); +}