source: rtems/bsps/arm/beagle/pwm/pwm.c @ db86c3eb

Last change on this file since db86c3eb was db86c3eb, checked in by James Fitzsimons <james.fitzsimons@…>, on 02/23/21 at 08:18:39

bsps/beagle: Adding QEP driver support to BeagleBoneBlack? BSP

  • Property mode set to 100644
File size: 11.9 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup arm_beagle
5 *
6 * @brief Support for PWM for the BeagleBone Black.
7 */
8
9/**
10 * Copyright (c) 2016 Punit Vara <punitvara@gmail.com>
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.org/license/LICENSE.
15 */
16
17/** This file is based on
18  * https://github.com/VegetableAvenger/BBBIOlib/blob/master/BBBio_lib/BBBiolib_PWMSS.c
19  */
20
21#include <libcpu/am335x.h>
22#include <stdio.h>
23#include <bsp/gpio.h>
24#include <bsp/bbb-gpio.h>
25#include <bsp.h>
26#include <bsp/pwmss.h>
27#include <bsp/bbb-pwm.h>
28#include <bsp/beagleboneblack.h>
29
30/* Currently these definitions are for BeagleBone Black board only
31 * Later on Beagle-xM board support can be added in this code.
32 * After support gets added if condition should be removed
33 */
34#if IS_AM335X
35
36/*
37 * @brief This function selects EPWM module to be enabled
38 *
39 * @param pwm_id It is the instance number of EPWM of pwm sub system.
40 *
41 * @return Base Address of respective pwm instant.
42 */
43static uint32_t select_pwm(BBB_PWMSS pwm_id)
44{
45  uint32_t baseAddr=0;
46 
47  if (pwm_id == BBB_PWMSS0) {
48    baseAddr = AM335X_EPWM_0_REGS;
49  } else if (pwm_id == BBB_PWMSS1) {
50    baseAddr = AM335X_EPWM_1_REGS;
51  } else if (pwm_id == BBB_PWMSS2) {
52    baseAddr = AM335X_EPWM_2_REGS;
53  } else {
54    baseAddr = 0;
55  }
56  return baseAddr;     
57}
58
59/*
60 * @brief This function selects PWM Sub system to be enabled
61 * 
62 * @param pwmss_id  The instance number of ePWMSS whose system clocks
63 *                  have to be configured.
64 *
65 * @return Base Address of respective pwmss instant.
66*/
67static uint32_t select_pwmss(BBB_PWMSS pwmss_id)
68{
69  uint32_t baseAddr=0;
70 
71  if (pwmss_id == BBB_PWMSS0) {
72    baseAddr = AM335X_PWMSS0_MMAP_ADDR;
73  } else if (pwmss_id == BBB_PWMSS1) {
74    baseAddr = AM335X_PWMSS1_MMAP_ADDR;
75  } else if (pwmss_id == BBB_PWMSS2) {
76    baseAddr = AM335X_PWMSS2_MMAP_ADDR;
77  } else {
78    baseAddr = 0;
79  }
80  return baseAddr;
81}
82
83bool beagle_pwm_pinmux_setup(bbb_pwm_pin_t pin_no, BBB_PWMSS pwm_id)
84{
85  bool is_valid = true;
86 
87  if(pwm_id == BBB_PWMSS0) {
88    if (pin_no == BBB_P9_21_0B) {
89      REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D0) = BBB_MUXMODE(BBB_P9_21_MUX_PWM);
90    } else if (pin_no == BBB_P9_22_0A) {
91      REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_SCLK) = BBB_MUXMODE(BBB_P9_22_MUX_PWM);
92    } else if (pin_no == BBB_P9_29_0B) {
93      REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_FSX) = BBB_MUXMODE(BBB_P9_29_MUX_PWM);
94    } else if (pin_no == BBB_P9_31_0A) {
95      REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_ACLKX) = BBB_MUXMODE(BBB_P9_31_MUX_PWM);
96    } else {
97      is_valid = false;
98    }
99   
100    } else if (pwm_id == BBB_PWMSS1) {
101        if (pin_no == BBB_P8_34_1B) {
102          REG(AM335X_PADCONF_BASE + BBB_CONTROL_CONF_LCD_DATA(11)) = BBB_MUXMODE(BBB_P8_34_MUX_PWM);
103        } else if (pin_no == BBB_P8_36_1A) {
104          REG(AM335X_PADCONF_BASE + BBB_CONTROL_CONF_LCD_DATA(10)) = BBB_MUXMODE(BBB_P8_36_MUX_PWM);
105        } else if (pin_no == BBB_P9_14_1A) {
106          REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_A2) = BBB_MUXMODE(BBB_P9_14_MUX_PWM);
107        } else if (pin_no == BBB_P9_16_1B) {
108          REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_A3) = BBB_MUXMODE(BBB_P9_16_MUX_PWM);
109        } else {
110          is_valid = false;
111        }
112   } else if (pwm_id == BBB_PWMSS2) {
113        if (pin_no == BBB_P8_13_2B) {
114          REG(AM335X_PADCONF_BASE + BBB_CONTROL_CONF_GPMC_AD(9)) = BBB_MUXMODE(BBB_P8_13_MUX_PWM);
115        } else if (pin_no == BBB_P8_19_2A) {
116          REG(AM335X_PADCONF_BASE + BBB_CONTROL_CONF_GPMC_AD(8)) = BBB_MUXMODE(BBB_P8_19_MUX_PWM);
117        } else if (pin_no == BBB_P8_45_2A) {
118          REG(AM335X_PADCONF_BASE + BBB_CONTROL_CONF_LCD_DATA(0)) = BBB_MUXMODE(BBB_P8_45_MUX_PWM);
119        } else if (pin_no == BBB_P8_46_2B) {
120          REG(AM335X_PADCONF_BASE + BBB_CONTROL_CONF_LCD_DATA(1)) = BBB_MUXMODE(BBB_P8_46_MUX_PWM);
121        } else {
122          is_valid = false;
123        }
124  } else {
125        is_valid = false;
126  }
127  return is_valid;
128}
129
130/**
131 * @brief   This function Enables TBCLK(Time Base Clock) for specific
132 *          EPWM instance of pwmsubsystem.
133 *
134 * @param   instance  It is the instance number of EPWM of pwmsubsystem.
135 *
136 * @return  true if successful
137 *          false if unsuccessful
138 **/
139static bool pwmss_tbclk_enable(BBB_PWMSS instance)
140{
141  uint32_t enable_bit;
142  bool is_valid = true;
143 
144  if (instance == BBB_PWMSS0)  {
145    enable_bit = AM335X_PWMSS_CTRL_PWMSS0_TBCLKEN;
146  }  else if (instance == BBB_PWMSS1)  {
147       enable_bit = AM335X_PWMSS_CTRL_PWMSS1_TBCLKEN;
148  }  else if (instance == BBB_PWMSS2)  {
149       enable_bit = AM335X_PWMSS_CTRL_PWMSS2_TBCLKEN;
150  }  else  {
151       is_valid = false;
152  }
153
154  if (is_valid)
155  {
156    REG(AM335X_PADCONF_BASE + AM335X_PWMSS_CTRL) |= enable_bit;
157  }
158
159  return is_valid;
160 }
161
162/**
163 * @brief   This functions enables clock for EHRPWM module in PWMSS subsystem.
164 *
165 * @param   pwm_id  It is the instance number of EPWM of pwm sub system.
166 *
167 * @return  true if successful
168 *          false if unsuccessful
169 *
170 **/
171static bool pwm_clock_enable(BBB_PWMSS pwm_id)
172{
173  const bool id_is_valid = pwm_id < BBB_PWMSS_COUNT;   
174  bool status = true;
175 
176  if (id_is_valid) {
177    const uint32_t baseAddr = select_pwmss(pwm_id);
178    REG(baseAddr + AM335X_PWMSS_CLKCONFIG) |= AM335X_PWMSS_CLK_EN_ACK;
179  }  else  {
180       status = false;
181  }
182  return status;
183}
184
185bool beagle_pwm_init(BBB_PWMSS pwmss_id)
186{
187  const bool id_is_valid = pwmss_id < BBB_PWMSS_COUNT;
188  bool status = true;
189 
190  if(id_is_valid) {
191    pwmss_module_clk_config(pwmss_id);
192    pwm_clock_enable(pwmss_id);
193    pwmss_tbclk_enable(pwmss_id);
194  } else {
195      status =false;
196  }
197  return status;
198}
199
200int beagle_pwm_configure(BBB_PWMSS pwm_id, float pwm_freq, float duty_a, float duty_b)
201{
202  uint32_t baseAddr;
203  int status = 1;
204  float cycle = 0.0f,divisor = 0;
205  unsigned int i,j;
206  const float CLKDIV_div[] = {1.0,2.0,4.0,8.0,16.0,32.0,64.0,128.0};
207  const float HSPCLKDIV_div[] = {1.0, 2.0, 4.0, 6.0, 8.0, 10.0,12.0, 14.0};
208  int NearCLKDIV =7,NearHSPCLKDIV =7,NearTBPRD =0;
209 
210  if (pwm_freq <= BBB_PWM_FREQ_THRESHOLD) {
211    status =0;
212  }
213 
214  if (duty_a < 0.0f || duty_a > 100.0f || duty_b < 0.0f || duty_b > 100.0f) {
215    status = 0;
216  }
217  duty_a /= 100.0f;
218  duty_b /= 100.0f;
219 
220  /** 10^9 /Hz compute time per cycle (ns) */
221  cycle = 1000000000.0f / pwm_freq;
222
223  /** am335x provide (128* 14) divider and per TBPRD means 10ns when divider
224    * and max TBPRD is 65535 so max cycle is 128 * 8 * 14 * 65535 * 10ns */
225  divisor = (cycle / 655350.0f);
226  if (divisor > (128 * 14)) {
227    return 0;
228  }
229  else {
230    for (i=0;i<8;i++) {
231      for(j=0 ; j<8; j++) {
232        if((CLKDIV_div[i] * HSPCLKDIV_div[j]) < (CLKDIV_div[NearCLKDIV]
233                            * HSPCLKDIV_div[NearHSPCLKDIV]) && (CLKDIV_div[i] * HSPCLKDIV_div[j] > divisor)) {
234          NearCLKDIV = i;
235          NearHSPCLKDIV = j;
236         }
237      }
238    }
239 
240  baseAddr = select_pwm(pwm_id);
241 
242  REG16(baseAddr + AM335X_EPWM_TBCTL) &= ~(AM335X_TBCTL_CLKDIV_MASK | AM335X_TBCTL_HSPCLKDIV_MASK);
243  const uint16_t clkdiv_clear = (REG16(baseAddr + AM335X_EPWM_TBCTL) &
244  (~AM335X_EPWM_TBCTL_CLKDIV));
245  const uint16_t clkdiv_write = ((NearCLKDIV
246  << AM335X_EPWM_TBCTL_CLKDIV_SHIFT) & AM335X_EPWM_TBCTL_CLKDIV);
247  REG16(baseAddr + AM335X_EPWM_TBCTL) = clkdiv_clear | clkdiv_write;
248  const uint16_t hspclkdiv_clear =  (REG16(baseAddr + AM335X_EPWM_TBCTL) &
249  (~AM335X_EPWM_TBCTL_HSPCLKDIV));
250  const uint16_t hspclkdiv_write = ((NearHSPCLKDIV <<
251  AM335X_EPWM_TBCTL_HSPCLKDIV_SHIFT) & AM335X_EPWM_TBCTL_HSPCLKDIV);
252  REG16(baseAddr + AM335X_EPWM_TBCTL) = hspclkdiv_clear | hspclkdiv_write;
253  NearTBPRD = (cycle / (10.0 * CLKDIV_div[NearCLKDIV] * HSPCLKDIV_div[NearHSPCLKDIV]));
254  const uint16_t shadow_mask =  (REG16(baseAddr + AM335X_EPWM_TBCTL) &
255  (~AM335X_EPWM_PRD_LOAD_SHADOW_MASK));
256  const uint16_t shadow_disable =  (((bool)AM335X_EPWM_SHADOW_WRITE_DISABLE <<
257  AM335X_EPWM_TBCTL_PRDLD_SHIFT) & AM335X_EPWM_PRD_LOAD_SHADOW_MASK);
258  REG16(baseAddr + AM335X_EPWM_TBCTL) = shadow_mask | shadow_disable;
259  const uint16_t counter_mask = (REG16(baseAddr + AM335X_EPWM_TBCTL) &
260  (~AM335X_EPWM_COUNTER_MODE_MASK));
261  const uint16_t counter_shift = (((unsigned int)AM335X_EPWM_COUNT_UP <<
262  AM335X_TBCTL_CTRMODE_SHIFT) &  AM335X_EPWM_COUNTER_MODE_MASK);
263  REG16(baseAddr + AM335X_EPWM_TBCTL) = counter_mask | counter_shift;
264  /*setting clock divider and freeze time base*/
265  REG16(baseAddr + AM335X_EPWM_CMPB) = (unsigned short)((float)(NearTBPRD) * duty_b);
266  REG16(baseAddr + AM335X_EPWM_CMPA) = (unsigned short)((float)(NearTBPRD) * duty_a);
267  REG16(baseAddr + AM335X_EPWM_TBPRD) = (unsigned short)NearTBPRD;
268  REG16(baseAddr + AM335X_EPWM_TBCNT) = 0;
269  }
270  return status;
271}
272
273bool beagle_pwm_enable(BBB_PWMSS pwmid)
274{
275  const bool id_is_valid = pwmid < BBB_PWMSS_COUNT;
276  bool status = true;
277 
278  if (id_is_valid)  {
279    const uint32_t baseAddr = select_pwm(pwmid);
280  /* Initially set EPWMxA o/p high , when increasing counter = CMPA toggle o/p of EPWMxA */
281    REG16(baseAddr + AM335X_EPWM_AQCTLA) = AM335X_EPWM_AQCTLA_ZRO_XAHIGH | (AM335X_EPWM_AQCTLA_CAU_EPWMXATOGGLE << AM335X_EPWM_AQCTLA_CAU_SHIFT);
282  /* Initially set EPWMxB o/p high , when increasing counter = CMPA toggle o/p of EPWMxB */ 
283    REG16(baseAddr + AM335X_EPWM_AQCTLB) = AM335X_EPWM_AQCTLB_ZRO_XBHIGH | (AM335X_EPWM_AQCTLB_CBU_EPWMXBTOGGLE << AM335X_EPWM_AQCTLB_CBU_SHIFT);
284    REG16(baseAddr + AM335X_EPWM_TBCNT) = 0;
285  /* Set counter mode : Up-count mode */
286    REG16(baseAddr + AM335X_EPWM_TBCTL) |=  AM335X_TBCTL_FREERUN  | AM335X_TBCTL_CTRMODE_UP;
287  }  else  {
288       status =false;
289  }
290  return status;       
291}
292
293bool beagle_pwm_disable(BBB_PWMSS pwmid)
294{
295  const bool id_is_valid = pwmid < BBB_PWMSS_COUNT;
296  bool status = true;
297 
298  if (id_is_valid) {
299    const uint32_t baseAddr = select_pwm(pwmid);
300    REG16(baseAddr + AM335X_EPWM_TBCTL) = AM335X_EPWM_TBCTL_CTRMODE_STOPFREEZE;
301    REG16(baseAddr + AM335X_EPWM_AQCTLA) = AM335X_EPWM_AQCTLA_ZRO_XALOW | (AM335X_EPWM_AQCTLA_CAU_EPWMXATOGGLE << AM335X_EPWM_AQCTLA_CAU_SHIFT);
302    REG16(baseAddr + AM335X_EPWM_AQCTLB) = AM335X_EPWM_AQCTLA_ZRO_XBLOW | (AM335X_EPWM_AQCTLB_CBU_EPWMXBTOGGLE << AM335X_EPWM_AQCTLB_CBU_SHIFT);
303    REG16(baseAddr + AM335X_EPWM_TBCNT)  = 0;
304  }  else  {
305        status = false;
306  }
307  return status;
308}
309
310/**
311 * @brief   This functions determines whether time base clock is enabled for EPWMSS
312 *
313 * @param   pwmss_id  The instance number of ePWMSS whose time base clock need to
314 *                    be checked
315 *                   
316 * @return  returns 4 for PWMSS_ID = 2
317 *          returns 2 for PWMSS_ID = 1
318 *          returns 1 for PWMSS_ID = 0
319 **/
320static int pwmss_tb_clock_check(unsigned int pwmss_id)
321{
322  unsigned int reg_value;
323
324  /*control module check*/
325  reg_value = REG(AM335X_CONTROL_MODULE + AM335X_PWMSS_CTRL);
326  return (reg_value & (1 << pwmss_id));
327}
328
329/**
330 * @brief   This functions determines whether clock for EPWMSS is enabled or not.
331 *
332 * @param   It is the Memory address of the PWMSS instance used.
333 *
334 * @return 
335 *
336 **/
337static unsigned int pwmss_clock_en_status(unsigned int pwmid)
338{
339  unsigned int status;
340  const uint32_t baseAddr = select_pwmss(pwmid);
341 
342  status = REG(baseAddr + AM335X_PWMSS_CLKSTATUS);
343  status = status >> 8 & 0x1;
344  return status;
345}
346
347bool beagle_pwmss_is_running(unsigned int pwmss_id)
348{
349  const bool id_is_valid = pwmss_id < BBB_PWMSS_COUNT;
350  bool status=true;
351 
352  if (id_is_valid) {
353    status = pwmss_clock_en_status(pwmss_id);
354    if(status){
355    status = pwmss_tb_clock_check(pwmss_id);
356    } else {
357        status = false;
358    } 
359  } else {
360  status = false;
361  }
362  return status;
363}
364
365#endif
366
367/* For support of BeagleboardxM */
368#if IS_DM3730
369
370/* Currently this section is just to satisfy
371 * GPIO API and to make the build successful.
372 * Later on support can be added here.
373 */
374bool beagle_pwm_init(BBB_PWMSS pwmss_id)
375{
376  return false;
377}
378bool beagle_pwm_disable(BBB_PWMSS pwmid)
379{
380  return false;
381}
382bool beagle_pwm_enable(BBB_PWMSS pwmid)
383{
384  return false;
385}
386int beagle_pwm_configure(BBB_PWMSS pwm_id, float pwm_freq, float duty_a, float duty_b)
387{
388  return -1;
389}
390bool beagle_pwm_pinmux_setup(bbb_pwm_pin_t pin_no, BBB_PWMSS pwm_id)
391{
392  return false;
393}
394bool beagle_pwmss_is_running(unsigned int pwmss_id)
395{
396return false;
397}
398#endif
Note: See TracBrowser for help on using the repository browser.