Update configure
[gnuk/neug.git] / src / adc_stm32f103.c
index 4e1a9fc..567df8d 100644 (file)
@@ -1,10 +1,13 @@
 /*
  * adc_stm32f103.c - ADC driver for STM32F103
+ *                   In this ADC driver, there are NeuG specific parts.
+ *                   You need to modify to use this as generic ADC driver.
  *
- * Copyright (C) 2011, 2012 Free Software Initiative of Japan
+ * Copyright (C) 2011, 2012, 2013, 2015
+ *               Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
- * This file is a part of NeuG, a Random Number Generator
+ * This file is a part of NeuG, a True Random Number Generator
  * implementation based on quantization error of ADC (for STM32F103).
  *
  * NeuG is free software: you can redistribute it and/or modify it
@@ -12,7 +15,7 @@
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
- * Gnuk is distributed in the hope that it will be useful, but WITHOUT
+ * NeuG 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.
  *
  */
 
-#include "ch.h"
-#include "hal.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <chopstx.h>
+
 #include "neug.h"
+#include "stm32f103.h"
 #include "adc.h"
 
 #define NEUG_CRC32_COUNTS 4
 
 #define STM32_ADC_ADC1_DMA_PRIORITY         2
-#define STM32_ADC_ADC1_IRQ_PRIORITY         5
 
 #define ADC_SMPR1_SMP_VREF(n)   ((n) << 21)
 #define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18)
@@ -40,6 +45,8 @@
 
 #define ADC_SMPR2_SMP_AN0(n)    ((n) << 0)
 #define ADC_SMPR2_SMP_AN1(n)    ((n) << 3)
+#define ADC_SMPR2_SMP_AN2(n)    ((n) << 6)
+#define ADC_SMPR2_SMP_AN9(n)    ((n) << 27)
 
 #define ADC_SQR1_NUM_CH(n)      (((n) - 1) << 20)
 
@@ -52,6 +59,8 @@
 
 #define ADC_CHANNEL_IN0         0
 #define ADC_CHANNEL_IN1         1
+#define ADC_CHANNEL_IN2         2
+#define ADC_CHANNEL_IN9         9
 #define ADC_CHANNEL_IN10        10
 #define ADC_CHANNEL_IN11        11
 #define ADC_CHANNEL_SENSOR      16
 #endif
 
 #define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1
-#define NEUG_DMA_MODE_SAMPLE                                            \
+#define NEUG_DMA_MODE                                                  \
   (  STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY)                     \
      | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD               \
      | STM32_DMA_CR_MINC       | STM32_DMA_CR_TCIE                     \
-     | STM32_DMA_CR_TEIE)
-
-#define NEUG_DMA_MODE_CRC32                                             \
-  (  STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY)                     \
-     | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD               \
-     | STM32_DMA_CR_TCIE       | STM32_DMA_CR_TEIE)
+     | STM32_DMA_CR_TEIE  )
 
 #define NEUG_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF)     \
                               | ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR)
                               | ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT)     
 #define NEUG_ADC_SETTING1_NUM_CHANNELS 4
 
-#if !defined(NEUG_ADC_SETTING2_SMPR1)
-#define NEUG_ADC_SETTING2_SMPR1 0
-#define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)    \
-                              | ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
-#define NEUG_ADC_SETTING2_SQR3  ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)      \
-                              | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1)
-#define NEUG_ADC_SETTING2_NUM_CHANNELS 2
-#endif
-
 
 /*
  * Do calibration for both of ADCs.
  */
 void adc_init (void)
 {
-  chSysLock ();
-  rccEnableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+  RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
+  RCC->APB2RSTR = (RCC_APB2RSTR_ADC1RST | RCC_APB2RSTR_ADC2RST);
+  RCC->APB2RSTR = 0;
+
   ADC1->CR1 = 0;
   ADC1->CR2 = ADC_CR2_ADON;
   ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
@@ -125,21 +122,76 @@ void adc_init (void)
   while ((ADC2->CR2 & ADC_CR2_CAL) != 0)
     ;
   ADC2->CR2 = 0;
-  rccDisableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
-  chSysUnlock ();
+  RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
+}
+
+#include "sys.h"
+#if defined(HAVE_SYS_H)
+# define SYS_BOARD_ID sys_board_id
+#else
+# include "board.h"
+# define SYS_BOARD_ID BOARD_ID
+#endif
+
+static void
+get_adc_config (uint32_t config[4])
+{
+  config[2] = ADC_SQR1_NUM_CH(2);
+  switch (SYS_BOARD_ID)
+    {
+    case BOARD_ID_FST_01:
+      config[0] = 0;
+      config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
+               | ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5);
+      config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
+               | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9);
+      break;
+
+    case BOARD_ID_OLIMEX_STM32_H103:
+    case BOARD_ID_STBEE:
+      config[0] = ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5) 
+               | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5);
+      config[1] = 0;
+      config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10)
+               | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11);
+      break;
+
+    case BOARD_ID_STBEE_MINI:
+      config[0] = 0;
+      config[1] = ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
+               | ADC_SMPR2_SMP_AN2(ADC_SAMPLE_1P5);
+      config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN1)
+               | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN2);
+      break;
+
+    case BOARD_ID_CQ_STARM:
+    case BOARD_ID_FST_01_00:
+    case BOARD_ID_MAPLE_MINI:
+    case BOARD_ID_STM32_PRIMER2:
+    case BOARD_ID_STM8S_DISCOVERY:
+    default:
+      config[0] = 0;
+      config[1] = ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)
+               | ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5);
+      config[3] = ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)
+               | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1);
+      break;
+    }
 }
 
-static void adc_lld_serve_rx_interrupt (void *arg, uint32_t flags);
 
 void adc_start (void)
 {
-  dmaStreamAllocate (NEUG_DMA_CHANNEL, STM32_ADC_ADC1_IRQ_PRIORITY,
-                    adc_lld_serve_rx_interrupt, NULL);
-  dmaStreamSetPeripheral (NEUG_DMA_CHANNEL, &ADC1->DR);
+  uint32_t config[4];
 
-  chSysLock ();
+  get_adc_config (config);
 
-  rccEnableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+  /* Use DMA channel 1.  */
+  RCC->AHBENR |= RCC_AHBENR_DMA1EN;
+  DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE;
+  DMA1->IFCR = 0xffffffff;
+
+  RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
 
   ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
               | ADC_CR1_SCAN);
@@ -154,76 +206,61 @@ void adc_start (void)
   ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
               | ADC_CR1_SCAN);
   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
-  ADC2->SMPR1 = NEUG_ADC_SETTING2_SMPR1;
-  ADC2->SMPR2 = NEUG_ADC_SETTING2_SMPR2;
-  ADC2->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING2_NUM_CHANNELS);
+  ADC2->SMPR1 = config[0];
+  ADC2->SMPR2 = config[1];
+  ADC2->SQR1 = config[2];
   ADC2->SQR2 = 0;
-  ADC2->SQR3 = NEUG_ADC_SETTING2_SQR3;
+  ADC2->SQR3 = config[3];
 
 #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
+  /*
+   * We could just let ADC run continuously always and only enable DMA
+   * to receive stable data from ADC.  But our purpose is not to get
+   * correct data but noise.  In fact, we can get more noise when we
+   * start/stop ADC each time.
+   */
   ADC2->CR2 = 0;
   ADC1->CR2 = 0;
+#else
+  /* Start conversion.  */
+  ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
+  ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
+              | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
 #endif
-
-  chSysUnlock ();
 }
 
-static int adc_mode;
-static uint32_t *adc_ptr;
-static int adc_size;
+uint32_t adc_buf[64];
 
-static void adc_start_conversion_internal (void)
+void adc_start_conversion (int offset, int count)
 {
+  DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;        /* SetPeripheral */
+  DMA1_Channel1->CMAR = (uint32_t)&adc_buf[offset]; /* SetMemory0    */
+  DMA1_Channel1->CNDTR = count;                     /* Counter       */
+  DMA1_Channel1->CCR = NEUG_DMA_MODE | DMA_CCR1_EN; /* Mode   */
+
 #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
   /* Power on */
   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
   ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
               | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
-  /* Start conversion.  tSTAB is 1uS, but we don't follow the spec.  */
-  ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
-  ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
-              | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
-#else
+  /*
+   * Start conversion.  tSTAB is 1uS, but we don't follow the spec, to
+   * get more noise.
+   */
   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
   ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
               | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
 #endif
 }
 
-void adc_start_conversion (int mode, uint32_t *p, int size)
-{
-  adc_mode = mode;
-  adc_ptr = p;
-  adc_size = size;
-
- if (mode == ADC_SAMPLE_MODE)
-    {
-      dmaStreamSetMemory0 (NEUG_DMA_CHANNEL, p);
-      dmaStreamSetTransactionSize (NEUG_DMA_CHANNEL, size / 4);
-      dmaStreamSetMode (NEUG_DMA_CHANNEL, NEUG_DMA_MODE_SAMPLE);
-      dmaStreamEnable (NEUG_DMA_CHANNEL);
-    }
-  else
-    {
-      dmaStreamSetMemory0 (NEUG_DMA_CHANNEL, &CRC->DR);
-      dmaStreamSetTransactionSize (NEUG_DMA_CHANNEL, NEUG_CRC32_COUNTS);
-      dmaStreamSetMode (NEUG_DMA_CHANNEL, NEUG_DMA_MODE_CRC32);
-      dmaStreamEnable (NEUG_DMA_CHANNEL);
-    }
-
- adc_start_conversion_internal ();
-}
-
 
 static void adc_stop_conversion (void)
 {
-  dmaStreamDisable (NEUG_DMA_CHANNEL);
+  DMA1_Channel1->CCR &= ~DMA_CCR1_EN;
+
 #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
-  ADC1->CR2 = 0;
   ADC2->CR2 = 0;
-#else
-  ADC2->CR2 &= ~ADC_CR2_CONT;
-  ADC1->CR2 &= ~ADC_CR2_CONT;
+  ADC1->CR2 = 0;
 #endif
 }
 
@@ -235,50 +272,45 @@ void adc_stop (void)
   ADC2->CR1 = 0;
   ADC2->CR2 = 0;
 
-  dmaStreamRelease (NEUG_DMA_CHANNEL);
-  rccDisableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+  RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
+  RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
 }
 
 
-static void adc_lld_serve_rx_interrupt (void *arg, uint32_t flags)
+static uint32_t adc_err;
+
+/*
+ * Return 0 on success.
+ * Return 1 on error.
+ */
+int adc_wait_completion (chopstx_intr_t *intr)
 {
-  (void)arg;
+  uint32_t flags;
 
-  if ((flags & STM32_DMA_ISR_TEIF) != 0)  /* DMA errors  */
+  while (1)
     {
-      /* Should never happened.  If any, it's coding error. */
-      /* Access an unmapped address space or alignment violation.  */
-      adc_stop_conversion ();
-    }
-  else
-    {
-      if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
+      chopstx_intr_wait (intr);
+      flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause.  */
+      /*
+       * Clear interrupt cause of channel 1.
+       *
+       * Note that CGIFx=0, as CGIFx=1 clears all of GIF, HTIF, TCIF
+       * and TEIF.
+       */
+      DMA1->IFCR = (flags & ~1);
+
+      if ((flags & STM32_DMA_ISR_TEIF) != 0)  /* DMA errors  */
        {
+         /* Should never happened.  If any, it's coding error. */
+         /* Access an unmapped address space or alignment violation.  */
+         adc_err++;
          adc_stop_conversion ();
-
-         if (adc_mode != ADC_SAMPLE_MODE)
-           {
-             adc_size -= 4;
-             *adc_ptr++ = CRC->DR;
-
-             if (adc_size > 0)
-               {
-                 dmaStreamSetMemory0 (NEUG_DMA_CHANNEL, &CRC->DR);
-                 dmaStreamSetTransactionSize (NEUG_DMA_CHANNEL, NEUG_CRC32_COUNTS);
-                 dmaStreamSetMode (NEUG_DMA_CHANNEL, NEUG_DMA_MODE_CRC32);
-                 dmaStreamEnable (NEUG_DMA_CHANNEL);
-
-                 adc_start_conversion_internal ();
-               }
-           }
-
-         if (adc_mode == ADC_SAMPLE_MODE || adc_size <= 0)
-           {
-             chSysLockFromIsr();
-             if (rng_thread)
-               chEvtSignalFlagsI (rng_thread, ADC_DATA_AVAILABLE);
-             chSysUnlockFromIsr();
-           }
+         return 1;
+       }
+      else if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
+       {
+         adc_stop_conversion ();
+         return 0;
        }
     }
 }