【STM32H7教程】第24章 STM32H7的Cache解读(非常重要)

安富莱电子 2019-06-12 12:39:00 阅读数:30 评论数:0 收藏数:0

完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980

第24章       STM32H7的Cache解读(非常重要)

本章教程为大家讲解STM32H7初学过程中最重要的一个知识点Cache。Cache在STM32H7的高性能发挥中占着举足轻重的作用。所以掌握好Cache是提升STM32H7性能的关键一步。

24.1 初学者重要提示

24.2 引出问题

24.3 支持的Cache配置

24.4 四种Cache(MPU)配置的读写操作流程

24.5 面对繁冗复杂的Cache配置,推荐方式和安全隐患解决办法

24.6 Cache的相关函数

24.7 总结

 

 

24.1 初学者重要提示

  1.   学习本章节前,务必保证已经学习了第23章的MPU知识。
  2.   本章是半年的实践经验总结,非常具有参考价值,而且是入门STM32H7的必学章节。
  3.   Cache的熟练运用需要不断的经验积累。对于初学者来说,可能无法一下子理解所有知识点,但是一定要的花时间多读几遍,随着后面章节的不断运用,认识会不断的深入。

24.2 引出问题

当前芯片厂商出的M7内核芯片基本都做了一级Cache支持,Cache又分数据缓存D-Cache和指令缓冲I-Cache,STM32H7的数据缓存和指令缓存大小都是16KB。对于指令缓冲,用户不用管,这里主要说的是数据缓存D-Cache。以STM32H7为例,主频是400MHz,除了TCM和Cache以400MHz工作,其它AXI SRAM,SRAM1,SRAM2等都是以200MHz工作。数据缓存D-Cache就是解决CPU加速访问SRAM。

如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了200MHz到400MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。

对于使能了Cache的SRAM区,要分读写两种情况考虑。

  •   读操作:

如果CPU要读取的SRAM区数据在Cache中已经加载好,这就叫读命中(Cache hit),如果Cache里面没有怎么办,这就是所谓的读Cache Miss。

  •   写操作:

如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域(专业词汇叫Cache Line,以32字节为单位),这就叫写命中(Cache hit),如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。

 

24.3 支持的Cache配置

这个知识点在上一章节进行了详细说明,这里再简述下核心内容

Cache的配置是通过MPU来设置的,通常只用到下几种方式。

 

其中的TEX是用来设置Cache策略的,C是Cache,B是缓冲用来配合Cache设置的,而S是共享,用来解决多总线或者多核访问时的同步问题。MPU配置的时候,最主要的也是配置这几个参数。

Cache支持的策略有如下四种:

 

有了这四种方式,就可以正式进入本章的主题,Cache的读写操作是如何工作的,下面分这四种情况做介绍。

24.4 四种Cache(MPU)配置的读写操作流程

24.4.1 配置Non-cacheable

这个最好理解,就是正常的读写操作,无Cache。

对应四种MPU配置如下:

  •   TEX = 000  C=0  B=0  S=忽略此位,强制为共享
  •   TEX = 000  C=0  B=1  S=忽略此位,强制为共享
  •   TEX = 001  C=0  B=0  S=0
  •   TEX = 001  C=0  B=0  S=1

24.4.2 配置Write through,read allocate,no write allocate

注意,M7内核只要开启了Cache,read allocate就是开启的。

  •   使能了此配置的SRAM缓冲区写操作

    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会同时写到Cache里面和SRAM里面;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。

    在写Cache命中的情况下,这个方式的优点是Cache和SRAM的数据同步更新了,没有多总线访问造成的数据一致性问题。缺点也明显,Cache在写操作上无法有效发挥性能。

  •   使能了此配置的SRAM缓冲区读操作

    如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。

    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。

  •   对应的两种MPU配置如下:

TEX = 000 C=1 B=0  S=1

TEX = 000 C=1 B=0  S=0

24.4.3 配置Write back,read allocate,no write allocate

注意,M7内核只要开启了Cache,read allocate就是开启的。

  •   使能了此配置的SRAM缓冲区写操作

    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。

    安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。

  •   使能了此配置的SRAM缓冲区读操作

   如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。

    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。

  •   对应两种MPU配置如下:

TEX = 000 C=1 B=1  S=1

TEX = 000 C=1 B=1  S=0

24.4.4 配置Write back,read allocate,write allocate

注意,M7内核只要开启了Cache,read allocate就是开启的。

  •   使能了此配置的SRAM缓冲区写操作

    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置write allocate了,意思就是CPU写到往SRAM里面的数据,会同步在Cache里面开辟一个空间将SRAM中写入的数据加载进来,如果此时立即读此SRAM区,那么就会有很大的速度优势。

    安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。

  •   使能了此配置的SRAM缓冲区读操作

    如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。

    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。

    这个配置被誉为可以最大程度发挥Cache性能,不过具体应用仍需具体分析。

  •   对应两种MPU配置如下:

TEX = 001 C=1 B=1  S=1

TEX = 001 C=1 B=1  S=0

24.4.5 共享配置是个隐形的大坑

STM32H7编程手册对其的描述是多核共享。

 

而H7的应用笔记对齐的描述是开启共享基本等同于关闭Cache。

 

实际测试下面四种开Cache的情况,开关共享对缓冲区的大批量数据的读操作影响很大,基本差出两倍,而写操作基本没有影响,也许这就是所谓的多总线同步读造成的。另外共享开关仅对开启了Cache的情况下有影响,而对于关闭了Cache的情况是没有影响的,开不开没关系。

24.4.6 总结这几种方式的几个关键知识点

  1. Cortex-M7内核的L1 Cache由多行内存区组成,每行有32字节,每行都配有一个地址标签。数据缓冲DCache是每4行为一组,称为4-way set associative。而指令缓冲区ICache是2行为一组,这样节省地址标签,不用每个行都标记一个地址。
  2. 对于读操作,只有在第1次访问指定地址时才会加载到Cache,而写操作的话,可以直接写到内存中(write-through模式)或者放到Cache里面,后面再写入(write-back模式)。
  3. 如果采用的是Write back,Cache line会被标为dirty,等到此行被evicted时,才会执行实际的写操作,将Cache Line里面的数据写入到相应的存储区。
  4. Cache命中是访问的地址落在了给定的Cache Line里面,所以硬件需要做少量的地址比较工作,以检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记新行,填充新的读写操作。如果所有行都分配完毕了,Cache控制器将支持eviction操作。根据Cache Line替换算法,一行将被清除Clean,无效化Invalid或者重新配置。数据缓存和指令缓存是采用的伪随机替换算法。
  5. Cache支持的4种基本操作,使能,禁止,清空和无效化。Clean清空操作是将Cache Line中标记为dirty的数据写入到内存里面,而无效化Invalid是将Cache Line标记为无效,即删除操作。

24.5 面对繁冗复杂的Cache配置,推荐方式和安全隐患解决办法

  •   推荐使用128KB的TCM作为主RAM区,其它的专门用于大缓冲和DMA操作等。
  •   Cache问题主要是CPU和DMA都操作这个缓冲区时容易出现,使用时要注意。
  •   Cache配置的选择,优先考虑的是WB,然后是WT和关闭Cache,其中WB和WT的使用中可以配合ARM提供的函数解决上面说到的隐患问题(见本章24.6小节)。但不是万能的,在不起作用的时候,直接暴力选择函数SCB_CleanInvlaidateDCache解决。关于这个问题,在分别配置以太网MAC的描述符缓冲区,发送缓冲区和接收缓冲区时尤其突出。

24.6 Cache的相关函数

CMSIS软件包的core_cm7.h文件为Cache的配置提供了11个函数:

  •   SCB_EnableICache
  •   SCB_DisableICache
  •   SCB_InvalidateICache
  •   SCB_EnableDCache
  •   SCB_DisableDCache
  •   SCB_InvalidateDCache
  •   SCB_CleanDCache
  •   SCB_CleanInvalidateDCache
  •   SCB_InvalidateDCache_by_Addr
  •   SCB_CleanDCache_by_Addr
  •   SCB_CleanInvalidateDCache_by_Addr

 

下面将这几个函数依次做个讲解。其中前三个函数是指令Cache,比较容易掌握。重点是后面几个数据Cache函数。由于函数SCB_CleanInvalidateDCache,SCB_CleanDCache和SCB_InvalidateDCache是对整个Cache的操作,所以比最后的三个函数SCB_InvalidateDCache_by_Addr,SCB_CleanDCache_by_Addr和SCB_CleanInvalidateDCache_by_Addr要耗时,当然,如果用户操作的存储器超过了数据Cache的大小,即16KB,那么就跟前三个函数没有区别了。

24.6.1 函数SCB_EnableICache

函数原型:

__STATIC_INLINE void SCB_EnableICache (void)
{
  #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    __DSB();
    __ISB();
    SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */
    __DSB();
    __ISB();
    SCB->CCR |=  (uint32_t)SCB_CCR_IC_Msk;  /* enable I-Cache */
    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于使能指令Cache,系统上电后优先初始化即可。

注意事项:

  •   __STATIC_INLINE:

表示内联函数,这种类型函数的作用就是将函数直接嵌入到调用此函数的代码中,从而降低调用此函数所占用的时间。

  •   __DMB指令:

Data Memory Barrier(数据存储器隔离),DMB 指令保证所有在它前面的存储器访问操作都执行完毕后,才提交在它后面的存储器访问操作。

  •   __DSB指令:

Data Synchronization Barrier(数据同步隔离),比DMB严格,当所有在它前面的存储器访问操作都执行完毕后,才执行在它后面的指令。

  •   __ISB指令:

Instruction Synchronization Barrier(指令同步隔离),它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。

24.6.2 函数SCB_DisableICache

函数原型:

__STATIC_INLINE void SCB_DisableICache (void)
{
  #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    __DSB();
    __ISB();
    SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk;  /* disable I-Cache */
    SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */
    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于禁止指令Cache。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。

24.6.3 函数SCB_InvalidateICache

函数原型:

__STATIC_INLINE void SCB_InvalidateICache (void)
{
  #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    __DSB();
    __ISB();
    SCB->ICIALLU = 0UL;
    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于将指令Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的指令。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。

24.6.4 函数SCB_EnableDCache

函数原型:

__STATIC_INLINE void SCB_EnableDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
                      ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);
    __DSB();

    SCB->CCR |=  (uint32_t)SCB_CCR_DC_Msk;  /* enable D-Cache */

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于使能数据Cache,系统上电后优先初始化即可。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。

24.6.5 函数SCB_DisableDCache

函数原型:

__STATIC_INLINE void SCB_DisableDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    register uint32_t ccsidr;
    register uint32_t sets;
    register uint32_t ways;

    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();

    SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean & invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
                       ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于禁止数据Cache。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明

24.6.6 函数SCB_InvalidateDCache

函数原型:

__STATIC_INLINE void SCB_CleanDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
   __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
                      ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于将数据Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的数据。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。

24.6.7 函数SCB_CleanDCache

函数原型:

__STATIC_INLINE void SCB_CleanDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
   __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
                      ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数用于将数据Cache清除,清除的意思是将Cache Line中标记为dirty的数据写入到相应的存储区。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。

24.6.8 函数SCB_CleanInvalidateDCache

函数原型:

__STATIC_INLINE void SCB_CleanInvalidateDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean & invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
                       ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数是前面两个函数SCB_InvalidateDCache和SCB_CleanDCache的二合一。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。

注意事项:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。

24.6.9 函数SCB_InvalidateDCache_by_Addr

函数原型:

__STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     int32_t op_size = dsize;
    uint32_t op_addr = (uint32_t)addr;
     int32_t linesize = ;           /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

    __DSB();

    while (op_size > ) {
      SCB->DCIMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=           linesize;
    }

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数与本章24.6.6小节中讲解的函数作用一样,区别是这里可以指定地址和存储区大小。用于将数据Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的数据。

注意事项:

  •   __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。
  •   第1个参数addr : 操作的地址一定要是32字节对齐的,即这个地址对32求余数等于0。
  •   第2个参数dsize :一定要是32字节的整数倍。

24.6.10   函数SCB_CleanDCache_by_Addr

函数原型:

__STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     int32_t op_size = dsize;
    uint32_t op_addr = (uint32_t) addr;
     int32_t linesize = ;            /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

    __DSB();

    while (op_size > ) {
      SCB->DCCMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=           linesize;
    }

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数与本章24.6.7小节中讲解的函数作用一样,区别是这里可以指定地址和存储区大小。用于将数据Cache清除,清除的意思是将Cache Line中标记为dirty的数据写入到相应的存储区。

注意事项:

  •   __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。
  •   第1个参数addr : 操作的地址一定要是32字节对齐的,即这个地址对32求余数等于0。
  •   第2个参数dsize :一定要是32字节的整数倍。

24.6.11   函数SCB_CleanInvalidateDCache_by_Addr

函数原型:

__STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     int32_t op_size = dsize;
    uint32_t op_addr = (uint32_t) addr;
     int32_t linesize = ;          /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

    __DSB();

    while (op_size > ) {
      SCB->DCCIMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=           linesize;
    }

    __DSB();
    __ISB();
  #endif
}

函数描述:

此函数与本章24.6.8小节中讲解的函数作用一样,区别是这里可以指定地址和存储区大小。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。

注意事项:

  •   __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。
  •   第1个参数addr : 操作的地址一定要是32字节对齐的,即这个地址对32求余数等于0。
  •   第2个参数dsize :一定要是32字节的整数倍。

24.7 总结

本章节就为大家讲解这么多,务必要反复多读几遍,能理解多少算多少,随着后续章节的学习再回过头来再学习。

 


版权声明:本文为[安富莱电子]原创文章
转载请带上:http://copyfuture.com/blogs-details/20190612124713226oyh8mhmsmkd8nq0
或:https://www.cnblogs.com/armfly/p/11008913.html



  1. 维权车主特斯拉退款成功 网友:会哭的孩子有奶吃
  2. 脾胃不好容易导致糖尿病?上消口渴,糖尿病到底该怎么调脾胃?
  3. 种点儿花,养点儿草,生活乐无穷!
  4. 骏铃V8“绿通王”重磅来袭
  5. 心脏病,都需要支架治疗吗?告诉你答案
  6. 李嘉诚亮相香港慈山寺开光典礼,累计捐资30亿港元丨棱镜
  7. Jmeter元件——JSON Extractor后置处理器介绍2
  8. 美国非法移民在地下室做牙医打黑工被捕,牙科设备全靠从中国网购
  9. LeetCode算法题-Student Attendance Record I(Java实现)
  10. Linux环境下Tomcat的下载安装及配置
  11. 520最大新闻是张继科景甜分手?他俩这些小细节不得不让人多想啊
  12. 国际问题专家叶海林:战场新闻虚虚实实,印巴交战“实锤”在哪?
  13. python-django框架中使用FastDFS分布式文件系统
  14. ISME:菌根真菌菌丝分泌物中的果糖作为信号激发解磷细菌活化植酸
  15. 最近很火的毒鸡汤语录,来碗心灵砒霜!
  16. 心血管疾病患者,要阿司匹林和他汀药一起吃吗?临床医生讲出实情
  17. 比特币四年一度的盛会:区块奖励减半
  18. 明代马屁诗四首
  19. Hangfire源码解析-任务是如何执行的?
  20. 几只医药细分龙头股!!
  21. AtCoder Beginner Contest 120 解题报告
  22. 宇宙趣知识;两个太阳照耀的行星、宇宙中神秘变暗的恒星
  23. 健康丨有这个习惯的人,赶紧改掉,它会让你越来越丑……
  24. 300元一小时,周杰伦投资2000万的网吧,网友:上不起啊!
  25. 美军遇到13年来最棘手的事,五角大楼下达死命令,这回谁也帮不了
  26. Python的装饰器
  27. sql注入判断流程(结合sqli-labs学习)
  28. 石友:既然玩石头就要了解一下石头形成的原因
  29. 华为正式打出“王炸”!华为P30价格曝光,正式对标三星S10!
  30. 教女生一招!男朋友只知道玩游戏?不理你?用这个远程关他电脑!
  31. 脑残粉这么洗地,他这次怕是要凉透了吧
  32. 内斗、贪婪、自大,目睹创业之怪现状
  33. 宝宝春捂到底怎么捂?何时该减衣?谨记“三暖二凉”,宝宝少生病
  34. 为防女儿败光家产,船王狠心卖掉家产,买下2块地,如今赚了千亿
  35. 【C#】Learn C# in X minutes
  36. 湖人:后悔的肠子都青了;本赛季弃将集体爆发 ,一人得到顶薪!
  37. 多线程下的HashMap竟然绕环了
  38. JavaScript是如何工作的: Web推送通知的机制
  39. 标致雪铁龙在中国亏损40多亿,陷入巨亏漩涡,法系车一蹶不振?
  40. 微软经典“大眼夹”表情包短暂现身GitHub后再遭“下岗”
  41. 更换ubuntu软件源的方法
  42. 谷歌承认正研发可折叠手机原型 上市依然遥遥无期
  43. 春天去这些绝美天堂,怎么拍都很漂亮
  44. 在一个服务器的svn上,设置一个端口号对应一个项目
  45. 提前11秒,AI让神经科学家预知了你的决定
  46. 周源:知乎已成长为大社区 下一步构建特色社区生态
  47. 张居正逝世后被群臣怒骂,唯一求情的人,竟曾经被他流放边疆
  48. 大唐的英雄之城,被强敌围困攻打百年不倒,宋朝弄丢成千古遗恨
  49. easynetq发布订阅demo实现注意事项
  50. 字节跳动收购三七互娱子公司上海墨鹍 加快布局游戏
  51. 被毛阿敏“夺”饭碗,含恨退圈又被弟弟打成脑震荡,为治病成保姆
  52. 我没回老家过春节的那4点原因
  53. 地球大陆是在什么地方诞生的?
  54. 技术与工艺并举 品鉴积家超薄大师系列陀飞轮珐琅腕表
  55. 楼市持续降温 商品房销售面积时隔43个月再现下跌
  56. 五个小问题让你认识我们的太阳
  57. Windows上搭建web服务器
  58. 【故障公告】阿里云抢占式实例服务器被自动释放引发的故障
  59. 你弱我就强!原来孩子还能这么教!
  60. 设计原则的简单理解
  61. 软件测试知识体系
  62. 32万车位被霸占,业主使出“绝招”,车主上路被罚6万扣12分
  63. koa2 从入门到进阶之路 (六)
  64. 享受头等舱待遇 东风本田艾力绅给你提供VIP服务
  65. 被冠以“恒星工厂”之称的猎户座星云为何独受科学家的宠爱青睐?
  66. 四款被国人误认为是外国佬研发的办公软件,请务必低调收藏
  67. 杜特尔特1周2飙,澳大利亚竟甩锅给中国
  68. 海外社交巨头的一场精彩攻防战
  69. 邮轮撤走母港看中国海上旅游的前景
  70. 中国足协终于醒了
  71. 彻查孙小果案,比比到底谁的“后台”硬!
  72. 看看日本最豪华的“胶囊”酒店,没体验过真是人生遗憾!
  73. 90后的崩溃,也是从借钱开始的
  74. 除了5G之外,中美在这一重要领域开启比拼!美国或将再次耍阴招?
  75. 复联4里用到的方法论
  76. Google Stadia采用了AMD定制芯片 提供10.7 T-Flops运算性能
  77. 俄新型洲际导弹已入列,拥有一项独特能力,号称穿透所有反导系统
  78. 大数据技术之_14_Oozie学习_Oozie 的简介+Oozie 的功能模块介绍+Oozie 的部署+Oozie 的使用案列
  79. 孩子经常发脾气,也许是你的脑洞不够大
  80. Spring的后处理器-BeanPostProcessor跟BeanFactoryPostProcessorS
  81. 关于TCP或FTP异常断开的处理方法总结
  82. 分布式事务的思考与理解
  83. NBA人物志丨迈克尔乔丹,组建三叉戟,公牛拉开反攻的序幕
  84. redux源码学习笔记 - combineReducers
  85. 军史杂谈:三代长春舰见证人民海军70年沧桑巨变
  86. 美极了!100张童书/绘本封面(上)
  87. 该岛屿即将和大陆相连,面积居全国第三,这里的房价早已过万
  88. Python-爬虫03:urllib.request模块的使用
  89. "天琴一号"卫星年内升空 中国将在太空探测引力波
  90. centos7 开机启动服务链接说明
  91. 快速排序到底有多快?
  92. 英媒:希望曼联速卖德赫亚!他会把球队带向最坏极端,水准就那样
  93. 09姚明放现在是什么水平?杨毅评价一针见血,所谓天赋或已被善待
  94. 爱因斯坦那些你不知道的事儿
  95. 第二次作业 姜亦航201731083311
  96. Javascript高级编程学习笔记(47)—— 元素遍历
  97. 对话联想田日辉:工业互联网显成效至少还需3年
  98. 比三星还薄6毫米 京东方20年血泪史 Mate X划下行业最顶尖的标杆
  99. microLED可能在智能手机市场取代OLED
  100. 第一次跳槽之后的一点感悟

  1. 前端笔记之NodeJS(一)初识NodeJS&内置模块&特点(1755)
  2. Matlab 2019a 安装包下载以及安装和激活(1719)
  3. Delphi 开发微信公众平台 (二) 用户管理(1679)
  4. Python开发:部分第三方库无法在线安装解决方法(1563)
  5. React 与 React-Native 使用同一个 meteor 后台(1429)
  6. 《跃迁-成为高手的技术》之联机学习(1427)
  7. [深度应用]·实战掌握Dlib人脸识别开发教程(1427)
  8. 独家 | 寒武纪二代芯片发布在即,提前解密如何挑战英伟达!(1370)
  9. 使用 C 语言实现一个 HTTP GET 连接(1352)
  10. 币安称 4000 万美元比特币被盗(1316)
  11. WebGL three.js学习笔记 纹理贴图模拟太阳系运转(1237)
  12. 微软宣布 .NET 5 计划,支持跨平台、移动开发(1189)
  13. C#读取excel文件提示未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序(1186)
  14. 【译】.NET Core 是 .NET 的未来(1162)
  15. Linux学习(三):XShell连接虚拟机+开通22端口(1135)
  16. layui的table参数条件缓存问题(1114)
  17. 75条笑死人的知乎神回复,用60行代码就爬完了(1103)
  18. 2019年程序员最值得学习的思维利器——任务分解(971)
  19. 10亿元巨贪山西吕梁原副市长张中生二审维持死刑判决(958)
  20. Sublime Text3 最新版3207 安装及破解(947)
  21. 声明与定义的区别(889)
  22. 美方拟升级关税措施?中方:反制!(880)
  23. 绿盟科技互联网安全威胁周报NSFOCUS-19-13(870)
  24. css-博客样式初体验(843)
  25. 小米有品员工签军令状,自动放弃年终奖!(827)
  26. Vue之路由(815)
  27. 科学家在太平洋水域发现奇特的“砷呼吸”微生物(804)
  28. 【预警通告】Weblogic反序列化远程代码执行漏洞(779)
  29. Visual Studio 2019 正式发布,重磅更新,支持live share(742)
  30. 【预警通告】Apache Tomcat远程代码执行漏洞CVE-2019-0232(725)
  31. 【威胁通告】Oracle全系产品2019年4月关键补丁更新(703)
  32. SQL简介及MySQL的安装目录详解(683)
  33. 5月13日公告精读丨一字跌停后,这只300亿市值的白马股出来澄清了(653)
  34. 如果想转行学习WEB前端,这样学也许更加利于找工作(651)
  35. 彭博社:苹果A13芯片即将产量 新iPhone"浴霸"无疑(591)
  36. K8s集群安装--最新版 Kubernetes 1.14.1(567)
  37. MongoDB创建数据库和删除数据库05-14学习笔记(541)
  38. Confluence SSRF及远程代码执行漏洞处置手册(534)
  39. 吴奇隆当爹!前妻马雅舒开心复出拍戏,颜值吸睛气质超赞(532)
  40. PJzhang:Lucifer1993的struts-scan漏洞全量检测工具(531)
  41. 英媒:阿里将允许外国零售商在阿里平台上销售商品(529)
  42. 舍命生子产妇吴梦丈夫怒斥:没抢肺源不是精神分裂,网友断章取义(521)
  43. Visual Studio 2019 正式发布(511)
  44. [翻译] Visual Studio 2019: 极速编码. 智能工作. 创造未来.(485)
  45. 机器学习 ML.NET 发布 1.0 RC(478)
  46. 【硬盘版】下载利器IDM+优特(uTorrent)BT下载器类(473)
  47. 刘强东身边的CXO还有谁“幸存”(469)
  48. 阿里巴巴2018年纳税516亿元 同比增40%(468)
  49. 针对django2.2报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: ill....(465)
  50. 马光远:全球货币政策进入摇摆期,包括房价的资产价格何去何从(434)
  51. 太奇葩!买100元债只给1.63元购物券和1.11元现金?网友炸锅:得买多少债券才能换一双鞋(421)
  52. 雷军清华演讲实录:小米9年的创新、变革与未来(420)
  53. 我司使用了六年的分布式锁(419)
  54. Webpack 4教程 - 第八部分 使用prefetch和preload进行动态加载(405)
  55. 他联系叙恐怖分子“卖军火”,称能搞到2000枚导弹,关键时刻中国警察出手(404)
  56. Spring Boot 2.1.5 正式发布,1.5.x 即将结束使命!(402)
  57. F#周报2019年第14期(402)
  58. 《最强大脑》要垮?桑洁魏坤琳出轨细节被扒,戚薇才是神助攻(389)
  59. 直认与老公感情淡了!27岁TVB上位女星:我们不是好熟(382)
  60. 报告显示:一季度中国家庭总资产缩水而消费支出增加(375)
  61. 那些年,我们一起看的毛片(373)
  62. 谁是苏小明饭局爆粗偷拍者?知情人称另有其人(360)
  63. 苹果应用商店被判垄断?然而并没有(357)
  64. linux系统安装cdcfordb2udb(351)
  65. 如何设置使chrome新标签页中打开链接自动跳转到新标签页?(350)
  66. 迪玛希好惨!昨晚《歌手》为声入人心男团帮帮唱,却再被指控侵权(349)
  67. 女友被曝插足许志安郑秀文婚姻 知情人透露马国明已下定决心分手(346)
  68. 华电教授孙玉兵被指与昔日同学共同学术造假,多所高校调查(345)
  69. 智慧停车场系统开发建设解决方案(343)
  70. F#周报2019年第15期(332)
  71. spring-cloud-sleuth+zipkin源码探究(332)
  72. 深度学习python的配置(Windows)(325)
  73. 许志安出轨视频系蓄谋偷拍?司机被曝收40万装红外摄像头(323)
  74. 威廉王子出轨凯特王妃闺蜜? 外媒称婚外情致兄弟反目(323)
  75. 真实!这部8.5分的缉毒剧,毒贩公然贿赂警察:80万,把我放出去(316)
  76. NodeJs之邮件(email)发送(316)
  77. 视觉中国深夜道歉:全面配合监管部门彻底积极整改(313)
  78. 赌命生子九个月后,吴梦离世:前半辈子任性了,我用生命买单(311)
  79. 新更新kb4493472导致无法正常开机(306)
  80. 她做个半永久眉毛就被说整容了?(301)
  81. 第一次使用VS Code时你应该知道的一切配置(299)
  82. 韦杰落网,金诚集团终局(298)
  83. 山东庆云民企3000亩土地被贱卖 国企接盘拟转性(298)
  84. 华为推出方舟编译器 称可提升安卓系统效率(295)
  85. Google AI 系统 DeepMind 高中数学考试不及格(294)
  86. 读书笔记之《漫画算法:小灰的算法之旅》(293)
  87. 不要996!程序员创建955.WLB不加班公司名单,GitHub周榜第二(292)
  88. 机器学习基石笔记:01 The Learning Problem(291)
  89. 张丹峰出轨最新锤来了!毕滢的朋友圈简直刷新下限啊!(290)
  90. React Native升级方法——升级到最新版本0.59(287)
  91. axios(封装使用、拦截特定请求、判断所有请求加载完毕)(286)
  92. “国防”靠美国? 韩国瑜=马英九2.0? 走着瞧(280)
  93. 吹爆惠英红,《铁探》这位霸道总警司超带感!真乃港剧罕见大女主(279)
  94. Leetcode刷题指南和top100题目(275)
  95. 河南汝州农商行“百万丢款案”调查,两级法院现“判决书打架”(270)
  96. 堪称神器的Chrome插件(266)
  97. Codejam Qualification Round 2019(264)
  98. Weblogic CVE-2019-2647等相关XXE漏洞分析(263)
  99. CentOS7 部署zabbix4.2及添加客户端(261)
  100. 中国海军的逆袭之路(255)

  1. 在Java中使用Redis
  2. 共识协议——RAFT&PBFT
  3. 每日一问:到底为什么属性动画后 View 在新位置还能响应事件
  4. vue elementui 切换语言
  5. 【威胁通告】WebSphere远程代码执行漏洞(CVE-2019-4279)
  6. 市场平静蓄势,变盘窗口临近?(6月26日)
  7. Hadoop 三剑客之 —— 集群资源管理器 YARN
  8. 他在混沌中寻找秩序
  9. ES6新特性
  10. windows10安装nodejs 10和express 4
  11. 爱立信携手联发科技,联合中国电信完成5G SA端到端数据呼叫
  12. 周鸿祎谈华为鸿蒙系统:可以打造成安卓一样的开源系统
  13. Java基础--常用API--IO流相关API
  14. Spring AOP APIS
  15. 周杰伦为儿子庆生一家合照曝光,炫妻晒娃两不误
  16. Adobe cs6 全系列软件绿色破解版-一键安装
  17. Kafka主题中的分区数越多吞吐量就越高?BULLSHIT!!!
  18. 数据结构与算法(一):带你了解时间复杂度和空间复杂度到底是什么?
  19. Spring Schema扩展机制
  20. 线程安全
  21. 14.Python略有小成(模块)
  22. 为了追求极致的性能,Kafka掌控这11项要领
  23. 特斯拉负责汽车制造的副总裁在关键时期离职
  24. .NET程序员如何快入门Spring Boot
  25. Laravel5.x的php artisan migrate数据库迁移创建操作报错SQLSTATE[42000]解决
  26. hibernate和mybatis的区别?
  27. Qemu搭建ARM vexpress开发环境(二)----通过u-boot启动Linux内核
  28. 295亿宁波首富宣告破产!登顶首富到破产仅247天,千亿房企又倒一个?
  29. DIgital Root 的推导
  30. nRF24L01+组网方式及防撞(防冲突)机制的实战分享
  31. LinqMethod 实现 LeftJoin
  32. 苹果若将生产线转移到中国之外,到底有多难?
  33. 通过OSG实现对模型的日照模拟
  34. maven项目或者SpringBoot项目启动时报错在本地仓库中找不到jar包的解决办法
  35. 伊朗击落美军的无人机为啥一打一个准?俄罗斯有话要说
  36. 《柳叶刀》重磅报告,这是当今中国最严重的4大死亡风险因素
  37. python之mock模块基本使用
  38. 递归(三):排列
  39. 【搜索引擎】Solr Suggester 实现全文检索功能-分词和和自动提示
  40. 山口百惠 VS. 中岛美雪,成功女性的人生哪有什么固定模式
  41. 联想发布全球首款5G笔记本电脑 搭载8CX平台+X55模块
  42. 创业板龙头易主!迈瑞医疗最新市值1923亿元,赶超温氏股份
  43. 中国科技公司拥抱国产数据库
  44. 【数据结构】30、hashmap=》hash 计算方式
  45. ES6——class类继承(读书笔记)
  46. .NET Core 微服务之Polly熔断策略
  47. JavaScript系列之JS入门基本语法
  48. 7xex交易所——服务于全球交易用户的创新数字资产交易平台
  49. Python魔法方法__getattr__和__getattribute__详解
  50. 为了招BAT的程序员,年前把老员工辞掉,一个月后公司后悔了
  51. AspNetCore容器化(Docker)部署(四) —— Jenkins自动化部署
  52. python requests模块session的使用建议及整个会话中的所有cookie的方法
  53. 聊聊区块链,虽然我不挖矿!
  54. Laravel:php artisan key:generate三种报错解决方案,修改默认PHP版本(宝塔面板)
  55. (11)《数据结构与算法》之赫夫曼树
  56. 首次!腾讯全面公开整体开源路线图
  57. 一篇文章帮你彻底搞清楚“I/O多路复用”和“异步I/O”的前世今生
  58. pytorch实现yolov3(1) yolov3基本原理
  59. 【Web前端Talk】React-loadable 进行代码分割的基本使用
  60. Java入门第73课——String常量池
  61. Java入门第74课——获取String对象的长度
  62. 学位服加入中式元素遭吐槽像寿衣 设计方:照片光线问题,衣服没问题
  63. 1005 继续(3n+1)猜想(C#)
  64. ARM A57/A72/A76架构之父跳槽苹果:A系列处理器将变更强
  65. SpringCloud系列——TX-LCN分布式事务管理
  66. 高考报考以及心态调整健康贴士
  67. cloudsim 3.0.3下载与安装教程
  68. 为什么很多人转化做web前端而不选择其他的呢?
  69. 记录一次关于Cookie、Json中文乱码的解决方法
  70. 定制虚拟币多币种钱包,ERC20币钱包开发
  71. 第9章 用户自己建立数据类型
  72. VsCode中编写python环境配置
  73. 考生被提醒不要用搜索引擎找填志愿网站 百度回应
  74. HTTP状态码
  75. 离航天飞机只差一步!“史上最难“猎鹰火箭发射究竟难在哪?
  76. 基建狂魔:7分钟车程挖13年!最难隧道终迎来重大突破
  77. 中国铁塔两子公司挂牌成立 可提供电动车换电服务
  78. 请你讲一讲JavaScript有哪些数据类型, 数据类型判断有哪些方法?
  79. 敏捷开发中如何做好Sprint规划?
  80. android 写文件到sd卡问题小记
  81. vue+element 获取验证码
  82. 关于《java多线程核心编程技术》中小节“将任意对象作为对象监视器”的错误
  83. 【算法随记三】小半径中值模糊的急速实现(16MB图7.5ms实现) + Photoshop中蒙尘和划痕算法解读。
  84. 20年研发管理经验谈(十二)
  85. 权威机构学者:比特币只是一种网络游戏,是庞氏骗局、郁金香泡沫的升级版
  86. SpringCloud学习(SPRINGCLOUD微服务实战)一
  87. vue+TS(CLI3)
  88. 华为胡厚崑:鸿蒙系统没推出时间表 华为是安卓坚定支持者
  89. 【Python基础】循环嵌套
  90. k近邻算法之kd树优化(kd树的构造和搜索)——基于Python
  91. 美国小型电信运营商与诺基亚爱立信讨论替换华为设备
  92. Python基础(六) 函数
  93. JavaScript规定了几种语言类型?
  94. JS数据结构第三篇---双向链表和循环链表之约瑟夫问题
  95. 几个高逼格 Linux 命令!
  96. RS232
  97. C++中调用OC代码
  98. OPPO展示两大"黑科技":屏下摄像头和无网络通信
  99. TDD(测试驱动开发)死了吗?
  100. 华为被禁国内手机销量大增 胡厚崑感谢国民的情感支持