void MX_TIM1_Init(void)
{
long int Temp;
//==1、使能时钟===============
PWM_GPIO_RCC_ENABLE();
PWM_TIMER_RCC_ENABLE();
//============================
//==2、配置GPIO引脚================================================
gpio_init(GPIO_PORT_PWM_CH1, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
PWM_CH1_PIN);
gpio_init(GPIO_PORT_PWM_CH2, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
PWM_CH2_PIN);
gpio_init(GPIO_PORT_PWM_CH3, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
PWM_CH3_PIN);
gpio_init(GPIO_PORT_PWM_CH1N, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
PWM_CH1N_PIN);
gpio_init(GPIO_PORT_PWM_CH2N, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
PWM_CH2N_PIN);
gpio_init(GPIO_PORT_PWM_CH3N, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
PWM_CH3N_PIN);
//=====================================================================
//==3、复位寄存器================================================
/*reset register*/
TIMER_CTL0(PWM_TIMER) = 0;
TIMER_CTL1(PWM_TIMER) = 0;
TIMER_SMCFG(PWM_TIMER) = 0;
TIMER_DMAINTEN(PWM_TIMER) = 0;
TIMER_CHCTL0(PWM_TIMER) = 0;
TIMER_CHCTL1(PWM_TIMER) = 0;
//=================================================================
//==4、配置寄存器=======================================================
TIMER_CTL0(PWM_TIMER) =
(1 << 1) | (0 << 2) | (0 << 3) | (1 << 5) | (1 << 7) | (0 << 8);
TIMER_CTL1(PWM_TIMER) =
(0 << 0) | (0 << 2) | (0 << 3) | (7 << 4); // use O3CPRE trigger TRGO
TIMER_SMCFG(PWM_TIMER) = (1 << 4); // NO USE
TIMER_PSC(PWM_TIMER) = 0; //预分频器设置
TIMER_CAR(PWM_TIMER) =
(PWM_DOMAIN_CLK_FRQ >> 1) /
SYS_PWM_FREQ; //重载寄存器,设定计数器周期,根据PWM频率设置
TIMER_CREP(PWM_TIMER) = 0; //重载同期计数器
TIMER_CHCTL0(PWM_TIMER) = 0x6868;
TIMER_CHCTL1(PWM_TIMER) = 0x6868;//0x68代表
TIMER_CHCTL2(PWM_TIMER) |= 0x555;//配置TIM0的三个通道0、1、2的输出极性
/*configure deadtime*/
{
Temp = (int)(PWM_DEAD_TIME_VALUE * PWM_DOMAIN_CLK_FRQ *
0.000001); // 0.4us死区
if (Temp > 1008)
Temp = 1008;
else if (Temp >= 504) //(32 + x)*16
{
Temp = (Temp >> 4) - 32;
Temp |= 0x7 << 5;
} else if (Temp >= 254) //(32 + x)*8
{
Temp = (Temp >> 3) - 32;
Temp |= 0x6 << 5;
} else if (Temp >= 127) //(64 + x)*2
{
Temp = (Temp >> 1) - 64;
Temp |= 0x1 << 7;
Temp |= 0x2 << 6;
}
}
TIMER_CCHP(PWM_TIMER) =
0x4c00 + Temp; //后面的数据为死区时间的周期数,注意这个寄存器只能写一次
TIMER_CH0CV(PWM_TIMER) = TIMER_CAR(PWM_TIMER) >> 1;
TIMER_CH1CV(PWM_TIMER) = TIMER_CAR(PWM_TIMER) >> 1;
TIMER_CH2CV(PWM_TIMER) = TIMER_CAR(PWM_TIMER) >> 1;
TIMER_CH3CV(PWM_TIMER) =
(PWM_TRG_ADC_DELAY * PWM_DOMAIN_CLK_FRQ * 0.000001);
TIMER_CTL0(PWM_TIMER) &= ~(1 << 1);
TIMER_SWEVG(PWM_TIMER) = (1 << 0) | (1 << 5);
TIMER_INTF(PWM_TIMER) = 0; //清所有中断标志
/* TIMER_DMAINTEN(PWM_TIMER)= 1 << 0; //使能更新中断*/
TIMER_CHCTL0(PWM_TIMER) |= (1 << 11) | (1 << 3); // PWM预装载使能
TIMER_CHCTL1(PWM_TIMER) |= (1 << 3);
}
/********************************************
PA1 <--> FB_CurrentB <-->ADC0 <--> Ch1
PA2 <--> FB_CurrentC <-->ADC1 <--> Ch2
PA3 <--> ADC_PWR <--> ADC0 <--> Ch3
PA4 <--> ADC_BRK_FB <--> ADC0 <--> Ch4 no use
PA5 <--> ADC_TEMP <--> ADC1 <--> Ch5
PA6 <--> ADC_TEMP2 <--> ADC1 <--> Ch6
PA7 <--> ADC_TEMP3 <--> ADC0 <--> Ch7 no use
PC4<-->ADC_BUS_I <--> ADC0 <-->ch14
T(CONV) = (12.5(sample) + 7.5(hold))/30MHz = 0.666us
total time for inject = 4*T(CONV) = 2.666us
********************************************/
void HW_ADC_Init(void)
{
// 时钟配置
rcu_periph_clock_enable(RCU_ADC0);
rcu_periph_clock_enable(RCU_ADC1);
gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ,
GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_5 |
GPIO_PIN_6 | GPIO_PIN_7);
ADC_CTL0(ADC0) = (5UL << 16) //注入并行模式
| (0UL << 13) //间断模式下的转换数目
| (0UL << 12) //注入组间断模式禁止
| (0UL << 11) //规则组间断模式禁止
| (0UL << 10) //注入组自动转换禁止
| (1UL << 8) //扫描模式使能
| (1UL << 7); //EOIC中断使能
ADC_CTL1(ADC0) = (1UL << 23) //ʹADC0的通道16和17使能
| (0UL << 20) //规则组外部触发禁止
| (7UL << 17) //规则组软件触发
| (1UL << 15) //注入组外部触发使能
| (0UL << 12) //注入组外部触发选择定时器0 TRGO
| (0UL << 11) //最低有效位对齐
| (0UL << 8) //DMA请求禁止
| (0UL << 1) //禁止连续模式
| (0UL << 0); //禁止ADC并掉电
ADC_IOFF0(ADC0) = 0;
ADC_IOFF1(ADC0) = 0;
ADC_IOFF2(ADC0) = 0;
ADC_IOFF3(ADC0) = 0;
ADC_ISQ(ADC0) = (3UL << 20) //转换长度
| (ADC_CHANNEL_1 << 15) //刹车电压-->ADC_BUS_I
| (ADC_CHANNEL_1 << 10) //母线电压
| (ADC_CHANNEL_1 << 5) // B 相电流
| (ADC_CHANNEL_1 << 0); // B 相电流
ADC_SAMPT1(ADC0) &= ~((7UL << 3) | (7UL << 9) | (7UL << 12)); // ch0,ch1,ch2
ADC_SAMPT1(ADC0) |= ((MOTOR_PHASE_CURRENT_SAMPLE_TIME << 3) |
(MOTOR_PHASE_CURRENT_SAMPLE_TIME << 9) |
(MOTOR_PHASE_CURRENT_SAMPLE_TIME << 12));
ADC_CTL0(ADC1) = (5UL << 16) //注入并行模式
| (0UL << 13) //间断模式计数
| (0UL << 12) //注入通道上禁用间断模式
| (0UL << 11) //规则通道上禁用间断模式
| (0UL << 10) //关闭自动注入转换
| (1UL << 8) //开启扫描模式
| (0UL << 7); //允许注入中断
ADC_CTL1(ADC1) = (1UL << 23) //使能温度和内部参考
| (0UL << 20) //规则通道不使用外部事件触发
| (7UL << 17) //规则通道使用软件触发
| (1UL << 15) //注入通道使用外部事件触发
| (0UL << 12) //注入通道使用TIM0_TGRO触发
| (0UL << 11) //数据右对齐
| (0UL << 8) //不使用DMA
| (0UL << 1) //单次转换
| (0UL << 0); //使能ADC
ADC_IOFF0(ADC1) = 0;
ADC_IOFF1(ADC1) = 0;
ADC_IOFF2(ADC1) = 0;
ADC_IOFF3(ADC1) = 0;
ADC_ISQ(ADC1) = (3UL << 20) //转换长度
| (ADC_CHANNEL_2 << 15) // ADC_TEMP2
| (ADC_CHANNEL_2 << 10) // ADC_TEMP
| (ADC_CHANNEL_2 << 5) // C 相电流
| (ADC_CHANNEL_2 << 0); // C 相电流
ADC_SAMPT1(ADC1) &= ~((7UL << 3) | (7UL << 21) | (7UL << 18));
ADC_SAMPT1(ADC1) |= ((MOTOR_PHASE_CURRENT_SAMPLE_TIME << 3) |
(MOTOR_PHASE_CURRENT_SAMPLE_TIME << 21) |
(MOTOR_PHASE_CURRENT_SAMPLE_TIME << 18));
ADC_CTL1(ADC1) |= 1; //使能ADC
ADC_CTL1(ADC0) |= 1;
nvic_irq_enable(ADC_IRQ, 0, 0);
TIMER_CTL0(PWM_TIMER) |= 0x1; // enable PWM
}
一、计时器触发ADC采样
- 本工程ADC需要对六个通道进行采样。共用到ADC0和ADC1两个实例。除通道外,两个实例配置基本相同。
接下来的解释中ADC配置相同的,仅选取ADC1作例解释。
ADC_ISQ(ADC0) = (3UL << 20) //转换长度
| (ADC_CHANNEL_1 << 15) //选择通道 刹车电压-->ADC_BUS_I
| (ADC_CHANNEL_1 << 10) //母线电压
| (ADC_CHANNEL_1 << 5) // B 相电流
| (ADC_CHANNEL_1 << 0); // B 相电流
ADC_ISQ(ADC1) = (3UL << 20) //转换长度
| (ADC_CHANNEL_2 << 15) // ADC_TEMP2
| (ADC_CHANNEL_2 << 10) // ADC_TEMP
| (ADC_CHANNEL_2 << 5) // C 相电流
| (ADC_CHANNEL_2 << 0); // C 相电流
- 选用注入并行模式,且在触发信号的下降沿开始采样
ADC_CTL0(ADC1) = (5UL << 16) //注入并行模式
3. 注入通道选择TIM0_TGRO触发
ADC_CTL1(ADC1) = (1UL << 15) //注入通道使用外部事件触发
| (0UL << 12) //注入通道使用TIM0_TGRO触发
- TIMER0 (bit4)将TGRO触发源选择为O3CPRE(通道3的输出准备信号)
TIMER_CTL1(PWM_TIMER) =
(0 << 0) | (0 << 2) | (0 << 3) | (7 << 4); // use O3CPRE trigger TRGO
这里没有明确的描述,我认为意思就是:O3CPRE的形状和相位与TRGO完全相同,没有延迟。
5. OC3CPRE在CNT小于CH3CV时高电平,在达到CH3CV时变为低电平
TIMER_CHCTL0(PWM_TIMER) = 0x6868;
TIMER_CHCTL1(PWM_TIMER) = 0x6868;
TIMER_CHCTL0和TIMER_CHCTL1名为通道控制器。其中TIMER_CHCTL0负责配置通道0和通道1,TIMER_CHCTL1负责配置通道2和通道3。四个通道原理一致,下面配上通道2配置为0x6的含义解释。
6. 综上所述我认为配置的含义如图所示。
6.通道3捕获比较寄存器CH3CV的值,设置为延时1us。
#define PWM_TRG_ADC_DELAY (float)2.33f//2.33微秒
#define PWM_DOMAIN_CLK_FRQ rcu_clock_freq_get(CK_APB2)
TIMER_CTL0(PWM_TIMER) =
(1 << 1) | (0 << 2) | (0 << 3) | (1 << 5) | (1 << 7) | (0 << 8);//bit设置计数器对齐模式
TIMER_CH3CV(PWM_TIMER) = (PWM_TRG_ADC_DELAY * PWM_DOMAIN_CLK_FRQ * 0.000001); //通道3捕获比较寄存器
TIM0通过CTL0配置的计数方式为中央对齐向下计数置1模式。描述中涉及的比较中断标志位为CHxIF,与此例无关。
也就是说TIM0的CNT在从0开始延时2.33us以后触发ADC采样。
控制ADC采样时刻的意义在于避开PWM波形的上升沿或者下降沿,避免边沿电平抖动的影响。
- 实测波形?
待采集
TIMER_CHCTL2(PWM_TIMER) |= 0x555;//配置输出极性
0x5=0101B含义:
使能通道
高电平有效
使能互补输出
互补通道高电平有效
- CH0、CH1、CH2三路通道的PWM互补输出波形如何产生的?以及其上升沿、下降沿与死区时间的关系?