├── 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 | --------------------------------------------------------------------------------