当前位置: 首页 > news >正文

STM32-13-MPU

STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
STM32-10-定时器
STM32-11-电容触摸按键
STM32-12-OLED模块

文章目录

  • STM32-12-MPU
    • 1. 内存保护单元MPU
        • 1. MPU简介
        • 2. 内存地址映射
        • 3. MPU设置内存区域的访问权限
        • 4. MPU配置内存区域的访问属性
        • 5. 可共享 Master间数据同步
        • 6. 缓存缩略
    • 2. Cache简介
        • 1. 简介
        • 2. 读操作与写操作
        • 3. 内核基本操作
        • 4. 内核读取cache
        • 5. 内核写入cache
        • 6. 数据不一致解决办法
        • 7. Cache配置相关函数
    • 3. MPU相关寄存器
    • 4. MPU相关HAL库驱动
    • 5. MPU基本配置步骤
    • 6. 代码实现

STM32-12-MPU

1. 内存保护单元MPU

1. MPU简介
  • 内存保护单元:(memory protection unit),简称MPU.

  • MPU功能

    1. 设置不同存储区域的存储器访问权限(特权级用户级

      MPU可以根据特权级或用户级设置存储器区域的读、写、执行等权限,以限制对存储器的访问。

    2. 设置存储器(内存和外设)属性(可缓存可缓冲可共享

  • 具体功能

    • 阻止用户应用程序破坏操作系统使用的数据;
    • 阻止一个任务访问其他任务的数据区,从而隔离任务;
    • 把关键数据区域设置为只读,从根本上解决被破坏的可能;
    • 检测意外的存储访问,如堆栈溢出、数组越界等;
    • 将SRAM或RAM空间定义为不可执行,防止代码注入攻击;
    • 提高嵌入式系统的健壮性,使系统更加安全。
2. 内存地址映射

在这里插入图片描述

内核地址映射是指将物理内存地址映射到内核空间的过程,其中MPU可以通过配置保护内存区域来实现对内核地址空间的保护和管理。

在MPU中,可以配置多个内存保护区域,通常编号为Region0到Region15(针对H7芯片),每个区域都有一定的访问属性和权限。这些区域可以用来定义内核地址空间的访问规则,以确保内核的安全性和稳定性。

针对内核地址映射,需要注意以下配置:

  1. 优先级和编号: MPU中每个内存保护区域都有一个编号,通常编号范围是0到15。编号越小,优先级越低,这意味着编号为15的区域具有最高的权限和访问优先级。
  2. 访问属性和权限: 每个内存保护区域可以配置不同的访问属性和权限,包括读、写和执行权限。可以根据需要配置这些属性,以确保不同内存区域的安全性。例如,你可以设置某个区域为只读(不可写),或禁用某些区域的执行权限以防止代码注入攻击。
  3. 重叠和嵌套: 如果存在多个内存保护区域并且它们发生重叠或嵌套,MPU会按照优先级高的区域的配置规则来执行。这意味着在访问重叠或嵌套区域时,遵循优先级最高的区域的访问规则,以确保内存访问的安全性。
  4. 背景区: MPU通常还会定义一个默认的背景区,其序号通常为-1。背景区用于定义未被其他保护区域覆盖的内存空间的访问规则,这可以确保整个内存空间的完整性,即使没有显式地定义所有区域。

通过配置MPU,可以在STM32中实现不同内存区域的访问控制,确保系统的安全性和稳定性。

3. MPU设置内存区域的访问权限

MPU_REGION_NO_ACCESS:无访问(特权级&用户级都不可访问);

MPU_REGION_PRIV_RW:仅支持特权级读写访问;

MPU_REGION_PRIV_RW_URO:禁止用户级写访问(特权级可读写访问);

MPU_REGION_FULL_ACCESS:全访问(特权级&用户级都可访问);

MPU_REGION_PRIV_RO:仅支持特权级读访问;

MPU_REGION_PRIV_RO_URO:只读(特权级&用户级都不可以写)。

在配置了MPU的访问权限后,如果程序尝试访问未经授权的区域或者违反了权限配置,将触发错误异常MemManage),系统会相应地进行处理,通常是通过异常处理机制中的相关异常处理函数进行处理,例如重启系统或者输出错误信息等。

4. MPU配置内存区域的访问属性

在这里插入图片描述

在配置MPU时,可以为每个内存区域指定访问属性,以确保CPU对内存的访问方式符合要求。主要的内存类型包括:

  1. 正常内存(Normal Memory): 正常内存类型允许CPU使用缓存和优化访问。这种类型的内存通常用于RAMROM。访问顺序可以被优化,以提高性能。
  2. 设备内存(Device Memory): 这种类型的内存用于访问外设,确保访问的顺序和原子性。设备内存禁止缓存,以确保每次访问都直接与硬件通信。这种内存访问被认为是强顺序的。
  3. 强排序内存(Strongly Ordered Memory): 这种类型的内存访问顺序严格,所有内存访问按照程序顺序进行,不会被重排序。这种类型通常用于控制寄存器外设

配置步骤

初始化MPU

  • 启用MPU并设置默认内存访问权限。
  • 可以通过函数HAL_MPU_Enable()启用MPU。

配置内存区域

  • 使用MPU_Region_InitTypeDef结构体定义每个内存保护区域的属性。
  • 设置区域编号、起始地址、尺寸、访问权限、子区域禁用和其他属性。
  • 调用HAL_MPU_ConfigRegion()函数配置每个区域。

启用MPU保护

  • 在配置所有内存区域后,调用HAL_MPU_Enable()函数启用MPU保护。

代码示例

void MPU_Config(void)
{MPU_Region_InitTypeDef MPU_InitStruct;/* Disable MPU */HAL_MPU_Disable();/* Configure the MPU attributes as WT for SRAM */MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress = 0x20000000;MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER0;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Enable MPU (Background region) */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

这个例子配置了一个128KB大小的SRAM区域,允许全访问权限,并且在启用MPU时启用背景区域。

三种类型对应的情景
在这里插入图片描述

  1. Normal Memory

    应用场景:

    • 用于存储一般数据和程序代码,例如RAM和ROM。

    • 适用于需要高速访问和缓存优化的数据存储区域。

    特点:

    • 可缓存: 允许使用缓存,以提高访问速度和系统性能。

    • 访问优化: 访问顺序可以被CPU优化(乱序执行),以更高效地利用总线带宽。

    • 读写权限: 根据配置,可以设置为只读、只写或读写。

    示例:

    • 程序代码存储(Flash memory)

    • 动态数据存储(SRAM)

  2. Device Memory

    应用场景:

    • 用于与外设通信,例如GPIO、ADC、UART等外设寄存器。

    • 适用于必须确保访问顺序和数据完整性的硬件接口。

    特点:

    • 非缓存: 禁止使用缓存,以确保每次访问都直接与硬件通信。

    • 访问顺序严格: 保证访问顺序不被CPU重新排序,以确保硬件操作的原子性和一致性。

    • 特殊处理: 适用于需要特定处理的外设寄存器,如读写时有副作用的寄存器。

    示例:

    • 控制寄存器(GPIO)

    • 状态寄存器(UART状态寄存器)

  3. Strongly Ordered Memory

    应用场景:

    • 用于需要严格访问顺序的关键系统部分,例如控制寄存器和重要外设寄存器。

    • 适用于多处理器系统中的共享资源管理。

    特点:

    • 严格访问顺序: 所有内存访问严格按程序顺序执行,不允许任何形式的重新排序。

    • 数据完整性: 确保多处理器系统中访问共享资源时数据的完整性。

    • 非缓存: 通常禁止缓存,确保每次访问的准确性和一致性。

    示例:

    • 多处理器系统中的共享控制寄存器

    • 高优先级系统任务中的关键配置寄存器

5. 可共享 Master间数据同步

在这里插入图片描述

在多处理器系统或多核系统中确保数据同步一致性是非常重要的。以下是一些常见的方法:

  1. 锁机制(Locking):锁是一种最基本的同步机制,它可以确保在任何时刻只有一个线程可以访问共享资源。当一个核心想要访问共享资源时,它会请求获取锁,如果锁已被其他核心持有,则该核心会被阻塞直到锁可用。
  2. 信号量(Semaphore):信号量是一种更加灵活的同步机制,它允许多个线程同时访问共享资源,但是限制同时访问资源的线程数量。信号量维护一个计数器,当一个核心想要访问资源时,它首先尝试对信号量进行加锁,如果计数器大于零,则可以继续访问资源,并将计数器减一;否则,线程将被阻塞直到计数器变为正数。
  3. 条件变量(Condition Variables):条件变量允许线程在某些条件下等待或者被唤醒。在多处理器系统中,条件变量常与锁结合使用,以实现更复杂的同步机制。当一个核心等待某个条件时,它会释放锁并进入睡眠状态,直到其他核心改变了条件并唤醒了等待线程。
  4. 原子操作(Atomic Operations):原子操作是一种特殊的指令序列,可以在不被中断的情况下执行。在多处理器系统中,原子操作通常用于实现简单的同步操作,比如对共享变量的增加或减少。原子操作保证了这些操作的原子性,即它们要么完全执行成功,要么完全不执行,不会出现部分执行的情况。
  5. 屏障(Barrier):屏障用于确保在多个线程中的所有操作都完成之后才能继续执行下一步操作。在多处理器系统中,屏障可以用于同步多个核心的执行流,确保它们在某个点上同时到达并继续执行。
  6. 读-写锁(Read-Write Lock):读-写锁允许多个线程同时读取共享资源,但是只有一个线程可以写入共享资源。在多处理器系统中,读-写锁可以提高并发性能,因为多个线程可以同时读取资源而无需互斥。
  7. 共享内存: 共享内存是一种允许多个核心共享相同物理内存区域的机制。通过共享内存,不同核心可以直接访问同一块内存,从而实现数据的共享和同步。

这些方法通常会根据具体的应用场景和性能需求进行选择和组合,以实现高效的数据同步和一致性保证。

6. 缓存缩略
  • Write Through(写透方式): 每次写操作会同步到内存和缓存,可以确保数据一致性,但写操作的性能较低,因为需要等待数据写入到内存后才能继续执行。
  • Write Back(写回方式): 写操作首先写入到缓存,然后根据一定策略(如LRU)将数据写回到内存。写回方式可以提高写操作的性能,但可能会导致缓存和内存数据不一致的情况发生。
  • No Write Allocate(非写分配方式): 写操作直接写入到内存,不会分配缓存行。这种方式可以减少缓存污染,但会增加内存访问次数,影响性能。
  • Read Allocate(读分配方式): 当读操作发生时,如果数据不在缓存中,会将数据加载到缓存中。这种方式可以提高读操作的性能,但会增加缓存的占用。

2. Cache简介

1. 简介

M7内核芯片添加了一级缓存支持,这是个很不错的改进。一级缓存通常用于存储最频繁使用的数据和指令,以提高处理器的性能和效率。这种设计利用了局部性原理,即程序倾向于访问相邻的内存位置。D-Cache用于存储数据,而I-Cache则用于存储指令,这样可以更好地优化数据和指令的访问。这种优化可以显著提高处理器的运行速度,尤其是对于需要频繁访问内存的任务来说。

  1. 数据缓存(D-Cache)

    • 数据缓存主要用于存储程序执行期间使用的数据。当处理器需要访问内存中的某个数据时,它首先会检查数据缓存。如果数据在缓存中已经存在(即命中),处理器就可以直接从缓存中读取数据,而不必访问主内存。如果数据不在缓存中(即缓存未命中),处理器就需要从主内存中读取数据,并将其加载到缓存中,以便日后的访问。
  2. 指令缓存(I-Cache)

    • 指令缓存主要用于存储程序的指令,即处理器执行的操作序列。当处理器需要执行某个指令时,它会从指令缓存中获取指令。如果指令在缓存中已经存在,处理器就可以直接执行它,而不必从主内存中读取。如果指令不在缓存中,处理器就需要从主内存中读取指令,并将其加载到缓存中以供后续执行。
2. 读操作与写操作

在这里插入图片描述

关键点:

  • 命中(Cache Hit):当处理器需要访问的数据或指令在缓存中存在时,发生命中。
  • 未命中(Cache Miss):当处理器需要访问的数据或指令在缓存中不存在时,发生未命中,处理器需要从主内存中读取数据或指令。
  • 替换策略:当缓存已满且需要将新的数据或指令加载到缓存中时,缓存控制器会根据一定的替换策略选择要替换的缓存行,常见的替换策略包括最近最少使用(LRU)和先进先出(FIFO)等。
  • 写策略:数据缓存通常有写回(Write-Back)和写直通(Write-Through)两种写策略,写回会先在缓存中更新数据,然后在某个时机将更新的数据写回主内存,而写直通则会同时更新缓存和主内存。
  • 一致性:缓存一致性是指处理器对缓存中的数据进行更新时,要确保所有缓存中的副本都得到相应的更新,以保证数据的一致性。

通过使用数据缓存和指令缓存,处理器可以显著提高程序的执行速度,因为缓存可以提供比主内存更快的访问速度,减少了处理器访问主内存的频率,从而减少了存储系统的瓶颈。

3. 内核基本操作

在STM32系列的M7内核中,Cache支持以下基本操作:

  1. Invalidate(无效化缓存):
    • 无效化操作用于使缓存中的特定数据失效。这通常在其他系统组件(如DMA控制器)更新了内存中的数据时使用,以确保处理器从内存中获取最新数据而不是使用缓存中的旧数据。
    • 在STM32的M7内核中,可以通过无效化指令来无效化整个缓存或特定的缓存行。无效化操作不会将缓存中的数据写回到主内存,只是标记为无效。
  2. Clean(清理缓存):
    • 清理操作将缓存中的脏数据(已修改但尚未写回主内存的数据)写回到主内存,但不使缓存行无效。这有助于确保主内存中的数据是最新的,但缓存行仍然保持有效状态。
    • 该操作可以通过清理指令实现,可以针对整个缓存或特定的缓存行进行清理。
  3. Clean and Invalidate(清理并无效化缓存):
    • 这是清理和无效化的组合操作。它将缓存中的脏数据写回到主内存,然后使这些缓存行无效。此操作确保数据一致性,并在不需要保留缓存数据时使用。
    • 该操作可以通过清理并无效化指令进行,可以针对整个缓存或特定的缓存行进行。
  4. Enable/Disable(启用/禁用缓存):
    • 启用操作会打开缓存,使其开始工作并缓存数据和指令。禁用操作会关闭缓存,处理器将直接访问主内存而不经过缓存。
    • 启用和禁用缓存通常通过设置缓存控制寄存器(如CM7的控制寄存器)来实现。
4. 内核读取cache

在这里插入图片描述

Cache Hit (命中)

当 CPU 需要读取的数据位于 Cache 中,并且 Cache 中已经加载了该数据时,发生 Cache Hit。
在 Cache Hit 的情况下,CPU 可以直接从 Cache 中读取数据,而无需访问主存,这样可以大大提高读取速度。
Cache Miss (未命中):

当 CPU 需要读取的数据位于主存中,而不在 Cache 中时,发生 Cache Miss。
在 Cache Miss 的情况下,需要从主存中加载数据到 Cache,以便 CPU 可以读取。

有两种常见的处理方式:
Read Through (直接读取): CPU 直接从主存中读取数据,而不将数据加载到 Cache 中。这样做可以确保数据的一致性,但可能会降低读取速度,因为需要额外的主存访问。
Read Allocate (读取分配): CPU 将缺失的数据加载到 Cache 中,然后再从 Cache 中读取数据。这样做可以提高读取速度,因为之后的读取可以直接从 Cache 中进行,但可能会导致 Cache 中的其他数据被替换掉。

5. 内核写入cache

在这里插入图片描述

在STM32系列的M7内核中,缓存(Cache)支持多种操作方式,这些操作方式在缓存命中(Cache Hit)和未命中(Cache Miss)的情况下会有所不同。具体而言,可以根据不同的写策略来处理写操作。这些策略包括写透(Write Through)和写回(Write Back)策略,以及在缓存未命中的情况下的写分配(Write Allocate)和非写分配(No Write Allocate)策略。

Cache Hit(命中)操作

  1. Write Through(写透):

    • 操作: 在缓存命中的情况下,数据同时写入到缓存和内存。
    • 优点: 保持内存和缓存的一致性,确保内存中的数据始终是最新的。
    • 缺点: 写操作速度较慢,因为每次写操作都需要同时更新内存。
  2. Write Back(写回):

    • 操作: 在缓存命中的情况下,数据仅写入缓存,而不立即写入内存。只有当缓存行被替换或被明确要求写回时,才会将数据写入内存。
    • 优点: 提高写操作的速度,因为写操作只需更新缓存,不需要立即访问内存。
    • 缺点: 需要额外的机制来确保缓存和内存之间的一致性,这可能增加系统的复杂度。

Cache Miss(未命中)操作

  1. Write Allocate(写分配):

    • 操作: 在缓存未命中的情况下,将所需的数据块从内存加载到缓存,然后再执行写入操作。
    • 优点: 未来对同一数据块的写操作可以在缓存中直接进行,提高后续的写入速度。
    • 缺点: 可能会增加第一次写入的延迟,因为需要先从内存加载数据到缓存。
  2. No Write Allocate(非写分配):

    • 操作: 在缓存未命中的情况下,直接将数据写入内存,而不将数据块加载到缓存。
    • 优点: 避免了加载数据块到缓存的额外开销,适用于写操作频率较低的情况。
    • 缺点: 未来对同一数据块的写操作仍需直接访问内存,可能会降低后续写入操作的速度。
6. 数据不一致解决办法

解决数据不一致性问题的两种主要方法分别是设置共享属性软件进行缓存维护。下面是对这两种方法的详细分析:

  1. 设置共享属性

    • 优点

      • 简单直接: 通过将内存区域设置为共享属性,可以确保所有核心或外设都能够看到最新的数据。这个方法通过硬件机制保证数据一致性,而不需要额外的软件干预。

      • 保证一致性: 所有访问该内存区域的操作都会直接访问主存,从而确保数据的一致性。

    • 缺点

      • 性能下降: Cache相当于没有开启,因为所有的读写操作直接访问内存,无法利用Cache提升访问速度。特别是在频繁访问内存的场景下,性能可能会显著下降。
      • 浪费Cache资源: Cache的优势无法得到发挥,这在处理器设计中是一个浪费,因为Cache本来就是为了提升性能而设计的。
  2. 软件进行Cache维护

    2.1 Clean(清空

    • 优点

      • 数据一致性: 在数据被修改后,通过Clean操作将Cache中的相应数据写回内存,可以确保内存中的数据与Cache中的数据保持一致。这在需要确保数据一致性的关键操作中非常有用。

      • 保持性能: Clean操作后,Cache依然可以继续使用,之后的访问仍然可以从Cache中受益。

    • 缺点

      • 额外复杂性: 需要额外的软件操作来维护Cache,增加了系统的复杂性。

      • 性能损失: Clean操作会增加额外的开销,特别是在频繁执行的情况下,可能导致性能损失。

    2.2 Invalidate(无效化)

    • 优点

      • 数据一致性: 当内存中的数据被修改但Cache中的数据尚未更新时,通过Invalidate操作使Cache中的数据无效,以便从内存中重新加载最新的数据,从而确保数据一致性。

      • 保持性能: 在Invalidate操作之后,Cache依然可以继续使用,后续访问仍然可以从Cache中受益。

    • 缺点

      • 额外复杂性: 需要额外的软件操作来维护Cache,增加了系统的复杂性。
      • 性能损失: Invalidate操作会增加额外的开销,特别是在频繁执行的情况下,可能导致性能损失。

    总结

    设置共享属性是一种简单直接的方法,通过硬件机制确保数据一致性,但无法利用Cache的性能提升优势,适用于需要绝对数据一致性且对性能要求不高的场景。

    软件进行Cache维护则允许在使用Cache的同时,通过Clean和Invalidate操作来确保数据一致性。虽然增加了系统的复杂性和一些性能开销,但在需要高性能且仍需确保数据一致性的场景中,这是更为灵活和高效的方法。

    选择哪种方法取决于具体的应用场景和系统要求。如果数据一致性至关重要且对性能要求较低,可以选择设置共享属性。如果需要高性能且可以接受一定的复杂性,则可以选择通过软件进行Cache维护。

7. Cache配置相关函数

I-Cache 相关函数

SCB_EnableICache: 启用指令缓存(I-Cache) ;

SCB_DisableICache: 禁用指令缓存(I-Cache) ;

SCB_InvalidateICache: 使指令缓存(I-Cache)无效,将其中的所有条目标记为无效 ;

D-Cache 相关函数

SCB_EnableDCache: 启用数据缓存(D-Cache) ;

SCB_DisableDCache: 禁用数据缓存(D-Cache) ;

SCB_InvalidateDCache: 使数据缓存(D-Cache)无效,将其中的所有条目标记为无效 ;

SCB_CleanDCache: 清理数据缓存(D-Cache),将其中的已更改数据写回到主存中 ;

SCB_CleanInvalidateDCache: 清理并使数据缓存(D-Cache)无效,即执行清理和使无效两个操作 ;

SCB_InvalidateDCache_by_addr: 通过地址范围使数据缓存(D-Cache)无效 ;

SCB_CleanDCache_by_addr: 通过地址范围清理数据缓存(D-Cache) ;

SCB_CleanInvalidateDCache_by_add: 通过地址范围清理并使数据缓存(D-Cache)无效。

3. MPU相关寄存器

寄存器名称功能
MPU_TYPEMPU类型寄存器用于指明MPU的一些特征 (是否支持MPU、支持多少个Region)
MPU_CTRLMPU控制寄存器设置MPU使能
MPU_RNRMPU区域编号寄存器用于选择下一个要配置的region
MPU_RBARMPU基地址寄存器用于设置区域的起始地址
MPU_RASRMPU区域属性和容量寄存器用于设置每个区域的属性
  • MPU_TYPE 寄存器
    在这里插入图片描述

  • MPU_CTRL 寄存器
    在这里插入图片描述

  • MPU_RNR 寄存器
    在这里插入图片描述

  • MPU_RBAR 寄存器
    在这里插入图片描述

  • MPU_RASR 寄存器
    在这里插入图片描述

    • AP 相关位控制数据的访问权限
      在这里插入图片描述

    • TEX用来设置Cache策略
      在这里插入图片描述

      在STM32系列的M7内核中,缓存策略的选择对于性能优化和数据一致性维护非常重要。不同的缓存策略有不同的特性和应用场景。以下是对几种常见缓存策略的详细说明:

      1. Non-cacheable(非缓存)
      • 描述: 数据不会被缓存在缓存中,每次访问都会直接读取或写入主存。
      • 特性:
        • 每次访问主存: 每次数据访问都是直接与主存进行,不经过缓存。
        • 数据一致性: 保证数据一致性,因为所有数据访问都是直接访问主存。
        • 性能: 可能较低,因为每次访问都要经过较慢的主存。
      • 适用场景: 需要绝对数据一致性且对性能要求不高的场景。
      1. Write-through, read-allocated, no-write-allocate(写透传,读分配,不写分配)
      • 描述:
        • 写操作: 直接写入主存,并通过缓存透传到主存。
        • 读操作: 在缓存中未命中时会分配缓存。
      • 特性:
        • 写操作: 每次写操作都会直接写入主存,保证内存与缓存数据一致。
        • 读操作: 在缓存未命中时,会从主存加载数据到缓存中。
        • 性能: 写操作性能较低,因为每次写都需要访问主存;读操作性能较好,命中缓存时可以快速读取。
      • 适用场景: 需要高读性能,同时需要确保写操作数据一致性的场景。
      1. Write-back, read-allocated, no-write-allocate(写回,读分配,不写分配)
      • 描述:
        • 写操作: 先写入缓存,并标记为脏数据,如果缓存中有相应数据块。
        • 读操作: 在缓存未命中时会分配缓存。
      • 特性:
        • 写操作: 写入缓存并标记为脏数据,提高写操作的性能,不立即写入主存。
        • 读操作: 在缓存未命中时,从主存加载数据到缓存中。
        • 性能: 写操作性能高,因为多数写操作在缓存中完成;读操作性能也高,未命中时会分配缓存。
      • 适用场景: 写操作频繁且对写操作性能有较高要求的场景。
      1. Write-back, read-allocated, write-allocate(写回,读分配,写分配)
      • 描述:
        • 写操作: 先写入缓存并标记为脏数据,如果缓存中有相应数据块;如果没有,则分配缓存并写入。
        • 读操作: 在缓存未命中时会分配缓存。
      • 特性:
        • 写操作: 写入缓存并标记为脏数据,未命中时分配缓存,确保缓存命中率。
        • 读操作: 在缓存未命中时,从主存加载数据到缓存中。
        • 性能: 写操作和读操作性能都很高,因为缓存可以容纳更多的数据块,减少主存访问。
      • 适用场景: 读写操作都频繁且对性能有较高要求的场景。

      总结

      选择适当的缓存策略取决于应用的具体需求:

      • Non-cacheable: 适用于需要绝对数据一致性且性能要求不高的场景。
      • Write-through, read-allocated, no-write-allocate: 适用于需要高读性能且写操作需要确保数据一致性的场景。
      • Write-back, read-allocated, no-write-allocate: 适用于写操作频繁且对写操作性能有较高要求的场景。
      • Write-back, read-allocated, write-allocate: 适用于读写操作都频繁且对性能有较高要求的场景。

4. MPU相关HAL库驱动

驱动函数关联寄存器功能描述
HAL_MPU_Enable(…)CTRLMPU使能
HAL_MPU_Disable(…)CTRLMPU失能
HAL_MPU_ConfigRegion(…)RASR\RBAR\RNR配置MPU参数

5. MPU基本配置步骤

  1. 禁止MPU

    void HAL_MPU_Disable();
    
  2. 配置某个区域的MPU保护参数

    void HAL_MPU_ConfigRegion()
    
  3. 使能MPU

    void HAL_MPU_Enable();
    
  4. 编写MemManage中断服务函数

    void MemManage_Handler(void)
    

MPU基本配置步骤

  1. 禁用MPU

    • 在配置MPU之前,确保MPU处于禁用状态。

      MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
      
  2. 配置MPU区域

    • MPU支持多个保护区域,每个区域可以单独配置。以下是配置MPU区域的步骤:

    • 选择区域

      MPU->RNR = region_number; // 选择要配置的区域编号
      
    • 配置区域基地址

      MPU->RBAR = base_address & MPU_RBAR_ADDR_Msk; // 设置区域基地址
      
    • 配置区域属性

      • 访问权限(AP)
      • 缓存策略
      • 共享属性
      • 子区域禁用
      MPU->RASR = (attribute << MPU_RASR_AP_Pos)   |  // 访问权限(cache_policy << MPU_RASR_C_Pos) |  // 缓存策略(shareable << MPU_RASR_S_Pos)    |  // 共享属性(subregion << MPU_RASR_SRD_Pos)  |  // 子区域禁用(size << MPU_RASR_SIZE_Pos)      |  // 区域大小MPU_RASR_ENABLE_Msk;              // 使能区域
      
  3. 使能MPU

    • 在所有区域配置完成后,启用MPU。

    • 启用背景区域(可选)

      MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk; // 启用默认背景区域(可选)
      
    • 启用MPU

        MPU->CTRL |= MPU_CTRL_ENABLE_Msk; // 启用MPU
      
  4. 刷新指令和数据缓存

    • 在配置完成并启用MPU后,刷新指令和数据缓存以确保所有更改生效。

      __DSB();
      __ISB();
      

6. 代码实现

  • 设置某个区域的MPU保护函数

    uint8_t mpu_set_protection(uint32_t baseaddr, uint32_t size, uint32_t rnum, uint8_t de, uint8_t ap, uint8_t sen, uint8_t cen, uint8_t ben)
    {MPU_Region_InitTypeDef mpu_region_init_handle;           /* MPU初始化句柄 */HAL_MPU_Disable();                                       /* 配置MPU之前先关闭MPU,配置完成以后在使能MPU */mpu_region_init_handle.Enable = MPU_REGION_ENABLE;       /* 使能该保护区域 */mpu_region_init_handle.Number = rnum;                    /* 设置保护区域 */mpu_region_init_handle.BaseAddress = baseaddr;           /* 设置基址 */mpu_region_init_handle.Size = size;                      /* 设置保护区域大小 */mpu_region_init_handle.SubRegionDisable = 0X00;          /* 禁止子区域 */mpu_region_init_handle.TypeExtField = MPU_TEX_LEVEL0;    /* 设置类型扩展域为level0 */mpu_region_init_handle.AccessPermission = ap;            /* 设置访问权限 */mpu_region_init_handle.DisableExec = de;                 /* 是否允许指令访问 */mpu_region_init_handle.IsShareable = sen;                /* 是否允许共用 */mpu_region_init_handle.IsCacheable = cen;                /* 是否允许cache */mpu_region_init_handle.IsBufferable = ben;               /* 是否允许缓冲 */HAL_MPU_ConfigRegion(&mpu_region_init_handle);           /* 配置MPU */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);                  /* 开启MPU */return 0;
    }
    
  • 设置需要保护的存储块函数

    void mpu_memory_protection(void)
    {/* 保护整个DTCM,共128K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */mpu_set_protection(0x20000000, MPU_REGION_SIZE_128KB, MPU_REGION_NUMBER1, MPU_INSTRUCTION_ACCESS_ENABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);/* 保护整个AXI SRAM,共512K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */mpu_set_protection(0x24000000, MPU_REGION_SIZE_512KB,MPU_REGION_NUMBER2, MPU_INSTRUCTION_ACCESS_ENABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);/* 保护整个SRAM1~SRAM3,共288K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */mpu_set_protection(0x30000000, MPU_REGION_SIZE_512KB,MPU_REGION_NUMBER3, MPU_INSTRUCTION_ACCESS_ENABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);/* 保护整个SRAM4,共64K字节,允许指令访问,禁止共用,允许cache,允许缓冲 */mpu_set_protection(0x38000000, MPU_REGION_SIZE_64KB, MPU_REGION_NUMBER4, MPU_INSTRUCTION_ACCESS_ENABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);/* 保护MCU LCD屏所在的FMC区域,,共64M字节,允许指令访问,禁止共用,禁止cache,禁止缓冲 */mpu_set_protection(0x60000000, MPU_REGION_SIZE_64MB, MPU_REGION_NUMBER5, MPU_INSTRUCTION_ACCESS_ENABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_NOT_CACHEABLE, MPU_ACCESS_NOT_BUFFERABLE);/* 保护SDRAM区域,共64M字节,允许指令访问,禁止共用,允许cache,允许缓冲 */mpu_set_protection(0XC0000000, MPU_REGION_SIZE_64MB, MPU_REGION_NUMBER6, MPU_INSTRUCTION_ACCESS_ENABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_CACHEABLE, MPU_ACCESS_BUFFERABLE);/* 保护整个NAND FLASH区域,共256M字节,禁止指令访问,禁止共用,禁止cache,禁止缓冲 */mpu_set_protection(0X80000000, MPU_REGION_SIZE_256MB, MPU_REGION_NUMBER7, MPU_INSTRUCTION_ACCESS_DISABLE,MPU_REGION_FULL_ACCESS, MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_NOT_CACHEABLE, MPU_ACCESS_NOT_BUFFERABLE);
    }
    
  • MemManage错误处理中断

    void MemManage_Handler(void)
    {LED1(0);                            /* 点亮LED1(GREEN LED) */printf("Mem Access Error!!\r\n");   /* 输出错误信息 */delay_ms(1000);printf("Soft Reseting...\r\n");     /* 提示软件重启 */delay_ms(1000);NVIC_SystemReset();                 /* 软复位 */
    }
    
  • 主函数

    #include "stdlib.h"
    #include "./SYSTEM/sys/sys.h"
    #include "./SYSTEM/usart/usart.h"
    #include "./SYSTEM/delay/delay.h"
    #include "./BSP/LED/led.h"
    #include "./BSP/KEY/key.h"
    #include "./BSP/MPU/mpu.h"#if !(__ARMCC_VERSION >= 6010050)   /* 不是AC6编译器,即使用AC5编译器时 */
    uint8_t mpudata[128] __attribute__((at(0X20002000)));  /* 定义一个数组 */
    #else
    uint8_t mpudata[128] __attribute__((section(".bss.ARM.__at_0X20002000"))); /* 定义一个数组 */
    #endifint main(void)
    {uint8_t key = 0;uint8_t t = 0; sys_cache_enable();                 /* 打开L1-Cache */HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(240, 2, 2, 4); /* 设置时钟, 480Mhz */delay_init(480);                    /* 延时初始化 */usart_init(115200);                 /* 串口初始化为115200 */led_init();                         /* 初始化LED */key_init();                         /* 初始化按键 */printf("\r\n\r\nMPU closed!\r\n");  /* 提示MPU关闭 */mpu_memory_protection();while (1){key = key_scan(0);if (key == WKUP_PRES)           /* 使能MPU保护数组 mpudata */{mpu_set_protection(0X20002000, MPU_REGION_SIZE_128B, MPU_REGION_NUMBER0, MPU_INSTRUCTION_ACCESS_ENABLE, MPU_REGION_PRIV_RO_URO,MPU_ACCESS_NOT_SHAREABLE, MPU_ACCESS_NOT_CACHEABLE, MPU_ACCESS_BUFFERABLE);  /* 只读,禁止共用,禁止cache,允许缓冲 */printf("MPU open!\r\n");    /* 提示MPU打开 */}else if (key == KEY0_PRES)      /* 向数组中写入数据,如果开启了MPU保护的话会进入内存访问错误! */{printf("Start Writing data...\r\n");sprintf((char *)mpudata, "MPU test array %d", t);printf("Data Write finshed!\r\n");}else if (key == KEY1_PRES)      /* 从数组中读取数据,不管有没有开启MPU保护都不会进入内存访问错误! */{printf("Array data is:%s\r\n", mpudata);}else {delay_ms(10);}t++;if ((t % 50) == 0) {LED0_TOGGLE();      /* LED0取反 */}}
    }
    

声明:资料来源(战舰STM32F103ZET6开发板资源包)

  1. Cortex-M3权威指南(中文).pdf
  2. STM32F10xxx参考手册_V10(中文版).pdf
  3. STM32F103 战舰开发指南V1.3.pdf
  4. STM32F103ZET6(中文版).pdf
  5. 战舰V4 硬件参考手册_V1.0.pdf

相关文章:

STM32-13-MPU

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 文章目录 STM32-12-MPU1. 内存保护单元MPU1. M…...

(超详细)字符函数和字符串函数【上】

前言 C 语言中对字符和字符串的处理很是频繁&#xff0c;但是 C 语言本身是没有字符串类型的&#xff0c;字符串通常放在 常量字符串 中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数 . 1.求字符串长度函数 strlen函数 我们要求一个字符串函数的长度…...

AUS GLOBAL 荣获 Brokersview 颁奖盛典多项殊荣

2024年1月31日在迪拜 Sheikh Zayed Rd - Trade Centre - Trade Centre 1 举行的 Brokersview 颁奖盛典上&#xff0c;AUS GLOBAL&#xff08;澳洲环球&#xff09;再次展现了其在金融行业的卓越实力&#xff0c;并荣获多项殊荣。 AUS GLOBAL 作为一家全球领先的金融服务提供商…...

Spring Aop 实现对mapper层入参进行重新赋值

需求描述&#xff1a; 需要对mapper查询的入参的某个属性值进行特殊处理后查询 不影响原来业务且方便扩展维护 1&#xff0c;自定义注解 import java.lang.annotation.*;/*** 针对 mapper层入参 按照一定规则进行特殊处理重新赋值*/ Target(ElementType.METHOD) Retention(Ret…...

朗读亭主要作用有哪些?

朗读亭的主要作用有以下几个方面&#xff1a; 1. 提供朗读服务&#xff1a;朗读亭是一个专门的场所&#xff0c;提供给人们朗读的环境和场地。人们可以在朗读亭中选择自己喜欢的书籍或文章&#xff0c;并通过朗读将其表达出来。这样可以帮助人们提高朗读能力&#xff0c;增强自…...

力扣:226. 翻转二叉树

226. 翻转二叉树 已解答 简单 相关标签 相关企业 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a…...

深入解析 JSONPath:从入门到精通

码到三十五 &#xff1a; 个人主页 在数据处理和交换领域&#xff0c;JSON已经成为了一种广泛使用的数据格式&#xff0c; 如何有效地查询和操作这些数据也变得越来越重要。在这种情况下&#xff0c;JSONPath 应运而生&#xff0c;成为了一种在JSON数据中定位和提取信息的强大工…...

Python算法设计与分析期末

Python算法设计与分析期末通常涉及对算法基础知识的理解和应用&#xff0c;包括但不限于以下几个方面&#xff1a; 算法基础&#xff1a;了解算法的定义、特性&#xff08;确定性、有穷性、可行性等&#xff09;以及算法的分类。 时间复杂度和空间复杂度&#xff1a;学会分析算…...

pg_lakehouse 与 datafusion

原理分析 pg_lakehouse 是 ParadeDB 推出的一个开源插件&#xff0c;支持对多种数据湖里的数据做分析计算。它的出现&#xff0c;使得 Postgres 能够像访问本地数据一样轻松访问 S3 等对象存储&#xff0c;轻松访问 Delta Lake 上的表格&#xff0c;具备数据湖分析能力。 pg_…...

基于51单片机的酒精浓度检测仪的设计

一.硬件方案 硬件部分为利用MQ3气敏传感器测量空气中酒精浓度&#xff0c;并转换为电压信号&#xff0c;经A/D转换器转换成数字信号后传给单片机系统&#xff0c;由单片机及其相应外围电路进行信号的处理&#xff0c;显示酒精浓度值以及超阈值声光报警。电路主要由51单片机最小…...

重生之 SpringBoot3 入门保姆级学习(02、打包部署)

重生之 SpringBoot3 入门保姆级学习&#xff08;02、打包部署&#xff09; 1.6 打包插件1.7 测试 jar 包1.8 application.properties 的相关配置 1.6 打包插件 官网链接 https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-starte…...

Java-常用模块

文章目录 日期时间stream流 日期时间 jdk8新的日期时间类 解析和格式化DateTimeFormatter类&#xff08;线程安全&#xff09; LocalDateTime类 Instant类 Duration类String time "2013-02-11 11:00:00";DateTimeFormatter dateTimeFormatter DateTimeFormatter.o…...

c++大作业 调整字幕的时间

作业及其需求 有时候人们能够下载一些感兴趣的视频但是发现并没有字幕,到字幕网站上查找到字幕文件,但是发现时间进度上不能完美配合,一个视频数据的例子来源于链接: BBC.巴塔哥尼亚:地球秘密乐园 https://www.aliyundrive.com/s/LmF2sgrQzMu/folder/612af030c6fa4bf4b7c…...

Nmap使用方法

Nmap 介绍 Nmap是一个免费开放的网络扫描和嗅探工具包&#xff0c;也叫网络映射器&#xff08;Network Mapper&#xff09;。该工具其基本功能有三个&#xff0c;一是探测一组主机是否在线&#xff1b;其次是扫描主机端口&#xff0c;嗅探所提供的网络服务&#xff1b;三是可…...

任务3.1:采用面向对象方式求三角形面积

面向对象编程&#xff08;OOP&#xff09;是一种将现实世界中的实体抽象为对象&#xff0c;并通过类和对象来模拟现实世界中的行为和属性的编程范式。在本实战任务中&#xff0c;我们通过创建一个Triangle类来模拟现实世界中的三角形&#xff0c;并使用面向对象的方法来求解三角…...

解读《互联网政务应用安全管理规定》网络和数据安全中的身份认证和审计合规建设

为保障互联网政务应用安全&#xff0c;由中央网络安全和信息化委员会办公室、中央机构编制委员会办公室、工业和信息化部、公安部制定的《互联网政务应用安全管理规定》近日印发&#xff0c;自2024年7月1日起施行。 规定共8章&#xff0c;包括总则、开办和建设、信息安全、网络…...

HTML-JavaWeb

目录 1.标题排版 2.标题样式 ​编辑 ​编辑 小结 3.超链接 4.正文排版 ​编辑​编辑​编辑5.正文布局 6.表格标签 7.表单标签 8.表单项标签 1.标题排版 ● 图片标签 :< img> src:指定图像的ur1(绝对路径/相对路径) width:图像的宽度(像素/相对于父元素的百…...

数组-检查数组内是否存在和为7的倍数的子序列

一、题目描述 二、解题思路 这里首先要分辨清楚是子序列还是子数组 原数组&#xff1a;[1,2,3,4,5] 子序列&#xff1a;元素和元素之间相对位置保持不变&#xff0c;但是在原数组中不一定连续&#xff0c;如&#xff1a;[1,3,4]&#xff1b; 子数组&#xff1a;元素元素之间保…...

【图像处理与机器视觉】图像处理概述与像素

什么是数字图像处理 改善图像信息&#xff0c;便于作出解释 方便对图像传输&#xff0c;储存&#xff0c;方便机器理解 什么是数字图像 &#xff08;1&#xff09;模拟图像&#xff1a;连续二维函数 f&#xff08;x&#xff0c;y&#xff09;表示&#xff0c;其中 x&#xf…...

虚函数的性能消耗到底在哪?

虚函数的性能消耗 聊到虚函数的性能开销&#xff0c;大家的第一反应肯定是间接调用上&#xff0c;何为间接调用&#xff1f; 当调用一个虚函数时&#xff0c;实际执行的函数版本是在运行时通过虚函数表&#xff08;virtualtable&#xff09;查找确定的。这个查找过程是一个间接…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...