- 2024-08-18
-
发表了主题帖:
【中科昊芯HXS320F28025C】电机FOC开环
本帖最后由 jixulifu2 于 2024-8-18 23:36 编辑
Field-Oriented Control (FOC) —— 磁场定向控制
磁场定向控制(Field-Oriented Control,简称FOC)是一种先进的电机控制策略,主要用于交流电机(如感应电机和永磁同步电机)的高性能控制。FOC的主要目的是通过精确控制电机的磁场和转矩,来实现电机的高效和精确控制。
FOC的工作原理
FOC的核心思想是将电机的旋转坐标系(dq坐标系)与电机的磁场方向对齐,从而将电机的多相(通常是三相)电流分解成两个独立的分量:励磁电流(d轴电流)和转矩电流(q轴电流)。这种分解使得电机的控制变得更加直观和简单,因为可以通过单独控制这两个分量来分别控制电机的磁场和转矩。
下面是FOC经典框图
HXS320F280025C是昊芯浮点DSC平台上的最新产品,基于自主研发的H28x内核,32位浮点RISC-V DSP架构,支持三角函数数学单元和CRC扩展指令集,完美适配FOC。该片增加了可配置逻辑模块(CLB),用户可添加自定义逻辑:支持多种通信端口,增强型控制外设,可满足电机驱动/控制、光伏逆变器和数字电源等行业的产品布局;基于FPU浮点处理单元,支持FOC算法、有感/无感角度分析、多电平控制、复杂电力电子拓扑算法以及宽带半导体驱动等应用。
今天我们手撸一个简易FOC开环框架:
思路解析解析:
刨去三环,编码器和3相全桥电路,我们要实现的是输入Ud.Uq,angle,输出ABC桥控制信号,也就是占空比信息。
Ud、Uq:通常称为 dq 坐标系。这个坐标系包括 d 轴(励磁轴)和 q 轴(转矩轴)。Ud 表示 d 轴上的电压分量,Uq 是施加在 q 轴上的电压分量,用于控制转矩电流 Iq。转矩电流 Iq 与电机产生的转矩有关,通过控制 Uq,可以调整电机的转矩。这两个值是我们人为设定的,所以只需要在后面代码中传入参数计算就可以。
Ud、Uq与Uαβ的关系:无刷电机通常由UVW三相组成,为了方便计算,需要把三相中每一项的分量隐射到一个直角坐标系Uα,Uβ中,使用我们最常见的三角函数解一下,如下图示意
公式:
Uα=Udcos(θ)−Uqsin(θ)
Uβ=Udsin(θ)+Uqcos(θ)
Uα 和 Uβ 分别是 αβ 坐标系下的电压分量。
Ud和 Uq分别是 dq 坐标系下的电压分量。
θ 是电机定子磁场角度。
求出Uα和Uβ后传入SVPWM模块
SVPWM介绍:SVPWM的核心是将电机所需的电压表示为一系列空间矢量,并通过选择适当的电压矢量来合成期望的输出电压。这种方法能够更高效地利用逆变器的电压和电流容量,进而提高电机驱动系统的整体效率。
放两张教材里的图吧,详细介绍的话可以单独开一个篇章,有兴趣的小伙伴自行查看吧
接下来是Clark变换:
主要用于将三相静止坐标系下的信号转换到两相静止坐标系下,理解了Clark也就理解了反Park
减少维度:从三个变量减少到两个变量,简化了控制系统的设计。
保持功率不变:Clark变换是等功率变换,即变换前后系统的总功率保持不变。
便于控制:两相坐标系下的信号更容易被控制算法处理,特别是对于矢量控制技术而言
接下来就愉快的手撸代码吧:
延续上一期的工程,新建一个FOC.c和FOC.h
#include "FOC.h"
#include <math.h>
#define PWM_Period
#define _PI 3.14159265359
#define _PI_2 1.57079632679
#define _PI_3 1.0471975512
#define _2PI 6.28318530718
#define _3PI_2 4.71238898038
#define _PI_6 0.52359877559
#define _SQRT3 1.73205080757
float voltage_power_supply;
// 设置PWM
// 输入参数:
// - Uq: q轴电压分量
// - Ud: d轴电压分量
// - angle_el: 电角度
void SetSVPWM(float Uq, float Ud, float angle_el)
{
float Uref;
float U_alpha,U_beta;
float T0,T1,T2;
float Ta,Tb,Tc;
int sector;
//反Park
U_alpha=Ud*cos(angle_el)-Uq*sin(angle_el);
U_beta=Ud*sin(angle_el)+Uq*cos(angle_el);
//计算参考电压矢量的幅值
Uref=_sqrt(U_alpha*U_alpha + U_beta*U_beta) / voltage_power_supply;
//六边形的内切圆(SVPWM最大不失真旋转电压矢量赋值)根号3/3
if(Uref> 0.577)Uref= 0.577;
if(Uref<-0.577)Uref=-0.577;
//判断参考电压矢量所在扇区:
angle_el = Angle_deal(angle_el+_PI_2);
sector = (angle_el / _PI_3) + 1;
//计算两个相邻电压矢量作用时间
T1 = _SQRT3*sin(sector*_PI_3 - angle_el) * Uref;
T2 = _SQRT3*sin(angle_el - (sector-1.0)*_PI_3) * Uref;
T0 = 1 - T1 - T2;
switch(sector)
{
case 1:
Ta = T1 + T2 + T0/2;
Tb = T2 + T0/2;
Tc = T0/2;
break;
case 2:
Ta = T1 + T0/2;
Tb = T1 + T2 + T0/2;
Tc = T0/2;
break;
case 3:
Ta = T0/2;
Tb = T1 + T2 + T0/2;
Tc = T2 + T0/2;
break;
case 4:
Ta = T0/2;
Tb = T1+ T0/2;
Tc = T1 + T2 + T0/2;
break;
case 5:
Ta = T2 + T0/2;
Tb = T0/2;
Tc = T1 + T2 + T0/2;
break;
case 6:
Ta = T1 + T2 + T0/2;
Tb = T0/2;
Tc = T1 + T0/2;
break;
default: // 错误状态
Ta = 0;
Tb = 0;
Tc = 0;
}
//输出PWM,配置占空比
EPWM_setCounterCompareValue(epwm1Info.epwmModule, EPWM_COUNTER_COMPARE_A, Ta*PWM_Period);
EPWM_setCounterCompareValue(epwm2Info.epwmModule, EPWM_COUNTER_COMPARE_A, Tb*PWM_Period);
EPWM_setCounterCompareValue(epwm3Info.epwmModule, EPWM_COUNTER_COMPARE_A, Tc*PWM_Period);
}
//将输入的角度 angle 归一化到 [0, 2π) 区间内。
float Angle_deal(float angle)
{
float a = fmod(angle, _2PI);
return a >= 0 ? a : (a + _2PI);
}
代码中并没有角度获得方式,可以在主循环while(1)里模拟一个自增的开环角度,当然也可以来自编码器、霍尔或者无传感器算法估算的转子位置。
受限于手头并没有实物,我们就不做演示了。
- 2024-08-10
-
发表了主题帖:
【中科昊芯HXS320F28025C】PWM实现;死区设置。
EPWM模块
PWM是一种脉宽调制技术,广泛应用于电机控制、LED亮度调节、音频放大等领域。PWM的基本原理是通过改变脉冲信号的宽度来调节输出功率,从而实现对负载的有效控制。大部分MCU都内置了PWM功能(如STM32,ARDUINO等),可以直接通过专用的定时器或外围设备来生成PWM信号。这些MCU的PWM功能通常只能提供较为一般的功能。中科昊芯HXS320F28025C内置了增强型脉宽调制器(ePWM),相比市面常见的MCU,功能更加强,配置更灵活,安全保护更完善。更适合越来越复杂的电力电子与电机控制。
中科昊芯HXS320F28025C的增强型脉宽调制器(ePWM)有以下几个子模块:
•时基子模块 Time-Base
•计数器比较子模块Counter Compare
•动作限定子模块Action Qualifier
•死区发生器子模块Dead-Band Generator
•PWM斩波器(PC)子模块 PWM Chopper
•错误联防子模块Trip Zone
•事件触发子模块Event Trigger
•数字比较子模块Digital Compare
每个ePWM模块都支持以下功能:
•带周期和频率控制的专用16位时基计数器
•两个PWM输出(EPWMxA和EPWMxB),可配置为:
–两个独立的PWM输出,单边操作
–两个独立的PWM输出,双边对称模式
–一个独立的PWM输出,双边不对称模式
•通过软件对PWM信号进行异步超驰控制。
•对于其他ePWM模块的可编程的相位控制(滞后或超前)。
•逐周期地进行硬件锁定(同步)的相位关系。
•具有独立的上升沿和下降沿延迟控制的死区功能。
•在错误联防情况下,可编程的逐周期错误联防和单次错误联防。
•错误联防条件下,可强制PWM输出高、低或高阻状态逻辑电平。
•所有事件均可触发CPU中断和ADC转换开始(SOC)
•可编程的事件预分频可最大程度地减少中断时的CPU开销。
•通过高频载波信号进行PWM斩波,用于脉冲变压器栅极驱动
内部框图如下:
更多关于中科昊芯HXS320F28025C的EPWM的信息,可以自行查阅datasheet。
PWM信号由一系列周期性的脉冲组成,每个脉冲都有固定的周期T,脉冲的宽度(即高电平持续的时间)可以根据需要进行调节。脉冲的宽度与周期的比例称为占空比(Duty Cycle),占空比决定了输出信号的平均电压值。例如,如果脉冲宽度为周期的一半,则占空比为50%,输出信号的平均电压为电源电压的一半。我们配置输出一个1khz,占空比50%的PWM信号。
F28025C主频160Mhz,预分频16,高速分频10,160Mhz/16/10 = 1Mhz.
设置时基周期,500, 1M/(500*2)=1KHz = 1ms一个周期
占空比设置为50%
EPWM1设置在IO0.0和0.1上输出互补信号
/*设置时钟分频 时钟分频/16,高速时钟分频/10,160M/16/10=1M*/
EPWM_setClockPrescaler(myEPWM1_BASE, EPWM_CLOCK_DIVIDER_16, EPWM_HSCLOCK_DIVIDER_10);
/*设置时基周期,500, 1M/(500*2)=1KHz*/
EPWM_setTimeBasePeriod(myEPWM1_BASE, 500);
EPWM_setTimeBaseCounter(myEPWM1_BASE, 0);
/*设置时基计数模式,上下计数*/
EPWM_setTimeBaseCounterMode(myEPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
EPWM_disablePhaseShiftLoad(myEPWM1_BASE);
EPWM_setPhaseShift(myEPWM1_BASE, 0);
/*设置计数器比较值,COMPARE_A,500*/
EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_A, 250);
EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);
/*设置计数器比较值,COMPARE_B,1500*/
EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_B, 250);
EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
/*ePWM1A,输出引脚置低,时基计数器等于0*/
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
/*ePWM1A,输出引脚置高,时基计数器上升时等于CMPA*/
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
/*ePWM1A,输出引脚置低,时基计数器下降时等于CMPA*/
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
/*ePWM1B,输出引脚置低,时基计数器等于0*/
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
/*ePWM1B,输出引脚置高,时基计数器上升时等于CMPA*/
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
/*ePWM1B,输出引脚置低,时基计数器下降时等于CMPA*/
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
更改GPIO功能与开启时钟代码:
GPIO_setPinConfig(GPIO_0_EPWM1_A);
GPIO_setPinConfig(GPIO_1_EPWM1_B);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
同时开启一个板载LED灯闪烁,可以观察程序是否在运行。
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(31, GPIO_QUAL_SYNC);
GPIO_writePin(31,1);
for(;;)
{
GPIO_togglePin(31);
for(number = 0; number < 500; number ++)
DEVICE_DELAY_US(1000);
}
程序写好后点击DOWNLOAD,可以看到开发板板载红灯闪烁,证明程序已经正常运行,接上示波器查看IO00和IO01波形。
可以看到正常输出1khz的占空比50%的波形。
死区的概念:
简单解释:通常,大功率电机、变频器,末端都是由大功率管、IGBT等原件组成的
H桥或3湘桥,每个桥的上半桥和下半桥是绝对不能相同的,但高速的PWM驱动信号在达到功率元件的控制基时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥原件在应该关断时没有关断,造成功率元件烧毁
死区就是在上半桥关断后,延迟一段时间在打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁,这段延迟时间就是死区
中科昊芯HXS320F28025C自带死区产生模块
/*设置死区延时极性,死区下降沿,极性反向*/
EPWM_setDeadBandDelayPolarity(myEPWM1_BASE, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
/*设置死区延时模式,死区上升沿延时,开启*/
EPWM_setDeadBandDelayMode(myEPWM1_BASE, EPWM_DB_RED, true);
/*设置死区上升沿延时数,*/
EPWM_setRisingEdgeDelayCount(myEPWM1_BASE, 100);
/*设置死区延时模式,死区下降沿延时,开启*/
EPWM_setDeadBandDelayMode(myEPWM1_BASE, EPWM_DB_FED, true);
/*设置死区下降沿延时数,*/
EPWM_setFallingEdgeDelayCount(myEPWM1_BASE, 100);
再次查看波形
图中红线框内的时间差即为死区时间,可以有效防止MOS管频繁开关导致的损坏。
- 2024-07-14
-
发表了主题帖:
【中科昊芯HXS320F28025C】系统初始化函数学习和熟悉库函数风格
本帖最后由 jixulifu2 于 2024-7-14 16:39 编辑
上一章点灯调试串口的过程中,跳过了系统初始化部分。今天就来一起过一下吧。
0x00: Device_init()中的函数:
//
// Disable the watchdog
//
SysCtl_disableWatchdog();
//
// Call Device_cal function when run using debugger
// This function is called as part of the Boot code. The function is called
// in the Device_init function since during debug time resets, the boot code
// will not be executed and the gel script will reinitialize all the
// registers and the calibrated values will be lost.
// Sysctl_deviceCal is a wrapper function for PMUTrims_cal OscTrims_cal
//
SysCtl_deviceCal();
//
// Call Flash Initialization to setup flash waitstates. This function must
// reside in RAM.
//
Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);
//
// Set up PLL control and clock dividers
//
SysCtl_setClock(DEVICE_SETCLOCK_CFG);
//
// Make sure the LSPCLK divider is set to the default (divide by 4)
//
SysCtl_setLowSpeedClock(SYSCTL_LSPCLK_PRESCALE_4);
//
// These asserts will check that the #defines for the clock rates in
// device.h match the actual rates that have been configured. If they do
// not match, check that the calculations of DEVICE_SYSCLK_FREQ and
// DEVICE_LSPCLK_FREQ are accurate. Some examples will not perform as
// expected if these are not correct.
//
ASSERT(SysCtl_getClock(DEVICE_OSCSRC_FREQ) == DEVICE_SYSCLK_FREQ);
ASSERT(SysCtl_getLowSpeedClock(DEVICE_OSCSRC_FREQ) == DEVICE_LSPCLK_FREQ);
//
// Turn on all peripherals
//
Device_enableAllPeripherals();
//
// Lock VREGCTL Register
// The register VREGCTL is not supported in this device. It is locked to
// prevent any writes to this register
//
ASysCtl_lockVREG();
static inline void
SysCtl_disableWatchdog(void)
{
EALLOW;
//
// Set the disable bit.
//
HWREG(WD_BASE + SYSCTL_O_WDCR) = (HWREG(WD_BASE + SYSCTL_O_WDCR) & ~0x80)
| (SYSCTL_WD_CHKBITS | SYSCTL_WDCR_WDDIS);
EDIS;
}
使用静态+内联修饰函数,确保代码只提供接口,不能修改。内联修饰优化效率。
EALLOW;EDIS;是宏定义的汇编代码。
跳转定义后发现除了常用的NOP还有EINT;和DINT;
#define NOP asm volatile("nop")
#define EALLOW asm("csrsi 0x7C1, 0x01") // eallow register id is 0x7C1 ,enable write spieacl register
#define EDIS asm("csrci 0x7C1, 0x01") // disable
//#define ESTOP0 asm(" ESTOP0") //if in debug ,set 1 dsp stop,not in debug, just a nop
//#define ESTOP0 asm(" ebreak"); //send debug call
#define EINT asm("csrsi mstatus, 0x8")
#define DINT asm("csrci mstatus, 0x8")
EALLOW;EDIS;注释写的很清楚,分别是开启写特殊功能寄存器功能和关闭写特殊功能寄存器。
在官方参考手册中,有如下解释:
3.1.2 EALLOW 保护
系统中的一些寄存器通过 EALLOW 保护机制来防止出现虚假的 CPU 写操作。 它使用
特殊的 CPU 指令 EALLOW 和 EDIS 来启用和禁用对受保护寄存器的访问。 当前保护状态
由 CPU ST1 寄存器中的 EALLOW 位给出, 如表 3-1。
寄存器保护在启动时默认启用。 当受保护时, CPU 对受保护寄存器的所有写操作都
被忽略。 只允许 CPU 读、 JTAG 读和 JTAG 写。 如果通过执行 EALLOW 指令禁用了保护,
则允许 CPU 自由地写入受保护的寄存器。 在修改寄存器之后, 可以通过执行 EDIS 指令
清除 EALLOW 位来再次保护它们。
对时钟配置和外设时钟启用寄存器的写入可能会被禁用, 直到下一次通过写入特
殊锁寄存器进行复位
表 3-1 访问受 allow 保护的寄存器
EALLOW 位 CPU 写 CPU 读 JTAG 写 JTAG 读
0 Ignored Allowed Allowed Allowed
1 Allowed Allowed Allowed Allowed
(1) EALLOW 位被 JTAG 端口覆盖, 允许在代码调试期间完全访问受保护的寄存器 IDE
™ 接口。
DINT和EINT没有注释,查询参考手册里发现如下解释:
和 PIE 一样, CPU 为它的每个中断提供标志并使能寄存器位。 有一个使能寄存器
(IER)和一个标志寄存器(IFR), 它们都是内部 CPU 寄存器。 还有一个全局中断掩码,
由 Mstatus 寄存器中 MIE 位控制。 可以使用 CPU 的 SETC 和 CLRC 指令设置和清除此掩
码。 在 C 代码中, DINT 和 EINT 宏可以用于此目的。(不同)
可以发现DINT和EINT是开关全局中断的汇编
参考手册中3.5.4.3介绍禁用中断章节的内容中有实际流程设计DINT和EINT:
1.全局禁用中断( DINT)。
2.清除 PIEIER bit。
3.等待 5 个周期, 以确保任何传播中断已到达 CPU IFR 寄存器。
4.清除中断 PIE 组的 CPU IFR 位。
5.清除中断的 PIE 组的 PIEACK 位。
6.全局使能中断( EINT)。
可以使用 CPU IER 寄存器禁用中断组。 这不会导致竞争状况, 因此不需要特殊程
序。
看完汇编继续回来。disablewatchdog中除了汇编只有一句代码。
跳转HWREG
#define HWREG(x) \
(*((volatile uint32_t *)((uintptr_t)(x))))
#define HWREG_BP(x) \
(*((volatile uint32_t *)((uintptr_t)(x))))
使用volatile修饰的uint32_t类型的指针,直接操作硬件地址,是一种更底层但是效率极高的用法。
HWREG(WD_BASE + SYSCTL_O_WDCR) = (HWREG(WD_BASE + SYSCTL_O_WDCR) & ~0x80)| (SYSCTL_WD_CHKBITS | SYSCTL_WDCR_WDDIS);
传入HWREG函数的是WD的基地址加O_WDCR的偏移地址
#define WD_BASE 0x00038E00U
#define SYSCTL_O_WDCR 0x50U // Watchdog Control Register
把SYSCTL_O_WDCR实际地址上的0x80位清零并且与上SYSCTL_WD_CHKBITS和SYSCTL_WDCR_WDDIS
static inline void
SysCtl_deviceCal(void)
{
//
// Call the PMUTrims_cal OscTrims_cal function
//
(* PMUTrims_cal)();
(* OscTrims_cal)();
}
使用两个函数指针调用了宏定义分别对电源管理和时钟进行校准。
//
// Call Flash Initialization to setup flash waitstates. This function must
// reside in RAM.
//
Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);
看函数名就知道是配置关于flash的内容
//*****************************************************************************
//
// Flash_initModule
//
//*****************************************************************************
void CODE_SECTION("ramfuncs")
Flash_initModule(uint32_t ctrlBase, uint32_t eccBase, uint16_t waitstates)
{
//
// Check the arguments.
//
ASSERT(Flash_isCtrlBaseValid(ctrlBase));
ASSERT(Flash_isECCBaseValid(eccBase));
ASSERT(waitstates <= 0xFU);
//
// Set the bank fallback power mode to active.
//
Flash_setBankPowerMode(ctrlBase, FLASH_BANK, FLASH_BANK_PWR_ACTIVE);
//
// Disable cache and prefetch mechanism before changing wait states
//
Flash_disableCache(ctrlBase);
Flash_disablePrefetch(ctrlBase);
//
// Set waitstates according to frequency.
//
Flash_setWaitstates(ctrlBase, waitstates);
//
// Enable cache and prefetch mechanism to improve performance of code
// executed from flash.
//
Flash_enableCache(ctrlBase);
Flash_enablePrefetch(ctrlBase);
//
// At reset, ECC is enabled. If it is disabled by application software and
// if application again wants to enable ECC.
//
Flash_enableECC(eccBase);
//
// Force a pipeline flush to ensure that the write to the last register
// configured occurs before returning.
//
FLASH_DELAY_CONFIG;
}
修饰函数名称中有CODE_SECTION("ramfuncs")实际为#define CODE_SECTION(v) __attribute__((section(v)))的宏定义
表明这段代码定义再ram区固定块中。
通过断言判断传入参数的合理性,
设置后备电源模式为主动后备模式
禁用缓存和预取机制,然后根据频率设置等待状态,接着启用缓存和预取机制以提高从闪存执行的代码的性能。启动错误校验。
配置完成后通过flash_delay_config宏定义延迟,等待配置生效
#define FLASH_DELAY_CONFIG asm volatile(".align 2;RPTI 10,4;NOP")
时钟配置比较复杂,我们后面再看,接下来的
void Device_enableAllPeripherals(void)
{
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DMA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER0);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TIMER2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CPUBGCRC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HRPWM);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ERAD);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM4);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM5);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM6);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM7);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM8);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HRCAP);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SCIA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIB);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2CA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2CB);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_I2S);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCC);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS3);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CMPSS4);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_FSITXA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_FSIRXA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_LINA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_LINB);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_PMBUSA);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DCC0);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DCC1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB2);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_HICA);
}
使能了所有外设的时钟
static inline void ASysCtl_lockVREG(void)
{
EALLOW;
//
// Write a 1 to the lock bit in the LOCK register.
//
HWREG(ANALOGSUBSYS_BASE + ASYSCTL_O_LOCK) |= ASYSCTL_LOCK_VREGCTL;
EDIS;
}
设置了ADCLOCK寄存器的LOCK位
DEVICE_INITGPIO()解锁了所有IO口
void Device_initGPIO(void)
{
//
// Disable pin locks.
//
GPIO_unlockPortConfig(GPIO_PORT_A, 0xFFFFFFFF);
GPIO_unlockPortConfig(GPIO_PORT_B, 0xFFFFFFFF);
GPIO_unlockPortConfig(GPIO_PORT_H, 0xFFFFFFFF);
}
void
Interrupt_initModule(void)
{
//
// Disable and clear all interrupts at the CPU
//
(void)Interrupt_disableGlobal();
IER = 0x0000U;
IFR = 0x0000U;
//
// Clear all PIEIER registers
//
HWREG(PIECTRL_BASE + PIE_O_IER1) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER2) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER3) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER4) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER5) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER6) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER7) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER8) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER9) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER10) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER11) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IER12) = 0U;
//
// Clear all PIEIFR registers
//
HWREG(PIECTRL_BASE + PIE_O_IFR1) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR2) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR3) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR4) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR5) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR6) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR7) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR8) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR9) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR10) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR11) = 0U;
HWREG(PIECTRL_BASE + PIE_O_IFR12) = 0U;
//
// Enable vector fetching from PIE block
//
HWREG(PIECTRL_BASE + PIE_O_CTRL) |= PIE_CTRL_ENPIE;
}
//*****************************************************************************
//
// Interrupt_initVectorTable
//
//*****************************************************************************
void
Interrupt_initVectorTable(void)
{
uint32_t i;
EALLOW;
//
// We skip the first three locations because they are initialized by Boot
// ROM with boot variables.
//
for(i = 3U; i < 224U; i++)
{
HWREG(PIEVECTTABLE_BASE + (4U * i)) =
(uint32_t)Interrupt_defaultHandler;
}
//
// NMI and ITRAP get their own handlers.
//
HWREG(PIEVECTTABLE_BASE + ((INT_NMI >> 16U) * 4U)) =
(uint32_t)Interrupt_nmiHandler;
EDIS;
}
中断全部清零,中断向量表也全部清零。
- 2024-07-09
-
发表了主题帖:
【中科昊芯】国产DSP初体验之环境搭建与点灯
本帖最后由 lugl4313820 于 2024-7-19 08:32 编辑
1.实物开箱:
包装精美,布局合理,功能齐全,丝印清晰。油墨为深红色,和某德开发板颇为相近。
2.板载硬件
DSP:HXS320F28025C
--主频:160Mhz
--增强型外设:ePWM、HRPWM、eCAP、HRCAP、eQEP、ADC、CLB
--32BIT*3 定时器
--LQFP-64
HX-link 110V隔离调试器
CAN收发器、FSI、EQEP、
兼容Boosterpack扩展包
3.开发环境
Haawking IDE
--基于eclipse深度定制,是市面上众多MCU厂商的青睐之选。ST的CubeIDE、TruStudio、NXP的S32DS、TI的CCS都是基于此IDE。上手难度不会很高,资料众多,易于学习。
4.创建工程
第一次打开进入welcom界面
--
--可以选择新建工程或者下载例程
点击新建工程芯片选择HSX320F280025C-EDC
输入Project name
选择程序运行在flash中
新建的工程如下图:
Device_init()中包含了时钟配置和断言,使能外设,选择程序运行在FLASH等功能,
我们暂时不需要去管它。
----
在工程文件中找到外设驱动lib:
haawking-drivers - haawking-dsc280025_edc-board - inc
打开GPIO.C和GPIO.H文件。
粗看下来
GPIO_setDirectionMode(uint32_t pin, GPIO_Direction pinIO)
GPIO_setPinConfig(uint32_t pinConfig)
这两个函数跟输出配置有关。
打开开发板原理图,查看LED对应的端口为GPIO31、GOIO34
初始化两个引脚,配置为输出模式,默认不加上拉,用户手册上有toggle翻转寄存器,在.h里写好的函数
直接调用外加延时函数。
切换到haawking,点击bilid,没有报错,点击download下载到开发板上。
两个灯会亮了,但是没有闪烁。重新查看一遍代码,发现是想当然了。延时以us计算的。把他当成ms用了。
写一个for循环执行1000次,再次下载,小灯就闪烁起来啦!
我们平常用的串口在32单片机上叫UART,HXS280上名字是SCI。会有一些寄存器的配置,为了节省时间我们直接移植官方历程。
打开官方库中的SCI_LOOPBACK工程,可以看到关于SCI的配置都在board.c和board.h里,我们在工程里新建.C和.H文件,把它们复制过来
在主函数里初始化配置,根据SCI发送函数写一个字符串发送helloworld
间隔打印到串口。
编译烧录一气呵成,打开串口助手,可以看到COM35已经不停接收到开发板打印出来的字符串啦。
点完灯,调完串口,就算是对板子有一个初步的了解了。接下来让我们探究更多的外设吧!
- 2024-07-05
-
加入了学习《DIY作品演示》,观看 【FM33LG0系列开发板测评】07.LCD & 段码显示软件实现框架
-
回复了主题帖:
Vllink/JLINK/STLINK 下载速度测试
flyaqiao 发表于 2024-7-5 09:50
为啥我的VLLINK 5M及以上都识别不了芯片了.你们还能测试到10M
有线无线,V1和V2都是这样
STM32H750的 ...
5M的下载速度怎么样?日常使用会感觉到慢吗?
-
回复了主题帖:
Vllink/JLINK/STLINK 下载速度测试
flyaqiao 发表于 2024-7-5 09:50
为啥我的VLLINK 5M及以上都识别不了芯片了.你们还能测试到10M
有线无线,V1和V2都是这样
STM32H750的 ...
更新固件看看呢。我两台笔记本都能识别到V2,台式机不能识别。不清楚什么原因
-
发表了主题帖:
Vllink/JLINK/STLINK 下载速度测试
本帖最后由 jixulifu2 于 2024-7-5 01:05 编辑
环境:
1. 电脑系统:Windows7 64bit
2.MDK:5.39
3.测试DEMO编译完成后:
Program Size: Code=115630 RO-data=28662 RW-data=292 ZI-data=33752092
bin文件:142kb
hex文件:398kb
axf文件:1396kb
测试成员:
1.Vllink 无线模式
2.Vllink 有线模式
3.JLINK-V9 “国产”版
4.ST-linkV2
5.PWLINK-LITE
特别说明:
1.无线环境为中低干扰
2.台式机始终识别不到Vllink的CMSIS-DAPV2 所以Vllink 数据均基于CMSIS-DAP V1模式
下载速度:
1.Vllink 有线模式 10MHZ
下载用时:7s
2.Vllink 无线模式 10MHZ
下载用时:11s
3.JLINK-V9 50MHZ
下载用时:8s
4.ST-LINK V2 10MHZ
下载用时:9s
5.PW-LINK LITE
HID模式 下载用时:8s
WINUSB模式 下载用时:14s
总结:在基于没有调通DAP-V2的情况下,VVLINK2依然取得了一秒领先的成绩。我猜想这主要归功于这颗高达240MHZ的主控,在PW-LINK的身上可以显而易见地发现DAP-V2对下载速度会有巨大提升。可惜的是笔者通过更新固件,升级KEIL版本等方法,并没有如愿体验到满血模式的VVLINK。测试工程涵盖了七寸LCD驱动,MJPEG,Audio,Vedio,fatfs等功能。已经足够模拟大部分工作环境。VVLINK无线模式也仅落后常规下载器三秒左右。相较于便利性的提升,这3秒的时间是完成可以接受的。
- 2024-07-04
-
回复了主题帖:
【高速无线调试器】2、无线调试初体验-随机一块开发板
常见泽1 发表于 2024-7-2 12:55
对于CMSIS-DAP v2来说,本调试器需要5.36版本(keil)以
————
我用的5 ...
我是5.36,但是没有V2选项,不知道为什么?
- 2024-07-03
-
回复了主题帖:
测评入围名单: 中科昊芯HXS320F28025C,基于RISC-V的DSP
个人信息无误,确认可以完成测评分享计划
- 2024-07-01
-
回复了主题帖:
【Vllink Basic2无线调试器评测】
秦天qintian0303 发表于 2024-7-1 10:10
具体原因就是USB扩展口的问题?都在高速运行导致不识别了?
具体原因没有找出来。可能跟usb前面板的hub不兼容吧。
- 2024-06-30
-
发表了主题帖:
【Vllink Basic2无线调试器评测】
本帖最后由 jixulifu2 于 2024-6-30 15:02 编辑
Vllink Basic2无线烧录器评测
1.开箱
【实物图】
Vllink Basic2 简介:
Vllink Basic2是le062出品的高速无线调试器无干扰第二代,有线、无线调试场合均适用。无线调试速度可达130KB/s室内10m内可穿墙,室外无遮挡可传输50m;支持SWD、JTAG、UART-CDC;CMSIS-DAP V1/V2双免驱协议。
技术优势:
-USB2.0高速,跑V1 HID协议也不是龟速
-WiFi6 5.8G,默认165信道,此信道99%的无线路由器不会用,干扰少
-集成电平转换芯片,参考电平范围:1.2V-5.5V
-内置数字电压源:可通过VRef脚输出:1.8V/2.5V/3.3V/4.0V,限流200mA
主控采用爱科微的AIC8800M
RAM容量:992 KB (4M PSRAM)
Flash容量:2 MB
240MHz Cortex-M4 Dual
Core480MHz DSP
2.4G/5G Wi-Fi6BT
5.0 EDR/BLE 蓝牙双模
USB HS 2.0 OTG PHY
1x 60MHz SPI,1x I2C,3x UART,SDIO,I2S
2.环境安装
Vllink Basic2采用免驱方案,理论上是插入即用的,但是人生处处是惊喜(惊吓),此处留个坑,文末再讲。
不出意外的话,如下所示:
如果是WIN10以下的系统,可能需要自装驱动,参考官网链接:Windows7 驱动安装 — Vllogic 文档。
3.下载与仿真
出厂自带一主一从无线模式,双击按键所有指示灯闪烁表面正在切换模式,直到AP,STA指示灯全灭为有线模式。
根据接口定义连使用自带杜邦线连接目标板,对比标准jtag口引脚是顺的,不用被拧成麻花,这点好评!
需要注意的是Vref要接到VCC(optional)上才读的到芯片。
接下来进入仿真测试环节
测试环境:MDK v5.39
测试芯片:STM32F429IGT6
编译环境:AC5
建立测试工程项目过程略过,直接进入设置,仿真设备选择CMSIS-DAP,如下所示:
配置好下载器设置后重新编译工程,点击下载,可以看到Erase Done. Programming Done.Verify OK. 表明下载成功。
点击DEBUG按钮,进入仿真模式,全速运行,可以正常查看变量数据,暂停可以看到堆栈指针变化。
至此有线下载仿真结束。
接下来,先将调试器的数据线从计算机断开连接,此时,通过开发板的5V电源供电。为了切换至无线客户端(STA)模式,双击调试器上的按钮进行模式转换,此时STA指示灯,开始闪烁,表示设备正处于未连接到无线接入点(AP)的状态。
使用数据线将AP端与电脑相连。两个调试器便迅速配对完成,AP,STA灯进入长亮状态。打开手机wifi,能看到wifi名称
点击下载按钮。程序也是顺利下载进开发板里跑了起来。
[localvideo]a374366851aaa8e006c6a9957e88b685[/localvideo]
进入调试模式,打满断点,不断点击运行。能看到X的VALUE不断自增,开发板的幻灯片一张一张变换。
我是调试接线,裁剪图片,写文章同时进行的,从第一次连接上wifi到此时此刻,一共接近30分钟,反复烧写,退出进入仿真模式,都是稳如老狗,没有发生断触丢包。
今天只是开胃小菜,接下来还会进行
-极限距离烧写调试测试
-穿墙烧写调试测试
-强干扰下的调试测试
-还有st-link,jlink,pwlink同台竞技对比烧写速度
4.番外
上文中Vllink Basic2采用免驱方案,理论上是插入即用的,但是人生处处是惊喜(惊吓)
为什么是惊吓呢?我习惯通过前端面板的3个USB接口配合一根连接到机箱后部的USB延长线来使用我的PWLink和JLink调试器。我给Vllink Basic2通过前面板USB口上电后keil里查看不到设备,设备管理器里没有任何反应,音响传出叮咚叮咚反复断联重连的声音,反插 ,正插,换口,换机箱后延长线都不奏效。我心想不会是被我搞坏了吧,立刻打开笔记本尝试。一次成功。悬着的心放下来。排除了Vllink的问题,接下来开始找台式机的问题。首先想到的是会不会被我前面板USB口上的蓝牙模块和2.4G手柄模块干扰了。全部拔下,无果。会不会是前面板不兼容呢?后面板大概率不会不兼容,随即反复在延长线上尝试正反插,都没有效果,梅雨天气又闷又热,心中很是烦躁。会不会是平常调试的时候把后面板的这个USB口烧掉了呢?跑到后面把USB耳机拔下,把Vllink通过A-C的线直插这个口上,叮咚一声后便不再响了。心中大喜。果然正常连上了。擦了擦汗终于可以愉快的调试了。吃一堑长一智,以后碰到连不上的设备应该直接去后USB口试。
- 2024-06-24
-
回复了主题帖:
测评入围名单: 高速无线调试器(WiFi6免干扰),追加了4个
个人信息无误,确认可以完成测评分享计划