Update configure
[gnuk/neug.git] / src / adc_stm32f103.c
index 92b0834..567df8d 100644 (file)
@@ -1,7 +1,10 @@
 /*
  * 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, 2013 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 True Random Number Generator
 #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)
-
-#if 0
-#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)
-#else
-#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_MINC                                                       \
-     | STM32_DMA_CR_TCIE       | STM32_DMA_CR_TEIE)
-#endif
+     | 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.
@@ -144,39 +125,67 @@ void adc_init (void)
   RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
 }
 
-extern uint8_t __process4_stack_base__, __process4_stack_size__;
-const uint32_t __stackaddr_adc = (uint32_t)&__process4_stack_base__;
-const size_t __stacksize_adc = (size_t)&__process4_stack_size__;
-#define PRIO_ADC 3
-
-static void adc_lld_serve_rx_interrupt (uint32_t flags);
+#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
 
-#define INTR_REQ_DMA1_Channel1 11
-static void *
-adc_intr_thread (void *arg)
+static void
+get_adc_config (uint32_t config[4])
 {
-  chopstx_intr_t interrupt;
-
-  (void)arg;
-  chopstx_claim_irq (&interrupt, INTR_REQ_DMA1_Channel1);
-
-  while (1)
+  config[2] = ADC_SQR1_NUM_CH(2);
+  switch (SYS_BOARD_ID)
     {
-      uint32_t flags;
-
-      chopstx_intr_wait (&interrupt);
-      flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause.  */
-      DMA1->IFCR = STM32_DMA_ISR_MASK; /* Clear interrupt of channel 1.  */
-      adc_lld_serve_rx_interrupt (flags);
+    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;
     }
-
-  return NULL;
 }
 
-static chopstx_t adc_thd;
 
 void adc_start (void)
 {
+  uint32_t config[4];
+
+  get_adc_config (config);
+
   /* Use DMA channel 1.  */
   RCC->AHBENR |= RCC_AHBENR_DMA1EN;
   DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE;
@@ -197,81 +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
-
-  adc_thd = chopstx_create (PRIO_ADC, __stackaddr_adc, __stacksize_adc,
-                           adc_intr_thread, NULL);
 }
 
-static int adc_mode;
-static uint32_t *adc_ptr;
-static int adc_size;
-static uint32_t adc_buf[64];
+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)
-    {
-      DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
-      DMA1_Channel1->CMAR  = (uint32_t)p; /* SetMemory0 */
-      DMA1_Channel1->CNDTR  = (uint32_t)size / 4; /* counter */
-      DMA1_Channel1->CCR  = NEUG_DMA_MODE_SAMPLE; /*mode*/
-      DMA1_Channel1->CCR |= DMA_CCR1_EN;                   /* Enable */
-    }
-  else
-    {
-      DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
-      DMA1_Channel1->CMAR  = (uint32_t)adc_buf; /* SetMemory0 */
-      DMA1_Channel1->CNDTR  = size; /* counter */
-      DMA1_Channel1->CCR  = NEUG_DMA_MODE_CRC32; /*mode*/
-      DMA1_Channel1->CCR |= DMA_CCR1_EN;                   /* Enable */
-    }
-
- adc_start_conversion_internal ();
-}
-
 
 static void adc_stop_conversion (void)
 {
   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
 }
 
@@ -283,48 +272,45 @@ void adc_stop (void)
   ADC2->CR1 = 0;
   ADC2->CR2 = 0;
 
-  /* XXX: here to disable the associated IRQ vector; stop intr thread.  */
   RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
   RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
-
-  chopstx_cancel (adc_thd);
-  chopstx_join (adc_thd, NULL);
 }
 
 
-static void adc_lld_serve_rx_interrupt (uint32_t flags)
+static uint32_t adc_err;
+
+/*
+ * Return 0 on success.
+ * Return 1 on error.
+ */
+int adc_wait_completion (chopstx_intr_t *intr)
 {
-  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_stop_conversion ();
-    }
-  else
+  uint32_t flags;
+
+  while (1)
     {
-      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)
-           {
-             int i;
-
-             for (i = 0; i < adc_size;)
-               {
-                 CRC->DR = adc_buf[i++];
-                 CRC->DR = adc_buf[i++];
-                 CRC->DR = adc_buf[i++];
-                 CRC->DR = adc_buf[i++];
-                 *adc_ptr++ = CRC->DR;
-               }
-           }
-
-         chopstx_mutex_lock (&adc_mtx);
-         adc_data_available++;
-         if (adc_waiting)
-           chopstx_cond_signal (&adc_cond);
-         chopstx_mutex_unlock (&adc_mtx);
+         return 1;
+       }
+      else if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
+       {
+         adc_stop_conversion ();
+         return 0;
        }
     }
 }