Skip to content
Snippets Groups Projects
deck_analog.c 4.82 KiB
Newer Older
/*
 *    ||          ____  _ __
 * +------+      / __ )(_) /_______________ _____  ___
 * | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 * +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 *  ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
 *
 * Crazyflie control firmware
 *
 * Copyright (C) 2015 Bitcraze AB
 *
 * 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, in version 3.
 *
 * 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/>.
 *
 * deck_analog.c - Arduino-compatible analog input implementation
 */

#include "deck.h"

#include "stm32fxxx.h"

static  uint32_t  stregResolution;
static  uint32_t  adcRange;

void adcInit(void)
{
  /*
   * Note: This function initializes only ADC2, and only for single channel, single conversion mode. No DMA, no interrupts, no bells or whistles.
   */

  /* Note that this de-initializes registers for all ADCs (ADCx) */
  ADC_DeInit();

  /* Define ADC init structures */
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;

  /* Populates structures with reset values */
  ADC_StructInit(&ADC_InitStructure);
  ADC_CommonStructInit(&ADC_CommonInitStructure);

  /* enable ADC clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);

  /* init ADCs in independent mode, div clock by two */
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; /* HCLK = 168MHz, PCLK2 = 84MHz, ADCCLK = 42MHz (when using ADC_Prescaler_Div2) */
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* Init ADC2: 12bit, single-conversion. For Arduino compatibility set 10bit */
  analogReadResolution(12);

  /* Enable ADC2 */
  ADC_Cmd(ADC2, ENABLE);
}

static uint16_t analogReadChannel(uint8_t channel)
{
  /* According to datasheet, minimum sampling time for 12-bit conversion is 15 cycles. */
  ADC_RegularChannelConfig(ADC2, channel, 1, ADC_SampleTime_15Cycles);

  /* Start the conversion */
  ADC_SoftwareStartConv(ADC2);

  /* Wait until conversion completion */
  while(ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET);

  /* Get the conversion value */
  return ADC_GetConversionValue(ADC2);
}

uint16_t analogRead(const deckPin_t pin)
{
  assert_param(deckGPIOMapping[pin.id].adcCh > -1);

  /* Now set the GPIO pin to analog mode. */

  /* Enable clock for the peripheral of the pin.*/
  RCC_AHB1PeriphClockCmd(deckGPIOMapping[pin.id].periph, ENABLE);

  /* Populate structure with RESET values. */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_StructInit(&GPIO_InitStructure);

  /* Initialise the GPIO pin to analog mode. */
  GPIO_InitStructure.GPIO_Pin   = deckGPIOMapping[pin.id].pin;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;

  /* TODO: Any settling time before we can do ADC after init on the GPIO pin? */
  GPIO_Init(deckGPIOMapping[pin.id].port, &GPIO_InitStructure);

  /* Read the appropriate ADC channel. */
  return analogReadChannel((uint8_t)deckGPIOMapping[pin.id].adcCh);
}

void analogReference(uint8_t type)
{
  /*
   * TODO: We should probably support the Arduino EXTERNAL type here.
   * TODO: Figure out which voltage reference to compensate with.
   */
  assert_param(type == 0 /* DEFAULT */);
}

void analogReadResolution(uint8_t bits)
{
  ADC_InitTypeDef       ADC_InitStructure;

  assert_param((bits >= 6) && (bits <= 12));

  adcRange = 1 << bits;
  switch (bits)
  {
    case 12: stregResolution = ADC_Resolution_12b; break;
    case 10: stregResolution = ADC_Resolution_10b; break;
    case 8:  stregResolution = ADC_Resolution_8b; break;
    case 6:  stregResolution = ADC_Resolution_6b; break;
    default: stregResolution = ADC_Resolution_12b; break;
  }

  /* Init ADC2 witch new resolution */
  ADC_InitStructure.ADC_Resolution = stregResolution;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = 0;
  ADC_InitStructure.ADC_ExternalTrigConv = 0;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC2, &ADC_InitStructure);
}

float analogReadVoltage(const deckPin_t pin)
{
  float voltage;

  voltage = analogRead(pin) * VREF / adcRange;

  return voltage;
}