fixed point in robot system 2
[aversive.git] / modules / hardware / pwm_ng / pwm_ng.c
1 /*  
2  *  Copyright Droids Corporation, Microb Technology, Eirbot (2005)
3  * 
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Copyright Droids-corporation - Olivier MATZ - 2009
19  */
20 #include <string.h>
21
22 #include <aversive.h>
23 #include <aversive/parts.h>
24 #include <aversive/timers.h>
25
26 #include "pwm_ng.h"
27
28 /* value to be used for limiting inputs */
29 #define PWM_SIGNIFICANT_BITS 12
30 #define PWM_MAX ((1<< PWM_SIGNIFICANT_BITS)-1)
31 #define PWM_MIN (-PWM_MAX)
32
33 #define PWM_NG_TYPE_8   0
34 #define PWM_NG_TYPE_16  1
35
36 #define PWM_NG_NBITS_8   0
37 #define PWM_NG_NBITS_9   1
38 #define PWM_NG_NBITS_10  2
39
40 void pwm_ng_init(struct pwm_ng *pwm, uint8_t timer_nbits, 
41                  uint8_t pwm_nbits, uint8_t pwm_mode,
42                  volatile void *ocrn, 
43                  uint8_t com0, volatile uint8_t *tccrn,
44                  volatile uint8_t *pwm_port, uint8_t pwm_bit,
45                  volatile uint8_t *sign_port, uint8_t sign_bit)
46 {
47         memset(pwm, 0, sizeof(*pwm));
48
49         if (timer_nbits == 8) {
50                 pwm->type = PWM_NG_TYPE_8;
51                 pwm->u.ocr8 = ocrn;
52                 *pwm->u.ocr8 = 0;
53         }
54         else {
55                 pwm->type = PWM_NG_TYPE_16;
56                 pwm->u.ocr16 = ocrn;
57                 *pwm->u.ocr16 = 0;
58         }
59         switch (pwm_nbits) {
60         case 9:
61                 pwm->nbits = PWM_NG_NBITS_9;
62                 break;
63         case 10:
64                 pwm->nbits = PWM_NG_NBITS_10;
65                 break;
66         case 8:
67         default:
68                 pwm->nbits = PWM_NG_NBITS_8;
69                 break;
70         }
71         pwm->mode = pwm_mode;
72
73         *tccrn &= ~(0x03 << com0);
74         if (pwm_mode & PWM_NG_MODE_REVERSE)
75                 *tccrn |= (0x01 << com0);
76         else
77                 *tccrn |= (0x02 << com0);
78         
79         DDR(*pwm_port) |= (1 << pwm_bit);
80
81         if ((pwm_mode & PWM_NG_MODE_SIGNED) && (sign_port))
82                 DDR(*sign_port) |= (1 << sign_bit);
83         pwm->sign_port = sign_port;
84         pwm->sign_bit = sign_bit;
85 }
86
87 static inline void pwm_sign_set(struct pwm_ng *pwm)
88 {
89         if (pwm->mode & PWM_NG_MODE_SIGN_INVERTED)
90                 *pwm->sign_port &= ~(1 << pwm->sign_bit);
91         else
92                 *pwm->sign_port |= (1 << pwm->sign_bit);
93 }
94
95 static inline void pwm_sign_reset(struct pwm_ng *pwm)
96 {
97         if (pwm->mode &PWM_NG_MODE_SIGN_INVERTED)
98                 *pwm->sign_port |= (1 << pwm->sign_bit);
99         else
100                 *pwm->sign_port &= ~(1 << pwm->sign_bit);
101 }
102
103 static inline int32_t pwm_invert_value(struct pwm_ng *pwm, int32_t value)
104 {
105         if (pwm->mode & PWM_NG_MODE_SPECIAL_SIGN)
106                 return value & PWM_MAX;
107         else
108                 return -value;
109 }
110
111 #include <stdio.h>
112 void pwm_ng_set(void *data, int32_t value)
113 {
114         struct pwm_ng *pwm = data;
115         uint8_t nbits = 8 + pwm->nbits;
116
117         MAX(value, PWM_MAX);
118         if (pwm->mode & PWM_NG_MODE_SIGNED) {
119                 MIN(value, PWM_MIN);
120                 if (value < 0) {
121                         pwm_sign_set(pwm);
122                         value = pwm_invert_value(pwm, value);
123                 }
124                 else {
125                         pwm_sign_reset(pwm);
126                 }
127         }
128         else {
129                 MIN(value, 0);
130         }
131         if (pwm->type == PWM_NG_TYPE_8)
132                 *pwm->u.ocr8 = (uint8_t) (value >> (PWM_SIGNIFICANT_BITS - 8));
133         else
134                 *pwm->u.ocr16 = (value >> (PWM_SIGNIFICANT_BITS - nbits));
135 }
136