]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blobdiff - rpp/src/drv/adc.c
Trigger context switch after ADC interrupts - simpler version
[pes-rpp/rpp-lib.git] / rpp / src / drv / adc.c
index 64484decbf808ebaeb4923c6c9bd6ae1c8d64985..e8f8fca3367b8efd0421abf6f96e5de60af875d1 100644 (file)
@@ -1,21 +1,13 @@
-/* Copyright (C) 2012-2013 Czech Technical University in Prague
+/* Copyright (C) 2012-2013, 2015 Czech Technical University in Prague
  *
  * Authors:
  *     - Michal Horn
  *     - Carlos Jenkins <carlos@jenkins.co.cr>
  *
- * 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 <http://www.gnu.org/licenses/>.
+ * 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 : adc.c
  * Abstract:
  */
 
 
-#include "drv/adc.h"
+#include "drv/drv.h"
+#include "drv/port.h"
+#include "os/portmacro.h"
 
-// Binary semaphore for ADC1 GRP1 conversion (AIN)
-xSemaphoreHandle adcSemaphore_ADC1GRP1;
-// Binary semaphore for ADC2 GRP1 conversion (HOUT-IFBK)
-xSemaphoreHandle adcSemaphore_ADC2GRP1;
+// Binary semaphores for finish notifications
+static xSemaphoreHandle sem[2][2];
 
-// Mutex for AIN read control
-xSemaphoreHandle adcMutex_ADC;
-// Mutex for HOUTIFBK control
-xSemaphoreHandle adcMutex_HOUTIFBK;
+// Mutex for two ADCs
+xSemaphoreHandle mutex[2];
 
 void drv_adc_init()
 {
-    // Create semaphores
-    vSemaphoreCreateBinary(adcSemaphore_ADC1GRP1);
-    xSemaphoreTake(adcSemaphore_ADC1GRP1, 0);
-    vSemaphoreCreateBinary(adcSemaphore_ADC2GRP1);
-    xSemaphoreTake(adcSemaphore_ADC2GRP1, 0);
-
-    adcMutex_ADC       = xSemaphoreCreateMutex();
-    adcMutex_HOUTIFBK  = xSemaphoreCreateMutex();
-
-    // Low level init
-    adcInit();
+       int adc, grp;
+
+       for (adc = 0; adc < 2; adc++) {
+               for (grp = 0; grp < 2; grp++) {
+                       vSemaphoreCreateBinary(sem[adc][grp]);
+                       xSemaphoreTake(sem[adc][grp], 0);
+               }
+               mutex[adc] = xSemaphoreCreateMutex();
+       }
+       // Low level init
+       adcInit();
 }
 
 
@@ -69,123 +59,70 @@ void drv_adc_init()
  */
 void adcNotification(adcBASE_t *adc, uint32_t group)
 {
-    if(adcIsConversionComplete(adc, group) == ADC_CONVERSION_IS_FINISHED) {
-
-        // ADC1
-        if(adc == adcREG1) {
-            switch(group) {
-                case adcGROUP0:
-                    // Group0 is unused on RPP
-                    break;
-                case adcGROUP1:
-                    // According to FreeRTOS documentation second parameter is
-                    // optional (and can be set to NULL) from FreeRTOS
-                    // V7.3.0. We are using 7.0.2. I confirmed this in the
-                    // source code: src/os/queue.c line 821. - Carlos
-                    {
-                        signed portBASE_TYPE dummy;
-                        xSemaphoreGiveFromISR(adcSemaphore_ADC1GRP1, &dummy);
-                    }
-                    break;
-                default:
-                    // Group2 is unused on RPP
-                    break;
-            }
-        // ADC2
-        } else {
-            switch(group) {
-                case adcGROUP0:
-                    // Group0 is unused on RPP
-                    break;
-                case adcGROUP1:
-                    {
-                        signed portBASE_TYPE dummy;
-                        xSemaphoreGiveFromISR(adcSemaphore_ADC2GRP1, &dummy);
-                    }
-                    break;
-                default:
-                    // Group2 is unused on RPP
-                    break;
-            }
-        }
-    }
+       if (adcIsConversionComplete(adc, group) == ADC_CONVERSION_IS_FINISHED) {
+               int adc_idx = (adc == adcREG1) ? 0 : 1;
+               int grp_idx = (group == adcGROUP1) ? 0 : 1;
+               portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+
+               xSemaphoreGiveFromISR(sem[adc_idx][grp_idx], &xHigherPriorityTaskWoken);
+               portYIELD_FROM_ISR(xHigherPriorityTaskWoken); /* Cause context switch after return from interrupt */
+       }
 }
 
 
 uint32_t drv_adc_generic_read(adcBASE_t *adc, uint32_t group,
-                               xSemaphoreHandle adcSemaphore, adcData_t* data)
+                                                         adcData_t *data)
 {
-    // Calibrate
-    adcCalibration(adc);
-    adcMidPointCalibration(adc);
+       int adc_idx = (adc == adcREG1) ? 0 : 1;
+       int grp_idx = (group == adcGROUP1) ? 0 : 1;
 
-    // Start conversion
-    adcEnableNotification(adc, group);
-    adcStartConversion(adc, group);
+       xSemaphoreTake(mutex[adc_idx], portMAX_DELAY);
 
-    // Wait for conversion to complete
-    xSemaphoreTake(adcSemaphore, portMAX_DELAY);
-    adcDisableNotification(adc, group);
+       // Calibrate
+       adcCalibration(adc);
+       adcMidPointCalibration(adc);
 
-    // Get data
-    uint32_t channels = adcGetData(adc, group, data);
+       // Start conversion
+       adcEnableNotification(adc, group);
+       adcStartConversion(adc, group);
 
-    // Check if memory overrun
-    if(adcIsFifoFull(adc, group) == ADC_FIFO_OVERFLOW) {
-        // FIXME Should report somehow.
-        adcResetFiFo(adc, group);
-    }
+       // Wait for conversion to complete
+       xSemaphoreTake(sem[adc_idx][grp_idx], portMAX_DELAY);
+       adcDisableNotification(adc, group);
 
-    return channels;
-}
+       // Get data
+       uint32_t channels = adcGetData(adc, group, data);
 
+       // Check if memory overrun
+       if (adcIsFifoFull(adc, group) == ADC_FIFO_OVERFLOW)
+               // FIXME Should report somehow.
+               adcResetFiFo(adc, group);
 
-uint32_t drv_adc_read_adc(adcData_t* data)
-{
-    xSemaphoreTake(adcMutex_ADC, portMAX_DELAY);
-    uint32_t result = drv_adc_generic_read(
-                                adcREG1,
-                                adcGROUP1,
-                                adcSemaphore_ADC1GRP1,
-                                data
-                            );
-    xSemaphoreGive(adcMutex_ADC);
-    return result;
+       xSemaphoreGive(mutex[adc_idx]);
+
+       return channels;
 }
 
-uint32_t drv_adc_read_houtifbk(adcData_t* data)
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+int8_t port_adc_get(const struct port_desc *port, void *values, size_t size)
 {
-    xSemaphoreTake(adcMutex_HOUTIFBK, portMAX_DELAY);
-    uint32_t result = drv_adc_generic_read(
-                                adcREG2,
-                                adcGROUP1,
-                                adcSemaphore_ADC2GRP1,
-                                data
-                            );
-    xSemaphoreGive(adcMutex_HOUTIFBK);
-    return result;
-}
+       uint32_t i;
+       adcData_t data[ADC_MAX_CHANNELS];
+       int count = MIN(port->numchn, size/sizeof(uint16_t));
+       uint16_t *adcval = values;
 
-uint32_t adc_get_port_val(uint32_t* config, uint32_t num_channels,
-                           uint32_t* values) {
-    uint32_t i;
-    adcBASE_t* adcReg = (adcBASE_t *)config[0];
-    uint32_t adcGroup = config[1];
-    uint32_t adcSemaphore = config[2];
-    adcData_t data[ADC_MAX_CHANNELS];
-
-    drv_adc_generic_read(
-               adcReg,
-               adcGroup,
-               (adcSemaphore == 1) ? adcSemaphore_ADC1GRP1 : adcSemaphore_ADC2GRP1,
+       assert(port->bpch == 16);
+       assert(size % sizeof(uint16_t) == 0);
+
+       drv_adc_generic_read(
+               port->cfg.adc.reg,
+               port->cfg.adc.group,
                data
-       );
+               );
 
-    for (i = 0; i < num_channels; i++) {
-        values[i] = data[i].value;
-        values[i+num_channels] = data[i].id;
-    }
+       for (i = 0; i < count; i++)
+               adcval[i] = data[i].value;
 
-    return 0;
+       return 0;
 }
-