Vector Clock/Version Clock

本文介绍了分布式系统中物理时钟、Lamport逻辑时钟及VectorClock的基本原理,重点阐述了Dynamo如何利用VersionClock解决数据冲突问题。
Vector Clock/Version Clock

physical clock

     机器上的物理时钟,不同的机器在同一个时间点取到的physical clock不一样,之间会存在一定的误差,NTP可以用来控制这个误差,同一个机房内的机器之间的时钟误差可以控制在1us以内,跨机房可以控制在几十ms。两个事件a和b,a在机器M1上physical clock为12点5分0秒6ms发生,b在机器M2上physical clock为12点5分0秒7ms发生,这并不代表a发生在b之前,因为两个机器上取到的physical clock和真实时间(这个时间就是国际标准时间UTC,可以通过原子钟,internet,卫星获得)之间都有误差。比如机器M1的physical clock比真实时间慢10ms,那么事件a实际上是在真实时间12点5分0秒16ms发生的,机器M2的physical clock比真实事件慢5ms,那么事件b的实际上是在真实时间12点5分0秒12ms发生的,显然,事件a发生在事件b之后。

Lamport’s Logical Clock

    单机系统容易给发生的所有事件定义一个全局顺序(total order),但是分布式系统没有全局时钟,很难给所有事件定义一个全局顺序。所以,Lamport定义了一种偏序关系,happens-before.记作 ->

a->b意味着所有的进程都agree事件a发生在事件b之前。

    在三种情况下,可以很容易的得到这个关系:

  1. 如果事件a和事件b是同一个进程中的并且事件a发生在事件b前面,那么a->b;

  2. 如果进程A发送一条消息m给进程B,a代表进程A发送消息m的事件,b代表进程B接收消息m的事件,那么a->b(由于消息的传递需要时间)
  3. ->满足传递性,如果a->b AND b->c => a->c.

Lamport’s Logical Clock算法如下:

  1. 每个机器本地维护一个logical clock LCi;
  2. 每个机器本地每发生一个事件设置LCi = LCi + 1,并且把结果作为这个事件的logical clock;
  3. 当机器i给机器j发送消息m时,把LCi存在消息里;
  4. 当机器j收到消息m时候,LCj = max(LCj, m timestamp)+1,结果值作为收到消息m这个事件的时间戳。

     这个算法能够保证a->b,那么a事件的logical clock比b事件的logical clock小。反过来,通过只比较两个事件的logical clock不能得到a和b的先后。

Vector Clock

     每个机器维护一个向量VC,也就是Vector Clock,这个向量VC有如下属性:

  1. VCi[i] 是到目前为止机器i上发生的事件的个数;

  2. VCi[k] 是机器i知道的机器k发生的事件的个数(即机器i对机器j的知识).

     每个机器都有一个向量(Vector),每个向量中的元素都是一个logical clock,所以取名为Vector Clock。

     通过如下算法更新Vector Clock

  1. 机器i本地发生一个事件时将VCi[i]加1;
  2. 机器i给机器j发送消息m时,将整个VCi存在消息内;
  3. 机器j收到消息m时,VCj[k]=max(VCj[k],VCi[k]),同时,VCj[j]+1.

     可以看出,Vector Clock是一种maintain因果关系(causality)的一种手段,Vector Clock在机器之间传递达到给对方传递自己已有的关于其他机器知识的目的。

Dynamo为什么需要Vector Clock(实际上是Version Clock)

     Dynamo是一个分布式Key/Value存储系统,这个Value可以是一行,包含多个列, 为了容错,每个Key/Value保存多副本,通常在不同的机器上,一般是3,后面以3为例。对外是一个最终一致性系统,即客户端A写入一个值返回成功后,在一定的时间内另外一个客户端可能读不到最新的值。通常,成功写入两个副本成功即返回给客户端成功,同时请求会异步的同步到第三个副本。然而,高可用是Dynamo的主要设计目标之一,即使在出现网络分区或者机器宕机时依然可读可写。

假设Key K有三个副本k1,k2,k3分别在M1,M2,M3上。

正常情况

M1处理写请求,M1将请求发往M2,M3,只要有一个返回,即返回客户端成功。

网络分区

如果M1和M2/M3之间网络都不通,k1被更新(持续高可用,依然给客户端返回成功),随后,其他节点(集群中任意一个节点都可以接客户端请求,并且将请求路由到正确的节点上)路由了写请求给M2(假设其他节点和M1/M3之间网络不通),k2被更新。这时,k1和k2数据不一样,最后网络恢复,三个副本进行同步时,应该保留哪个版本?如果只保留k2,即采用last write win机制,那么同步后,第一个客户端会发现它写的数据丢了。

这个时候就需要Vector Clock,更确切的说是Version Clock。

为了处理这种场景,Dynamo使用Version Clock来捕获同一个Object的不同版本之间的causality。每个Object的每个版本会有一个相关联的Version Clock, 形如[(serverA,counter),(serverB,counter),…], 通过检查同一个Object不同版本的Version Clock,可以决定是否可以完全丢弃一个版本,仅保留另外一个版本,还是需要将两个版本进行merge。如果Object的版本A的VCA包含的每项(server, counter)在版本B的VCB中都有对应项,并且counter小于等于版本B中对应项的counter(记作VCB descends VCA),那么这个Object的版本A可以被丢弃,否则需要对两个版本进行merge。

回到刚才的例子,k1被更新,Version Clock(注:此处假设k1/k2/k3三个副本之前一模一样,那么就可以省略之前的Version Clock)为[(M1,1)],k2被更新,Version Clock为[(M2,1)],随后k1/k2网络通了,他们通过比较两个Version Clock发现两个Version Clock存在冲突,不是descends的关系,那么就两个版本都保留,当客户端来读Key K的时候,两个版本的数据和对应的VC都返回给客户端,由客户端进行冲突合并,客户端进行冲突合并后写入Key K的时候,带着合并后的VC[(M1, 1), [M2, 1]]发到M1/M2,覆盖服务器版本,冲突解决。

可以看出,Vector Clock最初是为了给分布式系统的事件定序发明的,本质上是一种捕获causality的手段,只是他们捕获的是事件的关系。而Version Clock是捕获同一个数据的不同版本之间的causality.

Riak这个系统也使用了Vector Clock来做冲突合并,对Vector Clock的用法可谓比较深入,具体可以看最后两篇参考资料。

参考资料

1.   Dynamo

2.   Scalable and Accurate Causality Tracking for Eventually Consistent Stores

3.   version-vectors-are-not-vector-clocks

4.   Causality Is Expensive

5.   Vector Clocks Revisited

6.   vector-clocks-revisited-part-2-dotted-version-vectors

转载地址: 爱订阅 吴镝的博文


module softmax_data_memory ( input wire clk, input wire rst_n, // PORTA input wire [11:0]BRAM_PORTA_1_addr, input wire [31:0]BRAM_PORTA_1_din, output wire [31:0]BRAM_PORTA_1_dout, input wire BRAM_PORTA_1_en, input wire BRAM_PORTA_1_rst, input wire [3:0]BRAM_PORTA_1_we, // PORTB input wire [31:0] mem_addr, input wire read_req, output reg read_ack, output wire [31:0] read_data, input wire write_req, input wire write_we, input wire [31:0] write_data, output reg write_ack ); // 参数定义 parameter DATA_WIDTH = 32; parameter MEMORY_SIZE = 2**11; // 内存大小(以32位为单位) parameter ADDR_WIDTH = 11; // 地址位宽 (2^32 ) parameter MEM_PRIMITIVE = "auto" ; //自动选择 Block/Distributed RAM parameter MEM_INIT_FILE = "none" ; parameter READ_LATENCY_A = 1 ; parameter READ_LATENCY_B = 1 ; // 地址转换(字节地址转换为字地址) wire [ADDR_WIDTH-1:0] word_addrb = mem_addr[ADDR_WIDTH+1:2]; // 原语控制信号 wire [DATA_WIDTH-1:0] doutb; wire ena = BRAM_PORTA_1_en; wire enb = write_req || read_req; wire [0:0] wea = |BRAM_PORTA_1_we; //单bit 写使能 wire [0:0] web = write_we; //单bit 写使能 // 应答逻辑(独立于原语) always@(posedge clk or negedge rst_n) begin if(!rst_n) begin read_ack <= 1'b0; write_ack <= 1'b0; end else begin read_ack <= read_req; //读延迟1周期 write_ack <= write_req & write_we; //写延迟1周期 end end // xpm_memory_tdpram: True Dual Port RAM // Xilinx Parameterized Macro, version 2021.2 //PORTA-CPU; PORTB-SOFTMAX xpm_memory_tdpram #( .ADDR_WIDTH_A(ADDR_WIDTH), // DECIMAL .ADDR_WIDTH_B(ADDR_WIDTH), // DECIMAL .AUTO_SLEEP_TIME(0), // DECIMAL .BYTE_WRITE_WIDTH_A(DATA_WIDTH), // DECIMAL .BYTE_WRITE_WIDTH_B(DATA_WIDTH), // DECIMAL .CASCADE_HEIGHT(0), // DECIMAL .CLOCKING_MODE("common_clock"), // String .ECC_MODE("no_ecc"), // String .MEMORY_INIT_FILE(MEM_INIT_FILE), // String .MEMORY_INIT_PARAM("0"), // String .MEMORY_OPTIMIZATION("true"), // String .MEMORY_PRIMITIVE(MEM_PRIMITIVE), // String .MEMORY_SIZE(MEMORY_SIZE*DATA_WIDTH), // DECIMAL .MESSAGE_CONTROL(0), // DECIMAL .READ_DATA_WIDTH_A(DATA_WIDTH), // DECIMAL .READ_DATA_WIDTH_B(DATA_WIDTH), // DECIMAL .READ_LATENCY_A(READ_LATENCY_A), // DECIMAL .READ_LATENCY_B(READ_LATENCY_B), // DECIMAL .READ_RESET_VALUE_A("0"), // String .READ_RESET_VALUE_B("0"), // String .RST_MODE_A("SYNC"), // String .RST_MODE_B("SYNC"), // String .SIM_ASSERT_CHK(1), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages .USE_EMBEDDED_CONSTRAINT(0), // DECIMAL .USE_MEM_INIT(1), // DECIMAL .USE_MEM_INIT_MMI(0), // DECIMAL .WAKEUP_TIME("disable_sleep"), // String .WRITE_DATA_WIDTH_A(DATA_WIDTH), // DECIMAL .WRITE_DATA_WIDTH_B(DATA_WIDTH), // DECIMAL .WRITE_MODE_A("no_change"), // String .WRITE_MODE_B("no_change"), // String .WRITE_PROTECT(1) // DECIMAL ) xpm_memory_tdpram_inst ( .dbiterra(), // 1-bit output: Status signal to indicate double bit error occurrence // on the data output of port A. .dbiterrb(), // 1-bit output: Status signal to indicate double bit error occurrence // on the data output of port A. .douta(BRAM_PORTA_1_dout), // READ_DATA_WIDTH_A-bit output: Data output for port A read operations. .doutb(read_data), // READ_DATA_WIDTH_B-bit output: Data output for port B read operations. .sbiterra(), // 1-bit output: Status signal to indicate single bit error occurrence // on the data output of port A. .sbiterrb(), // 1-bit output: Status signal to indicate single bit error occurrence // on the data output of port B. .addra(BRAM_PORTA_1_addr), // ADDR_WIDTH_A-bit input: Address for port A write and read operations. .addrb(word_addrb), // ADDR_WIDTH_B-bit input: Address for port B write and read operations. .clka(clk), // 1-bit input: Clock signal for port A. Also clocks port B when // parameter CLOCKING_MODE is "common_clock". .clkb(clk), // 1-bit input: Clock signal for port B when parameter CLOCKING_MODE is // "independent_clock". Unused when parameter CLOCKING_MODE is // "common_clock". .dina(BRAM_PORTA_1_din), // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations. .dinb(write_data), // WRITE_DATA_WIDTH_B-bit input: Data input for port B write operations. .ena(ena), // 1-bit input: Memory enable signal for port A. Must be high on clock // cycles when read or write operations are initiated. Pipelined // internally. .enb(enb), // 1-bit input: Memory enable signal for port B. Must be high on clock // cycles when read or write operations are initiated. Pipelined // internally. .injectdbiterra(1'b0), // 1-bit input: Controls double bit error injection on input data when // ECC enabled (Error injection capability is not available in // "decode_only" mode). .injectdbiterrb(1'b0), // 1-bit input: Controls double bit error injection on input data when // ECC enabled (Error injection capability is not available in // "decode_only" mode). .injectsbiterra(1'b0), // 1-bit input: Controls single bit error injection on input data when // ECC enabled (Error injection capability is not available in // "decode_only" mode). .injectsbiterrb(1'b0), // 1-bit input: Controls single bit error injection on input data when // ECC enabled (Error injection capability is not available in // "decode_only" mode). .regcea(1'b1), // 1-bit input: Clock Enable for the last register stage on the output // data path. .regceb(1'b1), // 1-bit input: Clock Enable for the last register stage on the output // data path. .rsta(~rst_n), // 1-bit input: Reset signal for the final port A output register stage. // Synchronously resets output port douta to the value specified by // parameter READ_RESET_VALUE_A. .rstb(~rst_n), // 1-bit input: Reset signal for the final port B output register stage. // Synchronously resets output port doutb to the value specified by // parameter READ_RESET_VALUE_B. .sleep(1'b0), // 1-bit input: sleep signal to enable the dynamic power saving feature. .wea(wea), // WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A-bit input: Write enable vector // for port A input data port dina. 1 bit wide when word-wide writes are // used. In byte-wide write configurations, each bit controls the // writing one byte of dina to address addra. For example, to // synchronously write only bits [15-8] of dina when WRITE_DATA_WIDTH_A // is 32, wea would be 4'b0010. .web(web) // WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B-bit input: Write enable vector // for port B input data port dinb. 1 bit wide when word-wide writes are // used. In byte-wide write configurations, each bit controls the // writing one byte of dinb to address addrb. For example, to // synchronously write only bits [15-8] of dinb when WRITE_DATA_WIDTH_B // is 32, web would be 4'b0010. ); // End of xpm_memory_tdpram_inst instantiation endmodule 这是同一块RAM,分地址真双端口独立访问吗,一共定义了几块ram
07-08
依照文件夹删除下面代码的注释,不要添加,只要删除,而且是要用keil5软件的代码:/** ****************************************************************************** * @file system_stm32f1xx.c * @author MCD Application Team * @version V4.2.0 * @date 31-March-2017 * @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Source File. * * 1. This file provides two functions and one global variable to be called from * user application: * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier * factors, AHB/APBx prescalers and Flash settings). * This function is called at startup just after reset and * before branch to main program. This call is made inside * the "startup_stm32f1xx_xx.s" file. * * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used * by the user application to setup the SysTick * timer or configure other parameters. * * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must * be called whenever the core clock is changed * during program execution. * * 2. After each device reset the HSI (8 MHz) is used as system clock source. * Then SystemInit() function is called, in "startup_stm32f1xx_xx.s" file, to * configure the system clock before to branch to main program. * * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depending on * the product used), refer to "HSE_VALUE". * When HSE is used as system clock source, directly or through PLL, and you * are using different crystal you have to adapt the HSE value to your own * configuration. * ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /** @addtogroup CMSIS * @{ */ /** @addtogroup stm32f1xx_system * @{ */ /** @addtogroup STM32F1xx_System_Private_Includes * @{ */ #include "stm32f1xx.h" /** * @} */ /** @addtogroup STM32F1xx_System_Private_TypesDefinitions * @{ */ /** * @} */ /** @addtogroup STM32F1xx_System_Private_Defines * @{ */ #if !defined (HSE_VALUE) #define HSE_VALUE 8000000U /*!< Default value of the External oscillator in Hz. This value can be provided and adapted by the user application. */ #endif /* HSE_VALUE */ #if !defined (HSI_VALUE) #define HSI_VALUE 8000000U /*!< Default value of the Internal oscillator in Hz. This value can be provided and adapted by the user application. */ #endif /* HSI_VALUE */ /*!< Uncomment the following line if you need to use external SRAM */ #if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) /* #define DATA_IN_ExtSRAM */ #endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */ /*!< Uncomment the following line if you need to relocate your vector Table in Internal SRAM. */ /* #define VECT_TAB_SRAM */ #define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. This value must be a multiple of 0x200. */ /** * @} */ /** @addtogroup STM32F1xx_System_Private_Macros * @{ */ /** * @} */ /** @addtogroup STM32F1xx_System_Private_Variables * @{ */ /******************************************************************************* * Clock Definitions *******************************************************************************/ #if defined(STM32F100xB) ||defined(STM32F100xE) uint32_t SystemCoreClock = 24000000U; /*!< System Clock Frequency (Core Clock) */ #else /*!< HSI Selected as System Clock source */ uint32_t SystemCoreClock = 72000000U; /*!< System Clock Frequency (Core Clock) */ #endif const uint8_t AHBPrescTable[16U] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t APBPrescTable[8U] = {0, 0, 0, 0, 1, 2, 3, 4}; /** * @} */ /** @addtogroup STM32F1xx_System_Private_FunctionPrototypes * @{ */ #if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) #ifdef DATA_IN_ExtSRAM static void SystemInit_ExtMemCtl(void); #endif /* DATA_IN_ExtSRAM */ #endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */ /** * @} */ /** @addtogroup STM32F1xx_System_Private_Functions * @{ */ /** * @brief Setup the microcontroller system * Initialize the Embedded Flash Interface, the PLL and update the * SystemCoreClock variable. * @note This function should be used only after reset. * @param None * @retval None */ void SystemInit (void) { /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ /* Set HSION bit */ RCC->CR |= 0x00000001U; /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ #if !defined(STM32F105xC) && !defined(STM32F107xC) RCC->CFGR &= 0xF8FF0000U; #else RCC->CFGR &= 0xF0FF0000U; #endif /* STM32F105xC */ /* Reset HSEON, CSSON and PLLON bits */ RCC->CR &= 0xFEF6FFFFU; /* Reset HSEBYP bit */ RCC->CR &= 0xFFFBFFFFU; /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ RCC->CFGR &= 0xFF80FFFFU; #if defined(STM32F105xC) || defined(STM32F107xC) /* Reset PLL2ON and PLL3ON bits */ RCC->CR &= 0xEBFFFFFFU; /* Disable all interrupts and clear pending bits */ RCC->CIR = 0x00FF0000U; /* Reset CFGR2 register */ RCC->CFGR2 = 0x00000000U; #elif defined(STM32F100xB) || defined(STM32F100xE) /* Disable all interrupts and clear pending bits */ RCC->CIR = 0x009F0000U; /* Reset CFGR2 register */ RCC->CFGR2 = 0x00000000U; #else /* Disable all interrupts and clear pending bits */ RCC->CIR = 0x009F0000U; #endif /* STM32F105xC */ #if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) #ifdef DATA_IN_ExtSRAM SystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM */ #endif #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ #endif } /** * @brief Update SystemCoreClock variable according to Clock Register Values. * The SystemCoreClock variable contains the core clock (HCLK), it can * be used by the user application to setup the SysTick timer or configure * other parameters. * * @note Each time the core clock (HCLK) changes, this function must be called * to update SystemCoreClock variable value. Otherwise, any configuration * based on this variable will be incorrect. * * @note - The system frequency computed by this function is not the real * frequency in the chip. It is calculated based on the predefined * constant and the selected clock source: * * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) * * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) * * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) * or HSI_VALUE(*) multiplied by the PLL factors. * * (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value * 8 MHz) but the real value may vary depending on the variations * in voltage and temperature. * * (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value * 8 MHz or 25 MHz, depending on the product used), user has to ensure * that HSE_VALUE is same as the real frequency of the crystal used. * Otherwise, this function may have wrong result. * * - The result of this function could be not correct when using fractional * value for HSE crystal. * @param None * @retval None */ void SystemCoreClockUpdate (void) { uint32_t tmp = 0U, pllmull = 0U, pllsource = 0U; #if defined(STM32F105xC) || defined(STM32F107xC) uint32_t prediv1source = 0U, prediv1factor = 0U, prediv2factor = 0U, pll2mull = 0U; #endif /* STM32F105xC */ #if defined(STM32F100xB) || defined(STM32F100xE) uint32_t prediv1factor = 0U; #endif /* STM32F100xB or STM32F100xE */ /* Get SYSCLK source -------------------------------------------------------*/ tmp = RCC->CFGR & RCC_CFGR_SWS; switch (tmp) { case 0x00U: /* HSI used as system clock */ SystemCoreClock = HSI_VALUE; break; case 0x04U: /* HSE used as system clock */ SystemCoreClock = HSE_VALUE; break; case 0x08U: /* PLL used as system clock */ /* Get PLL clock source and multiplication factor ----------------------*/ pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; #if !defined(STM32F105xC) && !defined(STM32F107xC) pllmull = ( pllmull >> 18U) + 2U; if (pllsource == 0x00U) { /* HSI oscillator clock divided by 2 selected as PLL clock entry */ SystemCoreClock = (HSI_VALUE >> 1U) * pllmull; } else { #if defined(STM32F100xB) || defined(STM32F100xE) prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U; /* HSE oscillator clock selected as PREDIV1 clock entry */ SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; #else /* HSE selected as PLL clock entry */ if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET) {/* HSE oscillator clock divided by 2 */ SystemCoreClock = (HSE_VALUE >> 1U) * pllmull; } else { SystemCoreClock = HSE_VALUE * pllmull; } #endif } #else pllmull = pllmull >> 18U; if (pllmull != 0x0DU) { pllmull += 2U; } else { /* PLL multiplication factor = PLL input clock * 6.5 */ pllmull = 13U / 2U; } if (pllsource == 0x00U) { /* HSI oscillator clock divided by 2 selected as PLL clock entry */ SystemCoreClock = (HSI_VALUE >> 1U) * pllmull; } else {/* PREDIV1 selected as PLL clock entry */ /* Get PREDIV1 clock source and division factor */ prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC; prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U; if (prediv1source == 0U) { /* HSE oscillator clock selected as PREDIV1 clock entry */ SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; } else {/* PLL2 clock selected as PREDIV1 clock entry */ /* Get PREDIV2 division factor and PLL2 multiplication factor */ prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4U) + 1U; pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8U) + 2U; SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull; } } #endif /* STM32F105xC */ break; default: SystemCoreClock = HSI_VALUE; break; } /* Compute HCLK clock frequency ----------------*/ /* Get HCLK prescaler */ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4U)]; /* HCLK clock frequency */ SystemCoreClock >>= tmp; } #if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) /** * @brief Setup the external memory controller. Called in startup_stm32f1xx.s * before jump to __main * @param None * @retval None */ #ifdef DATA_IN_ExtSRAM /** * @brief Setup the external memory controller. * Called in startup_stm32f1xx_xx.s/.c before jump to main. * This function configures the external SRAM mounted on STM3210E-EVAL * board (STM32 High density devices). This SRAM will be used as program * data memory (including heap and stack). * @param None * @retval None */ void SystemInit_ExtMemCtl(void) { __IO uint32_t tmpreg; /*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is required, then adjust the Register Addresses */ /* Enable FSMC clock */ RCC->AHBENR = 0x00000114U; /* Delay after an RCC peripheral clock enabling */ tmpreg = READ_BIT(RCC->AHBENR, RCC_AHBENR_FSMCEN); /* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */ RCC->APB2ENR = 0x000001E0U; /* Delay after an RCC peripheral clock enabling */ tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPDEN); (void)(tmpreg); /* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/ /*---------------- SRAM Address lines configuration -------------------------*/ /*---------------- NOE and NWE configuration --------------------------------*/ /*---------------- NE3 configuration ----------------------------------------*/ /*---------------- NBL0, NBL1 configuration ---------------------------------*/ GPIOD->CRL = 0x44BB44BBU; GPIOD->CRH = 0xBBBBBBBBU; GPIOE->CRL = 0xB44444BBU; GPIOE->CRH = 0xBBBBBBBBU; GPIOF->CRL = 0x44BBBBBBU; GPIOF->CRH = 0xBBBB4444U; GPIOG->CRL = 0x44BBBBBBU; GPIOG->CRH = 0x444B4B44U; /*---------------- FSMC Configuration ---------------------------------------*/ /*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/ FSMC_Bank1->BTCR[4U] = 0x00001091U; FSMC_Bank1->BTCR[5U] = 0x00110212U; } #endif /* DATA_IN_ExtSRAM */ #endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
最新发布
08-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值