ls1c_pwm.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2017-09-06 勤为本 first version
  9. */
  10. // 封装硬件pwm接口
  11. #include "ls1c_public.h"
  12. #include "ls1c_pin.h"
  13. #include "ls1c_pwm.h"
  14. #include "ls1c_clock.h"
  15. #include "ls1c_regs.h"
  16. // pwm的最大周期
  17. #define PWM_MAX_PERIOD (0xFFFFFF) // 计数器的值
  18. /*
  19. * 根据gpio获取相应pwm的基地址
  20. * @gpio pwm引脚
  21. * @ret pwm基地址
  22. */
  23. unsigned int pwm_get_reg_base(unsigned int gpio)
  24. {
  25. unsigned int reg_base = 0;
  26. switch (gpio)
  27. {
  28. case LS1C_PWM0_GPIO06:
  29. case LS1C_PWM0_GPIO04:
  30. reg_base = LS1C_REG_BASE_PWM0;
  31. break;
  32. case LS1C_PWM1_GPIO92:
  33. case LS1C_PWM1_GPIO05:
  34. reg_base = LS1C_REG_BASE_PWM1;
  35. break;
  36. case LS1C_PWM2_GPIO52:
  37. case LS1C_PWM2_GPIO46:
  38. reg_base = LS1C_REG_BASE_PWM2;
  39. break;
  40. case LS1C_PWM3_GPIO47:
  41. case LS1C_PWM3_GPIO53:
  42. reg_base = LS1C_REG_BASE_PWM3;
  43. break;
  44. }
  45. return reg_base;
  46. }
  47. /*
  48. * 禁止pwm
  49. * @pwm_info PWMn的详细信息
  50. */
  51. void pwm_disable(pwm_info_t *pwm_info)
  52. {
  53. unsigned int pwm_reg_base = 0;
  54. // 检查入参
  55. if (NULL == pwm_info)
  56. {
  57. return ;
  58. }
  59. pwm_reg_base = pwm_get_reg_base(pwm_info->gpio);
  60. reg_write_32(0, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_CTRL));
  61. return ;
  62. }
  63. /*
  64. * 使能PWM
  65. * @pwm_info PWMn的详细信息
  66. */
  67. void pwm_enable(pwm_info_t *pwm_info)
  68. {
  69. unsigned int pwm_reg_base = 0;
  70. unsigned int ctrl = 0;
  71. // 检查入参
  72. if (NULL == pwm_info)
  73. {
  74. return ;
  75. }
  76. // 获取基地址
  77. pwm_reg_base = pwm_get_reg_base(pwm_info->gpio);
  78. // 清零计数器
  79. reg_write_32(0, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_CNTR));
  80. // 设置控制寄存器
  81. ctrl = (0 << LS1C_PWM_INT_LRC_EN)
  82. | (0 << LS1C_PWM_INT_HRC_EN)
  83. | (0 << LS1C_PWM_CNTR_RST)
  84. | (0 << LS1C_PWM_INT_SR)
  85. | (0 << LS1C_PWM_INTEN)
  86. | (0 << LS1C_PWM_OE)
  87. | (1 << LS1C_PWM_CNT_EN);
  88. if (PWM_MODE_PULSE == pwm_info->mode) // 单脉冲
  89. {
  90. ctrl |= (1 << LS1C_PWM_SINGLE);
  91. }
  92. else // 连续脉冲
  93. {
  94. ctrl &= ~(1 << LS1C_PWM_SINGLE);
  95. }
  96. reg_write_32(ctrl, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_CTRL));
  97. return ;
  98. }
  99. /*
  100. * 初始化PWMn
  101. * @pwm_info PWMn的详细信息
  102. */
  103. void pwm_init(pwm_info_t *pwm_info)
  104. {
  105. unsigned int gpio;
  106. unsigned long pwm_clk = 0; // pwm模块的时钟频率
  107. unsigned long tmp = 0;
  108. unsigned int pwm_reg_base = 0;
  109. unsigned long period = 0;
  110. // 判断入参
  111. if (NULL == pwm_info)
  112. {
  113. // 入参非法,则直接返回
  114. return ;
  115. }
  116. gpio = pwm_info->gpio;
  117. // 配置相应引脚用作pwm,而非gpio
  118. pin_set_purpose(gpio, PIN_PURPOSE_OTHER);
  119. // 复用
  120. switch (gpio)
  121. {
  122. // 不需要复用
  123. case LS1C_PWM0_GPIO06:
  124. case LS1C_PWM1_GPIO92:
  125. break;
  126. case LS1C_PWM0_GPIO04: // gpio04的第三复用
  127. pin_set_remap(LS1C_PWM0_GPIO04, PIN_REMAP_THIRD);
  128. break;
  129. case LS1C_PWM1_GPIO05: // gpio05的第三复用
  130. pin_set_remap(LS1C_PWM1_GPIO05, PIN_REMAP_THIRD);
  131. break;
  132. case LS1C_PWM2_GPIO52: // gpio52的第四复用
  133. pin_set_remap(LS1C_PWM2_GPIO52, PIN_REMAP_FOURTH);
  134. break;
  135. case LS1C_PWM2_GPIO46: // gpio46的第四复用
  136. pin_set_remap(LS1C_PWM2_GPIO46, PIN_REMAP_FOURTH);
  137. break;
  138. case LS1C_PWM3_GPIO47: // gpio47的第四复用
  139. pin_set_remap(LS1C_PWM3_GPIO47, PIN_REMAP_FOURTH);
  140. break;
  141. case LS1C_PWM3_GPIO53: // gpio53的第四复用
  142. pin_set_remap(LS1C_PWM3_GPIO53, PIN_REMAP_FOURTH);
  143. break;
  144. default:
  145. break;
  146. }
  147. // 根据占空比和pwm周期计算寄存器HRC和LRC的值
  148. // 两个64位数相乘,只能得到低32位,linux下却可以得到64位结果,
  149. // 暂不清楚原因,用浮点运算代替
  150. pwm_clk = clk_get_apb_rate();
  151. period = (1.0 * pwm_clk * pwm_info->period_ns) / 1000000000;
  152. period = MIN(period, PWM_MAX_PERIOD); // 限制周期不能超过最大值
  153. tmp = period - (period * pwm_info->duty);
  154. // 写寄存器HRC和LRC
  155. pwm_reg_base = pwm_get_reg_base(gpio);
  156. reg_write_32(--tmp, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_HRC));
  157. reg_write_32(--period, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_LRC));
  158. // 写主计数器
  159. pwm_enable(pwm_info);
  160. return ;
  161. }