├── include
├── ADC_conf.h
├── UART_conf.h
├── timer_conf.h
├── main.h
├── stm32f4xx_it.h
└── stm32f4xx_conf.h
├── README.md
├── .gitignore
├── platformio.ini
└── src
├── ADC_conf.c
├── UART_conf.c
├── stm32f4xx_it.c
├── main.c
├── timer_conf.c
└── system_stm32f4xx.c
/include/ADC_conf.h:
--------------------------------------------------------------------------------
1 |
2 | void ADC1_conf(void);
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tcd1304-advanced
2 | Customized firmware for a LIBS setup, see https://github.com/g3gg0/SpectrumPlotter
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/include/UART_conf.h:
--------------------------------------------------------------------------------
1 | void USART2_conf(void);
2 | void UART2_Tx_DMA(void);
3 | void UART2_SendData(uint8_t *data, uint32_t length);
4 | void sort_aRxBuffer(void);
5 |
--------------------------------------------------------------------------------
/include/timer_conf.h:
--------------------------------------------------------------------------------
1 | void get_Timer_clocks(void);
2 | void TIM_CCD_fM_conf(void);
3 | void TIM_ADC_conf(void);
4 | void TIM_ICG_SH_conf(void);
5 | void TIM_ICG_SH_start(void);
6 | void TIM_ICG_SH_stop(void);
7 |
--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:nucleo_f411re]
12 | platform = ststm32
13 | board = nucleo_f401re
14 | framework = spl
15 | build_flags = -DHSE_VALUE=8000000
16 |
17 | [platformio]
18 | description = Firmware for the STM32F401RE Nucleo with TCD1304, based on https://tcd1304.wordpress.com/the-firmware/ adding remote triggering
19 |
--------------------------------------------------------------------------------
/include/main.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINH
2 | #define MAINH
3 |
4 | #include "stm32f4xx.h"
5 |
6 | /* Data definitions */
7 | #define CCDSize 3694
8 | #define RxDataSize 12
9 |
10 | /* CCD master clock in Hz */
11 | /* The values presented here are the prescalable frequencies between
12 | 1-2MHz with the STM32F401RE running at 84 MHz. Other frequencies
13 | are achievable when prescaling APB1 differently. 1 MHz does not
14 | seem to work well. */
15 | //#define CCD_fm 1000000
16 | //#define CCD_fm 1400000
17 | //#define CCD_fm 1500000
18 | //define CCD_fm 1680000
19 | //#define CCD_fm 1750000
20 | #define CCD_fm 2000000
21 |
22 | /* Comply with the CCD's timing requirements:
23 | The delay is dependent on the CCD_fM. These values appear to work:
24 | For 1.4-2.0 MHz use: ICG_delay = 11 and SH_delay = 12
25 | For 1.0 MHz use: ICG_delay = 12 and SH_delay = 12 */
26 | #define SH_delay 12
27 | #define ICG_delay 11
28 | #define fm_delay 3
29 |
30 |
31 |
32 | /* UART definitions */
33 | #define BAUDRATE 500000
34 |
35 |
36 | #include "stm32f4xx_it.h"
37 | #include "timer_conf.h"
38 | #include "ADC_conf.h"
39 | #include "UART_conf.h"
40 |
41 | void trigger_fired();
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/include/stm32f4xx_it.h:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file NVIC/NVIC_IRQMask/stm32f4xx_it.h
4 | * @author MCD Application Team
5 | * @version V1.5.0
6 | * @date 06-March-2015
7 | * @brief This file contains the headers of the interrupt handlers.
8 | ******************************************************************************
9 | * @attention
10 | *
11 | *
© COPYRIGHT 2015 STMicroelectronics
12 | *
13 | * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
14 | * You may not use this file except in compliance with the License.
15 | * You may obtain a copy of the License at:
16 | *
17 | * http://www.st.com/software_license_agreement_liberty_v2
18 | *
19 | * Unless required by applicable law or agreed to in writing, software
20 | * distributed under the License is distributed on an "AS IS" BASIS,
21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 | * See the License for the specific language governing permissions and
23 | * limitations under the License.
24 | *
25 | ******************************************************************************
26 | */
27 |
28 | /* Define to prevent recursive inclusion -------------------------------------*/
29 | #ifndef __STM32F4xx_IT_H
30 | #define __STM32F4xx_IT_H
31 |
32 | #ifdef __cplusplus
33 | extern "C" {
34 | #endif
35 |
36 | /* Includes ------------------------------------------------------------------*/
37 | #include "stm32f4xx.h"
38 |
39 | /* Exported types ------------------------------------------------------------*/
40 | /* Exported constants --------------------------------------------------------*/
41 | /* Exported macro ------------------------------------------------------------*/
42 | /* Exported functions ------------------------------------------------------- */
43 |
44 | void NMI_Handler(void);
45 | void HardFault_Handler(void);
46 | void MemManage_Handler(void);
47 | void BusFault_Handler(void);
48 | void UsageFault_Handler(void);
49 | void SVC_Handler(void);
50 | void DebugMon_Handler(void);
51 | void PendSV_Handler(void);
52 | void SysTick_Handler(void);
53 |
54 | void DMA1_Stream5_IRQHandler(void);
55 | void DMA2_Stream0_IRQHandler(void);
56 | void TIM5_IRQHandler(void);
57 |
58 | #ifdef __cplusplus
59 | }
60 | #endif
61 |
62 | #endif /* __STM32F4xx_IT_H */
63 |
64 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
65 |
--------------------------------------------------------------------------------
/include/stm32f4xx_conf.h:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file TIM/TIM_7PWMOutput/stm32f4xx_conf.h
4 | * @author MCD Application Team
5 | * @version V1.5.0
6 | * @date 06-March-2015
7 | * @brief Library configuration file.
8 | ******************************************************************************
9 | * @attention
10 | *
11 | * © COPYRIGHT 2015 STMicroelectronics
12 | *
13 | * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
14 | * You may not use this file except in compliance with the License.
15 | * You may obtain a copy of the License at:
16 | *
17 | * http://www.st.com/software_license_agreement_liberty_v2
18 | *
19 | * Unless required by applicable law or agreed to in writing, software
20 | * distributed under the License is distributed on an "AS IS" BASIS,
21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 | * See the License for the specific language governing permissions and
23 | * limitations under the License.
24 | *
25 | ******************************************************************************
26 | */
27 |
28 | /* Define to prevent recursive inclusion -------------------------------------*/
29 | #ifndef __STM32F4xx_CONF_H
30 | #define __STM32F4xx_CONF_H
31 |
32 | /* Includes ------------------------------------------------------------------*/
33 | /* Uncomment the line below to enable peripheral header file inclusion */
34 | #include "stm32f4xx_adc.h"
35 | #include "stm32f4xx_crc.h"
36 | #include "stm32f4xx_dbgmcu.h"
37 | #include "stm32f4xx_dma.h"
38 | #include "stm32f4xx_exti.h"
39 | #include "stm32f4xx_flash.h"
40 | #include "stm32f4xx_gpio.h"
41 | #include "stm32f4xx_i2c.h"
42 | #include "stm32f4xx_iwdg.h"
43 | #include "stm32f4xx_pwr.h"
44 | #include "stm32f4xx_rcc.h"
45 | #include "stm32f4xx_rtc.h"
46 | #include "stm32f4xx_sdio.h"
47 | #include "stm32f4xx_spi.h"
48 | #include "stm32f4xx_syscfg.h"
49 | #include "stm32f4xx_tim.h"
50 | #include "stm32f4xx_usart.h"
51 | #include "stm32f4xx_wwdg.h"
52 | #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
53 |
54 | #if defined (STM32F429_439xx)
55 | #include "stm32f4xx_cryp.h"
56 | #include "stm32f4xx_hash.h"
57 | #include "stm32f4xx_rng.h"
58 | #include "stm32f4xx_can.h"
59 | #include "stm32f4xx_dac.h"
60 | #include "stm32f4xx_dcmi.h"
61 | #include "stm32f4xx_dma2d.h"
62 | #include "stm32f4xx_fmc.h"
63 | #include "stm32f4xx_ltdc.h"
64 | #include "stm32f4xx_sai.h"
65 | #endif /* STM32F429_439xx */
66 |
67 | #if defined (STM32F427_437xx)
68 | #include "stm32f4xx_cryp.h"
69 | #include "stm32f4xx_hash.h"
70 | #include "stm32f4xx_rng.h"
71 | #include "stm32f4xx_can.h"
72 | #include "stm32f4xx_dac.h"
73 | #include "stm32f4xx_dcmi.h"
74 | #include "stm32f4xx_dma2d.h"
75 | #include "stm32f4xx_fmc.h"
76 | #include "stm32f4xx_sai.h"
77 | #endif /* STM32F427_437xx */
78 |
79 | #if defined (STM32F40_41xxx)
80 | #include "stm32f4xx_cryp.h"
81 | #include "stm32f4xx_hash.h"
82 | #include "stm32f4xx_rng.h"
83 | #include "stm32f4xx_can.h"
84 | #include "stm32f4xx_dac.h"
85 | #include "stm32f4xx_dcmi.h"
86 | #include "stm32f4xx_fsmc.h"
87 | #endif /* STM32F40_41xxx */
88 |
89 | /* Exported types ------------------------------------------------------------*/
90 | /* Exported constants --------------------------------------------------------*/
91 |
92 | /* If an external clock source is used, then the value of the following define
93 | should be set to the value of the external clock source, else, if no external
94 | clock is used, keep this define commented */
95 | /*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
96 |
97 |
98 | /* Uncomment the line below to expanse the "assert_param" macro in the
99 | Standard Peripheral Library drivers code */
100 | /* #define USE_FULL_ASSERT 1 */
101 |
102 | /* Exported macro ------------------------------------------------------------*/
103 | #ifdef USE_FULL_ASSERT
104 |
105 | /**
106 | * @brief The assert_param macro is used for function's parameters check.
107 | * @param expr: If expr is false, it calls assert_failed function
108 | * which reports the name of the source file and the source
109 | * line number of the call that failed.
110 | * If expr is true, it returns no value.
111 | * @retval None
112 | */
113 | #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
114 | /* Exported functions ------------------------------------------------------- */
115 | void assert_failed(uint8_t* file, uint32_t line);
116 | #else
117 | #define assert_param(expr) ((void)0)
118 | #endif /* USE_FULL_ASSERT */
119 |
120 | #endif /* __STM32F4xx_CONF_H */
121 |
122 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
123 |
--------------------------------------------------------------------------------
/src/ADC_conf.c:
--------------------------------------------------------------------------------
1 | /*-
2 | * Copyright (c) 2017 Esben Rossel
3 | * All rights reserved.
4 | *
5 | * Author: Esben Rossel
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | *
28 | */
29 |
30 |
31 | #include "main.h"
32 |
33 | extern __IO uint16_t aTxBuffer[CCDSize];
34 |
35 |
36 | /* ADC1 - Input on Ch10 (PC0) - Triggered by TIM4 Ch4 - DMA2 Ch0 Stream0 */
37 | void ADC1_conf()
38 | {
39 | ADC_InitTypeDef ADC_InitStructure;
40 | ADC_CommonInitTypeDef ADC_CommonInitStructure;
41 | DMA_InitTypeDef DMA_InitStructure;
42 | GPIO_InitTypeDef GPIO_InitStructure;
43 |
44 | /* Clock DMA2 and ADC1 */
45 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
46 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
47 |
48 | DMA_InitStructure.DMA_Channel = DMA_Channel_0;
49 | DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
50 | DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aTxBuffer;
51 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
52 | DMA_InitStructure.DMA_BufferSize = CCDSize;
53 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
54 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
55 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
56 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
57 | DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
58 | DMA_InitStructure.DMA_Priority = DMA_Priority_High;
59 | DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
60 | DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
61 | DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
62 | DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
63 | DMA_Init(DMA2_Stream0, &DMA_InitStructure);
64 | DMA_Cmd(DMA2_Stream0, ENABLE);
65 |
66 | /* DMA2 interrupt configuration */
67 | // DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
68 | DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
69 |
70 | /* Configure ADC1 Channel10 pin (PC0) as analog input */
71 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
72 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
73 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
74 | GPIO_Init(GPIOC, &GPIO_InitStructure);
75 |
76 | /* ADC1 Init */
77 | ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
78 | ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
79 | ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
80 | ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
81 | ADC_CommonInit(&ADC_CommonInitStructure);
82 |
83 | /* ADC1 Init - TIM4 Ch4 is used as external trigger */
84 | ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
85 | ADC_InitStructure.ADC_ScanConvMode = DISABLE;
86 | ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
87 | ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
88 | ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4;
89 | ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
90 | ADC_InitStructure.ADC_NbrOfConversion = 1;
91 | ADC_Init(ADC1, &ADC_InitStructure);
92 |
93 | ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles);
94 |
95 | /* Enable DMA request after last transfer (Single-ADC mode) */
96 | ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
97 |
98 | /* Enable ADC1 DMA */
99 | ADC_DMACmd(ADC1, ENABLE);
100 |
101 | /* Enable ADC1 */
102 | ADC_Cmd(ADC1, ENABLE);
103 | }
104 |
105 |
106 | /* TIM3 (fM) and TIM4 (ADC-clock) are not in phase. If you suspect the ADC is
107 | reading across two pixels, try and increase TIM5 pulse with 1. This will
108 | shift the pixel readings one period in relation to fM (and 1/4 of a period of
109 | the ADC-clock). */
110 |
111 | /* Since the pixel values come out at CCD_fM / 4 the maximum time the ADC has for
112 | each conversion is (with CCD_fM = 2.0 MHz):
113 | t_pix = (0.50 MHz)⁻¹ = 2.0 µs
114 | The ADC runs with a typical speed of 30 MHz, so each cycle takes:
115 | t_ac = (30 MHz)⁻¹ = 33 ns
116 | With a resolution of 12 bit the conversion time is:
117 | t_c = 12·33 ns = 0.40 µs
118 | This gives 1.6 µs for sampling each pixel, which in ADC clock cycles is:
119 | 1.6 µs / 33 ns = 48
120 |
121 | The available sampling times are:
122 | 3, 15, 28, 56, 84, 112, 144 and 480 clock cycles.
123 |
124 | So 28 is the longest possible sampletime. */
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/UART_conf.c:
--------------------------------------------------------------------------------
1 | /*-
2 | * Copyright (c) 2017 Esben Rossel
3 | * All rights reserved.
4 | *
5 | * Author: Esben Rossel
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | *
28 | */
29 |
30 | #include "main.h"
31 |
32 | extern volatile uint8_t aCmdTxBuffer[];
33 | extern __IO uint16_t aTxBuffer[CCDSize];
34 | extern __IO uint8_t aRxBuffer[RxDataSize];
35 | extern __IO uint8_t nRxBuffer[RxDataSize];
36 |
37 | /* USART2 is connected on PA2 / PA3 - DMA1 Ch4 Stream 5/6 */
38 | void USART2_conf()
39 | {
40 | USART_InitTypeDef USART_InitStructure;
41 | GPIO_InitTypeDef GPIO_InitStructure;
42 | DMA_InitTypeDef DMA_InitStructure;
43 |
44 | /* Enable USART & DMA clocks */
45 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
46 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
47 |
48 | /* Use PA2 and PA3 */
49 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
50 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
51 |
52 | /* Configure USART Tx and Rx as alternate function push-pull */
53 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
54 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; // 100 MHz?
55 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
56 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
57 |
58 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
59 | GPIO_Init(GPIOA, &GPIO_InitStructure);
60 |
61 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
62 | GPIO_Init(GPIOA, &GPIO_InitStructure);
63 |
64 | /* Configure USART2 - 115.2 kbps */
65 | // USART_OverSampling8Cmd(USARTx, ENABLE);
66 | USART_InitStructure.USART_BaudRate = BAUDRATE;
67 | USART_InitStructure.USART_WordLength = USART_WordLength_8b;
68 | USART_InitStructure.USART_StopBits = USART_StopBits_1;
69 | /* When using Parity the word length must be configured to 9 bits */
70 | USART_InitStructure.USART_Parity = USART_Parity_No;
71 | USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
72 | USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
73 | USART_Init(USART2, &USART_InitStructure);
74 |
75 | /* Configure DMA - common for Rx/Tx */
76 | DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
77 | DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
78 | DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
79 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
80 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
81 | DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(USART2->DR));
82 | DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
83 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
84 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
85 | DMA_InitStructure.DMA_Priority = DMA_Priority_High;
86 |
87 | /* Configure RX DMA */
88 | DMA_InitStructure.DMA_BufferSize = RxDataSize;
89 | DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Listen continously
90 | DMA_InitStructure.DMA_Channel = DMA_Channel_4;
91 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
92 | DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aRxBuffer;
93 | DMA_Init(DMA1_Stream5, &DMA_InitStructure);
94 |
95 | /* DMA1 Rx interrupt configuration */
96 | DMA_ITConfig(DMA1_Stream5, DMA_IT_TC, ENABLE);
97 |
98 | /* Configure TX DMA */
99 | DMA_InitStructure.DMA_BufferSize = 2 * CCDSize; // The data is 16-bit, but UART is 8-bit
100 | DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
101 | DMA_InitStructure.DMA_Channel = DMA_Channel_4;
102 | DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
103 | DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aTxBuffer;
104 | DMA_Init(DMA1_Stream6, &DMA_InitStructure);
105 |
106 | /* Enable USART */
107 | USART_Cmd(USART2, ENABLE);
108 |
109 |
110 | /* Enable Rx DMA stream */
111 | DMA_Cmd(DMA1_Stream5, ENABLE);
112 | USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
113 | }
114 |
115 | void UART2_SendData(uint8_t *data, uint32_t length)
116 | {
117 | DMA_SetCurrDataCounter(DMA1_Stream6, length);
118 | DMA_MemoryTargetConfig(DMA1_Stream6, data, DMA_Memory_0);
119 |
120 | /* Enable DMA stream */
121 | DMA_Cmd(DMA1_Stream6, ENABLE);
122 | USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
123 |
124 | /* Wait for transmission to complete */
125 | while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
126 | {
127 | }
128 | while (DMA_GetFlagStatus(DMA1_Stream6, DMA_FLAG_TCIF6) == RESET)
129 | {
130 | }
131 |
132 | /* Clear DMA Transfer Complete Flags */
133 | DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6);
134 | /* Clear USART Transfer Complete Flags */
135 | USART_ClearFlag(USART2, USART_FLAG_TC);
136 | }
137 |
138 | void UART2_Tx_DMA(void)
139 | {
140 | DMA_SetCurrDataCounter(DMA1_Stream6, 2 * CCDSize);
141 | DMA_MemoryTargetConfig(DMA1_Stream6, aTxBuffer, DMA_Memory_0);
142 |
143 | /* Notice that UART is 8-bit. The 12-bit data from the ADC
144 | is stored in a 16-bit array and sent 8-bit at a time. This
145 | causes an endianness-like problem on the receiving side eg:
146 | the uint16 0x0102 is received as 0x02 0x01
147 | This must be handled on the receiving side with
148 | proper_data[i] = (unsigned int)Rx_data[i+1] << 8 | Rx_data[i]; */
149 |
150 | /* Transmit 1x */
151 |
152 | /* Enable DMA stream */
153 | DMA_Cmd(DMA1_Stream6, ENABLE);
154 | USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
155 |
156 | /* Wait for transmission to complete */
157 | while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
158 | {
159 | }
160 | while (DMA_GetFlagStatus(DMA1_Stream6, DMA_FLAG_TCIF6) == RESET)
161 | {
162 | }
163 |
164 | /* Clear DMA Transfer Complete Flags */
165 | DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6);
166 | /* Clear USART Transfer Complete Flags */
167 | USART_ClearFlag(USART2, USART_FLAG_TC);
168 | }
169 |
170 | void sort_aRxBuffer()
171 | {
172 | int shift = -1;
173 | int i = 0;
174 |
175 | /* Examine for byte-shifts in aRxBuffer */
176 | for (i = 0; i < RxDataSize; i++)
177 | {
178 | if ((aRxBuffer[i] == 69) && (aRxBuffer[i + 1] == 82))
179 | shift = i;
180 | }
181 | if ((aRxBuffer[RxDataSize - 1] == 69) && (aRxBuffer[0] == 82))
182 | shift = RxDataSize - 1;
183 |
184 | /* If necessary permutate data */
185 | if (shift != -1)
186 | {
187 | for (i = 0; i < RxDataSize - shift; i++)
188 | nRxBuffer[i] = aRxBuffer[shift + i];
189 | for (i = 0; i < shift; i++)
190 | nRxBuffer[RxDataSize - shift + i] = aRxBuffer[i];
191 | }
192 |
193 | /* Clear aRxBuffer */
194 | for (i = 0; i < RxDataSize; i++)
195 | {
196 | aRxBuffer[i] = 0;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/stm32f4xx_it.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | #include "main.h"
5 |
6 | extern __IO uint32_t SH_period;
7 | extern __IO uint32_t ICG_period;
8 | extern __IO uint16_t aTxBuffer[CCDSize];
9 | extern __IO uint8_t aRxBuffer[RxDataSize];
10 | extern __IO uint8_t nRxBuffer[RxDataSize];
11 |
12 | extern __IO uint8_t change_exposure_flag;
13 | extern __IO uint8_t data_flag;
14 | extern __IO uint8_t pulse_counter;
15 | extern __IO uint8_t CCD_flushed;
16 | extern __IO uint8_t avg_exps;
17 | extern __IO uint8_t exps_left;
18 | extern __IO uint8_t coll_mode;
19 |
20 | /**
21 | * @brief This function handles NMI exception.
22 | * @param None
23 | * @retval None
24 | */
25 | void NMI_Handler(void)
26 | {
27 | }
28 |
29 | /**
30 | * @brief This function handles Hard Fault exception.
31 | * @param None
32 | * @retval None
33 | */
34 | void HardFault_Handler(void)
35 | {
36 | /* Go to infinite loop when Hard Fault exception occurs */
37 | while (1)
38 | {
39 | }
40 | }
41 |
42 | /**
43 | * @brief This function handles Memory Manage exception.
44 | * @param None
45 | * @retval None
46 | */
47 | void MemManage_Handler(void)
48 | {
49 | /* Go to infinite loop when Memory Manage exception occurs */
50 | while (1)
51 | {
52 | }
53 | }
54 |
55 | /**
56 | * @brief This function handles Bus Fault exception.
57 | * @param None
58 | * @retval None
59 | */
60 | void BusFault_Handler(void)
61 | {
62 | /* Go to infinite loop when Bus Fault exception occurs */
63 | while (1)
64 | {
65 | }
66 | }
67 |
68 | /**
69 | * @brief This function handles Usage Fault exception.
70 | * @param None
71 | * @retval None
72 | */
73 | void UsageFault_Handler(void)
74 | {
75 | /* Go to infinite loop when Usage Fault exception occurs */
76 | while (1)
77 | {
78 | }
79 | }
80 |
81 | /**
82 | * @brief This function handles SVCall exception.
83 | * @param None
84 | * @retval None
85 | */
86 | void SVC_Handler(void)
87 | {
88 | }
89 |
90 | /**
91 | * @brief This function handles Debug Monitor exception.
92 | * @param None
93 | * @retval None
94 | */
95 | void DebugMon_Handler(void)
96 | {
97 | }
98 |
99 | /**
100 | * @brief This function handles PendSVC exception.
101 | * @param None
102 | * @retval None
103 | */
104 | void PendSV_Handler(void)
105 | {
106 | }
107 |
108 | /**
109 | * @brief This function handles SysTick Handler.
110 | * @param None
111 | * @retval None
112 | */
113 | void SysTick_Handler(void)
114 | {
115 | }
116 |
117 | /******************************************************************************/
118 | /* STM32F4xx Peripherals Interrupt Handlers */
119 | /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
120 | /* available peripheral interrupt handler's name please refer to the startup */
121 | /* file (startup_stm32f40xx.s/startup_stm32f427x.s). */
122 | /******************************************************************************/
123 |
124 | /* This interrupt is invoked when UART-reception is completed */
125 | void DMA1_Stream5_IRQHandler(void)
126 | {
127 | if (DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5))
128 | {
129 | /* Clear DMA Stream Transfer Complete interrupt */
130 | DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
131 |
132 | /* Wait a short while - to let DMA finish ..or something */
133 | for (int i = 0; i < 8400; i++)
134 | {
135 | }
136 |
137 | /* Sort aRxBuffer into nRxBuffer */
138 | sort_aRxBuffer();
139 |
140 | /* Check the key before doing anything */
141 | if ((nRxBuffer[0] == 69) && (nRxBuffer[1] == 82))
142 | {
143 | /* reset the key */
144 | nRxBuffer[0] = 0;
145 | nRxBuffer[1] = 0;
146 |
147 | if (nRxBuffer[10] == 2)
148 | {
149 | extern __IO uint32_t trigger_delay;
150 | extern __IO uint8_t trigger_level;
151 |
152 | trigger_delay = (nRxBuffer[4] << 8) | nRxBuffer[5];
153 |
154 | if(nRxBuffer[6] == 0xFF)
155 | {
156 | UART2_SendData("[g3gg0.de]", 10);
157 | }
158 | else
159 | {
160 | trigger_level = nRxBuffer[6];
161 | }
162 | }
163 | else
164 | {
165 | /* set flags for main-loop */
166 | change_exposure_flag = 1;
167 | data_flag = 0;
168 |
169 | /* disable averaging by default */
170 | avg_exps = 1;
171 |
172 | /* continous or one-shot mode? */
173 | coll_mode = nRxBuffer[10];
174 |
175 | /* check if user averaging-request is valid */
176 | if ((nRxBuffer[11] < 16) && (nRxBuffer[11] > 0))
177 | {
178 | avg_exps = nRxBuffer[11];
179 | }
180 |
181 | exps_left = avg_exps;
182 | }
183 | }
184 | }
185 | }
186 |
187 | /* This interrupt is invoked when the ADC has finished reading the CCD.
188 | The function's two tasks is to:
189 | 1) Disable TIM4
190 | 2) Set the appropiate value for the data_flag:
191 | 1: Send data back immediately after 1st integration
192 | 2: Overwrite avgBuffer with the latest integration
193 | 3: Add the latest integration to avgBuffer
194 | 4: Calculate the averaged integration and transmit the result */
195 | void DMA2_Stream0_IRQHandler(void)
196 | {
197 | /* Test for DMA Stream Transfer Complete interrupt */
198 | if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
199 | {
200 | /* Clear DMA Stream Transfer Complete interrupt pending bit */
201 | DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
202 |
203 | /* Stop TIM4 and thus the ADC */
204 | TIM4->CR1 &= (uint16_t)~TIM_CR1_CEN;
205 |
206 | /* Keep track of the number of integrations performed */
207 | /* Are we collecting just once? */
208 | if (avg_exps == 1)
209 | {
210 | /* Set the data_flag to transmit */
211 | data_flag = 1;
212 | }
213 | else if (avg_exps > 1)
214 | {
215 | /* Is this the first collection of several? */
216 | if (exps_left == avg_exps)
217 | {
218 | // exps_left--;
219 | /* Set the pulse counter to 6 to start the ADC again
220 | at next ICG-pulse. */
221 | pulse_counter = 6;
222 | /* Set the data_flag to overwrite avgBuffer */
223 | data_flag = 2;
224 | }
225 |
226 | /* Is this a collection in the middle? */
227 | else if ((exps_left < avg_exps) && (exps_left > 1))
228 | {
229 | // exps_left--;
230 | /* Set the pulse counter to 6 to start the ADC again
231 | at next ICG-pulse. */
232 | pulse_counter = 6;
233 | /* Set the data_flag to sum integrations */
234 | data_flag = 3;
235 | }
236 |
237 | /* Is this the last collection of several? */
238 | else if (exps_left == 1)
239 | {
240 | // exps_left--;
241 | /* Set the data_flag to average integrations and tx */
242 | data_flag = 4;
243 | }
244 | exps_left--;
245 | }
246 | }
247 | }
248 |
249 | /* This interrupt is invoked when the ICG-pulse is sent,
250 | ie. when the CCD starts to output.
251 |
252 | At the 3rd pulse the CCD has been flushed.
253 | At the 6th pulse the CCD has been collecting once
254 | for the desired integration time.
255 |
256 | The pulse counter is (re)set to 6 by the DMA2-TC interrupt
257 | if more than one integration has been requested. */
258 | void TIM5_IRQHandler(void)
259 | {
260 | if (TIM_GetITStatus(TIM5, TIM_IT_Update))
261 | {
262 | /* Clear TIM5 update interrupt */
263 | TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
264 | if (pulse_counter == 6)
265 | {
266 | /* Restart TIM4 as this gets the ADC running again */
267 | TIM4->CR1 |= TIM_CR1_CEN;
268 | }
269 | else if (pulse_counter == 3)
270 | {
271 | CCD_flushed = 1;
272 | }
273 |
274 | pulse_counter++;
275 |
276 | /* prevent overflow */
277 | if (pulse_counter > 32)
278 | pulse_counter = 32;
279 |
280 | /* Flash the led to the beat of ICG */
281 | GPIOA->ODR ^= GPIO_Pin_5;
282 | }
283 | }
284 |
285 | void EXTI15_10_IRQHandler(void)
286 | {
287 | /* Make sure that interrupt flag is set */
288 | if (EXTI_GetITStatus(EXTI_Line13) != RESET)
289 | {
290 | trigger_fired();
291 | /* Clear interrupt flag */
292 | EXTI_ClearITPendingBit(EXTI_Line13);
293 | }
294 | }
295 |
296 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | /*-
2 | * Copyright (c) 2017 Esben Rossel
3 | * All rights reserved.
4 | *
5 | * Author: Esben Rossel
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | *
28 | */
29 |
30 |
31 | #include "main.h"
32 |
33 | void virtual_GND(void);
34 | void flush_CCD(void);
35 | void NVIC_conf(void);
36 |
37 |
38 | __IO uint8_t sampling_requested = 0;
39 | __IO uint8_t sampling_active = 0;
40 |
41 | __IO uint32_t trigger_delay = 0;
42 | __IO uint8_t trigger_level = 0;
43 | __IO uint32_t SH_period = 20;
44 | __IO uint32_t ICG_period = 500000;
45 | __IO uint8_t aCmdTxBuffer[32];
46 | __IO uint16_t aTxBuffer[CCDSize];
47 | __IO uint16_t avgBuffer[CCDSize] = {0};
48 | __IO uint8_t aRxBuffer[RxDataSize] = {0};
49 | __IO uint8_t nRxBuffer[RxDataSize] = {0};
50 |
51 | __IO uint8_t change_exposure_flag = 0;
52 | __IO uint8_t data_flag = 0;
53 | __IO uint8_t pulse_counter = 0;
54 | __IO uint8_t CCD_flushed = 0;
55 | __IO uint8_t avg_exps = 0;
56 | __IO uint8_t exps_left = 0;
57 | __IO uint8_t coll_mode = 0;
58 |
59 |
60 | void setup_trigger()
61 | {
62 | /* set up trigger */
63 | GPIO_InitTypeDef GPIO_InitStructure;
64 | EXTI_InitTypeDef EXTI_InitStruct;
65 | NVIC_InitTypeDef NVIC_InitStruct;
66 |
67 | /* Enable clock for GPIOB */
68 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
69 | /* Enable clock for SYSCFG */
70 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
71 |
72 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
73 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
74 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
75 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
76 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
77 | GPIO_Init(GPIOC, &GPIO_InitStructure);
78 |
79 | SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
80 |
81 | NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
82 | NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
83 | NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
84 | NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
85 | NVIC_Init(&NVIC_InitStruct);
86 |
87 | EXTI_InitStruct.EXTI_Line = EXTI_Line13;
88 | EXTI_InitStruct.EXTI_LineCmd = ENABLE;
89 | EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
90 | EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
91 | EXTI_Init(&EXTI_InitStruct);
92 |
93 | }
94 |
95 |
96 | void trigger_fired()
97 | {
98 | if(sampling_requested == 2)
99 | {
100 | uint16_t start_cnt = TIM_GetCounter(TIM9);
101 | uint16_t end_cnt = start_cnt + trigger_delay;
102 |
103 | /* overflow, wait for timer overflowing */
104 | if(end_cnt < start_cnt)
105 | {
106 | while(TIM_GetCounter(TIM9) > end_cnt)
107 | {
108 | }
109 | }
110 |
111 | while(TIM_GetCounter(TIM9) < end_cnt)
112 | {
113 | }
114 |
115 | TIM_ICG_SH_start();
116 | sampling_active = 1;
117 | sampling_requested = 0;
118 | }
119 | }
120 |
121 | /* TIM Configuration
122 | TIM2/5 are 32 bit and will serve the ICG and SH pulses that may require very long periods.
123 | TIM3/4 are 16 bit and will serve the fM (master clock) and ADC clock.
124 |
125 | fM (TIM3) PB0 (Ch3)
126 | SH (TIM2) PA1 (Ch2)
127 | ICG (TIM5) PA0 (Ch1)
128 | CCD-output PC0 (ADC-in10) */
129 |
130 | /* UART Configuration
131 | Tx on PA3
132 | Rx on PA2 */
133 |
134 | /* Other GPIOs
135 | PA0, PB2 and PC2 are driven low
136 | PA5 (LED) is enabled (but driven low by default) */
137 |
138 |
139 | int main(void)
140 | {
141 | int i = 0;
142 |
143 | /* virtual_GND() enables GPIOA, GPIOB and GPIOC clocks */
144 | virtual_GND();
145 | NVIC_conf();
146 | setup_trigger();
147 |
148 | /* Setup CCD_fM (TIM3) and ADC-timer (TIM4) */
149 | get_Timer_clocks();
150 | TIM_CCD_fM_conf();
151 | TIM_ADC_conf();
152 | /* Setup UART */
153 | USART2_conf();
154 | /* Setup ADC + ADC-DMA */
155 | ADC1_conf();
156 | /* Setup ICG (TIM5) and SH (TIM2) */
157 | TIM_ICG_SH_conf();
158 |
159 | int counter = 0;
160 | while(1)
161 | {
162 | counter++;
163 |
164 | if (change_exposure_flag == 1)
165 | {
166 | /* reset flag */
167 | change_exposure_flag = 0;
168 |
169 | flush_CCD();
170 |
171 | /* set new integration time */
172 | ICG_period = (nRxBuffer[6]<<24) | (nRxBuffer[7]<<16) | (nRxBuffer[8]<<8) | (nRxBuffer[9]);
173 | SH_period = (nRxBuffer[2]<<24) | (nRxBuffer[3]<<16) | (nRxBuffer[4]<<8) | (nRxBuffer[5]);
174 | TIM_ICG_SH_conf();
175 |
176 | sampling_active = 0;
177 | sampling_requested = 1;
178 | }
179 |
180 | if(sampling_requested == 1)
181 | {
182 | /* separate sampling start into a GPIO-triggered part */
183 | if(trigger_level == 2)
184 | {
185 | TIM_ICG_SH_start();
186 | sampling_active = 1;
187 | sampling_requested = 0;
188 | }
189 | else
190 | {
191 | uint8_t level_pin = GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13);
192 | uint8_t level_compare = trigger_level ? Bit_SET : Bit_RESET;
193 | uint8_t level_active = level_pin == level_compare;
194 |
195 | if(!level_active)
196 | {
197 | /* wait for pin change interrupt to activate timers */
198 | sampling_requested = 2;
199 | }
200 | }
201 | }
202 |
203 | if(sampling_active)
204 | {
205 | switch (data_flag)
206 | {
207 | case 1:
208 | /* reset flags */
209 | data_flag = 0;
210 |
211 | if (coll_mode == 1)
212 | {
213 | pulse_counter = 6;
214 | }
215 | else
216 | {
217 | TIM_ICG_SH_stop();
218 | }
219 |
220 | /* Transmit data in aTxBuffer */
221 | UART2_Tx_DMA();
222 | break;
223 |
224 | case 2:
225 | /* reset flags */
226 | data_flag = 0;
227 |
228 | /* This is the first integration of several so overwrite avgBuffer */
229 | for (i=0; i
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | * 1. Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | * SUCH DAMAGE.
27 | *
28 | */
29 |
30 | #include "main.h"
31 |
32 | extern __IO uint32_t SH_period;
33 | extern __IO uint32_t ICG_period;
34 |
35 | /* The timer prescalers are derived from the APB1 clock. */
36 | int apb1_freq;
37 |
38 | void get_Timer_clocks(void)
39 | {
40 | /* Get the apb-prescalers */
41 | int apb1 = (RCC->CFGR & RCC_CFGR_PPRE1) >> 10;
42 |
43 | /* APBx prescaler table */
44 | int apb2x[8] = {1, 0, 0, 0, 2, 4, 8, 16};
45 |
46 | /* Calculate the timer clocks */
47 | apb1_freq = SystemCoreClock / (apb2x[apb1] * (apb2x[apb1] == 1) + apb2x[apb1] / 2 * (apb2x[apb1] != 1));
48 | }
49 |
50 | /* fM is served by TIM3 on PB0 */
51 | void TIM_CCD_fM_conf(void)
52 | {
53 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
54 | TIM_OCInitTypeDef TIM_OCInitStructure;
55 | GPIO_InitTypeDef GPIO_InitStructure;
56 |
57 | /* Clock TIM3 */
58 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
59 |
60 | /* GPIOB Configuration: TIM3 CH4 (PB0) */
61 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
62 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
63 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
64 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
65 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
66 | GPIO_Init(GPIOB, &GPIO_InitStructure);
67 |
68 | /* Connect TIM pins to AF2 */
69 | GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);
70 |
71 | /* TIM3 Time base configuration
72 | Prescaler is 1 so timer clock is apb1_freq / 1
73 | Period is apb1_freq / CCD_fm, so timer frequency is CCD_fm in Hz
74 | (ie. apb1_freq/[apb1_freq/CCD_fm]) */
75 | TIM_TimeBaseStructure.TIM_Prescaler = 1 - 1;
76 | TIM_TimeBaseStructure.TIM_ClockDivision = 0;
77 | TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
78 | TIM_TimeBaseStructure.TIM_Period = apb1_freq / CCD_fm - 1;
79 | TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
80 |
81 | /* TIM3 PWM1 Mode configuration: Channel1
82 | Pulse is apb1_freq / (2*CCD_fm), so the duty cycle is 50% */
83 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
84 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
85 | TIM_OCInitStructure.TIM_Pulse = apb1_freq / (2 * CCD_fm);
86 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
87 |
88 | TIM_OC3Init(TIM3, &TIM_OCInitStructure);
89 | TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
90 | TIM_ARRPreloadConfig(TIM3, ENABLE);
91 |
92 | /* TIM3 enable counter */
93 | TIM_Cmd(TIM3, ENABLE);
94 |
95 |
96 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE);
97 | TIM_TimeBaseInitTypeDef timerInitStructure;
98 | timerInitStructure.TIM_Prescaler = apb1_freq / 1000000 - 1;
99 | timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
100 | timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
101 | timerInitStructure.TIM_Period = 0xFFFFFFFF;
102 | timerInitStructure.TIM_RepetitionCounter = 0;
103 | TIM_TimeBaseInit(TIM9, &timerInitStructure);
104 | TIM_Cmd(TIM9, ENABLE);
105 | }
106 |
107 | /* ADC is paced by TIM4 (optional output on PB9) */
108 | void TIM_ADC_conf(void)
109 | {
110 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
111 | TIM_OCInitTypeDef TIM_OCInitStructure;
112 |
113 | /* Clock TIM3 */
114 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
115 |
116 | /* GPIOB Configuration: TIM4 CH4 (PB9)
117 | optional - comment out */
118 | GPIO_InitTypeDef GPIO_InitStructure;
119 |
120 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
121 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
122 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
123 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
124 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
125 | GPIO_Init(GPIOB, &GPIO_InitStructure);
126 |
127 | GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_TIM4);
128 |
129 | /* TIM4 Time base configuration */
130 | /* Prescaler is 1 so timer clock is apb1_freq / 1
131 | Period is 4*apb1_freq / CCD_fm, so timer frequency is CCD_fm/4 in Hz
132 | (ie. apb1_freq/[apb1_freq/CCD_fm]) */
133 | TIM_TimeBaseStructure.TIM_Prescaler = 1 - 1;
134 | TIM_TimeBaseStructure.TIM_ClockDivision = 0;
135 | TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
136 | TIM_TimeBaseStructure.TIM_Period = 4 * apb1_freq / CCD_fm - 1;
137 | TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
138 |
139 | /* Pulse is apb1_freq / (2*CCD_fm), so the duty cycle is 12.5% */
140 | /* TIM4 PWM1: Channel4 */
141 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
142 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
143 | TIM_OCInitStructure.TIM_Pulse = apb1_freq / (2 * CCD_fm);
144 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
145 |
146 | TIM_OC4Init(TIM4, &TIM_OCInitStructure);
147 | TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
148 | TIM_ARRPreloadConfig(TIM4, ENABLE);
149 |
150 | /* TIM4 is enabled/disabled by IRQs */
151 | // TIM_Cmd(TIM4, ENABLE);
152 | }
153 |
154 | /* ---------------------------------------------------------------------------
155 |
156 | TIM2 (channel 2) on PA1 runs the SH-pulse.
157 | TIM5 (channel 1) on PA0 runs the ICG-pulse
158 |
159 | The following is based on the timing diagrams in the datasheet for TCD1304.
160 |
161 | 1) SH must go high with a delay (t2) of between 100 and 1000 ns after ICG goes low.
162 | 2) SH must stay high for (t3) a minium of 1000 ns.
163 | 3) ICG must go high with a delay (t1) of minimum 1000 ns after SH goes low.
164 | 4) ICG must go high when fM is high.
165 |
166 | To help achieve these requirements both timer clocks are set to the period length of fM.
167 | Furthermore the period of TIM2 should be a multiple of the period of TIM5.
168 |
169 | ####################################################################
170 | Don't forget that fm, SH and ICG are inverted by the TC74HC04 before
171 | reaching the CCD.
172 |
173 | Set TIM_OCInitStructure.TIM_OCPolarity:
174 | High for TIM3 (fM) and TIM2 (SH)
175 | Low for TIM5 (ICG)
176 | when a 74HC04 is NOT used.
177 |
178 | Set TIM_OCInitStructure.TIM_OCPolarity:
179 | Low for TIM3 (fM) and TIM2 (SH)
180 | High for TIM5 (ICG)
181 | when a 74HC04 IS in use.
182 |
183 | ####################################################################
184 |
185 |
186 | Notes on the SH and ICG pulses:
187 | The timing diagrams in the datasheet for TCD1304 can be a little confusing, and
188 | it doesn't get better that there are two of them.
189 |
190 | The ICG pulse marks the start of each read, so even if it's named 'Integration
191 | Clear Gate', it seems to function more as a shift gate. Since we want to be able
192 | to complete a full read of the entire CCD before starting a new read, and a pixel
193 | is clocked out for every 4 fM cycles, the period of ICG must be at least:
194 | 3694 * 4 = 14776
195 | because the timer controlling ICG runs with a clock speed identical to fM
196 |
197 | As the SH and ICG pulses must conform to the four criteria above, so it's
198 | advisable to confine the ICG periods to full multiples of the SH period.
199 |
200 | The SH pulse defines the integration time, and according to the datasheet this
201 | must be >10 us, so the SH period must be at least:
202 | 10 us * 2.0 MHz = 20
203 | The upper limit of the SH period is given by the ICG period, as each ICG pulse
204 | must coincide with an SH pulse. It seems that it's the SH signal that acts as
205 | the electronic shutter and not the ICG signal.
206 |
207 | At each ICG pulse TIM5 creates an interrupt which will start TIM4 that drives
208 | the ADC+DMA.
209 |
210 |
211 | ###############################################################
212 | In the following code I advise to only change the values of
213 | TIM_Period (and TIM_OCPolarity if you follow the schematic in
214 | the datasheet and put a 74HC04 between your GPIOs and the CCD).
215 | ###############################################################
216 |
217 | --------------------------------------------------------------------------- */
218 |
219 | void TIM_ICG_SH_conf(void)
220 | {
221 | GPIO_InitTypeDef GPIO_InitStructure;
222 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
223 | TIM_OCInitTypeDef TIM_OCInitStructure;
224 | // NVIC_InitTypeDef NVIC_InitStructure;
225 |
226 | TIM_ICG_SH_stop();
227 |
228 | /* TIM2 & TIM5 clock enable */
229 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
230 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
231 |
232 | /* GPIO Configuration: TIM2 CH2 (PA1) */
233 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
234 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
235 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
236 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
237 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
238 | GPIO_Init(GPIOA, &GPIO_InitStructure);
239 |
240 | /* Connect TIM2 pins to AF1 */
241 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2);
242 |
243 | /* GPIO Configuration: TIM5 CH1 (PA0) */
244 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
245 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
246 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
247 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
248 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
249 | GPIO_Init(GPIOA, &GPIO_InitStructure);
250 |
251 | /* Connect TIM5 pins to AF2 */
252 | GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM5);
253 |
254 | /* Time base configuration */
255 | /* The prescaler is set to period of TIM3 (apb1_freq / CCD_fm - 1),
256 | so TIM2 and TIM5's clocks are equal to the period of TIM3.
257 | Some numbers to consider for the period of the timers:
258 | ICG (TIM5): t_read = Period / CCD_fm MHz
259 | SH (TIM2): t_int = Period / CCD_fm MHz
260 | eg. integration time is:
261 | t_int = 20 / 2 MHz = 10 µs */
262 |
263 | /* Common for TIM2 & TIM5 */
264 | TIM_TimeBaseStructure.TIM_Prescaler = apb1_freq / CCD_fm - 1;
265 | TIM_TimeBaseStructure.TIM_ClockDivision = 0;
266 | TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
267 |
268 | /* TIM5 config */
269 | TIM_TimeBaseStructure.TIM_Period = ICG_period - 1;
270 | TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
271 |
272 | /* TIM2 config */
273 | TIM_TimeBaseStructure.TIM_Period = SH_period - 1;
274 | TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
275 |
276 | /* Set parameters for TIM5 PWM1 Mode configuration: Channel1 */
277 | /* The duty cycle should be 5 µs for ICG, so the pulse is:
278 | pulse = 5 µs * CCD_fm MHz
279 | Of course this is only accurate when CCD_fM in MHz is an integer.
280 | Change the Polarity to High if 74HC04 is in place */
281 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
282 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
283 | TIM_OCInitStructure.TIM_Pulse = (5 * CCD_fm) / 1000000;
284 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
285 | TIM_OC1Init(TIM5, &TIM_OCInitStructure);
286 |
287 | TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);
288 | TIM_ARRPreloadConfig(TIM5, ENABLE);
289 |
290 | /* Set parameters for TIM2 PWM1 Mode configuration: Channel2 */
291 | /* The duty cycle should be 2 µs for SH, so the pulse is:
292 | pulse = 2 µs * CCD_fm MHz
293 | Of course this is only accurate when CCD_fM in MHz is an integer.
294 | Change the Polarity to Low if 74HC04 is in place */
295 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
296 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
297 | TIM_OCInitStructure.TIM_Pulse = (2 * CCD_fm) / 1000000;
298 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
299 | TIM_OC2Init(TIM2, &TIM_OCInitStructure);
300 |
301 | TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
302 | TIM_ARRPreloadConfig(TIM2, ENABLE);
303 |
304 | /* Clear TIM5 update pending flags */
305 | TIM_ClearFlag(TIM5, TIM_FLAG_Update);
306 |
307 | /* Enable the TIM5 Interrupt. Interrupt routine is located in stm32f4xx_it.c */
308 | TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
309 | }
310 |
311 | void TIM_ICG_SH_start(void)
312 | {
313 | /* Set counters close to expiration, as the integration times may be very long.
314 | (For example: with an ICG-period of 300s we'd have to wait 600s for two ICG-
315 | pulses if we don't cut the first one short.)
316 | The SH-period is slightly delayed to comply with the CCD's timing requirements. */
317 | TIM2->CNT = SH_period - SH_delay; // + (SH_period % 2);
318 | TIM5->CNT = ICG_period - ICG_delay;
319 | TIM3->CNT = fm_delay;
320 |
321 | TIM_Cmd(TIM5, ENABLE);
322 | TIM_Cmd(TIM2, ENABLE);
323 | }
324 |
325 | void TIM_ICG_SH_stop(void)
326 | {
327 | TIM_Cmd(TIM5, DISABLE);
328 | TIM_Cmd(TIM2, DISABLE);
329 | }
330 |
331 | /* For continous reading of the CCD consider the following:
332 | The data from the CCD is stored in the TxBuffer for the UART, which in best case
333 | is 642 ms to complete the transmission. Taking this into account and to allow for
334 | some overhead in transmission time the minimum ICG-period becomes:
335 | 700 ms * 2.0 MHz = 1400000
336 | with fM = 2.0 MHz.
337 |
338 | The above is not yet cut in stone. Minimum is still 14776..
339 | */
340 |
--------------------------------------------------------------------------------
/src/system_stm32f4xx.c:
--------------------------------------------------------------------------------
1 | /**
2 | ******************************************************************************
3 | * @file system_stm32f4xx.c
4 | * @author MCD Application Team
5 | * @version V1.1.0
6 | * @date 18-September-2019
7 | * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
8 | * This file contains the system clock configuration for STM32F4xx devices,
9 | * and is generated by the clock configuration tool
10 | * stm32f4xx_Clock_Configuration_V1.1.0.xls
11 | *
12 | * 1. This file provides two functions and one global variable to be called from
13 | * user application:
14 | * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
15 | * and Divider factors, AHB/APBx prescalers and Flash settings),
16 | * depending on the configuration made in the clock xls tool.
17 | * This function is called at startup just after reset and
18 | * before branch to main program. This call is made inside
19 | * the "startup_stm32f4xx.s" file.
20 | *
21 | * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
22 | * by the user application to setup the SysTick
23 | * timer or configure other parameters.
24 | *
25 | * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
26 | * be called whenever the core clock is changed
27 | * during program execution.
28 | *
29 | * 2. After each device reset the HSI (16 MHz) is used as system clock source.
30 | * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to
31 | * configure the system clock before to branch to main program.
32 | *
33 | * 3. If the system clock source selected by user fails to startup, the SystemInit()
34 | * function will do nothing and HSI still used as system clock source. User can
35 | * add some code to deal with this issue inside the SetSysClock() function.
36 | *
37 | * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define
38 | * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or
39 | * through PLL, and you are using different crystal you have to adapt the HSE
40 | * value to your own configuration.
41 | *
42 | * 5. This file configures the system clock as follows:
43 | *=============================================================================
44 | *=============================================================================
45 | * Supported STM32F40xx/41xx/427x/437x devices
46 | *-----------------------------------------------------------------------------
47 | * System Clock source | PLL (HSE)
48 | *-----------------------------------------------------------------------------
49 | * SYSCLK(Hz) | 72000000
50 | *-----------------------------------------------------------------------------
51 | * HCLK(Hz) | 72000000
52 | *-----------------------------------------------------------------------------
53 | * AHB Prescaler | 1
54 | *-----------------------------------------------------------------------------
55 | * APB1 Prescaler | 2
56 | *-----------------------------------------------------------------------------
57 | * APB2 Prescaler | 1
58 | *-----------------------------------------------------------------------------
59 | * HSE Frequency(Hz) | 8000000
60 | *-----------------------------------------------------------------------------
61 | * PLL_M | 8
62 | *-----------------------------------------------------------------------------
63 | * PLL_N | 288
64 | *-----------------------------------------------------------------------------
65 | * PLL_P | 4
66 | *-----------------------------------------------------------------------------
67 | * PLL_Q | 7
68 | *-----------------------------------------------------------------------------
69 | * PLLI2S_N | NA
70 | *-----------------------------------------------------------------------------
71 | * PLLI2S_R | NA
72 | *-----------------------------------------------------------------------------
73 | * I2S input clock | NA
74 | *-----------------------------------------------------------------------------
75 | * VDD(V) | 3,3
76 | *-----------------------------------------------------------------------------
77 | * Main regulator output voltage | Scale1 mode
78 | *-----------------------------------------------------------------------------
79 | * Flash Latency(WS) | 2
80 | *-----------------------------------------------------------------------------
81 | * Prefetch Buffer | OFF
82 | *-----------------------------------------------------------------------------
83 | * Instruction cache | ON
84 | *-----------------------------------------------------------------------------
85 | * Data cache | ON
86 | *-----------------------------------------------------------------------------
87 | *=============================================================================
88 | ******************************************************************************
89 | * @attention
90 | *
91 | * © COPYRIGHT 2013 STMicroelectronics
92 | *
93 | * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
94 | * You may not use this file except in compliance with the License.
95 | * You may obtain a copy of the License at:
96 | *
97 | * http://www.st.com/software_license_agreement_liberty_v2
98 | *
99 | * Unless required by applicable law or agreed to in writing, software
100 | * distributed under the License is distributed on an "AS IS" BASIS,
101 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
102 | * See the License for the specific language governing permissions and
103 | * limitations under the License.
104 | *
105 | ******************************************************************************
106 | */
107 |
108 | #include "stm32f4xx.h"
109 |
110 | /************************* Miscellaneous Configuration ************************/
111 | /*!< Uncomment the following line if you need to use external SRAM mounted
112 | on STM324xG_EVAL/STM324x7I_EVAL board as data memory */
113 | /* #define DATA_IN_ExtSRAM */
114 |
115 | /*!< Uncomment the following line if you need to relocate your vector Table in
116 | Internal SRAM. */
117 | /* #define VECT_TAB_SRAM */
118 | #define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. \
119 | This value must be a multiple of 0x200. */
120 | /******************************************************************************/
121 |
122 | /************************* PLL Parameters *************************************/
123 | /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
124 | #define PLL_M 8
125 | #define PLL_N 288
126 |
127 | /* SYSCLK = PLL_VCO / PLL_P */
128 | #define PLL_P 4
129 |
130 | /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
131 | #define PLL_Q 7
132 |
133 | /******************************************************************************/
134 |
135 | uint32_t SystemCoreClock = 72000000;
136 |
137 | __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
138 |
139 | static void SetSysClock(void);
140 | #ifdef DATA_IN_ExtSRAM
141 | static void SystemInit_ExtMemCtl(void);
142 | #endif /* DATA_IN_ExtSRAM */
143 |
144 | void SystemInit(void)
145 | {
146 | /* FPU settings ------------------------------------------------------------*/
147 | #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
148 | SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */
149 | #endif
150 | /* Reset the RCC clock configuration to the default reset state ------------*/
151 | /* Set HSION bit */
152 | RCC->CR |= (uint32_t)0x00000001;
153 |
154 | /* Reset CFGR register */
155 | RCC->CFGR = 0x00000000;
156 |
157 | /* Reset HSEON, CSSON and PLLON bits */
158 | RCC->CR &= (uint32_t)0xFEF6FFFF;
159 |
160 | /* Reset PLLCFGR register */
161 | RCC->PLLCFGR = 0x24003010;
162 |
163 | /* Reset HSEBYP bit */
164 | RCC->CR &= (uint32_t)0xFFFBFFFF;
165 |
166 | /* Disable all interrupts */
167 | RCC->CIR = 0x00000000;
168 |
169 | #ifdef DATA_IN_ExtSRAM
170 | SystemInit_ExtMemCtl();
171 | #endif /* DATA_IN_ExtSRAM */
172 |
173 | /* Configure the System clock source, PLL Multiplier and Divider factors,
174 | AHB/APBx prescalers and Flash settings ----------------------------------*/
175 | SetSysClock();
176 |
177 | /* Configure the Vector Table location add offset address ------------------*/
178 | #ifdef VECT_TAB_SRAM
179 | SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
180 | #else
181 | SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
182 | #endif
183 | }
184 |
185 | /**
186 | * @brief Update SystemCoreClock variable according to Clock Register Values.
187 | * The SystemCoreClock variable contains the core clock (HCLK), it can
188 | * be used by the user application to setup the SysTick timer or configure
189 | * other parameters.
190 | *
191 | * @note Each time the core clock (HCLK) changes, this function must be called
192 | * to update SystemCoreClock variable value. Otherwise, any configuration
193 | * based on this variable will be incorrect.
194 | *
195 | * @note - The system frequency computed by this function is not the real
196 | * frequency in the chip. It is calculated based on the predefined
197 | * constant and the selected clock source:
198 | *
199 | * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
200 | *
201 | * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
202 | *
203 | * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
204 | * or HSI_VALUE(*) multiplied/divided by the PLL factors.
205 | *
206 | * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value
207 | * 16 MHz) but the real value may vary depending on the variations
208 | * in voltage and temperature.
209 | *
210 | * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value
211 | * 25 MHz), user has to ensure that HSE_VALUE is same as the real
212 | * frequency of the crystal used. Otherwise, this function may
213 | * have wrong result.
214 | *
215 | * - The result of this function could be not correct when using fractional
216 | * value for HSE crystal.
217 | *
218 | * @param None
219 | * @retval None
220 | */
221 | void SystemCoreClockUpdate(void)
222 | {
223 | uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
224 |
225 | /* Get SYSCLK source -------------------------------------------------------*/
226 | tmp = RCC->CFGR & RCC_CFGR_SWS;
227 |
228 | switch (tmp)
229 | {
230 | case 0x00: /* HSI used as system clock source */
231 | SystemCoreClock = HSI_VALUE;
232 | break;
233 | case 0x04: /* HSE used as system clock source */
234 | SystemCoreClock = HSE_VALUE;
235 | break;
236 | case 0x08: /* PLL used as system clock source */
237 |
238 | /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
239 | SYSCLK = PLL_VCO / PLL_P
240 | */
241 | pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
242 | pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
243 |
244 | if (pllsource != 0)
245 | {
246 | /* HSE used as PLL clock source */
247 | pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
248 | }
249 | else
250 | {
251 | /* HSI used as PLL clock source */
252 | pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
253 | }
254 |
255 | pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >> 16) + 1) * 2;
256 | SystemCoreClock = pllvco / pllp;
257 | break;
258 | default:
259 | SystemCoreClock = HSI_VALUE;
260 | break;
261 | }
262 | /* Compute HCLK frequency --------------------------------------------------*/
263 | /* Get HCLK prescaler */
264 | tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
265 | /* HCLK frequency */
266 | SystemCoreClock >>= tmp;
267 | }
268 |
269 | /**
270 | * @brief Configures the System clock source, PLL Multiplier and Divider factors,
271 | * AHB/APBx prescalers and Flash settings
272 | * @Note This function should be called only once the RCC clock configuration
273 | * is reset to the default reset state (done in SystemInit() function).
274 | * @param None
275 | * @retval None
276 | */
277 | static void SetSysClock(void)
278 | {
279 | /******************************************************************************/
280 | /* PLL (clocked by HSE) used as System clock source */
281 | /******************************************************************************/
282 | __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
283 |
284 | /* Enable HSE */
285 | RCC->CR |= ((uint32_t)RCC_CR_HSEON);
286 |
287 | /* Wait till HSE is ready and if Time out is reached exit */
288 | do
289 | {
290 | HSEStatus = RCC->CR & RCC_CR_HSERDY;
291 | StartUpCounter++;
292 | } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
293 |
294 | if ((RCC->CR & RCC_CR_HSERDY) != RESET)
295 | {
296 | HSEStatus = (uint32_t)0x01;
297 | }
298 | else
299 | {
300 | HSEStatus = (uint32_t)0x00;
301 | }
302 |
303 | if (HSEStatus == (uint32_t)0x01)
304 | {
305 | /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
306 | RCC->APB1ENR |= RCC_APB1ENR_PWREN;
307 | PWR->CR |= PWR_CR_VOS;
308 |
309 | /* HCLK = SYSCLK / 1*/
310 | RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
311 |
312 | /* PCLK2 = HCLK / 1*/
313 | RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
314 |
315 | /* PCLK1 = HCLK / 2*/
316 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
317 |
318 | /* Configure the main PLL */
319 | RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) |
320 | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
321 |
322 | /* Enable the main PLL */
323 | RCC->CR |= RCC_CR_PLLON;
324 |
325 | /* Wait till the main PLL is ready */
326 | while ((RCC->CR & RCC_CR_PLLRDY) == 0)
327 | {
328 | }
329 |
330 | /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
331 | FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_2WS;
332 |
333 | /* Select the main PLL as system clock source */
334 | RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
335 | RCC->CFGR |= RCC_CFGR_SW_PLL;
336 |
337 | /* Wait till the main PLL is used as system clock source */
338 | while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
339 | {
340 | }
341 | }
342 | else
343 | { /* If HSE fails to start-up, the application will have wrong clock
344 | configuration. User can add here some code to deal with this error */
345 | }
346 | }
347 |
348 | /**
349 | * @brief Setup the external memory controller. Called in startup_stm32f4xx.s
350 | * before jump to __main
351 | * @param None
352 | * @retval None
353 | */
354 | #ifdef DATA_IN_ExtSRAM
355 | /**
356 | * @brief Setup the external memory controller.
357 | * Called in startup_stm32f4xx.s before jump to main.
358 | * This function configures the external SRAM mounted on STM324xG_EVAL/STM324x7I_EVAL board
359 | * This SRAM will be used as program data memory (including heap and stack).
360 | * @param None
361 | * @retval None
362 | */
363 | void SystemInit_ExtMemCtl(void)
364 | {
365 | /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
366 | RCC->AHB1ENR |= 0x00000078;
367 |
368 | /* Connect PDx pins to FSMC Alternate function */
369 | GPIOD->AFR[0] = 0x00cc00cc;
370 | GPIOD->AFR[1] = 0xcccccccc;
371 | /* Configure PDx pins in Alternate function mode */
372 | GPIOD->MODER = 0xaaaa0a0a;
373 | /* Configure PDx pins speed to 100 MHz */
374 | GPIOD->OSPEEDR = 0xffff0f0f;
375 | /* Configure PDx pins Output type to push-pull */
376 | GPIOD->OTYPER = 0x00000000;
377 | /* No pull-up, pull-down for PDx pins */
378 | GPIOD->PUPDR = 0x00000000;
379 |
380 | /* Connect PEx pins to FSMC Alternate function */
381 | GPIOE->AFR[0] = 0xcccccccc;
382 | GPIOE->AFR[1] = 0xcccccccc;
383 | /* Configure PEx pins in Alternate function mode */
384 | GPIOE->MODER = 0xaaaaaaaa;
385 | /* Configure PEx pins speed to 100 MHz */
386 | GPIOE->OSPEEDR = 0xffffffff;
387 | /* Configure PEx pins Output type to push-pull */
388 | GPIOE->OTYPER = 0x00000000;
389 | /* No pull-up, pull-down for PEx pins */
390 | GPIOE->PUPDR = 0x00000000;
391 |
392 | /* Connect PFx pins to FSMC Alternate function */
393 | GPIOF->AFR[0] = 0x00cccccc;
394 | GPIOF->AFR[1] = 0xcccc0000;
395 | /* Configure PFx pins in Alternate function mode */
396 | GPIOF->MODER = 0xaa000aaa;
397 | /* Configure PFx pins speed to 100 MHz */
398 | GPIOF->OSPEEDR = 0xff000fff;
399 | /* Configure PFx pins Output type to push-pull */
400 | GPIOF->OTYPER = 0x00000000;
401 | /* No pull-up, pull-down for PFx pins */
402 | GPIOF->PUPDR = 0x00000000;
403 |
404 | /* Connect PGx pins to FSMC Alternate function */
405 | GPIOG->AFR[0] = 0x00cccccc;
406 | GPIOG->AFR[1] = 0x000000c0;
407 | /* Configure PGx pins in Alternate function mode */
408 | GPIOG->MODER = 0x00080aaa;
409 | /* Configure PGx pins speed to 100 MHz */
410 | GPIOG->OSPEEDR = 0x000c0fff;
411 | /* Configure PGx pins Output type to push-pull */
412 | GPIOG->OTYPER = 0x00000000;
413 | /* No pull-up, pull-down for PGx pins */
414 | GPIOG->PUPDR = 0x00000000;
415 |
416 | /*-- FSMC Configuration ------------------------------------------------------*/
417 | /* Enable the FSMC interface clock */
418 | RCC->AHB3ENR |= 0x00000001;
419 |
420 | /* Configure and enable Bank1_SRAM2 */
421 | FSMC_Bank1->BTCR[2] = 0x00001011;
422 | FSMC_Bank1->BTCR[3] = 0x00000201;
423 | FSMC_Bank1E->BWTR[2] = 0x0fffffff;
424 | }
425 | #endif /* DATA_IN_ExtSRAM */
426 |
--------------------------------------------------------------------------------