summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/beagle/pwm/README
blob: d41f5ca668c4ffa904ddf5d00a733867ed811a3a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
Pulse Width Modulation subsystem includes EPWM, ECAP , EQEP. There are
different instances available for each one. For PWM there are three
different individual EPWM module 0 , 1 and 2. So wherever pwmss word is
used that affects whole PWM sub system such as EPWM, ECAP and EQEP. This code
has only implementation Non high resolution PWM module. APIs for high
resolution PWM has been yet to develop.

For Each EPWM instance, has two PWM channels, e.g. EPWM0 has two channel
EPWM0A and EPWM0B. If you configure two PWM outputs(e.g. EPWM0A , EPWM0B)
in the same device, then they *must* be configured with the same frequency.
Changing frequency on one channel (e.g EPWMxA) will automatically change
frequency on another channel(e.g. EPWMxB). However, it is possible to set
different pulse-width/duty cycle to different channel at a time. So always
set the frequency first and then pulse-width/duty cycle.

For more you can refer :
http://www.ofitselfso.com/BBBCSIO/Source/PWMPortEnum.cs.html
 
Pulse Width Modulation uses the system frequency of Beagle Bone Black.

System frequency = SYSCLKOUT, that is, CPU clock. TBCLK = SYSCLKOUT(By Default)
SYCLKOUT = 100 MHz

Please visit following link to check why SYSCLKDIV = 100MHz:
https://groups.google.com/forum/#!topic/beagleboard/Ed2J9Txe_E4
(Refer Technical Reference Manual (TRM) Table 15-41 as well)

To generate different frequencies with the help of PWM module , SYSCLKOUT
need to be scaled down, which will act as TBCLK and TBCLK will be base clock
for the pwm subsystem.

TBCLK = SYSCLKOUT/(HSPCLKDIV * CLKDIV)

                 |----------------| 
                 |     clock      | 
 SYSCLKOUT--->   |                |---> TBCLK 
                 |   prescale     |
                 |----------------|         
                   ^           ^
                   |           |
 TBCTL[CLKDIV]-----            ------TBCTL[HSPCLKDIV]


CLKDIV and HSPCLKDIV bits are part of the TBCTL register (Refer TRM).
CLKDIV - These bits determine part of the time-base clock prescale value.
Please use the following values of CLKDIV to scale down sysclk respectively.
0h (R/W) = /1 
1h (R/W) = /2
2h (R/W) = /4
3h (R/W) = /8
4h (R/W) = /16
5h (R/W) = /32
6h (R/W) = /64
7h (R/W) = /128

These bits determine part of the time-base clock prescale value.
Please use following value of HSPCLKDIV to scale down sysclk respectively
0h (R/W) = /1
1h (R/W) = /2
2h (R/W) = /4
3h (R/W) = /6
4h (R/W) = /8
5h (R/W) = /10
6h (R/W) = /12
7h (R/W) = /14

For example, if you set CLKDIV = 3h and HSPCLKDIV= 2h Then
SYSCLKOUT will be divided by (1/8)(1/4). It means SYSCLKOUT/32

How to generate frequency ?

freq = 1/Period

TBPRD register is responsible to generate the frequency. These bits determine
the period of the time-base counter.

By default TBCLK = SYSCLKOUT = 100 MHz

Here by default period is 1/100MHz = 10 nsec

Following example shows value to be loaded into TBPRD
 
e.g. TBPRD = 1 = 1 count
  count x Period = 1 x 1ns = 1ns
  freq = 1/Period = 1 / 1ns = 100 MHz

For duty cycle CMPA and CMPB are the responsible registers.

To generate single with 50% Duty cycle & 100MHz freq.
 
 CMPA = count x Duty Cycle
       = TBPRD x Duty Cycle
       = 1 x 50/100
       = 0.2

The value in the active CMPA register is continuously compared to
the time-base counter (TBCNT). When the values are equal, the
counter-compare module generates a "time-base counter equal to
counter compare A" event. This event is sent to the action-qualifier
where it is qualified and converted it into one or more actions.
These actions can be applied to either the EPWMxA or the
EPWMxB output depending on the configuration of the AQCTLA and
AQCTLB registers.
 
List of pins for that can be used for different PWM instance :

  ------------------------------------------------ 
  |  EPWM2        | EPWM1         | EPWM0        |
  ------------------------------------------------
  |  BBB_P8_13_2B | BBB_P8_34_1B  | BBB_P9_21_0B |  
  |  BBB_P8_19_2A | BBB_P8_36_1A  | BBB_P9_22_0A |
  |  BBB_P8_45_2A | BBB_P9_14_1A  | BBB_P9_29_0B |
  |  BBB_P8_46_2B | BBB_P9_16_1B  | BBB_P9_31_0A |
  ------------------------------------------------
BBB_P8_13_2B represents P8 Header , pin number 13 , 2nd PWM instance and B channel. 

Following sample program can be used to generate 7 Hz frequency.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/test.h>
#include <bsp.h>
#include <bsp/gpio.h>
#include <stdio.h>
#include <stdlib.h>
#include <bsp/bbb-pwm.h>

const char rtems_test_name[] = "Testing PWM driver";
rtems_printer rtems_test_printer;

static void inline delay_sec(int sec)
{
  rtems_task_wake_after(sec*rtems_clock_get_ticks_per_second());
}  

rtems_task Init(rtems_task_argument argument);

rtems_task Init(
	rtems_task_argument ignored
)
{
  rtems_test_begin(); 
  printf("Starting PWM Testing");
  
  /*Initialize GPIO pins in BBB*/
  rtems_gpio_initialize();
  
  /* Set P9 Header , 21 Pin number , PWM B channel and 0 PWM instance to generate frequency*/ 
  beagle_epwm_pinmux_setup(BBB_P9_21_0B,BBB_PWMSS0);
  
/** Initialize clock for PWM sub system
  * Turn on time base clock for PWM o instance
  */
  beagle_pwm_init(BBB_PWMSS0);

  float PWM_HZ = 7.0f ;           /* 7 Hz */
  float duty_A = 20.0f ;          /* 20% Duty cycle for PWM 0_A output */
  const float duty_B = 50.0f ;    /* 50% Duty cycle for PWM 0_B output*/
  
  /*Note: Always check whether pwmss clocks are enabled or not before configuring PWM*/
  bool is_running = beagle_pwmss_is_running(BBB_PWMSS2);
  
  if(is_running) {
  
  /*To analyse the two different duty cycle Output should be observed at P8_45 and P8_46 pin number */
  beagle_pwm_configure(BBB_PWMSS0, PWM_HZ ,duty_A , duty_B);
  printf("PWM  enable for 10s ....\n");
 
  /*Set Up counter and enable pwm module */
  beagle_pwm_enable(BBB_PWMSS0);
  delay_sec(10);
  
  /*freeze the counter and disable pwm module*/
  beagle_epwm_disable(BBB_PWMSS0);
  }
}

/* NOTICE: the clock driver is enabled */
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER

#define CONFIGURE_MAXIMUM_TASKS            1
#define CONFIGURE_USE_DEVFS_AS_BASE_FILESYSTEM

#define CONFIGURE_MAXIMUM_SEMAPHORES    1

#define CONFIGURE_RTEMS_INIT_TASKS_TABLE 

#define CONFIGURE_EXTRA_TASK_STACKS         (2 * RTEMS_MINIMUM_STACK_SIZE)

#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION

#define CONFIGURE_INIT
#include <rtems/confdefs.h>