123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- #include "asm/mcpwm.h"
- #include "asm/clock.h"
- #include "asm/gpio.h"
- #define MCPWM_DEBUG_ENABLE 0
- #if MCPWM_DEBUG_ENABLE
- #define mcpwm_debug(fmt, ...) printf("[MCPWM] "fmt, ##__VA_ARGS__)
- #else
- #define mcpwm_debug(...)
- #endif
- #define MCPWM_CLK clk_get("mcpwm")
- PWM_TIMER_REG *get_pwm_timer_reg(pwm_ch_num_type index)
- {
- PWM_TIMER_REG *reg = NULL;
- switch (index) {
- case pwm_ch0:
- reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR0_CON));
- break;
- case pwm_ch1:
- reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR1_CON));
- break;
- case pwm_ch2:
- reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR2_CON));
- break;
- case pwm_ch3:
- reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR3_CON));
- break;
- default:
- break;
- }
- return reg;
- }
- PWM_CH_REG *get_pwm_ch_reg(pwm_ch_num_type index)
- {
- PWM_CH_REG *reg = NULL;
- switch (index) {
- case pwm_ch0:
- reg = (PWM_CH_REG *)(&(JL_MCPWM->CH0_CON0));
- break;
- case pwm_ch1:
- reg = (PWM_CH_REG *)(&(JL_MCPWM->CH1_CON0));
- break;
- case pwm_ch2:
- reg = (PWM_CH_REG *)(&(JL_MCPWM->CH2_CON0));
- break;
- case pwm_ch3:
- reg = (PWM_CH_REG *)(&(JL_MCPWM->CH3_CON0));
- break;
- default:
- break;
- }
- return reg;
- }
- /*
- * @brief 更改MCPWM的频率
- * @parm frequency 频率
- */
- void mcpwm_set_frequency(pwm_ch_num_type ch, pwm_aligned_mode_type align, u32 frequency)
- {
- PWM_TIMER_REG *reg = get_pwm_timer_reg(ch);
- if (reg == NULL) {
- return;
- }
- reg->tmr_con = 0;
- reg->tmr_cnt = 0;
- reg->tmr_pr = 0;
- u32 i = 0;
- u32 mcpwm_div_clk = 0;
- u32 mcpwm_tmr_pr = 0;
- u32 mcpwm_fre_min = 0;
- u32 clk = MCPWM_CLK;
- for (i = 0; i < 16; i++) {
- mcpwm_fre_min = clk / (65536 * (1 << i));
- if ((frequency >= mcpwm_fre_min) || (i == 15)) {
- break;
- }
- }
- reg->tmr_con |= (i << 3); //div 2^i
- mcpwm_div_clk = clk / (1 << i);
- if (frequency == 0) {
- mcpwm_tmr_pr = 0;
- } else {
- if (align == pwm_center_aligned) { //中心对齐
- mcpwm_tmr_pr = mcpwm_div_clk / (frequency * 2) - 1;
- } else {
- mcpwm_tmr_pr = mcpwm_div_clk / frequency - 1;
- }
- }
- reg->tmr_pr = mcpwm_tmr_pr;
- //timer mode
- if (align == pwm_center_aligned) { //中心对齐
- reg->tmr_con |= 0b10;
- } else {
- reg->tmr_con |= 0b01;
- }
- }
- static u32 old_mcpwm_clk = 0;
- static void clock_critical_enter(void)
- {
- old_mcpwm_clk = clk_get("mcpwm");
- }
- static void clock_critical_exit(void)
- {
- u32 new_mcpwm_clk = clk_get("mcpwm");
- if (new_mcpwm_clk == old_mcpwm_clk) {
- return;
- }
- PWM_CH_REG *pwm_reg = NULL;
- PWM_TIMER_REG *timer_reg = NULL;
- for (u8 ch = 0; ch < 4; ch++) {
- if (JL_MCPWM->MCPWM_CON0 & BIT(ch + 8)) {
- pwm_reg = get_pwm_ch_reg(ch);
- timer_reg = get_pwm_timer_reg(ch);
- if (new_mcpwm_clk > old_mcpwm_clk) {
- timer_reg->tmr_pr = timer_reg->tmr_pr * (new_mcpwm_clk / old_mcpwm_clk);
- pwm_reg->ch_cmpl = pwm_reg->ch_cmpl * (new_mcpwm_clk / old_mcpwm_clk);
- } else {
- timer_reg->tmr_pr = timer_reg->tmr_pr / (old_mcpwm_clk / new_mcpwm_clk);
- pwm_reg->ch_cmpl = pwm_reg->ch_cmpl / (old_mcpwm_clk / new_mcpwm_clk);
- }
- pwm_reg->ch_cmph = pwm_reg->ch_cmpl;
- }
- }
- }
- CLOCK_CRITICAL_HANDLE_REG(mcpwm, clock_critical_enter, clock_critical_exit)
- /*
- * @brief 设置一个通道的占空比
- * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
- * @parm duty 占空比:0 ~ 10000 对应 0% ~ 100%
- */
- void mcpwm_set_duty(pwm_ch_num_type pwm_ch, u16 duty)
- {
- PWM_TIMER_REG *timer_reg = get_pwm_timer_reg(pwm_ch);
- PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
- if (pwm_reg && timer_reg) {
- pwm_reg->ch_cmpl = timer_reg->tmr_pr * duty / 10000;
- pwm_reg->ch_cmph = pwm_reg->ch_cmpl;
- timer_reg->tmr_cnt = 0;
- timer_reg->tmr_con |= 0b01;
- if (duty == 10000) {
- timer_reg->tmr_cnt = 0;
- timer_reg->tmr_con &= ~(0b11);
- } else if (duty == 0) {
- timer_reg->tmr_cnt = pwm_reg->ch_cmpl;
- timer_reg->tmr_con &= ~(0b11);
- }
- }
- }
- /*
- * @brief 打开或者关闭一个时基
- * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
- * @parm enable 1:打开 0:关闭
- */
- void mctimer_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable)
- {
- if (pwm_ch > pwm_ch_max) {
- return;
- }
- if (enable) {
- JL_MCPWM->MCPWM_CON0 |= BIT(pwm_ch + 8); //TnEN
- } else {
- JL_MCPWM->MCPWM_CON0 &= (~BIT(pwm_ch + 8)); //TnDIS
- }
- }
- /*
- * @brief 打开或者关闭一个通道
- * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
- * @parm enable 1:打开 0:关闭
- */
- void mcpwm_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable)
- {
- if (pwm_ch >= pwm_ch_max) {
- return;
- }
- if (enable) {
- JL_MCPWM->MCPWM_CON0 |= BIT(pwm_ch); //PWMnEN
- } else {
- JL_MCPWM->MCPWM_CON0 &= (~BIT(pwm_ch)); //PWMnDIS
- }
- }
- /*
- * @brief 关闭MCPWM模块
- */
- void mcpwm_open(pwm_ch_num_type pwm_ch)
- {
- if (pwm_ch >= pwm_ch_max) {
- return;
- }
- PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
- pwm_reg->ch_con1 &= ~(0b111 << 8);
- pwm_reg->ch_con1 |= (pwm_ch << 8); //sel mctmr
- mcpwm_ch_open_or_close(pwm_ch, 1);
- mctimer_ch_open_or_close(pwm_ch, 1);
- }
- /*
- * @brief 关闭MCPWM模块
- */
- void mcpwm_close(pwm_ch_num_type pwm_ch)
- {
- mctimer_ch_open_or_close(pwm_ch, 0);
- mcpwm_ch_open_or_close(pwm_ch, 0);
- }
- void log_pwm_info(pwm_ch_num_type pwm_ch)
- {
- PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
- PWM_TIMER_REG *timer_reg = get_pwm_timer_reg(pwm_ch);
- mcpwm_debug("tmr%d con0 = 0x%x", pwm_ch, timer_reg->tmr_con);
- mcpwm_debug("tmr%d pr = 0x%x", pwm_ch, timer_reg->tmr_pr);
- mcpwm_debug("pwm ch%d_con0 = 0x%x", pwm_ch, pwm_reg->ch_con0);
- mcpwm_debug("pwm ch%d_con1 = 0x%x", pwm_ch, pwm_reg->ch_con1);
- mcpwm_debug("pwm ch%d_cmph = 0x%x, pwm ch%d_cmpl = 0x%x", pwm_ch, pwm_reg->ch_cmph, pwm_ch, pwm_reg->ch_cmpl);
- mcpwm_debug("MCPWM_CON0 = 0x%x", JL_MCPWM->MCPWM_CON0);
- mcpwm_debug("mcpwm clk = %d", MCPWM_CLK);
- }
- void mcpwm_init(struct pwm_platform_data *arg)
- {
- //set output IO
- PWM_CH_REG *pwm_reg = get_pwm_ch_reg(arg->pwm_ch_num);
- if (pwm_reg == NULL) {
- return;
- }
- //set mctimer frequency
- mcpwm_set_frequency(arg->pwm_ch_num, arg->pwm_aligned_mode, arg->frequency);
- pwm_reg->ch_con0 = 0;
- if (arg->complementary_en) { //是否互补
- pwm_reg->ch_con0 &= ~(BIT(5) | BIT(4));
- pwm_reg->ch_con0 |= BIT(5); //L_INV
- } else {
- pwm_reg->ch_con0 &= ~(BIT(5) | BIT(4));
- }
- mcpwm_open(arg->pwm_ch_num); //mcpwm enable
- //set duty
- mcpwm_set_duty(arg->pwm_ch_num, arg->duty);
- //H:
- if (arg->h_pin < IO_MAX_NUM) { //任意引脚
- pwm_reg->ch_con0 |= BIT(2); //H_EN
- gpio_set_fun_output_port(arg->h_pin, FO_MCPWM_CH0H + 2 * arg->pwm_ch_num, 0, 1);
- gpio_set_direction(arg->h_pin, 0); //DIR output
- }
- //L:
- if (arg->l_pin < IO_MAX_NUM) { //任意引脚
- pwm_reg->ch_con0 |= BIT(3); //L_EN
- gpio_set_fun_output_port(arg->l_pin, FO_MCPWM_CH0L + 2 * arg->pwm_ch_num, 0, 1);
- gpio_set_direction(arg->l_pin, 0); //DIR output
- }
- log_pwm_info(arg->pwm_ch_num);
- }
- ///////////// for test code //////////////////
- void mcpwm_test(void)
- {
- #define PWM_CH0_ENABLE 1
- #define PWM_CH1_ENABLE 1
- #define PWM_CH2_ENABLE 1
- #define PWM_CH3_ENABLE 1
- struct pwm_platform_data pwm_p_data;
- #if PWM_CH0_ENABLE
- pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
- pwm_p_data.pwm_ch_num = pwm_ch0; //通道号
- pwm_p_data.frequency = 1000; //1KHz
- pwm_p_data.duty = 5000; //占空比50%
- pwm_p_data.h_pin = IO_PORTA_06; //任意引脚
- pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
- pwm_p_data.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
- mcpwm_init(&pwm_p_data);
- #endif
- #if PWM_CH1_ENABLE
- pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
- pwm_p_data.pwm_ch_num = pwm_ch1; //通道号
- pwm_p_data.frequency = 1000; //1KHz
- pwm_p_data.duty = 2500; //占空比25%
- pwm_p_data.h_pin = IO_PORTA_01; //任意引脚
- pwm_p_data.l_pin = IO_PORTA_02; //任意引脚,不需要就填-1
- pwm_p_data.complementary_en = 1; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
- mcpwm_init(&pwm_p_data);
- #endif
- #if PWM_CH2_ENABLE
- pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
- pwm_p_data.pwm_ch_num = pwm_ch2; //通道号
- pwm_p_data.frequency = 10000; //10KHz
- pwm_p_data.duty = 5000; //占空比50%
- pwm_p_data.h_pin = IO_PORTA_03; //任意引脚
- pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
- mcpwm_init(&pwm_p_data);
- #endif
- #if PWM_CH3_ENABLE
- pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
- pwm_p_data.pwm_ch_num = pwm_ch3; //通道号
- pwm_p_data.frequency = 10000; //10KHz
- pwm_p_data.duty = 7500; //占空比75%
- pwm_p_data.h_pin = IO_PORTA_04; //任意引脚
- pwm_p_data.l_pin = IO_PORTA_05; //任意引脚,不需要就填-1
- pwm_p_data.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
- mcpwm_init(&pwm_p_data);
- #endif
- extern void clk_out(u8 gpio, enum CLK_OUT_SOURCE clk);
- clk_out(IO_PORTA_07, LSB_CLK_OUT);
- extern void wdt_clear();
- while (1) {
- wdt_clear();
- }
- }
- /******************************* 外部引脚中断参考代码 ***************************/
- void (*io_isr_cbfun)(u8 index) = NULL;
- void set_io_ext_interrupt_cbfun(void (*cbfun)(u8 index))
- {
- io_isr_cbfun = cbfun;
- }
- ___interrupt
- void io_interrupt(void)
- {
- u32 io_index = -1;
- if (JL_MCPWM->CH0_CON1 & BIT(15)) {
- JL_MCPWM->CH0_CON1 |= BIT(14);
- io_index = 0;
- } else if (JL_MCPWM->CH1_CON1 & BIT(15)) {
- JL_MCPWM->CH1_CON1 |= BIT(14);
- io_index = 1;
- } else if (JL_MCPWM->CH2_CON1 & BIT(15)) {
- JL_MCPWM->CH2_CON1 |= BIT(14);
- io_index = 2;
- } else if (JL_MCPWM->CH3_CON1 & BIT(15)) {
- JL_MCPWM->CH3_CON1 |= BIT(14);
- io_index = 3;
- } else {
- return;
- }
- if (io_isr_cbfun) {
- io_isr_cbfun(io_index);
- }
- }
- void io_ext_interrupt_init(u8 index, u8 port, u8 trigger_mode)
- {
- if (port > IO_PORT_MAX) {
- return;
- }
- gpio_set_die(port, 1);
- gpio_set_direction(port, 1);
- if (trigger_mode) {
- gpio_set_pull_up(port, 1);
- gpio_set_pull_down(port, 0);
- JL_MCPWM->FPINCON &= ~BIT(16 + index);//下降沿触发
- } else {
- gpio_set_pull_up(port, 0);
- gpio_set_pull_down(port, 1);
- JL_MCPWM->FPINCON |= BIT(16 + index);//上升沿触发
- }
- JL_MCPWM->FPINCON |= BIT(8 + index);//开启滤波
- JL_MCPWM->FPINCON |= (0b111111 << 0); //滤波时间 = 16 * 64 / hsb_clk (单位:s)
- gpio_set_fun_input_port(port, PFI_MCPWM_FPIN_A + index * 4);
- request_irq(IRQ_CHX_PWM_IDX, 3, io_interrupt, 0); //注册中断函数
- PWM_CH_REG *pwm_reg = get_pwm_ch_reg(index);
- pwm_reg->ch_con1 = BIT(14) | BIT(11) | BIT(4) | (index << 0);
- JL_MCPWM->MCPWM_CON0 |= BIT(index);
- printf("JL_MCPWM->CH%d_CON1 = 0x%x\n", index, pwm_reg->ch_con1);
- printf("JL_MCPWM->FPINCON = 0x%x\n", JL_MCPWM->FPINCON);
- printf("JL_MCPWM->MCPWM_CON0 = 0x%x\n", JL_MCPWM->MCPWM_CON0);
- }
- void io_ext_interrupt_close(u8 index, u8 port)
- {
- if (port > IO_PORT_MAX) {
- return;
- }
- gpio_set_die(port, 0);
- gpio_set_direction(port, 1);
- gpio_set_pull_up(port, 0);
- gpio_set_pull_down(port, 0);
- gpio_disable_fun_input_port(PFI_MCPWM_FPIN_A + index * 4);
- PWM_CH_REG *pwm_reg = get_pwm_ch_reg(index);
- pwm_reg->ch_con1 = BIT(14);
- }
- ///////////// 使用举例如下 //////////////////
- void my_io_isr_cbfun(u32 index)
- {
- printf("io index --> %d Hello world !\n", index);
- }
- void io_ext_interrupt_test(void)
- {
- set_io_ext_interrupt_cbfun(my_io_isr_cbfun);
- io_ext_interrupt_init(0, IO_PORTA_01, 1);
- io_ext_interrupt_init(1, IO_PORTA_02, 1);
- io_ext_interrupt_init(2, IO_PORTA_03, 1);
- io_ext_interrupt_init(3, IO_PORTA_04, 1);
- extern void wdt_clear();
- while (1) {
- wdt_clear();
- }
- }
- /******************************* 用timer做pwm的参考代码 ***************************/
- /**
- * @param JL_TIMERx : JL_TIMER0/1/2/3
- * @param pwm_io : JL_PORTA_01, JL_PORTB_02,,,等等,支持任意普通IO
- * @param fre : 频率,单位Hz
- * @param duty : 初始占空比,0~10000对应0~100%
- */
- void timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 pwm_io, u32 fre, u32 duty)
- {
- switch ((u32)JL_TIMERx) {
- case (u32)JL_TIMER0 :
- gpio_set_fun_output_port(pwm_io, FO_TMR0_PWM, 0, 1);
- break;
- case (u32)JL_TIMER1 :
- gpio_set_fun_output_port(pwm_io, FO_TMR1_PWM, 0, 1);
- break;
- case (u32)JL_TIMER2 :
- gpio_set_fun_output_port(pwm_io, FO_TMR2_PWM, 0, 1);
- break;
- case (u32)JL_TIMER3 :
- bit_clr_ie(IRQ_TIME3_IDX);
- gpio_set_fun_output_port(pwm_io, FO_TMR3_PWM, 0, 1);
- break;
- default:
- return;
- }
- u32 u_clk = 24000000;
- //初始化timer
- JL_TIMERx->CON = 0;
- JL_TIMERx->CON |= (0b110 << 10); //时钟源选择STD_24M时钟源
- JL_TIMERx->CON |= (0b0001 << 4); //时钟源再4分频
- JL_TIMERx->CNT = 0; //清计数值
- JL_TIMERx->PRD = u_clk / (4 * fre); //设置周期
- JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //设置初始占空比,0~10000对应0~100%
- JL_TIMERx->CON |= (0b01 << 0); //计数模式
- JL_TIMERx->CON |= BIT(8); //PWM使能
- //设置引脚状态
- gpio_set_die(pwm_io, 1);
- gpio_set_pull_up(pwm_io, 0);
- gpio_set_pull_down(pwm_io, 0);
- gpio_set_direction(pwm_io, 0);
- printf("JL_TIMERx->PRD = 0x%x\n", JL_TIMERx->PRD);
- printf("JL_TIMERx->CON = 0x%x\n", JL_TIMERx->CON);
- }
- void set_timer_pwm_duty(JL_TIMER_TypeDef *JL_TIMERx, u32 duty)
- {
- JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //0~10000对应0~100%
- }
- void timer_pwm_test(void)
- {
- timer_pwm_init(JL_TIMER2, IO_PORTA_01, 10000, 2000);
- timer_pwm_init(JL_TIMER3, IO_PORTA_02, 10000, 5000);
- extern void wdt_clear();
- while (1) {
- wdt_clear();
- }
- }
|