暫存
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "uart_cmd_srv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
Reference in New Issue
Block a user