Update for chopstx_join/_exit/_cancel
[gnuk/neug.git] / src / adc_stm32f103.c
1 /*
2  * adc_stm32f103.c - ADC driver for STM32F103
3  *
4  * Copyright (C) 2011, 2012, 2013 Free Software Initiative of Japan
5  * Author: NIIBE Yutaka <gniibe@fsij.org>
6  *
7  * This file is a part of NeuG, a True Random Number Generator
8  * implementation based on quantization error of ADC (for STM32F103).
9  *
10  * NeuG is free software: you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * NeuG is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <chopstx.h>
28
29 #include "neug.h"
30 #include "stm32f103.h"
31 #include "adc.h"
32
33 #define NEUG_CRC32_COUNTS 4
34
35 #define STM32_ADC_ADC1_DMA_PRIORITY         2
36
37 #define ADC_SMPR1_SMP_VREF(n)   ((n) << 21)
38 #define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18)
39
40 #define ADC_SMPR1_SMP_AN10(n)   ((n) << 0)
41 #define ADC_SMPR1_SMP_AN11(n)   ((n) << 3)
42
43 #define ADC_SMPR2_SMP_AN0(n)    ((n) << 0)
44 #define ADC_SMPR2_SMP_AN1(n)    ((n) << 3)
45 #define ADC_SMPR2_SMP_AN2(n)    ((n) << 6)
46 #define ADC_SMPR2_SMP_AN9(n)    ((n) << 27)
47
48 #define ADC_SQR1_NUM_CH(n)      (((n) - 1) << 20)
49
50 #define ADC_SQR3_SQ1_N(n)       ((n) << 0)
51 #define ADC_SQR3_SQ2_N(n)       ((n) << 5)
52 #define ADC_SQR3_SQ3_N(n)       ((n) << 10)
53 #define ADC_SQR3_SQ4_N(n)       ((n) << 15)
54
55 #define ADC_SAMPLE_1P5          0
56
57 #define ADC_CHANNEL_IN0         0
58 #define ADC_CHANNEL_IN1         1
59 #define ADC_CHANNEL_IN2         2
60 #define ADC_CHANNEL_IN9         9
61 #define ADC_CHANNEL_IN10        10
62 #define ADC_CHANNEL_IN11        11
63 #define ADC_CHANNEL_SENSOR      16
64 #define ADC_CHANNEL_VREFINT     17
65
66 #define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
67 #define DELIBARATELY_DO_IT_WRONG_START_STOP
68
69 #ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
70 #define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
71 #define ADC_SAMPLE_SENSOR ADC_SAMPLE_1P5
72 #else
73 #define ADC_SAMPLE_VREF ADC_SAMPLE_239P5
74 #define ADC_SAMPLE_SENSOR ADC_SAMPLE_239P5
75 #endif
76
77 #define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1
78 #define NEUG_DMA_MODE_SAMPLE                                            \
79   (  STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY)                      \
80      | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD                \
81      | STM32_DMA_CR_MINC       | STM32_DMA_CR_TCIE                      \
82      | STM32_DMA_CR_TEIE)
83
84 #define NEUG_DMA_MODE_CRC32                                             \
85   (  STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY)                      \
86      | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD                \
87      | STM32_DMA_CR_TCIE       | STM32_DMA_CR_TEIE)
88
89 #define NEUG_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF)     \
90                               | ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR)
91 #define NEUG_ADC_SETTING1_SMPR2 0
92 #define NEUG_ADC_SETTING1_SQR3  ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT)     \
93                               | ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR)      \
94                               | ADC_SQR3_SQ3_N(ADC_CHANNEL_SENSOR)      \
95                               | ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT)     
96 #define NEUG_ADC_SETTING1_NUM_CHANNELS 4
97
98 #if !defined(NEUG_ADC_SETTING2_SMPR1)
99 #define NEUG_ADC_SETTING2_SMPR1 0
100 #define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)    \
101                               | ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
102 #define NEUG_ADC_SETTING2_SQR3  ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)      \
103                               | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1)
104 #define NEUG_ADC_SETTING2_NUM_CHANNELS 2
105 #endif
106
107
108 /*
109  * Do calibration for both of ADCs.
110  */
111 void adc_init (void)
112 {
113   RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
114   RCC->APB2RSTR = (RCC_APB2RSTR_ADC1RST | RCC_APB2RSTR_ADC2RST);
115   RCC->APB2RSTR = 0;
116
117   ADC1->CR1 = 0;
118   ADC1->CR2 = ADC_CR2_ADON;
119   ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
120   while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
121     ;
122   ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
123   while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
124     ;
125   ADC1->CR2 = 0;
126
127   ADC2->CR1 = 0;
128   ADC2->CR2 = ADC_CR2_ADON;
129   ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
130   while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
131     ;
132   ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
133   while ((ADC2->CR2 & ADC_CR2_CAL) != 0)
134     ;
135   ADC2->CR2 = 0;
136   RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
137 }
138
139 extern uint8_t __process4_stack_base__, __process4_stack_size__;
140 const uint32_t __stackaddr_adc = (uint32_t)&__process4_stack_base__;
141 const size_t __stacksize_adc = (size_t)&__process4_stack_size__;
142 #define PRIO_ADC 1
143
144 static void adc_lld_serve_rx_interrupt (uint32_t flags);
145
146 #define INTR_REQ_DMA1_Channel1 11
147 static void *
148 adc_intr_thread (void *arg)
149 {
150   chopstx_intr_t interrupt;
151
152   (void)arg;
153   chopstx_claim_irq (&interrupt, INTR_REQ_DMA1_Channel1);
154
155   while (1)
156     {
157       uint32_t flags;
158
159       chopstx_intr_wait (&interrupt);
160       flags = DMA1->ISR & STM32_DMA_ISR_MASK; /* Channel 1 interrupt cause.  */
161       DMA1->IFCR = STM32_DMA_ISR_MASK; /* Clear interrupt of channel 1.  */
162       adc_lld_serve_rx_interrupt (flags);
163     }
164
165   return NULL;
166 }
167
168 static chopstx_t adc_thd;
169
170 void adc_start (void)
171 {
172   chopstx_attr_t attr;
173
174   /* Use DMA channel 1.  */
175   RCC->AHBENR |= RCC_AHBENR_DMA1EN;
176   DMA1_Channel1->CCR = STM32_DMA_CCR_RESET_VALUE;
177   DMA1->IFCR = 0xffffffff;
178
179   RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
180
181   ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
182                | ADC_CR1_SCAN);
183   ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
184                | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
185   ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1;
186   ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
187   ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
188   ADC1->SQR2 = 0;
189   ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
190
191   ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
192                | ADC_CR1_SCAN);
193   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
194   ADC2->SMPR1 = NEUG_ADC_SETTING2_SMPR1;
195   ADC2->SMPR2 = NEUG_ADC_SETTING2_SMPR2;
196   ADC2->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING2_NUM_CHANNELS);
197   ADC2->SQR2 = 0;
198   ADC2->SQR3 = NEUG_ADC_SETTING2_SQR3;
199
200 #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
201   ADC2->CR2 = 0;
202   ADC1->CR2 = 0;
203 #endif
204
205   chopstx_attr_init (&attr);
206   chopstx_attr_setschedparam (&attr, PRIO_ADC);
207   chopstx_attr_setstack (&attr, __stackaddr_adc, __stacksize_adc);
208   chopstx_create (&adc_thd, &attr, adc_intr_thread, NULL);
209 }
210
211 static int adc_mode;
212 static uint32_t *adc_ptr;
213 static int adc_size;
214
215 static void adc_start_conversion_internal (void)
216 {
217 #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
218   /* Power on */
219   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
220   ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
221                | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
222   /* Start conversion.  tSTAB is 1uS, but we don't follow the spec.  */
223   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
224   ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
225                | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
226 #else
227   ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
228   ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
229                | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
230 #endif
231 }
232
233 void adc_start_conversion (int mode, uint32_t *p, int size)
234 {
235   adc_mode = mode;
236   adc_ptr = p;
237   adc_size = size;
238
239  if (mode == ADC_SAMPLE_MODE)
240     {
241       DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
242       DMA1_Channel1->CMAR  = (uint32_t)p; /* SetMemory0 */
243       DMA1_Channel1->CNDTR  = (uint32_t)size / 4; /* size */
244       DMA1_Channel1->CCR  = NEUG_DMA_MODE_SAMPLE; /*mode*/
245       DMA1_Channel1->CCR |= DMA_CCR1_EN;                    /* Enable */
246     }
247   else
248     {
249       DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
250       DMA1_Channel1->CMAR  = (uint32_t)&CRC->DR; /* SetMemory0 */
251       DMA1_Channel1->CNDTR  = NEUG_CRC32_COUNTS; /* size */
252       DMA1_Channel1->CCR  = NEUG_DMA_MODE_CRC32; /*mode*/
253       DMA1_Channel1->CCR |= DMA_CCR1_EN;                    /* Enable */
254     }
255
256  adc_start_conversion_internal ();
257 }
258
259
260 static void adc_stop_conversion (void)
261 {
262   DMA1_Channel1->CCR &= ~DMA_CCR1_EN;
263
264 #ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
265   ADC1->CR2 = 0;
266   ADC2->CR2 = 0;
267 #else
268   ADC2->CR2 &= ~ADC_CR2_CONT;
269   ADC1->CR2 &= ~ADC_CR2_CONT;
270 #endif
271 }
272
273 void adc_stop (void)
274 {
275   ADC1->CR1 = 0;
276   ADC1->CR2 = 0;
277
278   ADC2->CR1 = 0;
279   ADC2->CR2 = 0;
280
281   /* XXX: here to disable the associated IRQ vector; stop intr thread.  */
282   RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
283   RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN);
284
285   chopstx_cancel (adc_thd);
286   chopstx_join (adc_thd, NULL);
287 }
288
289
290 static void adc_lld_serve_rx_interrupt (uint32_t flags)
291 {
292   if ((flags & STM32_DMA_ISR_TEIF) != 0)  /* DMA errors  */
293     {
294       /* Should never happened.  If any, it's coding error. */
295       /* Access an unmapped address space or alignment violation.  */
296       adc_stop_conversion ();
297     }
298   else
299     {
300       if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
301         {
302           adc_stop_conversion ();
303
304           if (adc_mode != ADC_SAMPLE_MODE)
305             {
306               adc_size -= 4;
307               *adc_ptr++ = CRC->DR;
308
309               if (adc_size > 0)
310                 {
311                   DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; /* SetPeripheral */
312                   DMA1_Channel1->CMAR  = (uint32_t)&CRC->DR; /* SetMemory0 */
313                   DMA1_Channel1->CNDTR = NEUG_CRC32_COUNTS; /* size */
314                   DMA1_Channel1->CCR  = NEUG_DMA_MODE_CRC32; /*mode*/
315                   DMA1_Channel1->CCR |= DMA_CCR1_EN;                /* Enable */
316                   adc_start_conversion_internal ();
317                 }
318             }
319
320           if (adc_mode == ADC_SAMPLE_MODE || adc_size <= 0)
321             {
322               chopstx_mutex_lock (&adc_mtx);
323               adc_data_available++;
324               if (adc_waiting)
325                 chopstx_cond_signal (&adc_cond);
326               chopstx_mutex_unlock (&adc_mtx);
327             }
328         }
329     }
330 }