Mercurial > controller
annotate pwm.h @ 4:e2ec8dc3a6d8 default tip
Always empty the receive buffer
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Thu, 15 Sep 2016 00:03:04 +0200 |
| parents | 2b5078b37907 |
| children |
| rev | line source |
|---|---|
|
0
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
1 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
2 * PWM library which allows you to control an arbitrary number of outputs. All |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
3 * outputs must have the same period, but each one can have a different phase. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
4 * This library relies on a 16 bit TIMER1, so cannot be run on any chip which |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
5 * does not have access to this hardware. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
6 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
7 * Please set CDEF PWM_PORTx_UNUSED for all ports which either are not on your |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
8 * chip, or which are not being used for PWM. (If your chip does not have a |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
9 * given port, e.g. the ATMega168 does not have a PORTA, then there will be |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
10 * compile errors. If you have the hardware, but are not using it for PWM, |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
11 * then it will just use (slightly) more memory and will be (slightly) slower. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
12 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
13 * Written by Wyatt Olson and Warren Janssens http://digitalcave.ca Released |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
14 * under the Creative Commons Attribution-NonCommercial-ShareAlike license. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
15 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
16 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
17 #ifndef PWM_H |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
18 #define PWM_H |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
19 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
20 #define PWM_PORTA_UNUSED |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
21 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
22 #include <avr/io.h> |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
23 #include <avr/interrupt.h> |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
24 #include <math.h> |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
25 #include <stdlib.h> |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
26 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
27 // The absolute maximum number of pins defined. The actual 'used' count is |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
28 // passed into pwm_init, and there is no problem with having a larger number |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
29 // here than is actually used (other than a bit of wasted SRAM space for |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
30 // pre-defined arrays). By default we set this to 4 as that is a decently |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
31 // large number, but not so huge that tons of excess SRAM is wasted. If you |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
32 // are low on memory, or need more outputs, feel free to redefine this in your |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
33 // makefile (in the CDEFS variable, beside where F_CPU is defined). |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
34 #ifndef PWM_MAX_PINS |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
35 #define PWM_MAX_PINS 18 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
36 #endif |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
37 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
38 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
39 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
40 * Initializes the PWM library at a given period, using the specified ports. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
41 * You can have up to PWM_MAX_PINS pins defined here. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
42 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
43 * To initialize this, you must pass in references to each of the PORTs, DDRs, |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
44 * and the values of each pin. You can do it like this: |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
45 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
46 * volatile uint8_t *ports[8]; ports[0] = &PORTB; ports[1] = &PORTD; .... |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
47 * ports[5] = &PORTD; |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
48 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
49 * uint8_t pins[8]; pins[0] = 1; .... pins[5] = 3; |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
50 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
51 * pwm_init(ports, pins, 6, 20000); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
52 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
53 * While the code to do this is uglier than if it were to just be a function |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
54 * call, by allowing an arbitrary number of PWM pins, it is best to do it like |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
55 * this. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
56 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
57 * The period must be less than 3354624us (about 3.3 seconds); any more than |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
58 * this and we just set it to the maximum. There is no theoretical minimum, |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
59 * but in practice you should probably keep it at 1000us or so (1ms). |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
60 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
61 void pwm_init(volatile uint8_t *ports[], uint8_t pins[], uint8_t count, |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
62 uint32_t period); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
63 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
64 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
65 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
66 * Sets the phase of the pin at the given index to the specified value. The |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
67 * index matches the index used for the arrays in pwm_init(). Internally, this |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
68 * calls pwm_set_phase_batch() and then pwm_apply_batch(). |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
69 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
70 void pwm_set_phase(uint8_t index, uint32_t phase); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
71 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
72 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
73 * Sets the phase of the pin at the given index to the specified value, but |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
74 * does not apply the change (recalculate all pin values). This can be called |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
75 * multiple times for different pins with minimal overhead; when completed all |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
76 * changes, call pwm_apply_batch(). |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
77 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
78 void pwm_set_phase_batch(uint8_t index, uint32_t phase); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
79 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
80 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
81 * Recalculates all pin / timer values. Required after calling |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
82 * pwm_set_phase_batch(). |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
83 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
84 void pwm_apply_batch(); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
85 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
86 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
87 * Sets the period of the PWM generator, changing the period specified in |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
88 * init(). Applies to all active PWM pins. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
89 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
90 void pwm_set_period(uint32_t period); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
91 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
92 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
93 * Turns off the PWM generator and stops the timer clock. Does not clear any |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
94 * config variables. You can turn PWM back on again using the pwm_start() |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
95 * function. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
96 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
97 void pwm_stop(); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
98 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
99 /* |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
100 * Turns on the PWM generator, starting back at 0. This should be called after |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
101 * pwm_off() has been called, but pwm_init() *must* already have been called. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
102 * Calling this when the generator is already on will reset the timer to 0, but |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
103 * otherwise will have no effect. |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
104 * |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
105 * If TIMER1 control registers have been modified by other libraries, you must |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
106 * call pwm_init() instead of pwm_start(). |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
107 */ |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
108 void pwm_start(); |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
109 |
|
2b5078b37907
Working servo PWM
Radomir Dopieralski <sheep-devel@sheep.art.pl>
parents:
diff
changeset
|
110 #endif |
