]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blob - rpp/lib/rpp/src/drv/hbridge.c
c6bafe07d75df437684a5cb06c689b82a76c80b6
[pes-rpp/rpp-test-sw.git] / rpp / lib / rpp / src / drv / hbridge.c
1 /* Copyright (C) 2013 Czech Technical University in Prague
2  *
3  * Authors:
4  *     - Michal Horn
5  *     - Carlos Jenkins <carlos@jenkins.co.cr>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  * File : ain.c
21  * Abstract:
22  *     RPP driver implementation for HBR.
23  *
24  * References:
25  *     hbridge.h
26  */
27
28 // This file contains functions to control H-bridge.
29 // A keep-alive watchdog is implemented.
30 // PWM is available for HBR control.
31
32
33 #include "drv/drv.h"
34
35 //Flag variable if pwm was initialized and is ready to start.
36 static boolean_t pwm_initialized = FALSE;
37
38
39 /// Watchdog Task --------------------------------------------------------------
40 static boolean_t wdg_running = FALSE;
41
42
43 // Prepared command to be send on SPI.
44 // Default value is watchdog reset command.
45 uint16_t hbr_spi_wdg_tx = 0x03DB;
46
47 // Shadow variable of hbr_spi_wdg_tx
48 uint16_t hbr_spi_wdg_tx_shd = 0x03DB;
49
50 // Response from SPI.
51 uint16_t hbr_spi_wdg_rx = 0;
52
53 // Shadow variable of hbr_spi_wdg_shd
54 uint16_t hbr_spi_wdg_rx_shd = 0;
55
56 /**
57  * @brief   SPI callback function
58  *
59  * This function is called each time SPI transfer finishes.
60  * Gets response and prepare command for next sending.
61  * Copy response from shadow variable,
62  * Copy prepared command to shadow variable
63  *
64  * @param[in]   ifc     Pointer to SPI driver structure
65  * @param[in]   code    SPI transfer status code
66  * @param[in]   msg     Pointer to message definition structure
67  *
68  * @return  always zero
69  */
70 int drv_hbr_spi_wdg_callback(struct spi_drv* ifc, int code,
71                          struct spi_msg_head* msg)
72 {
73     if (code == SPI_MSG_FINISHED) {
74         hbr_spi_wdg_rx = hbr_spi_wdg_rx_shd;
75         hbr_spi_wdg_tx_shd = hbr_spi_wdg_tx;
76     }
77     return 0;
78 }
79
80
81 // SPI message format definition for watchdog reset command
82 spi_msg_head_t hbr_spi_wdg = {
83         .flags = 0,
84         .addr = 0,
85         .rq_len = 2,
86         .tx_buf = (uint8_t*) &hbr_spi_wdg_tx_shd,
87         .rx_buf = (uint8_t*) &hbr_spi_wdg_rx_shd,
88         .callback = drv_hbr_spi_wdg_callback,
89         .private = 1
90 };
91
92 /**
93  * Watchdog FreeRTOS Task function.
94  *
95  * Select appropriate spi address
96  * Initialize task timer
97  * Send watchdog keep-alive command each 10ms.
98  *
99  * @param[in]   p    Pointer to parameter, unused.
100  */
101 void drv_hbr_wdg_task(void *p)
102 {
103     spi_drv_t* ifc;
104     ifc = spi_find_drv(NULL, 4);
105
106     if(ifc == NULL) {
107         wdg_running = FALSE;
108         vTaskDelete(NULL);
109     }
110
111     portTickType xLastWakeTime;
112     xLastWakeTime = xTaskGetTickCount();
113
114     while(TRUE) {
115         if(wdg_running) {
116             spi_msg_rq_ins(ifc, &hbr_spi_wdg);
117         }
118         vTaskDelayUntil(&xLastWakeTime, (10 / portTICK_RATE_MS));
119     }
120 }
121
122
123 /// Watchdog API ---------------------------------------------------------------
124 static xTaskHandle wdg_handle = NULL;
125
126 /**
127  * Start the watchdog task to send keep-alive commands periodically to H-Bridge.
128  *
129  * @return SUCCESS if watchdog could be started.\n
130  *         FAILURE if H-Bridge not setup (call drv_hbr_set_signal() first), the
131  *                 watchdog is running already or the task could not be created.
132  */
133 int8_t drv_hbr_wdg_start()
134 {
135     if(!pwm_initialized) {
136         return FAILURE;
137     }
138
139     if(wdg_running) {
140         return FAILURE;
141     }
142
143     // Task already created
144     if(wdg_handle != NULL) {
145         wdg_running = TRUE;
146
147     // Task never started
148     } else {
149         wdg_running = TRUE;
150         if(xTaskCreate(drv_hbr_wdg_task,
151                        (const signed char *)"hbr_wdg_task",
152                        256, NULL, 1, &wdg_handle) != pdPASS) {
153             wdg_running = FALSE;
154             return FAILURE;
155         }
156     }
157
158     return SUCCESS;
159 }
160
161
162 /**
163  * Stop the watchdog task.
164  *
165  * @return SUCCESS if watchdog could be stopped.\n
166  *         FAILURE if watchdog wasn't running.
167  */
168 int8_t drv_hbr_wdg_stop()
169 {
170     if(!pwm_initialized) {
171         return FAILURE;
172     }
173
174     if(!wdg_running) {
175         return FAILURE;
176     }
177
178     wdg_running = FALSE;
179     return SUCCESS;
180 }
181
182
183 /// H-Bridge API ---------------------------------------------------------------
184 /**
185  * @brief Set PWM period and duty cycle to HBR_PWM pin
186  *
187  * Set period and dutycycle to HBR_PWM pin.
188  * Period is expected to be in us, duty cycle in percent of the period,
189  *
190  * If period is lower than 1 or duty greater than 100, function returns without having effect.
191  *
192  * @param[in]   period      Period of PWM in us
193  * @param[in]   duty        Width of duty in %
194  */
195 int8_t drv_hbr_pwm_set_signal(double period, uint32_t duty)
196 {
197     hetSIGNAL_t tmp_signal;
198
199     if(duty > 100) {
200         return FAILURE;
201     }
202
203     if(period < 1) {
204         return FAILURE;
205     }
206
207     tmp_signal.duty   = duty;
208     tmp_signal.period = period;
209     pwmSetSignal(hetRAM1, pwm0, tmp_signal);
210
211     pwm_initialized = TRUE;
212
213     return SUCCESS;
214 }
215
216
217 /**
218  * Start PWM on HBR_PWM pin
219  *
220  * If PWM was set previously by hbr_pwm_set_signal function, this procedure starts it.
221  * Otherwise function returns and PWM is not started.
222  *
223  * @return  0 if success, -1 when PWM was not yes set.
224  */
225 int8_t drv_hbr_pwm_start()
226 {
227     if (pwm_initialized) {
228
229         pwmStart(hetRAM1, pwm0);
230         return SUCCESS;
231
232     } else {
233
234         return FAILURE;
235     }
236 }
237
238 /**
239  * @brief Stop PWM on HBR_PWM pin
240  */
241 void drv_hbr_pwm_stop() {
242     pwmStop(hetRAM1, pwm0);
243 }
244
245 void drv_hbr_pwm_set_duty(uint8_t percent)
246 {
247     // Don't mind doing range check, pwmSetDuty handles this in error free
248     // manner.
249     pwmSetDuty(hetRAM1, pwm0, percent);
250 }
251
252 /**
253  * @brief Get duty width of PWM on HBR_PWM pin
254  *
255  * @return      Duty width of PWM in %
256  */
257 uint32_t drv_hbr_pwm_get_duty() {
258     hetSIGNAL_t tmp_signal;
259     tmp_signal = pwmGetSignal(hetRAM1, pwm0);
260     return tmp_signal.duty;
261 }
262
263 /**
264  * @brief Get period of PWM on HBR_PWM pin
265  *
266  * @return      Period of PWM in us
267  */
268 double drv_hbr_pwm_get_period() {
269     hetSIGNAL_t tmp_signal;
270     tmp_signal = pwmGetSignal(hetRAM1, pwm0);
271     return tmp_signal.period;
272
273 }
274
275 /**
276  *  @brief  Set value to HBR_DIR pin.
277  *
278  *  @param[in]  direction   If O, set hbr_dir to 0, otherwise to 1
279  */
280 void drv_hbr_set_dir(int direction) {
281     hal_gpio_pin_set_value(PIN_DSC_HBRDIR, direction);
282 }
283
284 /**
285  *  @brief  Get value of hbr_dir
286  *
287  *  @return return 0 or 1 - the value of hbr_dir
288  */
289 int drv_hbr_get_dir() {
290     return hal_gpio_pin_get_value(PIN_DSC_HBRDIR);
291 }
292
293 /**
294  *  @brief  Set value to HBR_EN pin.
295  *
296  *  @param[in]  direction   If O, set hbr_en to 0, otherwise to 1
297  */
298 void drv_hbr_set_en(int value) {
299     hal_gpio_pin_set_value(PIN_DSC_HBREN, value);
300 }
301
302 /**
303  *  @brief  Get value of HBR_EN
304  *
305  *  @return return 0 or 1 - the value of hbr_en
306  */
307 int drv_hbr_get_en() {
308     return hal_gpio_pin_get_value(PIN_DSC_HBREN);
309 }