From 78718e57df6f55c0670cdb6b70337204dd045dba Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka <gniibe@fsij.org> Date: Thu, 2 Jun 2016 11:01:11 +0900 Subject: Move files --- ChangeLog | 15 ++ board/board-stm32f0-discovery.h | 2 + contrib/adc-mkl27z.c | 320 ++++++++++++++++++++++++++++++ contrib/adc-stm32f103.c | 328 +++++++++++++++++++++++++++++++ example-led/Makefile | 2 +- mcu/adc-mkl27z.c | 320 ------------------------------ mcu/adc-stm32f103.c | 328 ------------------------------- mcu/sys-stm32f0.c | 422 ++++++++++++++++++++++++++++++++++++++++ mcu/sys-stm32f0.h | 134 +++++++++++++ mcu/sys-stm32f030.c | 422 ---------------------------------------- mcu/sys-stm32f030.h | 130 ------------- rules.mk | 2 +- sys.h | 4 +- 13 files changed, 1226 insertions(+), 1203 deletions(-) create mode 100644 contrib/adc-mkl27z.c create mode 100644 contrib/adc-stm32f103.c delete mode 100644 mcu/adc-mkl27z.c delete mode 100644 mcu/adc-stm32f103.c create mode 100644 mcu/sys-stm32f0.c create mode 100644 mcu/sys-stm32f0.h delete mode 100644 mcu/sys-stm32f030.c delete mode 100644 mcu/sys-stm32f030.h diff --git a/ChangeLog b/ChangeLog index caa6385..3c7188f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2016-06-02 Niibe Yutaka <gniibe@fsij.org> + + * contrib/adc-mkl27z.c: Move from mcu. + * contrib/adc-stm32f103.c: Move from mcu. + + * example-led/Makefile (CHIP): Define as stm32f0. + + * mcu/sys-stm32f0.h: Rename from sys-stm32f030.h, + as we share it among STM32F030 and STM32F050. + * mcu/sys-stm32f0.c: Likewise. + + * board/board-stm32f0-discovery.h (MCU_STM32F0): Define. + + * sys.h: Support STM32F0. + 2016-06-01 NIIBE Yutaka <gniibe@fsij.org> * chopstx.h (chx_fatal): Remove weak attribute from declaration. diff --git a/board/board-stm32f0-discovery.h b/board/board-stm32f0-discovery.h index 38ae214..48aa3d3 100644 --- a/board/board-stm32f0-discovery.h +++ b/board/board-stm32f0-discovery.h @@ -1,6 +1,8 @@ #define BOARD_NAME "STM32F0 Discovery" #define BOARD_ID 0xde4b4bc1 +#define MCU_STM32F0 1 + /* * Running at 48MHz with HSI as clock source. * diff --git a/contrib/adc-mkl27z.c b/contrib/adc-mkl27z.c new file mode 100644 index 0000000..19f9f5b --- /dev/null +++ b/contrib/adc-mkl27z.c @@ -0,0 +1,320 @@ +/* + * adc-mkl27z.c - ADC driver for MKL27Z + * In this ADC driver, there are NeuG specific parts. + * It only records lower 8-bit of 16-bit data. + * You need to modify to use this as generic ADC driver. + * + * Copyright (C) 2016 Flying Stone Technology + * Author: NIIBE Yutaka <gniibe@fsij.org> + * + * This file is a part of Chopstx, a thread library for embedded. + * + * Chopstx 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. + * + * Chopstx 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/>. + * + * As additional permission under GNU GPL version 3 section 7, you may + * distribute non-source form of the Program without the copy of the + * GNU GPL normally required by section 4, provided you inform the + * receipents of GNU GPL by a written offer. + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <chopstx.h> +#include <mcu/mkl27z.h> + +struct DMAMUX { + volatile uint32_t CHCFG0; + volatile uint32_t CHCFG1; + volatile uint32_t CHCFG2; + volatile uint32_t CHCFG3; +}; +static struct DMAMUX *const DMAMUX = (struct DMAMUX *const)0x40021000; + +#define INTR_REQ_DMA0 0 + +struct DMA { + volatile uint32_t SAR; + volatile uint32_t DAR; + volatile uint32_t DSR_BCR; + volatile uint32_t DCR; +}; +static struct DMA *const DMA0 = (struct DMA *const)0x40008100; +static struct DMA *const DMA1 = (struct DMA *const)0x40008110; + + +/* We don't use ADC interrupt. Just for reference. */ +#define INTR_REQ_ADC 15 + +struct ADC { + volatile uint32_t SC1[2];/* Status and Control Registers 1 */ + volatile uint32_t CFG1; /* Configuration Register 1 */ + volatile uint32_t CFG2; /* Configuration Register 2 */ + volatile uint32_t R[2]; /* Data Result Register */ + + /* Compare Value Registers 1, 2 */ + volatile uint32_t CV1; + volatile uint32_t CV2; + + volatile uint32_t SC2; /* Status and Control Register 2 */ + volatile uint32_t SC3; /* Status and Control Register 3 */ + + volatile uint32_t OFS; /* Offset Correction Register */ + volatile uint32_t PG; /* Plus-Side Gain Register */ + volatile uint32_t MG; /* Minus-Side Gain Register */ + + /* Plus-Side General Calibration Value Registers */ + volatile uint32_t CLPD; + volatile uint32_t CLPS; + volatile uint32_t CLP4; + volatile uint32_t CLP3; + volatile uint32_t CLP2; + volatile uint32_t CLP1; + volatile uint32_t CLP0; + uint32_t rsvd0; + /* Minus-Side General Calibration Value Registers */ + volatile uint32_t CLMD; + volatile uint32_t CLMS; + volatile uint32_t CLM4; + volatile uint32_t CLM3; + volatile uint32_t CLM2; + volatile uint32_t CLM1; + volatile uint32_t CLM0; +}; +static struct ADC *const ADC0 = (struct ADC *const)0x4003B000; + +/* SC1 */ +#define ADC_SC1_DIFF (1 << 5) +#define ADC_SC1_AIEN (1 << 6) +#define ADC_SC1_COCO (1 << 7) +#define ADC_SC1_TEMPSENSOR 26 +#define ADC_SC1_BANDGAP 27 +#define ADC_SC1_ADCSTOP 31 + +/* CFG1 */ +#define ADC_CLOCK_SOURCE_ASYNCH (3 << 0) +#define ADC_MODE_16BIT (3 << 2) +#define ADC_ADLSMP_SHORT (0 << 4) +#define ADC_ADLSMP_LONG (1 << 4) +#define ADC_ADIV_1 (0 << 5) +#define ADC_ADIV_8 (3 << 5) +#define ADC_ADLPC_NORMAL (0 << 7) +#define ADC_ADLPC_LOWPOWER (1 << 7) +/**/ +#define ADC_CLOCK_SOURCE ADC_CLOCK_SOURCE_ASYNCH +#define ADC_MODE ADC_MODE_16BIT +#define ADC_ADLSMP ADC_ADLSMP_SHORT +#define ADC_ADIV ADC_ADIV_1 +#define ADC_ADLPC ADC_ADLPC_LOWPOWER + +/* CFG2 */ +#define ADC_ADLSTS_DEFAULT 0 /* 24 cycles if CFG1.ADLSMP=1, 4 if not. */ +#define ADC_ADHSC_NORMAL (0 << 2) +#define ADC_ADHSC_HIGHSPEED (1 << 2) +#define ADC_ADACK_DISABLE (0 << 3) +#define ADC_ADACK_ENABLE (1 << 3) +#define ADC_MUXSEL_A (0 << 4) +#define ADC_MUXSEL_B (1 << 4) +/**/ +#define ADC_ADLSTS ADC_ADLSTS_DEFAULT +#define ADC_ADHSC ADC_ADHSC_NORMAL +#define ADC_ADACKEN ADC_ADACK_ENABLE +#define ADC_MUXSEL ADC_MUXSEL_A + +/* SC2 */ +#define ADC_SC2_REFSEL_DEFAULT 1 /* Internal Voltage Reference??? */ +#define ADC_SC2_DMAEN (1 << 2) +#define ADC_SC2_ACREN (1 << 3) +#define ADC_SC2_ACFGT (1 << 4) +#define ADC_SC2_ACFE (1 << 5) +#define ADC_SC2_ADTRG (1 << 6) /* For hardware trigger */ + +/* SC3 */ +#define ADC_SC3_AVGS11 0x03 +#define ADC_SC3_AVGE (1 << 2) +#define ADC_SC3_ADCO (1 << 3) +#define ADC_SC3_CALF (1 << 6) +#define ADC_SC3_CAL (1 << 7) + +#define ADC_DMA_SLOT_NUM 40 + +/* + * Buffer to save ADC data. + */ +uint32_t adc_buf[64]; + +static const uint32_t adc0_sc1_setting = ADC_SC1_TEMPSENSOR; + +static chopstx_intr_t adc_intr; + +struct adc_internal { + uint32_t buf[64]; + uint8_t *p; + int phase : 8; + int count : 8; +}; +struct adc_internal adc; + +/* + * Initialize ADC module, do calibration. + * + * This is called by MAIN, only once, hopefully before creating any + * other threads (to be accurate). + * + * We configure ADC0 to kick DMA0, configure DMA0 to kick DMA1. + * DMA0 records output of ADC0 to the ADC.BUF. + * DMA1 kicks ADC0 again to get another value. + * + * ADC0 --[finish conversion]--> DMA0 --[Link channel 1]--> DMA1 + */ +int +adc_init (void) +{ + uint32_t v; + + /* Enable ADC0 and DMAMUX clock. */ + SIM->SCGC6 |= (1 << 27) | (1 << 1); + /* Enable DMA clock. */ + SIM->SCGC7 |= (1 << 8); + + /* ADC0 setting for calibration. */ + ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC; + ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL; + ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT; + ADC0->SC3 = ADC_SC3_CAL | ADC_SC3_CALF | ADC_SC3_AVGE | ADC_SC3_AVGS11; + + /* Wait ADC completion */ + while ((ADC0->SC1[0] & ADC_SC1_COCO) == 0) + if ((ADC0->SC3 & ADC_SC3_CALF) != 0) + /* Calibration failure */ + return -1; + + if ((ADC0->SC3 & ADC_SC3_CALF) != 0) + /* Calibration failure */ + return -1; + + /* Configure PG by the calibration values. */ + v = ADC0->CLP0 + ADC0->CLP1 + ADC0->CLP2 + ADC0->CLP3 + ADC0->CLP4 + ADC0->CLPS; + ADC0->PG = 0x8000 | (v >> 1); + + /* Configure MG by the calibration values. */ + v = ADC0->CLM0 + ADC0->CLM1 + ADC0->CLM2 + ADC0->CLM3 + ADC0->CLM4 + ADC0->CLMS; + ADC0->MG = 0x8000 | (v >> 1); + + ADC0->SC1[0] = ADC_SC1_ADCSTOP; + + /* DMAMUX setting. */ + DMAMUX->CHCFG0 = (1 << 7) | ADC_DMA_SLOT_NUM; + + /* DMA0 initial setting. */ + DMA0->SAR = (uint32_t)&ADC0->R[0]; + + /* DMA1 initial setting. */ + DMA1->SAR = (uint32_t)&adc0_sc1_setting; + DMA1->DAR = (uint32_t)&ADC0->SC1[0]; + + chopstx_claim_irq (&adc_intr, INTR_REQ_DMA0); + return 0; +} + +/* + * Start using ADC. + */ +void +adc_start (void) +{ + ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC; + ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL; + ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT | ADC_SC2_DMAEN; + ADC0->SC3 = 0; +} + +/* + * Kick getting data for COUNT times. + * Data will be saved in ADC_BUF starting at OFFSET. + */ +static void +adc_start_conversion_internal (int count) +{ + /* DMA0 setting. */ + DMA0->DAR = (uint32_t)&adc.buf[0]; + DMA0->DSR_BCR = 4 * count; + DMA0->DCR = (1 << 31) | (1 << 30) | (1 << 29) | (0 << 20) | (1 << 19) + | (0 << 17) | (1 << 7) | (2 << 4) | (1 << 2); + + /* Kick DMA1. */ + DMA1->DSR_BCR = 4 * count; + DMA1->DCR = (1 << 30) | (1 << 29) | (0 << 19) | (0 << 17) | (1 << 16) | (1 << 7); +} + + +/* + * Kick getting data for COUNT times. + * Data will be saved in ADC_BUF starting at OFFSET. + */ +void +adc_start_conversion (int offset, int count) +{ + adc.p = (uint8_t *)&adc_buf[offset]; + adc.phase = 0; + adc.count = count; + adc_start_conversion_internal (count); +} + + +static void +adc_stop_conversion (void) +{ + ADC0->SC1[0] = ADC_SC1_ADCSTOP; +} + +/* + * Stop using ADC. + */ +void +adc_stop (void) +{ + SIM->SCGC6 &= ~(1 << 27); +} + +/* + * Return 0 on success. + * Return 1 on error. + */ +int +adc_wait_completion (void) +{ + while (1) + { + int i; + + /* Wait DMA completion */ + chopstx_poll (NULL, 1, &adc_intr); + + DMA0->DSR_BCR = (1 << 24); + DMA1->DSR_BCR = (1 << 24); + + adc_stop_conversion (); + + for (i = 0; i < adc.count; i++) + *adc.p++ = (uint8_t)adc.buf[i]; + + if (++adc.phase >= 4) + break; + + adc_start_conversion_internal (adc.count); + } + + return 0; +} diff --git a/contrib/adc-stm32f103.c b/contrib/adc-stm32f103.c new file mode 100644 index 0000000..6a8076e --- /dev/null +++ b/contrib/adc-stm32f103.c @@ -0,0 +1,328 @@ +/* + * 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 Chopstx, a thread library for embedded. + * + * Chopstx 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. + * + * Chopstx 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/>. + * + * As additional permission under GNU GPL version 3 section 7, you may + * distribute non-source form of the Program without the copy of the + * GNU GPL normally required by section 4, provided you inform the + * receipents of GNU GPL by a written offer. + * + */ + +#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 "sys.h" + +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/example-led/Makefile b/example-led/Makefile index b490fb1..d7d978c 100644 --- a/example-led/Makefile +++ b/example-led/Makefile @@ -10,7 +10,7 @@ LDSCRIPT= sample.ld ### LDSCRIPT= sample.ld.m3 CSRC = sample.c -CHIP=stm32f030 +CHIP=stm32f0 USE_SYS = yes ################################### diff --git a/mcu/adc-mkl27z.c b/mcu/adc-mkl27z.c deleted file mode 100644 index 19f9f5b..0000000 --- a/mcu/adc-mkl27z.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * adc-mkl27z.c - ADC driver for MKL27Z - * In this ADC driver, there are NeuG specific parts. - * It only records lower 8-bit of 16-bit data. - * You need to modify to use this as generic ADC driver. - * - * Copyright (C) 2016 Flying Stone Technology - * Author: NIIBE Yutaka <gniibe@fsij.org> - * - * This file is a part of Chopstx, a thread library for embedded. - * - * Chopstx 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. - * - * Chopstx 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/>. - * - * As additional permission under GNU GPL version 3 section 7, you may - * distribute non-source form of the Program without the copy of the - * GNU GPL normally required by section 4, provided you inform the - * receipents of GNU GPL by a written offer. - * - */ - -#include <stdint.h> -#include <stdlib.h> -#include <chopstx.h> -#include <mcu/mkl27z.h> - -struct DMAMUX { - volatile uint32_t CHCFG0; - volatile uint32_t CHCFG1; - volatile uint32_t CHCFG2; - volatile uint32_t CHCFG3; -}; -static struct DMAMUX *const DMAMUX = (struct DMAMUX *const)0x40021000; - -#define INTR_REQ_DMA0 0 - -struct DMA { - volatile uint32_t SAR; - volatile uint32_t DAR; - volatile uint32_t DSR_BCR; - volatile uint32_t DCR; -}; -static struct DMA *const DMA0 = (struct DMA *const)0x40008100; -static struct DMA *const DMA1 = (struct DMA *const)0x40008110; - - -/* We don't use ADC interrupt. Just for reference. */ -#define INTR_REQ_ADC 15 - -struct ADC { - volatile uint32_t SC1[2];/* Status and Control Registers 1 */ - volatile uint32_t CFG1; /* Configuration Register 1 */ - volatile uint32_t CFG2; /* Configuration Register 2 */ - volatile uint32_t R[2]; /* Data Result Register */ - - /* Compare Value Registers 1, 2 */ - volatile uint32_t CV1; - volatile uint32_t CV2; - - volatile uint32_t SC2; /* Status and Control Register 2 */ - volatile uint32_t SC3; /* Status and Control Register 3 */ - - volatile uint32_t OFS; /* Offset Correction Register */ - volatile uint32_t PG; /* Plus-Side Gain Register */ - volatile uint32_t MG; /* Minus-Side Gain Register */ - - /* Plus-Side General Calibration Value Registers */ - volatile uint32_t CLPD; - volatile uint32_t CLPS; - volatile uint32_t CLP4; - volatile uint32_t CLP3; - volatile uint32_t CLP2; - volatile uint32_t CLP1; - volatile uint32_t CLP0; - uint32_t rsvd0; - /* Minus-Side General Calibration Value Registers */ - volatile uint32_t CLMD; - volatile uint32_t CLMS; - volatile uint32_t CLM4; - volatile uint32_t CLM3; - volatile uint32_t CLM2; - volatile uint32_t CLM1; - volatile uint32_t CLM0; -}; -static struct ADC *const ADC0 = (struct ADC *const)0x4003B000; - -/* SC1 */ -#define ADC_SC1_DIFF (1 << 5) -#define ADC_SC1_AIEN (1 << 6) -#define ADC_SC1_COCO (1 << 7) -#define ADC_SC1_TEMPSENSOR 26 -#define ADC_SC1_BANDGAP 27 -#define ADC_SC1_ADCSTOP 31 - -/* CFG1 */ -#define ADC_CLOCK_SOURCE_ASYNCH (3 << 0) -#define ADC_MODE_16BIT (3 << 2) -#define ADC_ADLSMP_SHORT (0 << 4) -#define ADC_ADLSMP_LONG (1 << 4) -#define ADC_ADIV_1 (0 << 5) -#define ADC_ADIV_8 (3 << 5) -#define ADC_ADLPC_NORMAL (0 << 7) -#define ADC_ADLPC_LOWPOWER (1 << 7) -/**/ -#define ADC_CLOCK_SOURCE ADC_CLOCK_SOURCE_ASYNCH -#define ADC_MODE ADC_MODE_16BIT -#define ADC_ADLSMP ADC_ADLSMP_SHORT -#define ADC_ADIV ADC_ADIV_1 -#define ADC_ADLPC ADC_ADLPC_LOWPOWER - -/* CFG2 */ -#define ADC_ADLSTS_DEFAULT 0 /* 24 cycles if CFG1.ADLSMP=1, 4 if not. */ -#define ADC_ADHSC_NORMAL (0 << 2) -#define ADC_ADHSC_HIGHSPEED (1 << 2) -#define ADC_ADACK_DISABLE (0 << 3) -#define ADC_ADACK_ENABLE (1 << 3) -#define ADC_MUXSEL_A (0 << 4) -#define ADC_MUXSEL_B (1 << 4) -/**/ -#define ADC_ADLSTS ADC_ADLSTS_DEFAULT -#define ADC_ADHSC ADC_ADHSC_NORMAL -#define ADC_ADACKEN ADC_ADACK_ENABLE -#define ADC_MUXSEL ADC_MUXSEL_A - -/* SC2 */ -#define ADC_SC2_REFSEL_DEFAULT 1 /* Internal Voltage Reference??? */ -#define ADC_SC2_DMAEN (1 << 2) -#define ADC_SC2_ACREN (1 << 3) -#define ADC_SC2_ACFGT (1 << 4) -#define ADC_SC2_ACFE (1 << 5) -#define ADC_SC2_ADTRG (1 << 6) /* For hardware trigger */ - -/* SC3 */ -#define ADC_SC3_AVGS11 0x03 -#define ADC_SC3_AVGE (1 << 2) -#define ADC_SC3_ADCO (1 << 3) -#define ADC_SC3_CALF (1 << 6) -#define ADC_SC3_CAL (1 << 7) - -#define ADC_DMA_SLOT_NUM 40 - -/* - * Buffer to save ADC data. - */ -uint32_t adc_buf[64]; - -static const uint32_t adc0_sc1_setting = ADC_SC1_TEMPSENSOR; - -static chopstx_intr_t adc_intr; - -struct adc_internal { - uint32_t buf[64]; - uint8_t *p; - int phase : 8; - int count : 8; -}; -struct adc_internal adc; - -/* - * Initialize ADC module, do calibration. - * - * This is called by MAIN, only once, hopefully before creating any - * other threads (to be accurate). - * - * We configure ADC0 to kick DMA0, configure DMA0 to kick DMA1. - * DMA0 records output of ADC0 to the ADC.BUF. - * DMA1 kicks ADC0 again to get another value. - * - * ADC0 --[finish conversion]--> DMA0 --[Link channel 1]--> DMA1 - */ -int -adc_init (void) -{ - uint32_t v; - - /* Enable ADC0 and DMAMUX clock. */ - SIM->SCGC6 |= (1 << 27) | (1 << 1); - /* Enable DMA clock. */ - SIM->SCGC7 |= (1 << 8); - - /* ADC0 setting for calibration. */ - ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC; - ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL; - ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT; - ADC0->SC3 = ADC_SC3_CAL | ADC_SC3_CALF | ADC_SC3_AVGE | ADC_SC3_AVGS11; - - /* Wait ADC completion */ - while ((ADC0->SC1[0] & ADC_SC1_COCO) == 0) - if ((ADC0->SC3 & ADC_SC3_CALF) != 0) - /* Calibration failure */ - return -1; - - if ((ADC0->SC3 & ADC_SC3_CALF) != 0) - /* Calibration failure */ - return -1; - - /* Configure PG by the calibration values. */ - v = ADC0->CLP0 + ADC0->CLP1 + ADC0->CLP2 + ADC0->CLP3 + ADC0->CLP4 + ADC0->CLPS; - ADC0->PG = 0x8000 | (v >> 1); - - /* Configure MG by the calibration values. */ - v = ADC0->CLM0 + ADC0->CLM1 + ADC0->CLM2 + ADC0->CLM3 + ADC0->CLM4 + ADC0->CLMS; - ADC0->MG = 0x8000 | (v >> 1); - - ADC0->SC1[0] = ADC_SC1_ADCSTOP; - - /* DMAMUX setting. */ - DMAMUX->CHCFG0 = (1 << 7) | ADC_DMA_SLOT_NUM; - - /* DMA0 initial setting. */ - DMA0->SAR = (uint32_t)&ADC0->R[0]; - - /* DMA1 initial setting. */ - DMA1->SAR = (uint32_t)&adc0_sc1_setting; - DMA1->DAR = (uint32_t)&ADC0->SC1[0]; - - chopstx_claim_irq (&adc_intr, INTR_REQ_DMA0); - return 0; -} - -/* - * Start using ADC. - */ -void -adc_start (void) -{ - ADC0->CFG1 = ADC_CLOCK_SOURCE | ADC_MODE | ADC_ADLSMP | ADC_ADIV | ADC_ADLPC; - ADC0->CFG2 = ADC_ADLSTS | ADC_ADHSC | ADC_ADACKEN | ADC_MUXSEL; - ADC0->SC2 = ADC_SC2_REFSEL_DEFAULT | ADC_SC2_DMAEN; - ADC0->SC3 = 0; -} - -/* - * Kick getting data for COUNT times. - * Data will be saved in ADC_BUF starting at OFFSET. - */ -static void -adc_start_conversion_internal (int count) -{ - /* DMA0 setting. */ - DMA0->DAR = (uint32_t)&adc.buf[0]; - DMA0->DSR_BCR = 4 * count; - DMA0->DCR = (1 << 31) | (1 << 30) | (1 << 29) | (0 << 20) | (1 << 19) - | (0 << 17) | (1 << 7) | (2 << 4) | (1 << 2); - - /* Kick DMA1. */ - DMA1->DSR_BCR = 4 * count; - DMA1->DCR = (1 << 30) | (1 << 29) | (0 << 19) | (0 << 17) | (1 << 16) | (1 << 7); -} - - -/* - * Kick getting data for COUNT times. - * Data will be saved in ADC_BUF starting at OFFSET. - */ -void -adc_start_conversion (int offset, int count) -{ - adc.p = (uint8_t *)&adc_buf[offset]; - adc.phase = 0; - adc.count = count; - adc_start_conversion_internal (count); -} - - -static void -adc_stop_conversion (void) -{ - ADC0->SC1[0] = ADC_SC1_ADCSTOP; -} - -/* - * Stop using ADC. - */ -void -adc_stop (void) -{ - SIM->SCGC6 &= ~(1 << 27); -} - -/* - * Return 0 on success. - * Return 1 on error. - */ -int -adc_wait_completion (void) -{ - while (1) - { - int i; - - /* Wait DMA completion */ - chopstx_poll (NULL, 1, &adc_intr); - - DMA0->DSR_BCR = (1 << 24); - DMA1->DSR_BCR = (1 << 24); - - adc_stop_conversion (); - - for (i = 0; i < adc.count; i++) - *adc.p++ = (uint8_t)adc.buf[i]; - - if (++adc.phase >= 4) - break; - - adc_start_conversion_internal (adc.count); - } - - return 0; -} diff --git a/mcu/adc-stm32f103.c b/mcu/adc-stm32f103.c deleted file mode 100644 index 6a8076e..0000000 --- a/mcu/adc-stm32f103.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 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 Chopstx, a thread library for embedded. - * - * Chopstx 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. - * - * Chopstx 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/>. - * - * As additional permission under GNU GPL version 3 section 7, you may - * distribute non-source form of the Program without the copy of the - * GNU GPL normally required by section 4, provided you inform the - * receipents of GNU GPL by a written offer. - * - */ - -#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 "sys.h" - -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/sys-stm32f0.c b/mcu/sys-stm32f0.c new file mode 100644 index 0000000..f811b97 --- /dev/null +++ b/mcu/sys-stm32f0.c @@ -0,0 +1,422 @@ +/* + * sys.c - system routines for the initial page for STM32F030 / STM32F103. + * + * Copyright (C) 2013, 2014, 2015, 2016 Flying Stone Technology + * Author: NIIBE Yutaka <gniibe@fsij.org> + * + * Copying and distribution of this file, with or without modification, + * are permitted in any medium without royalty provided the copyright + * notice and this notice are preserved. This file is offered as-is, + * without any warranty. + * + * When the flash ROM is protected, we cannot modify the initial page. + * We put some system routines (which is useful for any program) here. + */ + +#include <stdint.h> +#include <stdlib.h> +#include "board.h" + +#define STM32F0_USE_VECTOR_ON_RAM +#include "mcu/clk_gpio_init-stm32.c" + + +static void +usb_cable_config (int enable) +{ +#if defined(GPIO_USB_SET_TO_ENABLE) + if (enable) + GPIO_USB->BSRR = (1 << GPIO_USB_SET_TO_ENABLE); + else + GPIO_USB->BRR = (1 << GPIO_USB_SET_TO_ENABLE); +#elif defined(GPIO_USB_CLEAR_TO_ENABLE) + if (enable) + GPIO_USB->BRR = (1 << GPIO_USB_CLEAR_TO_ENABLE); + else + GPIO_USB->BSRR = (1 << GPIO_USB_CLEAR_TO_ENABLE); +#else + (void)enable; +#endif +} + +void +set_led (int on) +{ +#if defined(GPIO_LED_CLEAR_TO_EMIT) + if (on) + GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT); + else + GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT); +#else + if (on) + GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT); + else + GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT); +#endif +} + +static void wait (int count) +{ + int i; + + for (i = 0; i < count; i++) + asm volatile ("" : : "r" (i) : "memory"); +} + + +static void +usb_lld_sys_shutdown (void) +{ + RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; + RCC->APB1RSTR = RCC_APB1RSTR_USBRST; + usb_cable_config (0); +} + +static void +usb_lld_sys_init (void) +{ + if ((RCC->APB1ENR & RCC_APB1ENR_USBEN) + && (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0) + /* Make sure the device is disconnected, even after core reset. */ + { + usb_lld_sys_shutdown (); + /* Disconnect requires SE0 (>= 2.5uS). */ + wait (300); + } + + usb_cable_config (1); + RCC->APB1ENR |= RCC_APB1ENR_USBEN; + RCC->APB1RSTR = RCC_APB1RSTR_USBRST; + RCC->APB1RSTR = 0; +} + +#define FLASH_KEY1 0x45670123UL +#define FLASH_KEY2 0xCDEF89ABUL + +enum flash_status +{ + FLASH_BUSY = 1, + FLASH_ERROR_PG, + FLASH_ERROR_WRP, + FLASH_COMPLETE, + FLASH_TIMEOUT +}; + +static void __attribute__ ((used)) +flash_unlock (void) +{ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; +} + + +#define intr_disable() asm volatile ("cpsid i" : : : "memory") +#define intr_enable() asm volatile ("cpsie i" : : : "memory") + +#define FLASH_SR_BSY 0x01 +#define FLASH_SR_PGERR 0x04 +#define FLASH_SR_WRPRTERR 0x10 +#define FLASH_SR_EOP 0x20 + +#define FLASH_CR_PG 0x0001 +#define FLASH_CR_PER 0x0002 +#define FLASH_CR_MER 0x0004 +#define FLASH_CR_OPTPG 0x0010 +#define FLASH_CR_OPTER 0x0020 +#define FLASH_CR_STRT 0x0040 +#define FLASH_CR_LOCK 0x0080 +#define FLASH_CR_OPTWRE 0x0200 +#define FLASH_CR_ERRIE 0x0400 +#define FLASH_CR_EOPIE 0x1000 + +static int +flash_wait_for_last_operation (uint32_t timeout) +{ + int status; + + do + { + status = FLASH->SR; + if (--timeout == 0) + break; + } + while ((status & FLASH_SR_BSY) != 0); + + return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR); +} + +#define FLASH_PROGRAM_TIMEOUT 0x00010000 +#define FLASH_ERASE_TIMEOUT 0x01000000 + +static int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + + intr_disable (); + if (status == 0) + { + FLASH->CR |= FLASH_CR_PG; + + *(volatile uint16_t *)addr = data; + + status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); + FLASH->CR &= ~FLASH_CR_PG; + } + intr_enable (); + + return status; +} + +static int +flash_erase_page (uint32_t addr) +{ + int status; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + + intr_disable (); + if (status == 0) + { + FLASH->CR |= FLASH_CR_PER; + FLASH->AR = addr; + FLASH->CR |= FLASH_CR_STRT; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + FLASH->CR &= ~FLASH_CR_PER; + } + intr_enable (); + + return status; +} + +static int +flash_check_blank (const uint8_t *p_start, size_t size) +{ + const uint8_t *p; + + for (p = p_start; p < p_start + size; p++) + if (*p != 0xff) + return 0; + + return 1; +} + +#define FLASH_START_ADDR 0x08000000 /* Fixed for all STM32F0/F1. */ +#define FLASH_OFFSET 0x1000 /* First pages are not-writable + when protected. */ +#if defined(__ARM_ARCH_6M__) +#define FLASH_SIZE_REG ((uint16_t *)0x1ffff7cc) +#define CHIP_ID_REG ((uint32_t *)0x40015800) +#else +#define FLASH_SIZE_REG ((uint16_t *)0x1ffff7e0) +#define CHIP_ID_REG ((uint32_t *)0xe0042000) +#endif +#define FLASH_START (FLASH_START_ADDR+FLASH_OFFSET) + +static int +flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) +{ + int status; + uint32_t flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024; + + if (dst_addr < FLASH_START || dst_addr + len > flash_end) + return 0; + + while (len) + { + uint16_t hw = *src++; + + hw |= (*src++ << 8); + status = flash_program_halfword (dst_addr, hw); + if (status != 0) + return 0; /* error return */ + + dst_addr += 2; + len -= 2; + } + + return 1; +} + +#define OPTION_BYTES_ADDR 0x1ffff800 + +static int +flash_protect (void) +{ + int status; + uint32_t option_bytes_value; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + + intr_disable (); + if (status == 0) + { + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + FLASH->CR |= FLASH_CR_OPTER; + FLASH->CR |= FLASH_CR_STRT; + + status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); + FLASH->CR &= ~FLASH_CR_OPTER; + } + intr_enable (); + + if (status != 0) + return 0; + + option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR; + return (option_bytes_value & 0xff) == 0xff ? 1 : 0; +} + +static void __attribute__((naked)) +flash_erase_all_and_exec (void (*entry)(void)) +{ + uint32_t addr = FLASH_START; + uint32_t end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024; + uint32_t page_size = 1024; + int r; + + if (((*CHIP_ID_REG) & 0xfff) == 0x0414) + page_size = 2048; + + while (addr < end) + { + r = flash_erase_page (addr); + if (r != 0) + break; + + addr += page_size; + } + + if (addr >= end) + (*entry) (); + + for (;;); +} + +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]; +}; + +#define SCS_BASE (0xE000E000) +#define SCB_BASE (SCS_BASE + 0x0D00) +static struct SCB *const SCB = ((struct SCB *const) SCB_BASE); + +#define SYSRESETREQ 0x04 +static void +nvic_system_reset (void) +{ + SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ); + asm volatile ("dsb"); + for (;;); +} + +static void __attribute__ ((naked)) +reset (void) +{ + /* + * This code may not be at the start of flash ROM, because of DFU. + * So, we take the address from PC. + */ +#if defined(__ARM_ARCH_6M__) + asm volatile ("cpsid i\n\t" /* Mask all interrupts. */ + "ldr r0, 1f\n\t" /* r0 = RAM start */ + "mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */ + "mov r2, #0x10\n\t" + "lsl r2, #8\n\t" + "add r1, r1, r2\n\t" + "sub r2, r2, #1\n\t" + "bic r1, r1, r2\n\t" + "mov r2, #188\n" + "2:\n\t" /* Copy vectors. It will be enabled later by clock_init. */ + "ldr r3, [r1, r2]\n\t" + "str r3, [r0, r2]\n\t" + "sub r2, #4\n\t" + "bcs 2b\n\t" + "msr MSP, r3\n\t" /* Main (exception handler) stack. */ + "ldr r0, [r1, #4]\n\t" /* Reset handler. */ + "bx r0\n\t" + ".align 2\n" + "1: .word 0x20000000" + : /* no output */ : /* no input */ : "memory"); +#else + extern const uint32_t FT0[256], FT1[256], FT2[256]; + asm volatile ("cpsid i\n\t" /* Mask all interrupts. */ + "ldr r0, 1f\n\t" /* r0 = SCR */ + "mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */ + "mov r2, #0x1000\n\t" + "add r1, r1, r2\n\t" + "sub r2, r2, #1\n\t" + "bic r1, r1, r2\n\t" + "str r1, [r0, #8]\n\t" /* Set SCR->VCR */ + "ldr r0, [r1], #4\n\t" + "msr MSP, r0\n\t" /* Main (exception handler) stack. */ + "ldr r0, [r1]\n\t" /* Reset handler. */ + "bx r0\n\t" + ".align 2\n" + "1: .word 0xe000ed00" + : /* no output */ : /* no input */ : "memory"); + /* Artificial entry to refer FT0, FT1, and FT2. */ + asm volatile ("" + : : "r" (FT0), "r" (FT1), "r" (FT2)); +#endif + /* Never reach here. */ +} + +typedef void (*handler)(void); +extern uint8_t __ram_end__; + +handler vector[] __attribute__ ((section(".vectors"))) = { + (handler)&__ram_end__, + reset, + (handler)set_led, + flash_unlock, + (handler)flash_program_halfword, + (handler)flash_erase_page, + (handler)flash_check_blank, + (handler)flash_write, + (handler)flash_protect, + (handler)flash_erase_all_and_exec, + usb_lld_sys_init, + usb_lld_sys_shutdown, + nvic_system_reset, + clock_init, + gpio_init, + NULL, +}; + +const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = { + 3*2+2, /* bLength */ + 0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */ + /* sys version: "3.0" */ + '3', 0, '.', 0, '0', 0, +}; + +const uint32_t __attribute__((section(".sys.board_id"))) +sys_board_id = BOARD_ID; + +const uint8_t __attribute__((section(".sys.board_name"))) +sys_board_name[] = BOARD_NAME; diff --git a/mcu/sys-stm32f0.h b/mcu/sys-stm32f0.h new file mode 100644 index 0000000..bd2d87d --- /dev/null +++ b/mcu/sys-stm32f0.h @@ -0,0 +1,134 @@ +#if defined(__ARM_ARCH_6M__) +#define BOARD_ID_STM32F0_DISCOVERY 0xde4b4bc1 +#define BOARD_ID_FSM_55 0x83433c76 +#else +#define BOARD_ID_CQ_STARM 0xc5480875 +#define BOARD_ID_FST_01_00 0x613870a9 +#define BOARD_ID_FST_01 0x696886af +#define BOARD_ID_MAPLE_MINI 0x7a445272 +#define BOARD_ID_OLIMEX_STM32_H103 0xf92bb594 +#define BOARD_ID_STBEE_MINI 0x1f341961 +#define BOARD_ID_STBEE 0x945c37e8 +#define BOARD_ID_STM32_PRIMER2 0x21e5798d +#define BOARD_ID_STM8S_DISCOVERY 0x2f0976bb +#define BOARD_ID_ST_DONGLE 0x2cd4e471 +#define BOARD_ID_ST_NUCLEO_F103 0x9b87c16d +#endif + +extern const uint8_t sys_version[8]; +#if defined(USE_SYS3) || defined(USE_SYS_BOARD_ID) +extern const uint32_t sys_board_id; +extern const uint8_t sys_board_name[]; +#else +# define SYS_BOARD_ID BOARD_ID +#endif + +typedef void (*handler)(void); +extern handler vector[16]; + +static inline const uint8_t * +unique_device_id (void) +{ + /* STM32F103 has 96-bit unique device identifier */ + const uint8_t *addr = (const uint8_t *)0x1ffff7e8; + + return addr; +} + +static inline void +set_led (int on) +{ + void (*func) (int) = (void (*)(int))vector[2]; + + return (*func) (on); +} + +static inline void +flash_unlock (void) +{ + (*vector[3]) (); +} + +static inline int +flash_program_halfword (uint32_t addr, uint16_t data) +{ + int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4]; + + return (*func) (addr, data); +} + +static inline int +flash_erase_page (uint32_t addr) +{ + int (*func) (uint32_t) = (int (*)(uint32_t))vector[5]; + + return (*func) (addr); +} + +static inline int +flash_check_blank (const uint8_t *p_start, size_t size) +{ + int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6]; + + return (*func) (p_start, size); +} + +static inline int +flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) +{ + int (*func) (uint32_t, const uint8_t *, size_t) + = (int (*)(uint32_t, const uint8_t *, size_t))vector[7]; + + return (*func) (dst_addr, src, len); +} + +static inline int +flash_protect (void) +{ + int (*func) (void) = (int (*)(void))vector[8]; + + return (*func) (); +} + +static inline void __attribute__((noreturn)) +flash_erase_all_and_exec (void (*entry)(void)) +{ + void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9]; + + (*func) (entry); + for (;;); +} + +static inline void +usb_lld_sys_init (void) +{ + (*vector[10]) (); +} + +static inline void +usb_lld_sys_shutdown (void) +{ + (*vector[11]) (); +} + +static inline void +nvic_system_reset (void) +{ + (*vector[12]) (); +} + +#ifdef REQUIRE_CLOCK_GPIO_SETTING_IN_SYS +/* Provide the function entries. */ + +static void __attribute__ ((used)) +clock_init (void) +{ + (*vector[13]) (); +} + +static void __attribute__ ((used)) +gpio_init (void) +{ + (*vector[14]) (); +} +#endif diff --git a/mcu/sys-stm32f030.c b/mcu/sys-stm32f030.c deleted file mode 100644 index f811b97..0000000 --- a/mcu/sys-stm32f030.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * sys.c - system routines for the initial page for STM32F030 / STM32F103. - * - * Copyright (C) 2013, 2014, 2015, 2016 Flying Stone Technology - * Author: NIIBE Yutaka <gniibe@fsij.org> - * - * Copying and distribution of this file, with or without modification, - * are permitted in any medium without royalty provided the copyright - * notice and this notice are preserved. This file is offered as-is, - * without any warranty. - * - * When the flash ROM is protected, we cannot modify the initial page. - * We put some system routines (which is useful for any program) here. - */ - -#include <stdint.h> -#include <stdlib.h> -#include "board.h" - -#define STM32F0_USE_VECTOR_ON_RAM -#include "mcu/clk_gpio_init-stm32.c" - - -static void -usb_cable_config (int enable) -{ -#if defined(GPIO_USB_SET_TO_ENABLE) - if (enable) - GPIO_USB->BSRR = (1 << GPIO_USB_SET_TO_ENABLE); - else - GPIO_USB->BRR = (1 << GPIO_USB_SET_TO_ENABLE); -#elif defined(GPIO_USB_CLEAR_TO_ENABLE) - if (enable) - GPIO_USB->BRR = (1 << GPIO_USB_CLEAR_TO_ENABLE); - else - GPIO_USB->BSRR = (1 << GPIO_USB_CLEAR_TO_ENABLE); -#else - (void)enable; -#endif -} - -void -set_led (int on) -{ -#if defined(GPIO_LED_CLEAR_TO_EMIT) - if (on) - GPIO_LED->BRR = (1 << GPIO_LED_CLEAR_TO_EMIT); - else - GPIO_LED->BSRR = (1 << GPIO_LED_CLEAR_TO_EMIT); -#else - if (on) - GPIO_LED->BSRR = (1 << GPIO_LED_SET_TO_EMIT); - else - GPIO_LED->BRR = (1 << GPIO_LED_SET_TO_EMIT); -#endif -} - -static void wait (int count) -{ - int i; - - for (i = 0; i < count; i++) - asm volatile ("" : : "r" (i) : "memory"); -} - - -static void -usb_lld_sys_shutdown (void) -{ - RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; - RCC->APB1RSTR = RCC_APB1RSTR_USBRST; - usb_cable_config (0); -} - -static void -usb_lld_sys_init (void) -{ - if ((RCC->APB1ENR & RCC_APB1ENR_USBEN) - && (RCC->APB1RSTR & RCC_APB1RSTR_USBRST) == 0) - /* Make sure the device is disconnected, even after core reset. */ - { - usb_lld_sys_shutdown (); - /* Disconnect requires SE0 (>= 2.5uS). */ - wait (300); - } - - usb_cable_config (1); - RCC->APB1ENR |= RCC_APB1ENR_USBEN; - RCC->APB1RSTR = RCC_APB1RSTR_USBRST; - RCC->APB1RSTR = 0; -} - -#define FLASH_KEY1 0x45670123UL -#define FLASH_KEY2 0xCDEF89ABUL - -enum flash_status -{ - FLASH_BUSY = 1, - FLASH_ERROR_PG, - FLASH_ERROR_WRP, - FLASH_COMPLETE, - FLASH_TIMEOUT -}; - -static void __attribute__ ((used)) -flash_unlock (void) -{ - FLASH->KEYR = FLASH_KEY1; - FLASH->KEYR = FLASH_KEY2; -} - - -#define intr_disable() asm volatile ("cpsid i" : : : "memory") -#define intr_enable() asm volatile ("cpsie i" : : : "memory") - -#define FLASH_SR_BSY 0x01 -#define FLASH_SR_PGERR 0x04 -#define FLASH_SR_WRPRTERR 0x10 -#define FLASH_SR_EOP 0x20 - -#define FLASH_CR_PG 0x0001 -#define FLASH_CR_PER 0x0002 -#define FLASH_CR_MER 0x0004 -#define FLASH_CR_OPTPG 0x0010 -#define FLASH_CR_OPTER 0x0020 -#define FLASH_CR_STRT 0x0040 -#define FLASH_CR_LOCK 0x0080 -#define FLASH_CR_OPTWRE 0x0200 -#define FLASH_CR_ERRIE 0x0400 -#define FLASH_CR_EOPIE 0x1000 - -static int -flash_wait_for_last_operation (uint32_t timeout) -{ - int status; - - do - { - status = FLASH->SR; - if (--timeout == 0) - break; - } - while ((status & FLASH_SR_BSY) != 0); - - return status & (FLASH_SR_BSY|FLASH_SR_PGERR|FLASH_SR_WRPRTERR); -} - -#define FLASH_PROGRAM_TIMEOUT 0x00010000 -#define FLASH_ERASE_TIMEOUT 0x01000000 - -static int -flash_program_halfword (uint32_t addr, uint16_t data) -{ - int status; - - status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); - - intr_disable (); - if (status == 0) - { - FLASH->CR |= FLASH_CR_PG; - - *(volatile uint16_t *)addr = data; - - status = flash_wait_for_last_operation (FLASH_PROGRAM_TIMEOUT); - FLASH->CR &= ~FLASH_CR_PG; - } - intr_enable (); - - return status; -} - -static int -flash_erase_page (uint32_t addr) -{ - int status; - - status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); - - intr_disable (); - if (status == 0) - { - FLASH->CR |= FLASH_CR_PER; - FLASH->AR = addr; - FLASH->CR |= FLASH_CR_STRT; - - status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); - FLASH->CR &= ~FLASH_CR_PER; - } - intr_enable (); - - return status; -} - -static int -flash_check_blank (const uint8_t *p_start, size_t size) -{ - const uint8_t *p; - - for (p = p_start; p < p_start + size; p++) - if (*p != 0xff) - return 0; - - return 1; -} - -#define FLASH_START_ADDR 0x08000000 /* Fixed for all STM32F0/F1. */ -#define FLASH_OFFSET 0x1000 /* First pages are not-writable - when protected. */ -#if defined(__ARM_ARCH_6M__) -#define FLASH_SIZE_REG ((uint16_t *)0x1ffff7cc) -#define CHIP_ID_REG ((uint32_t *)0x40015800) -#else -#define FLASH_SIZE_REG ((uint16_t *)0x1ffff7e0) -#define CHIP_ID_REG ((uint32_t *)0xe0042000) -#endif -#define FLASH_START (FLASH_START_ADDR+FLASH_OFFSET) - -static int -flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) -{ - int status; - uint32_t flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024; - - if (dst_addr < FLASH_START || dst_addr + len > flash_end) - return 0; - - while (len) - { - uint16_t hw = *src++; - - hw |= (*src++ << 8); - status = flash_program_halfword (dst_addr, hw); - if (status != 0) - return 0; /* error return */ - - dst_addr += 2; - len -= 2; - } - - return 1; -} - -#define OPTION_BYTES_ADDR 0x1ffff800 - -static int -flash_protect (void) -{ - int status; - uint32_t option_bytes_value; - - status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); - - intr_disable (); - if (status == 0) - { - FLASH->OPTKEYR = FLASH_KEY1; - FLASH->OPTKEYR = FLASH_KEY2; - - FLASH->CR |= FLASH_CR_OPTER; - FLASH->CR |= FLASH_CR_STRT; - - status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT); - FLASH->CR &= ~FLASH_CR_OPTER; - } - intr_enable (); - - if (status != 0) - return 0; - - option_bytes_value = *(uint32_t *)OPTION_BYTES_ADDR; - return (option_bytes_value & 0xff) == 0xff ? 1 : 0; -} - -static void __attribute__((naked)) -flash_erase_all_and_exec (void (*entry)(void)) -{ - uint32_t addr = FLASH_START; - uint32_t end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024; - uint32_t page_size = 1024; - int r; - - if (((*CHIP_ID_REG) & 0xfff) == 0x0414) - page_size = 2048; - - while (addr < end) - { - r = flash_erase_page (addr); - if (r != 0) - break; - - addr += page_size; - } - - if (addr >= end) - (*entry) (); - - for (;;); -} - -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]; -}; - -#define SCS_BASE (0xE000E000) -#define SCB_BASE (SCS_BASE + 0x0D00) -static struct SCB *const SCB = ((struct SCB *const) SCB_BASE); - -#define SYSRESETREQ 0x04 -static void -nvic_system_reset (void) -{ - SCB->AIRCR = (0x05FA0000 | (SCB->AIRCR & 0x70) | SYSRESETREQ); - asm volatile ("dsb"); - for (;;); -} - -static void __attribute__ ((naked)) -reset (void) -{ - /* - * This code may not be at the start of flash ROM, because of DFU. - * So, we take the address from PC. - */ -#if defined(__ARM_ARCH_6M__) - asm volatile ("cpsid i\n\t" /* Mask all interrupts. */ - "ldr r0, 1f\n\t" /* r0 = RAM start */ - "mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */ - "mov r2, #0x10\n\t" - "lsl r2, #8\n\t" - "add r1, r1, r2\n\t" - "sub r2, r2, #1\n\t" - "bic r1, r1, r2\n\t" - "mov r2, #188\n" - "2:\n\t" /* Copy vectors. It will be enabled later by clock_init. */ - "ldr r3, [r1, r2]\n\t" - "str r3, [r0, r2]\n\t" - "sub r2, #4\n\t" - "bcs 2b\n\t" - "msr MSP, r3\n\t" /* Main (exception handler) stack. */ - "ldr r0, [r1, #4]\n\t" /* Reset handler. */ - "bx r0\n\t" - ".align 2\n" - "1: .word 0x20000000" - : /* no output */ : /* no input */ : "memory"); -#else - extern const uint32_t FT0[256], FT1[256], FT2[256]; - asm volatile ("cpsid i\n\t" /* Mask all interrupts. */ - "ldr r0, 1f\n\t" /* r0 = SCR */ - "mov r1, pc\n\t" /* r1 = (PC + 0x1000) & ~0x0fff */ - "mov r2, #0x1000\n\t" - "add r1, r1, r2\n\t" - "sub r2, r2, #1\n\t" - "bic r1, r1, r2\n\t" - "str r1, [r0, #8]\n\t" /* Set SCR->VCR */ - "ldr r0, [r1], #4\n\t" - "msr MSP, r0\n\t" /* Main (exception handler) stack. */ - "ldr r0, [r1]\n\t" /* Reset handler. */ - "bx r0\n\t" - ".align 2\n" - "1: .word 0xe000ed00" - : /* no output */ : /* no input */ : "memory"); - /* Artificial entry to refer FT0, FT1, and FT2. */ - asm volatile ("" - : : "r" (FT0), "r" (FT1), "r" (FT2)); -#endif - /* Never reach here. */ -} - -typedef void (*handler)(void); -extern uint8_t __ram_end__; - -handler vector[] __attribute__ ((section(".vectors"))) = { - (handler)&__ram_end__, - reset, - (handler)set_led, - flash_unlock, - (handler)flash_program_halfword, - (handler)flash_erase_page, - (handler)flash_check_blank, - (handler)flash_write, - (handler)flash_protect, - (handler)flash_erase_all_and_exec, - usb_lld_sys_init, - usb_lld_sys_shutdown, - nvic_system_reset, - clock_init, - gpio_init, - NULL, -}; - -const uint8_t sys_version[8] __attribute__((section(".sys.version"))) = { - 3*2+2, /* bLength */ - 0x03, /* bDescriptorType = USB_STRING_DESCRIPTOR_TYPE */ - /* sys version: "3.0" */ - '3', 0, '.', 0, '0', 0, -}; - -const uint32_t __attribute__((section(".sys.board_id"))) -sys_board_id = BOARD_ID; - -const uint8_t __attribute__((section(".sys.board_name"))) -sys_board_name[] = BOARD_NAME; diff --git a/mcu/sys-stm32f030.h b/mcu/sys-stm32f030.h deleted file mode 100644 index ddd83af..0000000 --- a/mcu/sys-stm32f030.h +++ /dev/null @@ -1,130 +0,0 @@ -#if defined(__ARM_ARCH_6M__) -#define BOARD_ID_STM32F0_DISCOVERY 0xde4b4bc1 -#define BOARD_ID_FSM_55 0x83433c76 -#else -#define BOARD_ID_CQ_STARM 0xc5480875 -#define BOARD_ID_FST_01_00 0x613870a9 -#define BOARD_ID_FST_01 0x696886af -#define BOARD_ID_MAPLE_MINI 0x7a445272 -#define BOARD_ID_OLIMEX_STM32_H103 0xf92bb594 -#define BOARD_ID_STBEE_MINI 0x1f341961 -#define BOARD_ID_STBEE 0x945c37e8 -#define BOARD_ID_STM32_PRIMER2 0x21e5798d -#define BOARD_ID_STM8S_DISCOVERY 0x2f0976bb -#define BOARD_ID_ST_DONGLE 0x2cd4e471 -#define BOARD_ID_ST_NUCLEO_F103 0x9b87c16d -#endif - -extern const uint8_t sys_version[8]; -extern const uint32_t sys_board_id; -extern const uint8_t sys_board_name[]; - -typedef void (*handler)(void); -extern handler vector[16]; - -static inline const uint8_t * -unique_device_id (void) -{ - /* STM32F103 has 96-bit unique device identifier */ - const uint8_t *addr = (const uint8_t *)0x1ffff7e8; - - return addr; -} - -static inline void -set_led (int on) -{ - void (*func) (int) = (void (*)(int))vector[2]; - - return (*func) (on); -} - -static inline void -flash_unlock (void) -{ - (*vector[3]) (); -} - -static inline int -flash_program_halfword (uint32_t addr, uint16_t data) -{ - int (*func) (uint32_t, uint16_t) = (int (*)(uint32_t, uint16_t))vector[4]; - - return (*func) (addr, data); -} - -static inline int -flash_erase_page (uint32_t addr) -{ - int (*func) (uint32_t) = (int (*)(uint32_t))vector[5]; - - return (*func) (addr); -} - -static inline int -flash_check_blank (const uint8_t *p_start, size_t size) -{ - int (*func) (const uint8_t *, int) = (int (*)(const uint8_t *, int))vector[6]; - - return (*func) (p_start, size); -} - -static inline int -flash_write (uint32_t dst_addr, const uint8_t *src, size_t len) -{ - int (*func) (uint32_t, const uint8_t *, size_t) - = (int (*)(uint32_t, const uint8_t *, size_t))vector[7]; - - return (*func) (dst_addr, src, len); -} - -static inline int -flash_protect (void) -{ - int (*func) (void) = (int (*)(void))vector[8]; - - return (*func) (); -} - -static inline void __attribute__((noreturn)) -flash_erase_all_and_exec (void (*entry)(void)) -{ - void (*func) (void (*)(void)) = (void (*)(void (*)(void)))vector[9]; - - (*func) (entry); - for (;;); -} - -static inline void -usb_lld_sys_init (void) -{ - (*vector[10]) (); -} - -static inline void -usb_lld_sys_shutdown (void) -{ - (*vector[11]) (); -} - -static inline void -nvic_system_reset (void) -{ - (*vector[12]) (); -} - -#ifdef REQUIRE_CLOCK_GPIO_SETTING_IN_SYS -/* Provide the function entries. */ - -static void __attribute__ ((used)) -clock_init (void) -{ - (*vector[13]) (); -} - -static void __attribute__ ((used)) -gpio_init (void) -{ - (*vector[14]) (); -} -#endif diff --git a/rules.mk b/rules.mk index 0034a4f..3619bf8 100644 --- a/rules.mk +++ b/rules.mk @@ -13,7 +13,7 @@ ifneq ($(USE_USB),) CSRC += $(CHOPSTX)/mcu/usb-$(CHIP).c endif ifneq ($(USE_ADC),) -CSRC += $(CHOPSTX)/mcu/adc-$(CHIP).c +CSRC += $(CHOPSTX)/contrib/adc-$(CHIP).c endif INCDIR += $(CHOPSTX) diff --git a/sys.h b/sys.h index 0b65b29..a546371 100644 --- a/sys.h +++ b/sys.h @@ -1,5 +1,7 @@ -#ifdef MCU_KINETIS_L +#if defined(MCU_KINETIS_L) #include "mcu/sys-mkl27z.h" +#elif defined(MCU_STM32F0) +#include "mcu/sys-stm32f0.h" #else #include "mcu/sys-stm32f103.h" #endif -- cgit v1.2.3