-/*
- * 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;
}