mcpwm.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. #include "asm/mcpwm.h"
  2. #include "asm/clock.h"
  3. #include "asm/gpio.h"
  4. #define MCPWM_DEBUG_ENABLE 0
  5. #if MCPWM_DEBUG_ENABLE
  6. #define mcpwm_debug(fmt, ...) printf("[MCPWM] "fmt, ##__VA_ARGS__)
  7. #else
  8. #define mcpwm_debug(...)
  9. #endif
  10. #define MCPWM_CLK clk_get("mcpwm")
  11. PWM_TIMER_REG *get_pwm_timer_reg(pwm_ch_num_type index)
  12. {
  13. PWM_TIMER_REG *reg = NULL;
  14. switch (index) {
  15. case pwm_ch0:
  16. reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR0_CON));
  17. break;
  18. case pwm_ch1:
  19. reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR1_CON));
  20. break;
  21. case pwm_ch2:
  22. reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR2_CON));
  23. break;
  24. case pwm_ch3:
  25. reg = (PWM_TIMER_REG *)(&(JL_MCPWM->TMR3_CON));
  26. break;
  27. default:
  28. break;
  29. }
  30. return reg;
  31. }
  32. PWM_CH_REG *get_pwm_ch_reg(pwm_ch_num_type index)
  33. {
  34. PWM_CH_REG *reg = NULL;
  35. switch (index) {
  36. case pwm_ch0:
  37. reg = (PWM_CH_REG *)(&(JL_MCPWM->CH0_CON0));
  38. break;
  39. case pwm_ch1:
  40. reg = (PWM_CH_REG *)(&(JL_MCPWM->CH1_CON0));
  41. break;
  42. case pwm_ch2:
  43. reg = (PWM_CH_REG *)(&(JL_MCPWM->CH2_CON0));
  44. break;
  45. case pwm_ch3:
  46. reg = (PWM_CH_REG *)(&(JL_MCPWM->CH3_CON0));
  47. break;
  48. default:
  49. break;
  50. }
  51. return reg;
  52. }
  53. /*
  54. * @brief 更改MCPWM的频率
  55. * @parm frequency 频率
  56. */
  57. void mcpwm_set_frequency(pwm_ch_num_type ch, pwm_aligned_mode_type align, u32 frequency)
  58. {
  59. PWM_TIMER_REG *reg = get_pwm_timer_reg(ch);
  60. if (reg == NULL) {
  61. return;
  62. }
  63. reg->tmr_con = 0;
  64. reg->tmr_cnt = 0;
  65. reg->tmr_pr = 0;
  66. u32 i = 0;
  67. u32 mcpwm_div_clk = 0;
  68. u32 mcpwm_tmr_pr = 0;
  69. u32 mcpwm_fre_min = 0;
  70. u32 clk = MCPWM_CLK;
  71. for (i = 0; i < 16; i++) {
  72. mcpwm_fre_min = clk / (65536 * (1 << i));
  73. if ((frequency >= mcpwm_fre_min) || (i == 15)) {
  74. break;
  75. }
  76. }
  77. reg->tmr_con |= (i << 3); //div 2^i
  78. mcpwm_div_clk = clk / (1 << i);
  79. if (frequency == 0) {
  80. mcpwm_tmr_pr = 0;
  81. } else {
  82. if (align == pwm_center_aligned) { //中心对齐
  83. mcpwm_tmr_pr = mcpwm_div_clk / (frequency * 2) - 1;
  84. } else {
  85. mcpwm_tmr_pr = mcpwm_div_clk / frequency - 1;
  86. }
  87. }
  88. reg->tmr_pr = mcpwm_tmr_pr;
  89. //timer mode
  90. if (align == pwm_center_aligned) { //中心对齐
  91. reg->tmr_con |= 0b10;
  92. } else {
  93. reg->tmr_con |= 0b01;
  94. }
  95. }
  96. static u32 old_mcpwm_clk = 0;
  97. static void clock_critical_enter(void)
  98. {
  99. old_mcpwm_clk = clk_get("mcpwm");
  100. }
  101. static void clock_critical_exit(void)
  102. {
  103. u32 new_mcpwm_clk = clk_get("mcpwm");
  104. if (new_mcpwm_clk == old_mcpwm_clk) {
  105. return;
  106. }
  107. PWM_CH_REG *pwm_reg = NULL;
  108. PWM_TIMER_REG *timer_reg = NULL;
  109. for (u8 ch = 0; ch < 4; ch++) {
  110. if (JL_MCPWM->MCPWM_CON0 & BIT(ch + 8)) {
  111. pwm_reg = get_pwm_ch_reg(ch);
  112. timer_reg = get_pwm_timer_reg(ch);
  113. if (new_mcpwm_clk > old_mcpwm_clk) {
  114. timer_reg->tmr_pr = timer_reg->tmr_pr * (new_mcpwm_clk / old_mcpwm_clk);
  115. pwm_reg->ch_cmpl = pwm_reg->ch_cmpl * (new_mcpwm_clk / old_mcpwm_clk);
  116. } else {
  117. timer_reg->tmr_pr = timer_reg->tmr_pr / (old_mcpwm_clk / new_mcpwm_clk);
  118. pwm_reg->ch_cmpl = pwm_reg->ch_cmpl / (old_mcpwm_clk / new_mcpwm_clk);
  119. }
  120. pwm_reg->ch_cmph = pwm_reg->ch_cmpl;
  121. }
  122. }
  123. }
  124. CLOCK_CRITICAL_HANDLE_REG(mcpwm, clock_critical_enter, clock_critical_exit)
  125. /*
  126. * @brief 设置一个通道的占空比
  127. * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
  128. * @parm duty 占空比:0 ~ 10000 对应 0% ~ 100%
  129. */
  130. void mcpwm_set_duty(pwm_ch_num_type pwm_ch, u16 duty)
  131. {
  132. PWM_TIMER_REG *timer_reg = get_pwm_timer_reg(pwm_ch);
  133. PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
  134. if (pwm_reg && timer_reg) {
  135. pwm_reg->ch_cmpl = timer_reg->tmr_pr * duty / 10000;
  136. pwm_reg->ch_cmph = pwm_reg->ch_cmpl;
  137. timer_reg->tmr_cnt = 0;
  138. timer_reg->tmr_con |= 0b01;
  139. if (duty == 10000) {
  140. timer_reg->tmr_cnt = 0;
  141. timer_reg->tmr_con &= ~(0b11);
  142. } else if (duty == 0) {
  143. timer_reg->tmr_cnt = pwm_reg->ch_cmpl;
  144. timer_reg->tmr_con &= ~(0b11);
  145. }
  146. }
  147. }
  148. /*
  149. * @brief 打开或者关闭一个时基
  150. * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
  151. * @parm enable 1:打开 0:关闭
  152. */
  153. void mctimer_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable)
  154. {
  155. if (pwm_ch > pwm_ch_max) {
  156. return;
  157. }
  158. if (enable) {
  159. JL_MCPWM->MCPWM_CON0 |= BIT(pwm_ch + 8); //TnEN
  160. } else {
  161. JL_MCPWM->MCPWM_CON0 &= (~BIT(pwm_ch + 8)); //TnDIS
  162. }
  163. }
  164. /*
  165. * @brief 打开或者关闭一个通道
  166. * @parm pwm_ch_num 通道号:pwm_ch0,pwm_ch1,pwm_ch2
  167. * @parm enable 1:打开 0:关闭
  168. */
  169. void mcpwm_ch_open_or_close(pwm_ch_num_type pwm_ch, u8 enable)
  170. {
  171. if (pwm_ch >= pwm_ch_max) {
  172. return;
  173. }
  174. if (enable) {
  175. JL_MCPWM->MCPWM_CON0 |= BIT(pwm_ch); //PWMnEN
  176. } else {
  177. JL_MCPWM->MCPWM_CON0 &= (~BIT(pwm_ch)); //PWMnDIS
  178. }
  179. }
  180. /*
  181. * @brief 关闭MCPWM模块
  182. */
  183. void mcpwm_open(pwm_ch_num_type pwm_ch)
  184. {
  185. if (pwm_ch >= pwm_ch_max) {
  186. return;
  187. }
  188. PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
  189. pwm_reg->ch_con1 &= ~(0b111 << 8);
  190. pwm_reg->ch_con1 |= (pwm_ch << 8); //sel mctmr
  191. mcpwm_ch_open_or_close(pwm_ch, 1);
  192. mctimer_ch_open_or_close(pwm_ch, 1);
  193. }
  194. /*
  195. * @brief 关闭MCPWM模块
  196. */
  197. void mcpwm_close(pwm_ch_num_type pwm_ch)
  198. {
  199. mctimer_ch_open_or_close(pwm_ch, 0);
  200. mcpwm_ch_open_or_close(pwm_ch, 0);
  201. }
  202. void log_pwm_info(pwm_ch_num_type pwm_ch)
  203. {
  204. PWM_CH_REG *pwm_reg = get_pwm_ch_reg(pwm_ch);
  205. PWM_TIMER_REG *timer_reg = get_pwm_timer_reg(pwm_ch);
  206. mcpwm_debug("tmr%d con0 = 0x%x", pwm_ch, timer_reg->tmr_con);
  207. mcpwm_debug("tmr%d pr = 0x%x", pwm_ch, timer_reg->tmr_pr);
  208. mcpwm_debug("pwm ch%d_con0 = 0x%x", pwm_ch, pwm_reg->ch_con0);
  209. mcpwm_debug("pwm ch%d_con1 = 0x%x", pwm_ch, pwm_reg->ch_con1);
  210. 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);
  211. mcpwm_debug("MCPWM_CON0 = 0x%x", JL_MCPWM->MCPWM_CON0);
  212. mcpwm_debug("mcpwm clk = %d", MCPWM_CLK);
  213. }
  214. void mcpwm_init(struct pwm_platform_data *arg)
  215. {
  216. //set output IO
  217. PWM_CH_REG *pwm_reg = get_pwm_ch_reg(arg->pwm_ch_num);
  218. if (pwm_reg == NULL) {
  219. return;
  220. }
  221. //set mctimer frequency
  222. mcpwm_set_frequency(arg->pwm_ch_num, arg->pwm_aligned_mode, arg->frequency);
  223. pwm_reg->ch_con0 = 0;
  224. if (arg->complementary_en) { //是否互补
  225. pwm_reg->ch_con0 &= ~(BIT(5) | BIT(4));
  226. pwm_reg->ch_con0 |= BIT(5); //L_INV
  227. } else {
  228. pwm_reg->ch_con0 &= ~(BIT(5) | BIT(4));
  229. }
  230. mcpwm_open(arg->pwm_ch_num); //mcpwm enable
  231. //set duty
  232. mcpwm_set_duty(arg->pwm_ch_num, arg->duty);
  233. //H:
  234. if (arg->h_pin < IO_MAX_NUM) { //任意引脚
  235. pwm_reg->ch_con0 |= BIT(2); //H_EN
  236. gpio_set_fun_output_port(arg->h_pin, FO_MCPWM_CH0H + 2 * arg->pwm_ch_num, 0, 1);
  237. gpio_set_direction(arg->h_pin, 0); //DIR output
  238. }
  239. //L:
  240. if (arg->l_pin < IO_MAX_NUM) { //任意引脚
  241. pwm_reg->ch_con0 |= BIT(3); //L_EN
  242. gpio_set_fun_output_port(arg->l_pin, FO_MCPWM_CH0L + 2 * arg->pwm_ch_num, 0, 1);
  243. gpio_set_direction(arg->l_pin, 0); //DIR output
  244. }
  245. log_pwm_info(arg->pwm_ch_num);
  246. }
  247. ///////////// for test code //////////////////
  248. void mcpwm_test(void)
  249. {
  250. #define PWM_CH0_ENABLE 1
  251. #define PWM_CH1_ENABLE 1
  252. #define PWM_CH2_ENABLE 1
  253. #define PWM_CH3_ENABLE 1
  254. struct pwm_platform_data pwm_p_data;
  255. #if PWM_CH0_ENABLE
  256. pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
  257. pwm_p_data.pwm_ch_num = pwm_ch0; //通道号
  258. pwm_p_data.frequency = 1000; //1KHz
  259. pwm_p_data.duty = 5000; //占空比50%
  260. pwm_p_data.h_pin = IO_PORTA_06; //任意引脚
  261. pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
  262. pwm_p_data.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
  263. mcpwm_init(&pwm_p_data);
  264. #endif
  265. #if PWM_CH1_ENABLE
  266. pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
  267. pwm_p_data.pwm_ch_num = pwm_ch1; //通道号
  268. pwm_p_data.frequency = 1000; //1KHz
  269. pwm_p_data.duty = 2500; //占空比25%
  270. pwm_p_data.h_pin = IO_PORTA_01; //任意引脚
  271. pwm_p_data.l_pin = IO_PORTA_02; //任意引脚,不需要就填-1
  272. pwm_p_data.complementary_en = 1; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
  273. mcpwm_init(&pwm_p_data);
  274. #endif
  275. #if PWM_CH2_ENABLE
  276. pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
  277. pwm_p_data.pwm_ch_num = pwm_ch2; //通道号
  278. pwm_p_data.frequency = 10000; //10KHz
  279. pwm_p_data.duty = 5000; //占空比50%
  280. pwm_p_data.h_pin = IO_PORTA_03; //任意引脚
  281. pwm_p_data.l_pin = -1; //任意引脚,不需要就填-1
  282. mcpwm_init(&pwm_p_data);
  283. #endif
  284. #if PWM_CH3_ENABLE
  285. pwm_p_data.pwm_aligned_mode = pwm_edge_aligned; //边沿对齐
  286. pwm_p_data.pwm_ch_num = pwm_ch3; //通道号
  287. pwm_p_data.frequency = 10000; //10KHz
  288. pwm_p_data.duty = 7500; //占空比75%
  289. pwm_p_data.h_pin = IO_PORTA_04; //任意引脚
  290. pwm_p_data.l_pin = IO_PORTA_05; //任意引脚,不需要就填-1
  291. pwm_p_data.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
  292. mcpwm_init(&pwm_p_data);
  293. #endif
  294. extern void clk_out(u8 gpio, enum CLK_OUT_SOURCE clk);
  295. clk_out(IO_PORTA_07, LSB_CLK_OUT);
  296. extern void wdt_clear();
  297. while (1) {
  298. wdt_clear();
  299. }
  300. }
  301. /******************************* 外部引脚中断参考代码 ***************************/
  302. void (*io_isr_cbfun)(u8 index) = NULL;
  303. void set_io_ext_interrupt_cbfun(void (*cbfun)(u8 index))
  304. {
  305. io_isr_cbfun = cbfun;
  306. }
  307. ___interrupt
  308. void io_interrupt(void)
  309. {
  310. u32 io_index = -1;
  311. if (JL_MCPWM->CH0_CON1 & BIT(15)) {
  312. JL_MCPWM->CH0_CON1 |= BIT(14);
  313. io_index = 0;
  314. } else if (JL_MCPWM->CH1_CON1 & BIT(15)) {
  315. JL_MCPWM->CH1_CON1 |= BIT(14);
  316. io_index = 1;
  317. } else if (JL_MCPWM->CH2_CON1 & BIT(15)) {
  318. JL_MCPWM->CH2_CON1 |= BIT(14);
  319. io_index = 2;
  320. } else if (JL_MCPWM->CH3_CON1 & BIT(15)) {
  321. JL_MCPWM->CH3_CON1 |= BIT(14);
  322. io_index = 3;
  323. } else {
  324. return;
  325. }
  326. if (io_isr_cbfun) {
  327. io_isr_cbfun(io_index);
  328. }
  329. }
  330. void io_ext_interrupt_init(u8 index, u8 port, u8 trigger_mode)
  331. {
  332. if (port > IO_PORT_MAX) {
  333. return;
  334. }
  335. gpio_set_die(port, 1);
  336. gpio_set_direction(port, 1);
  337. if (trigger_mode) {
  338. gpio_set_pull_up(port, 1);
  339. gpio_set_pull_down(port, 0);
  340. JL_MCPWM->FPINCON &= ~BIT(16 + index);//下降沿触发
  341. } else {
  342. gpio_set_pull_up(port, 0);
  343. gpio_set_pull_down(port, 1);
  344. JL_MCPWM->FPINCON |= BIT(16 + index);//上升沿触发
  345. }
  346. JL_MCPWM->FPINCON |= BIT(8 + index);//开启滤波
  347. JL_MCPWM->FPINCON |= (0b111111 << 0); //滤波时间 = 16 * 64 / hsb_clk (单位:s)
  348. gpio_set_fun_input_port(port, PFI_MCPWM_FPIN_A + index * 4);
  349. request_irq(IRQ_CHX_PWM_IDX, 3, io_interrupt, 0); //注册中断函数
  350. PWM_CH_REG *pwm_reg = get_pwm_ch_reg(index);
  351. pwm_reg->ch_con1 = BIT(14) | BIT(11) | BIT(4) | (index << 0);
  352. JL_MCPWM->MCPWM_CON0 |= BIT(index);
  353. printf("JL_MCPWM->CH%d_CON1 = 0x%x\n", index, pwm_reg->ch_con1);
  354. printf("JL_MCPWM->FPINCON = 0x%x\n", JL_MCPWM->FPINCON);
  355. printf("JL_MCPWM->MCPWM_CON0 = 0x%x\n", JL_MCPWM->MCPWM_CON0);
  356. }
  357. void io_ext_interrupt_close(u8 index, u8 port)
  358. {
  359. if (port > IO_PORT_MAX) {
  360. return;
  361. }
  362. gpio_set_die(port, 0);
  363. gpio_set_direction(port, 1);
  364. gpio_set_pull_up(port, 0);
  365. gpio_set_pull_down(port, 0);
  366. gpio_disable_fun_input_port(PFI_MCPWM_FPIN_A + index * 4);
  367. PWM_CH_REG *pwm_reg = get_pwm_ch_reg(index);
  368. pwm_reg->ch_con1 = BIT(14);
  369. }
  370. ///////////// 使用举例如下 //////////////////
  371. void my_io_isr_cbfun(u32 index)
  372. {
  373. printf("io index --> %d Hello world !\n", index);
  374. }
  375. void io_ext_interrupt_test(void)
  376. {
  377. set_io_ext_interrupt_cbfun(my_io_isr_cbfun);
  378. io_ext_interrupt_init(0, IO_PORTA_01, 1);
  379. io_ext_interrupt_init(1, IO_PORTA_02, 1);
  380. io_ext_interrupt_init(2, IO_PORTA_03, 1);
  381. io_ext_interrupt_init(3, IO_PORTA_04, 1);
  382. extern void wdt_clear();
  383. while (1) {
  384. wdt_clear();
  385. }
  386. }
  387. /******************************* 用timer做pwm的参考代码 ***************************/
  388. /**
  389. * @param JL_TIMERx : JL_TIMER0/1/2/3
  390. * @param pwm_io : JL_PORTA_01, JL_PORTB_02,,,等等,支持任意普通IO
  391. * @param fre : 频率,单位Hz
  392. * @param duty : 初始占空比,0~10000对应0~100%
  393. */
  394. void timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 pwm_io, u32 fre, u32 duty)
  395. {
  396. switch ((u32)JL_TIMERx) {
  397. case (u32)JL_TIMER0 :
  398. gpio_set_fun_output_port(pwm_io, FO_TMR0_PWM, 0, 1);
  399. break;
  400. case (u32)JL_TIMER1 :
  401. gpio_set_fun_output_port(pwm_io, FO_TMR1_PWM, 0, 1);
  402. break;
  403. case (u32)JL_TIMER2 :
  404. gpio_set_fun_output_port(pwm_io, FO_TMR2_PWM, 0, 1);
  405. break;
  406. case (u32)JL_TIMER3 :
  407. bit_clr_ie(IRQ_TIME3_IDX);
  408. gpio_set_fun_output_port(pwm_io, FO_TMR3_PWM, 0, 1);
  409. break;
  410. default:
  411. return;
  412. }
  413. u32 u_clk = 24000000;
  414. //初始化timer
  415. JL_TIMERx->CON = 0;
  416. JL_TIMERx->CON |= (0b110 << 10); //时钟源选择STD_24M时钟源
  417. JL_TIMERx->CON |= (0b0001 << 4); //时钟源再4分频
  418. JL_TIMERx->CNT = 0; //清计数值
  419. JL_TIMERx->PRD = u_clk / (4 * fre); //设置周期
  420. JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //设置初始占空比,0~10000对应0~100%
  421. JL_TIMERx->CON |= (0b01 << 0); //计数模式
  422. JL_TIMERx->CON |= BIT(8); //PWM使能
  423. //设置引脚状态
  424. gpio_set_die(pwm_io, 1);
  425. gpio_set_pull_up(pwm_io, 0);
  426. gpio_set_pull_down(pwm_io, 0);
  427. gpio_set_direction(pwm_io, 0);
  428. printf("JL_TIMERx->PRD = 0x%x\n", JL_TIMERx->PRD);
  429. printf("JL_TIMERx->CON = 0x%x\n", JL_TIMERx->CON);
  430. }
  431. void set_timer_pwm_duty(JL_TIMER_TypeDef *JL_TIMERx, u32 duty)
  432. {
  433. JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //0~10000对应0~100%
  434. }
  435. void timer_pwm_test(void)
  436. {
  437. timer_pwm_init(JL_TIMER2, IO_PORTA_01, 10000, 2000);
  438. timer_pwm_init(JL_TIMER3, IO_PORTA_02, 10000, 5000);
  439. extern void wdt_clear();
  440. while (1) {
  441. wdt_clear();
  442. }
  443. }