diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-30 15:13:55 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-30 15:13:55 +0900 |
commit | a933eebfd5ee2defdb149a30b31f55010ffefc34 (patch) | |
tree | 85511de282e40316875af2bdc92d8b74d3e3ba72 /mcu | |
parent | fae4c58d99a5fa1f2d16b2028e27bc9cc5b5190b (diff) |
Update for STM32F103
Diffstat (limited to 'mcu')
-rw-r--r-- | mcu/adc-stm32f103.c | 329 | ||||
-rw-r--r-- | mcu/stm32f103.h | 204 |
2 files changed, 533 insertions, 0 deletions
diff --git a/mcu/adc-stm32f103.c b/mcu/adc-stm32f103.c new file mode 100644 index 0000000..2ff852b --- /dev/null +++ b/mcu/adc-stm32f103.c @@ -0,0 +1,329 @@ +/* + * 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, 2015, 2016 + * Free Software Initiative of Japan + * Author: NIIBE Yutaka <gniibe@fsij.org> + * + * 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 + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <chopstx.h> +#include <mcu/stm32f103.h> +#include "adc.h" + +#define STM32_ADC_ADC1_DMA_PRIORITY 2 + +#define ADC_SMPR1_SMP_VREF(n) ((n) << 21) +#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18) + +#define ADC_SMPR1_SMP_AN10(n) ((n) << 0) +#define ADC_SMPR1_SMP_AN11(n) ((n) << 3) + +#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) + +#define ADC_SQR3_SQ1_N(n) ((n) << 0) +#define ADC_SQR3_SQ2_N(n) ((n) << 5) +#define ADC_SQR3_SQ3_N(n) ((n) << 10) +#define ADC_SQR3_SQ4_N(n) ((n) << 15) + +#define ADC_SAMPLE_1P5 0 + +#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 +#define ADC_CHANNEL_VREFINT 17 + +#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME +#define DELIBARATELY_DO_IT_WRONG_START_STOP + +#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME +#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5 +#define ADC_SAMPLE_SENSOR ADC_SAMPLE_1P5 +#else +#define ADC_SAMPLE_VREF ADC_SAMPLE_239P5 +#define ADC_SAMPLE_SENSOR ADC_SAMPLE_239P5 +#endif + +#define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1 +#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_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF) \ + | ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR) +#define NEUG_ADC_SETTING1_SMPR2 0 +#define NEUG_ADC_SETTING1_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT) \ + | ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) \ + | ADC_SQR3_SQ3_N(ADC_CHANNEL_SENSOR) \ + | ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT) +#define NEUG_ADC_SETTING1_NUM_CHANNELS 4 + +/* + * ADC finish interrupt + */ +#define INTR_REQ_DMA1_Channel1 11 + +static chopstx_intr_t adc_intr; + +/* + * Do calibration for both of ADCs. + */ +int +adc_init (void) +{ + 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; + while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0) + ; + ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL; + while ((ADC1->CR2 & ADC_CR2_CAL) != 0) + ; + ADC1->CR2 = 0; + + ADC2->CR1 = 0; + ADC2->CR2 = ADC_CR2_ADON; + ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL; + while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0) + ; + ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_CAL; + while ((ADC2->CR2 & ADC_CR2_CAL) != 0) + ; + ADC2->CR2 = 0; + RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN); + + chopstx_claim_irq (&adc_intr, INTR_REQ_DMA1_Channel1); + return 0; +} + +#include "board.h" +#include "mcu/sys-stm32f103.h" +#if defined(HAVE_SYS_H) +# define SYS_BOARD_ID sys_board_id +#else +# 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: + case BOARD_ID_ST_DONGLE: + case BOARD_ID_ST_NUCLEO_F103: + case BOARD_ID_NITROKEY_START: + 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; + } +} + + +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; + 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); + ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART + | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON); + ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1; + ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2; + ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS); + ADC1->SQR2 = 0; + ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3; + + 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 = config[0]; + ADC2->SMPR2 = config[1]; + ADC2->SQR1 = config[2]; + ADC2->SQR2 = 0; + 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 +} + +uint32_t adc_buf[64]; + +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, 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 +} + + +static void adc_stop_conversion (void) +{ + DMA1_Channel1->CCR &= ~DMA_CCR1_EN; + +#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP + ADC2->CR2 = 0; + ADC1->CR2 = 0; +#endif +} + +void +adc_stop (void) +{ + ADC1->CR1 = 0; + ADC1->CR2 = 0; + + ADC2->CR1 = 0; + ADC2->CR2 = 0; + + RCC->AHBENR &= ~RCC_AHBENR_DMA1EN; + RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN); +} + + +static uint32_t adc_err; + +/* + * Return 0 on success. + * Return 1 on error. + */ +int +adc_wait_completion (void) +{ + uint32_t flags; + + while (1) + { + chopstx_poll (NULL, 1, &adc_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 (); + return 1; + } + else if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */ + { + adc_stop_conversion (); + return 0; + } + } +} diff --git a/mcu/stm32f103.h b/mcu/stm32f103.h new file mode 100644 index 0000000..a4ecaa1 --- /dev/null +++ b/mcu/stm32f103.h @@ -0,0 +1,204 @@ +#define PERIPH_BASE 0x40000000 +#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) +#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) + +#define RCC_APB2RSTR_ADC1RST 0x00000200 +#define RCC_APB2RSTR_ADC2RST 0x00000400 + +struct RCC { + volatile uint32_t CR; + volatile uint32_t CFGR; + volatile uint32_t CIR; + volatile uint32_t APB2RSTR; + volatile uint32_t APB1RSTR; + volatile uint32_t AHBENR; + volatile uint32_t APB2ENR; + volatile uint32_t APB1ENR; + volatile uint32_t BDCR; + volatile uint32_t CSR; +}; + +#define RCC_BASE (AHBPERIPH_BASE + 0x1000) +static struct RCC *const RCC = ((struct RCC *const)RCC_BASE); + +#define RCC_AHBENR_DMA1EN 0x00000001 +#define RCC_AHBENR_CRCEN 0x00000040 + +#define RCC_APB2ENR_ADC1EN 0x00000200 +#define RCC_APB2ENR_ADC2EN 0x00000400 + +#define CRC_CR_RESET 0x00000001 + +struct CRC { + volatile uint32_t DR; + volatile uint8_t IDR; + uint8_t RESERVED0; + uint16_t RESERVED1; + volatile uint32_t CR; +}; + +#define CRC_BASE (AHBPERIPH_BASE + 0x3000) +static struct CRC *const CRC = ((struct CRC *const)CRC_BASE); + + +struct ADC { + volatile uint32_t SR; + volatile uint32_t CR1; + volatile uint32_t CR2; + volatile uint32_t SMPR1; + volatile uint32_t SMPR2; + volatile uint32_t JOFR1; + volatile uint32_t JOFR2; + volatile uint32_t JOFR3; + volatile uint32_t JOFR4; + volatile uint32_t HTR; + volatile uint32_t LTR; + volatile uint32_t SQR1; + volatile uint32_t SQR2; + volatile uint32_t SQR3; + volatile uint32_t JSQR; + volatile uint32_t JDR1; + volatile uint32_t JDR2; + volatile uint32_t JDR3; + volatile uint32_t JDR4; + volatile uint32_t DR; +}; + +#define ADC1_BASE (APB2PERIPH_BASE + 0x2400) +#define ADC2_BASE (APB2PERIPH_BASE + 0x2800) + +static struct ADC *const ADC1 = (struct ADC *const)ADC1_BASE; +static struct ADC *const ADC2 = (struct ADC *const)ADC2_BASE; + +#define ADC_CR1_DUALMOD_0 0x00010000 +#define ADC_CR1_DUALMOD_1 0x00020000 +#define ADC_CR1_DUALMOD_2 0x00040000 +#define ADC_CR1_DUALMOD_3 0x00080000 + +#define ADC_CR1_SCAN 0x00000100 + +#define ADC_CR2_ADON 0x00000001 +#define ADC_CR2_CONT 0x00000002 +#define ADC_CR2_CAL 0x00000004 +#define ADC_CR2_RSTCAL 0x00000008 +#define ADC_CR2_DMA 0x00000100 +#define ADC_CR2_ALIGN 0x00000800 +#define ADC_CR2_EXTSEL 0x000E0000 +#define ADC_CR2_EXTSEL_0 0x00020000 +#define ADC_CR2_EXTSEL_1 0x00040000 +#define ADC_CR2_EXTSEL_2 0x00080000 +#define ADC_CR2_EXTTRIG 0x00100000 +#define ADC_CR2_SWSTART 0x00400000 +#define ADC_CR2_TSVREFE 0x00800000 + +struct DMA_Channel { + volatile uint32_t CCR; + volatile uint32_t CNDTR; + volatile uint32_t CPAR; + volatile uint32_t CMAR; +}; + +struct DMA { + volatile uint32_t ISR; + volatile uint32_t IFCR; +}; + +#define STM32_DMA_CR_MINC DMA_CCR1_MINC +#define STM32_DMA_CR_MSIZE_WORD DMA_CCR1_MSIZE_1 +#define STM32_DMA_CR_PSIZE_WORD DMA_CCR1_PSIZE_1 +#define STM32_DMA_CR_TCIE DMA_CCR1_TCIE +#define STM32_DMA_CR_TEIE DMA_CCR1_TEIE +#define STM32_DMA_CR_HTIE DMA_CCR1_HTIE +#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1 +#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1 +#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1 + +#define STM32_DMA_ISR_MASK 0x0F +#define STM32_DMA_CCR_RESET_VALUE 0x00000000 +#define STM32_DMA_CR_PL_MASK DMA_CCR1_PL +#define STM32_DMA_CR_PL(n) ((n) << 12) + +#define DMA_CCR1_EN 0x00000001 +#define DMA_CCR1_TCIE 0x00000002 +#define DMA_CCR1_HTIE 0x00000004 +#define DMA_CCR1_TEIE 0x00000008 +#define DMA_CCR1_DIR 0x00000010 +#define DMA_CCR1_CIRC 0x00000020 +#define DMA_CCR1_PINC 0x00000040 +#define DMA_CCR1_MINC 0x00000080 +#define DMA_CCR1_PSIZE 0x00000300 +#define DMA_CCR1_PSIZE_0 0x00000100 +#define DMA_CCR1_PSIZE_1 0x00000200 +#define DMA_CCR1_MSIZE 0x00000C00 +#define DMA_CCR1_MSIZE_0 0x00000400 +#define DMA_CCR1_MSIZE_1 0x00000800 +#define DMA_CCR1_PL 0x00003000 +#define DMA_CCR1_PL_0 0x00001000 +#define DMA_CCR1_PL_1 0x00002000 +#define DMA_CCR1_MEM2MEM 0x00004000 + +#define DMA_ISR_GIF1 0x00000001 +#define DMA_ISR_TCIF1 0x00000002 +#define DMA_ISR_HTIF1 0x00000004 +#define DMA_ISR_TEIF1 0x00000008 +#define DMA_ISR_GIF2 0x00000010 +#define DMA_ISR_TCIF2 0x00000020 +#define DMA_ISR_HTIF2 0x00000040 +#define DMA_ISR_TEIF2 0x00000080 +#define DMA_ISR_GIF3 0x00000100 +#define DMA_ISR_TCIF3 0x00000200 +#define DMA_ISR_HTIF3 0x00000400 +#define DMA_ISR_TEIF3 0x00000800 +#define DMA_ISR_GIF4 0x00001000 +#define DMA_ISR_TCIF4 0x00002000 +#define DMA_ISR_HTIF4 0x00004000 +#define DMA_ISR_TEIF4 0x00008000 +#define DMA_ISR_GIF5 0x00010000 +#define DMA_ISR_TCIF5 0x00020000 +#define DMA_ISR_HTIF5 0x00040000 +#define DMA_ISR_TEIF5 0x00080000 +#define DMA_ISR_GIF6 0x00100000 +#define DMA_ISR_TCIF6 0x00200000 +#define DMA_ISR_HTIF6 0x00400000 +#define DMA_ISR_TEIF6 0x00800000 +#define DMA_ISR_GIF7 0x01000000 +#define DMA_ISR_TCIF7 0x02000000 +#define DMA_ISR_HTIF7 0x04000000 +#define DMA_ISR_TEIF7 0x08000000 + +#define DMA1_BASE (AHBPERIPH_BASE + 0x0000) +static struct DMA *const DMA1 = (struct DMA *const)DMA1_BASE; + +#define DMA1_Channel1_BASE (AHBPERIPH_BASE + 0x0008) +static struct DMA_Channel *const DMA1_Channel1 = + (struct DMA_Channel *const)DMA1_Channel1_BASE; + +/* System Control Block */ +struct SCB +{ + volatile uint32_t CPUID; + volatile uint32_t ICSR; + volatile uint32_t VTOR; + volatile uint32_t AIRCR; + volatile uint32_t SCR; + volatile uint32_t CCR; + volatile uint8_t SHP[12]; + volatile uint32_t SHCSR; + volatile uint32_t CFSR; + volatile uint32_t HFSR; + volatile uint32_t DFSR; + volatile uint32_t MMFAR; + volatile uint32_t BFAR; + volatile uint32_t AFSR; + volatile uint32_t PFR[2]; + volatile uint32_t DFR; + volatile uint32_t ADR; + volatile uint32_t MMFR[4]; + volatile uint32_t ISAR[5]; + uint32_t RESERVED0[5]; + volatile uint32_t CPACR; +}; + +#define SCS_BASE 0xE000E000 +#define SCB_BASE (SCS_BASE + 0x0D00) +static struct SCB *const SCB = (struct SCB *const)SCB_BASE; |