]> 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 b33faf0c253d02386a0fc00d22d5168cdd45f9d8..e8f8fca3367b8efd0421abf6f96e5de60af875d1 100644 (file)
-/*
- * adc_cmd.c
+/* Copyright (C) 2012-2013, 2015 Czech Technical University in Prague
  *
- *  Created on: 23.11.2012
- *      Author: Michal Horn
+ * Authors:
+ *     - Michal Horn
+ *     - Carlos Jenkins <carlos@jenkins.co.cr>
  *
- *     This file contains low level and high level functions for reading from ADC.
- *     One function for reading from ADC port on the board is also defined.
+ * 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:
+ *     RPP driver implementation for ADC.
+ *
+ * References:
+ *     ti_drv_adc.c
  */
-#include "drv_adc.h"
 
-/** @brief Semaphore blocking task when it waits for interrupt signaling end of the conversion */
-//xSemaphoreHandle adcDataConverted;
-/** @brief Data structure containing converted data from ADC */
-MyAdcData_t adcData;
-/**    Place to store converted data **/
-static adcData_t adc_data_origin[ADC_MAX_CHANNELS_COUNT*2];
 
+#include "drv/drv.h"
+#include "drv/port.h"
+#include "os/portmacro.h"
 
-/**
- * @brief Function called by ADC interrupt handler, stores data from ADC
- *
- *  If conversion has finished on ADC, store measured data and detect weather right number of channels was measured.
- *  If memory overrun was detected, set appropriate flag, reset ADC FIFO to be allow future measurement.
- *
- *  @param[in] adc     Pointer to ADC registers
- *  @param[in] group   Identificator of the ADC group, whic caused the interrupt
- */
-void adcNotification(adcBASE_t *adc, uint32_t group)
+// Binary semaphores for finish notifications
+static xSemaphoreHandle sem[2][2];
+
+// Mutex for two ADCs
+xSemaphoreHandle mutex[2];
+
+void drv_adc_init()
 {
-       /* FIXME Move this implementation and header somewhere else
-       // Group selected by group selector has been read
-       if (adc->GxINTFLG[group] & 8) {
-               uint32_t ch_count;
-               ch_count = adcGetData(adc, group, &adcData.adc_data[0]);
-               adcData.flags |= (ch_count == adcData.ch_count) ? 0 : BAD_CHANNELS_COUNT;
-               xSemaphoreGiveFromISR(adcDataConverted, NULL);
-       }
-       // Memory overrun detected - set flag
-       if (adc->GxINTFLG[group] & 2) {
-               print((uint8_t *)"Warning: ADC overrun detected!\r\n");
-               adcData.flags |= MEM_OVERRUN;
-               adc->GxFIFORESETCR[1] = 1;
+       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();
 }
 
+
 /**
- * @brief      Master function for AD conversion
- *
- * This function expects adcData.adc_data to be initialized to proper size (ADC_NUM_CHANNELS*2)
- * Function waits until conversion completes (by semaphore, which is released in ADC ISR
+ * ADC notification called by ADC conversion finished ISR.
  *
- * @param[in]  adc     Pointer to ADC registers
- * @param[in]  group   ADC group identificator
+ * This procedure will just give semaphore.
  *
- * @return     0 when success, 1 when error
+ *   @param[in] adc Pointer to ADC module:
+ *              - adcREG1: ADC1 module pointer
+ *              - adcREG2: ADC2 module pointer
+ *   @param[in] group Hardware group of ADC module:
+ *              - adcGROUP0: ADC event group
+ *              - adcGROUP1: ADC group 1
+ *              - adcGROUP2: ADC group 2
  */
-int read_adc(adcBASE_t* adc, uint32_t group) {
-       /* FIXME Move this implementation and header somewhere else
-       if (adcData.adc_data == NULL) {         // ADC data structure was not initialized
-               return 1;
+void adcNotification(adcBASE_t *adc, uint32_t group)
+{
+       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 */
        }
-       adcDataConverted = xSemaphoreCreateCounting(1, 0);
-       adcEnableNotification(adc, group);
-    adcCalibration(adc);
-    adcMidPointCalibration(adc);
+}
+
+
+uint32_t drv_adc_generic_read(adcBASE_t *adc, uint32_t group,
+                                                         adcData_t *data)
+{
+       int adc_idx = (adc == adcREG1) ? 0 : 1;
+       int grp_idx = (group == adcGROUP1) ? 0 : 1;
+
+       xSemaphoreTake(mutex[adc_idx], portMAX_DELAY);
 
+       // Calibrate
+       adcCalibration(adc);
+       adcMidPointCalibration(adc);
+
+       // Start conversion
+       adcEnableNotification(adc, group);
        adcStartConversion(adc, group);
-       xSemaphoreTake(adcDataConverted, portMAX_DELAY);                // Wait the measurement to complete
-
-    if (adcData.flags & BAD_CHANNELS_COUNT) {
-       print((uint8_t *)"\r\nERROR: Bad count of channels was read! Can not proceed.");
-       adcData.flags &= ~BAD_CHANNELS_COUNT;
-       adcDisableNotification(adc, group);
-       vSemaphoreDelete(adcDataConverted);
-       return 1;
-    }
-    if (adcData.flags & MEM_OVERRUN) {
-       print((uint8_t *)"\r\nWARNING: ADC Memory overrun detected. Values can be imprecise.");
-       adcData.flags &= ~MEM_OVERRUN;
-    }
+
+       // Wait for conversion to complete
+       xSemaphoreTake(sem[adc_idx][grp_idx], portMAX_DELAY);
        adcDisableNotification(adc, group);
-       vSemaphoreDelete(adcDataConverted);
-    return 0;
-    */
-       return 0;
-}
 
-/**
- * @brief      High level general function for AD conversion
- *
- * @param[out] adc_data_origin Pointer to adc data array, where converted data will be stored
- * @param[in]  adc_num_channels        Number of channels to be converted
- * @param[in]  adc     Pointer to ADC registers
- * @param[in]  group   ADC group identificator
- */
-int adc_read_values(adcData_t* adc_data_origin, uint32_t adc_num_channels, adcBASE_t* adc, uint32_t group) {
-    /* ADCData structure initialization */
-    adcData.adc_data = adc_data_origin;
-    adcData.ch_count = adc_num_channels;
-
-    if (read_adc(adc, group) == 1)
-       return 1;
-    return 0;
+       // 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);
+
+       xSemaphoreGive(mutex[adc_idx]);
+
+       return channels;
 }
 
-/**
- * @brief      High level function fot data conversion from AD port on the board
- *
- * @param[in]  Pointer to ADC registers
- * @param[in]  Number of channels to be converted
- * @param[out] Converted values
- *
- * @return 0 when success, 1 when error
- */
-uint32_t adc_get_port_val(uint32_t* config, uint32_t num_channels, uint32_t* values) {
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+int8_t port_adc_get(const struct port_desc *port, void *values, size_t size)
+{
        uint32_t i;
-       adcBASE_t* adcReg = (adcBASE_t *)config[0];
-       uint32_t adcGroup = config[1];
-
-    adcData.adc_data = adc_data_origin;
-    adcData.ch_count = num_channels;
-    if (read_adc(adcReg, adcGroup) == 1)
-       return 1;
-
-    for (i = 0; i < num_channels; i++) {
-       values[i] = adcData.adc_data[i].value;
-       values[i+num_channels] = adcData.adc_data[i].id;
-    }
-    adcData.adc_data = NULL;
+       adcData_t data[ADC_MAX_CHANNELS];
+       int count = MIN(port->numchn, size/sizeof(uint16_t));
+       uint16_t *adcval = values;
+
+       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 < count; i++)
+               adcval[i] = data[i].value;
+
        return 0;
 }