X-Git-Url: http://rtime.felk.cvut.cz/gitweb/pes-rpp/rpp-lib.git/blobdiff_plain/4d70424bd3959d19c5f092a1672b73036aaa150a..52d30217bc3de89b45821c2d5aee5bbb61bd73a7:/rpp/src/drv/hbridge.c diff --git a/rpp/src/drv/hbridge.c b/rpp/src/drv/hbridge.c index e0a17e2..08b4efc 100644 --- a/rpp/src/drv/hbridge.c +++ b/rpp/src/drv/hbridge.c @@ -1,21 +1,13 @@ -/* Copyright (C) 2013 Czech Technical University in Prague +/* Copyright (C) 2013, 2015, 2016 Czech Technical University in Prague * * Authors: * - Michal Horn * - Carlos Jenkins * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * This document contains proprietary information belonging to Czech + * Technical University in Prague. Passing on and copying of this + * document, and communication of its contents is not permitted + * without prior written authorization. * * File : ain.c * Abstract: @@ -28,30 +20,35 @@ // This file contains functions to control H-bridge. // A keep-alive watchdog is implemented. // PWM is available for HBR control. - - #include "drv/drv.h" +#include +#include "drv/spi_tms570.h" +#include "drv/gio_tab.h" //Flag variable if pwm was initialized and is ready to start. static boolean_t pwm_initialized = FALSE; - /// Watchdog Task -------------------------------------------------------------- -static boolean_t wdg_running = FALSE; - +static boolean_t wdg_start = FALSE; // Prepared command to be send on SPI. // Default value is watchdog reset command. -uint16_t hbr_spi_wdg_tx = 0x03DB; - -// Shadow variable of hbr_spi_wdg_tx -uint16_t hbr_spi_wdg_tx_shd = 0x03DB; +static const uint8_t hbr_spi_wdg_tx[2] = { 0x03, 0xDB }; // Response from SPI. -uint16_t hbr_spi_wdg_rx = 0; +static uint8_t hbr_spi_wdg_rx[2] = {0}; // Shadow variable of hbr_spi_wdg_shd -uint16_t hbr_spi_wdg_rx_shd = 0; +static uint8_t hbr_spi_wdg_rx_shd[2] = {0}; + +// SPI communication result code (one of SPI_MSG_*) +int hbr_spi_code = 0; + +// In certain situation the H-Bridge stops working without signaling that in +// its status byte. This happens when the watchdog message is sent +// approximately 25us after asserting EN signal. To prevent this situation we +// have to synchronize EN signal with watchdog thread. +static xSemaphoreHandle wdg_sync; /** * @brief SPI callback function @@ -67,26 +64,25 @@ uint16_t hbr_spi_wdg_rx_shd = 0; * * @return always zero */ -int drv_hbr_spi_wdg_callback(struct spi_drv* ifc, int code, - struct spi_msg_head* msg) +int drv_hbr_spi_wdg_callback(struct spi_drv *ifc, int code, + struct spi_msg *msg) { - if (code == SPI_MSG_FINISHED) { - hbr_spi_wdg_rx = hbr_spi_wdg_rx_shd; - hbr_spi_wdg_tx_shd = hbr_spi_wdg_tx; - } - return 0; + hbr_spi_code = code; + if (code == SPI_MSG_FINISHED) { + memcpy(hbr_spi_wdg_rx, hbr_spi_wdg_rx_shd, sizeof(hbr_spi_wdg_rx)); + } + return 0; } - // SPI message format definition for watchdog reset command -spi_msg_head_t hbr_spi_wdg = { - .flags = 0, - .addr = 0, - .rq_len = 2, - .tx_buf = (uint8_t*) &hbr_spi_wdg_tx_shd, - .rx_buf = (uint8_t*) &hbr_spi_wdg_rx_shd, - .callback = drv_hbr_spi_wdg_callback, - .private = 1 +spi_msg_t hbr_spi_wdg = { + .flags = 0, + .dev = SPIDEV_L99H01, + .rq_len = sizeof(hbr_spi_wdg_tx), + .tx_buf = hbr_spi_wdg_tx, + .rx_buf = hbr_spi_wdg_rx_shd, + .callback = drv_hbr_spi_wdg_callback, + .private = 1 }; /** @@ -100,26 +96,22 @@ spi_msg_head_t hbr_spi_wdg = { */ void drv_hbr_wdg_task(void *p) { - spi_drv_t* ifc; - ifc = spi_find_drv(NULL, 4); - - if(ifc == NULL) { - wdg_running = FALSE; - vTaskDelete(NULL); - } - - portTickType xLastWakeTime; - xLastWakeTime = xTaskGetTickCount(); - - while(TRUE) { - if(wdg_running) { - spi_msg_rq_ins(ifc, &hbr_spi_wdg); - } - vTaskDelayUntil(&xLastWakeTime, (10 / portTICK_RATE_MS)); - } + portTickType xLastWakeTime; + xLastWakeTime = xTaskGetTickCount(); + + while (TRUE) { + vTaskDelayUntil(&xLastWakeTime, (10 / portTICK_RATE_MS)); + xSemaphoreTake(wdg_sync, portMAX_DELAY); + if (wdg_start) { + xLastWakeTime = xTaskGetTickCount(); + wdg_start = FALSE; + } + else + spi_msg_rq_ins(&hbr_spi_wdg); + xSemaphoreGive(wdg_sync); + } } - /// Watchdog API --------------------------------------------------------------- static xTaskHandle wdg_handle = NULL; @@ -127,38 +119,34 @@ static xTaskHandle wdg_handle = NULL; * Start the watchdog task to send keep-alive commands periodically to H-Bridge. * * @return SUCCESS if watchdog could be started.\n - * FAILURE if H-Bridge not setup (call drv_hbr_set_signal() first), the - * watchdog is running already or the task could not be created. + * -RPP_EBUSY if watchdog is running already + * -RPP_ENOMEM if the task could not be created */ int8_t drv_hbr_wdg_start() { - if(!pwm_initialized) { - return FAILURE; - } - - if(wdg_running) { - return FAILURE; - } - - // Task already created - if(wdg_handle != NULL) { - wdg_running = TRUE; - - // Task never started - } else { - wdg_running = TRUE; - if(xTaskCreate(drv_hbr_wdg_task, - (const signed char *)"hbr_wdg_task", - 256, NULL, 1, &wdg_handle) != pdPASS) { - wdg_running = FALSE; - return FAILURE; - } - } - - return SUCCESS; + if (wdg_start) + return -RPP_EBUSY; + + wdg_start = TRUE; + // Task never started + if (wdg_handle == NULL ) { + wdg_sync = xSemaphoreCreateMutex(); + if (wdg_sync == NULL ) + return -RPP_ENOMEM; + if (xTaskCreate(drv_hbr_wdg_task, + "hbr_wdg_task", + 1024, NULL, 1, &wdg_handle) != pdPASS) { + wdg_start = FALSE; + return -RPP_ENOMEM; + } + } + else + // Task already created + vTaskResume(drv_hbr_wdg_task); + + return SUCCESS; } - /** * Stop the watchdog task. * @@ -167,19 +155,15 @@ int8_t drv_hbr_wdg_start() */ int8_t drv_hbr_wdg_stop() { - if(!pwm_initialized) { - return FAILURE; - } + if (!wdg_start) + return FAILURE; - if(!wdg_running) { - return FAILURE; - } - - wdg_running = FALSE; - return SUCCESS; + xSemaphoreTake(wdg_sync, portMAX_DELAY); + vTaskSuspend(drv_hbr_wdg_task); + xSemaphoreGive(wdg_sync); + return SUCCESS; } - /// H-Bridge API --------------------------------------------------------------- /** * @brief Set PWM period and duty cycle to HBR_PWM pin @@ -194,26 +178,23 @@ int8_t drv_hbr_wdg_stop() */ int8_t drv_hbr_pwm_set_signal(double period, uint32_t duty) { - hetSIGNAL_t tmp_signal; + hetSIGNAL_t tmp_signal; - if(duty > 100) { - return FAILURE; - } + if (duty > 100) + return FAILURE; - if(period < 50) { - return FAILURE; - } + if (period < 50) + return FAILURE; - tmp_signal.duty = duty; - tmp_signal.period = period; - pwmSetSignal(hetRAM1, pwm0, tmp_signal); + tmp_signal.duty = duty; + tmp_signal.period = period; + pwmSetSignal(hetRAM1, pwm0, tmp_signal); - pwm_initialized = TRUE; + pwm_initialized = TRUE; - return SUCCESS; + return SUCCESS; } - /** * Start PWM on HBR_PWM pin * @@ -224,29 +205,30 @@ int8_t drv_hbr_pwm_set_signal(double period, uint32_t duty) */ int8_t drv_hbr_pwm_start() { - if (pwm_initialized) { + if (pwm_initialized) { - pwmStart(hetRAM1, pwm0); - return SUCCESS; + pwmStart(hetRAM1, pwm0); + return SUCCESS; - } else { + } + else - return FAILURE; - } + return FAILURE; } /** * @brief Stop PWM on HBR_PWM pin */ -void drv_hbr_pwm_stop() { - pwmStop(hetRAM1, pwm0); +void drv_hbr_pwm_stop() +{ + pwmStop(hetRAM1, pwm0); } void drv_hbr_pwm_set_duty(uint8_t percent) { - // Don't mind doing range check, pwmSetDuty handles this in error free - // manner. - pwmSetDuty(hetRAM1, pwm0, percent); + // Don't mind doing range check, pwmSetDuty handles this in error free + // manner. + pwmSetDuty(hetRAM1, pwm0, percent); } /** @@ -254,10 +236,12 @@ void drv_hbr_pwm_set_duty(uint8_t percent) * * @return Duty width of PWM in % */ -uint32_t drv_hbr_pwm_get_duty() { - hetSIGNAL_t tmp_signal; - tmp_signal = pwmGetSignal(hetRAM1, pwm0); - return tmp_signal.duty; +uint32_t drv_hbr_pwm_get_duty() +{ + hetSIGNAL_t tmp_signal; + + tmp_signal = pwmGetSignal(hetRAM1, pwm0); + return tmp_signal.duty; } /** @@ -265,10 +249,12 @@ uint32_t drv_hbr_pwm_get_duty() { * * @return Period of PWM in us */ -double drv_hbr_pwm_get_period() { - hetSIGNAL_t tmp_signal; - tmp_signal = pwmGetSignal(hetRAM1, pwm0); - return tmp_signal.period; +double drv_hbr_pwm_get_period() +{ + hetSIGNAL_t tmp_signal; + + tmp_signal = pwmGetSignal(hetRAM1, pwm0); + return tmp_signal.period; } @@ -277,8 +263,9 @@ double drv_hbr_pwm_get_period() { * * @param[in] direction If O, set hbr_dir to 0, otherwise to 1 */ -void drv_hbr_set_dir(int direction) { - hal_gpio_pin_set_value(PIN_DSC_HBRDIR, direction); +void drv_hbr_set_dir(int direction) +{ + gio_tab_set(PIN_HBRDIR, !!direction); } /** @@ -286,8 +273,9 @@ void drv_hbr_set_dir(int direction) { * * @return return 0 or 1 - the value of hbr_dir */ -int drv_hbr_get_dir() { - return hal_gpio_pin_get_value(PIN_DSC_HBRDIR); +int drv_hbr_get_dir() +{ + return gio_tab_get(PIN_HBRDIR) ? 1 : 0; } /** @@ -295,8 +283,9 @@ int drv_hbr_get_dir() { * * @param[in] direction If O, set hbr_en to 0, otherwise to 1 */ -void drv_hbr_set_en(int value) { - hal_gpio_pin_set_value(PIN_DSC_HBREN, value); +void drv_hbr_set_en(int value) +{ + gio_tab_set(PIN_HBREN, !!value); } /** @@ -304,6 +293,7 @@ void drv_hbr_set_en(int value) { * * @return return 0 or 1 - the value of hbr_en */ -int drv_hbr_get_en() { - return hal_gpio_pin_get_value(PIN_DSC_HBREN); +int drv_hbr_get_en() +{ + return gio_tab_get(PIN_HBREN) ? 1 : 0; }