STM32 Customer BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建

news2024/10/6 2:28:42

STM32 Customer BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建

文章目录

  • STM32 Customer BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建
      • 功能与作用
      • 典型工作流程
    • 1. 硬件原理图介绍
    • 2. STM32 CubeMX工程搭建
      • 2.1 创建工程
      • 2.2 系统配置
      • 2.3 USART串口配置
      • 2.4 时钟树配置
      • 2.5 工程导出设置
    • 3. 代码编写
    • 4. 工程下载和调试

首先用STM32CubeMX 软件搭建基础工程,来作为二级BootLoader,一级BootLoader是STM32官方自带的startup_stm32f407zgtx.s。我们基于上述最小工程来实现Customer BootLoader的功能。本项目采用的是通过串口实现固件刷新。

下面简单介绍一下二级BootLoder的功能与作用:

二级Customer BootLoader(CBL,Customer BootLoader)是一种在嵌入式系统中常见的软件组件。它主要负责在系统启动时执行初始引导操作,加载和运行应用程序代码。二级Customer BootLoader与一级BootLoader(通常称为Primary BootLoader, PBL)一起工作,提供了更灵活和复杂的引导机制。

功能与作用

  1. 硬件初始化: 二级Customer BootLoader通常负责对特定硬件的初始化工作。虽然一级BootLoader已经完成了一些基本的硬件初始化,但二级BootLoader会进行更详细的硬件配置,如设置外设(例如UART、SPI、I2C等)、初始化存储设备(如Flash、EEPROM等)以及配置系统时钟等。
  2. 固件验证与更新: 二级Customer BootLoader常常用于验证固件的完整性和合法性。这可以通过校验和(Checksum)、加密签名等方式来实现。若检测到固件损坏或版本过旧,BootLoader可以从预设的位置(如网络、USB设备或备用存储区)下载并更新固件。
  3. 安全启动: 为了增强系统安全性,二级BootLoader可以实现安全启动机制。它会检查固件的数字签名或哈希值,确保只有经过验证和授权的固件才能被加载和执行,从而防止恶意代码的运行。
  4. 引导多种操作系统或应用程序: 二级Customer BootLoader可以配置为引导不同的操作系统或应用程序。例如,在嵌入式系统中,可能需要根据不同的条件引导进入不同的应用程序模块,BootLoader可以根据预设的规则进行选择和加载。
  5. 配置和诊断功能: 二级BootLoader可以提供一些配置和诊断功能。例如,它可以允许用户通过串口或网络接口进入配置模式,调整系统参数,进行硬件诊断和调试。
  6. 引导时间优化: 由于嵌入式系统通常需要快速启动,二级BootLoader可以优化引导过程,减少启动时间。它可以通过压缩固件、优化初始化代码等手段来实现快速引导。

典型工作流程

  1. 系统加电后,一级BootLoader(PBL)启动
    • 负责基本硬件初始化(如设置堆栈指针、初始化RAM等)。
    • 加载并执行二级BootLoader(CBL)。
  2. 二级BootLoader启动
    • 执行更详细的硬件初始化。
    • 验证固件的完整性和合法性。
    • 根据系统配置和状态,选择合适的固件或操作系统进行引导。
    • 加载并启动应用程序或操作系统。

目前本项目的Customer BootLoader具备:

  1. 获取软件版本;
  2. 读芯片Chip ID;
  3. 获取Flash Read Protection等级;
  4. 擦除指定Flash Sector;
  5. 更新指定Flash Sector内容;
  6. 使能读/写保护;

下面开始我们本章内容的工程搭建,其中部分图借用洋桃电子杜老师的STM F4系列的课程内容。

1. 硬件原理图介绍

本项目采用正点原子探索者v2开发板,选用其中的左下角的USB串口进行和上位机之间的串口通信。

image-20240608085309250

正点原子STM32F4 探索者V2开发板,如下图所示,通过短接PA9-RXD,短接PA10-TXD,即将USART1与CH340芯片连接在一起,串口USART1与上位机可通过USB进行通信。

image-20240601085106572

如下图电路所示,使用一根MicroUSB结构的USB数据线,一端连接计算机的USB口,一端连接开发版左下角的USB_232口上,就可以在计算机上虚拟出一个串口,通过这个虚拟串口可以进行计算机与开发板之间的串口通信。

image-20240601085723436

image-20240601185940740

2. STM32 CubeMX工程搭建

2.1 创建工程

打开STM32CubdeMX,点击New Project创建新工程

image-20240519214220349

选择 STM32F407 ZGT6

image-20240520070646930

2.2 系统配置

点击左侧System Core,选择RCC,将HSE和LSE都设置为Crystal/Ceramic Resonator(晶体/陶瓷振荡器)

image-20240604074221880

点击SYS,选择Debug功能为JTAG(5 pins),跟板子调试口对应image-20240604075633710

2.3 USART串口配置

选择左侧的Connecttivity选项,点击USART1,如下图所示,点击Mode开始配置

image-20240604080347571

STM32对USART模块提供了下面的这些模式,根据需求选择相应模式,本项目选择的是异步模式Asynchronous。

image-20240604080404318

下面我们来对USART进行配置,首先开发板上的串口对应的USART1串口,Mode配置为异步模式Asynchronous,STMCubeMX会自动分配引脚,目前分配的USART1_RX对于PA10,USART1_TX对于PA9,和我们开发板的引脚正好对应,如果不对应的话,可以根据芯片的data Sheet改成相应的引脚。

下面的参数配置Parameter Settings按照默认配置来,波特率为 115200 bit/s,这里确保主从机是一致的,才能通信成功,数据位 8,无校验位,停止位1,数据方向:Receive and Transmit,采样:16.

image-20240604080436567

点击下方的GPIO Settings,可以看到为USART1自动分配的默认引脚

image-20240604080454808

2.4 时钟树配置

点击上方的Clock Configuration,开始配置时钟

image-20240611074559483

下面我们来看一下时钟树的结构,如下图所示

image-20240604081134525

现在开始配置开发板相关的时钟频率,首先选择做左边的Input frequency,选择外部8M的晶振,选择HSE,选择PLLCLK,在HCLK处将时钟敲定为168MHz,即STM32F407可支持的最大时钟频率

image-20240604081430121

2.5 工程导出设置

如下图所示,设置工程

image-20240604213948820

代码生成设置

image-20240604214023852

高级设置Advanced Settings

image-20240604214510752

点击右上角,生成代码GENERATE CODE

image-20240611075023223

点击Open Project,本项目是使用STM32CubeIDE作为集成开发环境,做到编译和调试代码的工具

image-20240604214643976

3. 代码编写

我们目前使用的是Hal库进行的工程实现,如下图所示,是串口轮询发送函数HAL_UART_Transmit(),在发送的过程中,会一直在该函数中进行发送,是Polling Mode。

image-20240608084049717

下图是串口接收函数 HAL_UART_Receive(),也是Polling Mode,在接收数据的过程中,CPU无法被抢占,一直需要等到数据被发送完成后才可退出该函数

image-20240608084138029

下面是在main.c中的代码实现:

引用c标准头文件

image-20240611080012875

宏定义,BL_DEBUG_MSG_EN是为调试用的,重定义huart1,设置数据bl_rx_buffer

image-20240611075845775

在main()函数中调用bootloader_uart_read_data()函数进行数据接收和发送

image-20240611075754745

bootloader_uart_read_data()函数中先接收在发送。

image-20240611075915162

printmsg()打印数据函数实现。

image-20240611075926137

下面是main.c的完整代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define BL_DEBUG_MSG_EN
#define BL_RX_LEN  200

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
#define C_UART   &huart1

uint8_t bl_rx_buffer[BL_RX_LEN];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
void  bootloader_uart_read_data(void);
static void printmsg(char *format,...);

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  bootloader_uart_read_data();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */

void  bootloader_uart_read_data(void)
{
	uint8_t rcv_len = 0;
	uint8_t rcv_flag = 0;
	memset(bl_rx_buffer, 0, 200);
	//here we will read and decode the commands coming from host
	//first read only one byte from the host , which is the "length" field of the command packet
	HAL_UART_Receive(C_UART, (uint8_t *)bl_rx_buffer, 1, HAL_MAX_DELAY);
	rcv_len= bl_rx_buffer[0];
	if (rcv_len != 0)
	{
		HAL_UART_Transmit(C_UART,(uint8_t *)&rcv_len, 1, HAL_MAX_DELAY);
		rcv_flag = 1;
	}
	if (rcv_flag == 1)
	{
		printmsg("-> Going to BL mode\n\r");
	}

}

/* prints formatted string to console over UART */
 void printmsg(char *format,...)
 {
#ifdef BL_DEBUG_MSG_EN
	char str[80];

	/*Extract the the argument list using VA apis */
	va_list args;
	va_start(args, format);
	vsprintf(str, format,args);
	HAL_UART_Transmit(C_UART,(uint8_t *)str, strlen(str),HAL_MAX_DELAY);
	va_end(args);
#endif
 }


/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

4. 工程下载和调试

将工程编译,之后下载到板子中。

image-20240608084959855

打开设备管理器,查看串口的端口号COM

image-20240608084402078

打开正点原子的串口调试助手,选择刚才设备管理器中串口的COM号,波特率设置为115200,其他默认,打开串口,随便发送一个数据,开发板接收到这个数据,都会原封不动的将该数据打印出来,然后在执行打印Going to BL mode,说明能够接收并发送数据,至此,我们开发Customer BootLoader的第一步,最小工程代码已经搭建完成,后续我们进行上位机与开发板之间的通信协议开发。

image-20240608084720673

如果大家有什么疑问,请随时私信联系我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1821664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos系统yum安装mysql数据库

安装之前需要将系统自带的mariadb-libs软件包删除。 检查是否存在mariadb-libs包。 yum list installed|grep mariadb-libs 删除mariadb-libs包 yum -y remove mariadb-libs 声明&#xff1a; 系统&#xff1a;CentOS-7-x86_64-DVD-2009 安装为最小化安装&#xff0c;没…

跟卖五种常用采集方式,关键词采集升级,更加让新手上手更快!

今天给大家分享一个跟卖选品软件&#xff0c;相信很多卖家都在为选品而苦恼&#xff0c;人工筛选一天也筛选不出几个能用的链接&#xff0c;不仅耗费时间精力&#xff0c;还提升不了选品效率&#xff0c;今天就分享一款实用的选品工具&#xff0c;它能够帮助我们节省选品时间&a…

计算机网络实验(15):基于Socket的网络编程(附JAVA源码.txt)

一、实验名称 UDP客户服务器即时通信程序 二、实验目的&#xff1a; 掌握基于SOCKET的网络编程方法。 基于JAVA语言&#xff0c;编写一个SOCKET的即时通信小程序 三、实验内容和要求 实验内容&#xff1a; 基于JAVA语言&#xff0c;编写一个SOCKET的即时通信小程序 实…

手把手教你构建和使用Redis Cluster去中心化集群

Redis Cluster是Redis官方提供的分布式解决方案。当遇到内存、并发、流量等瓶颈时&#xff0c;就可以采用Cluster架构达到负载均衡目的。官方文档:Scale with Redis Cluster | Docs 1.为什么要用redis-cluster集群&#xff1f; 1.首先Redis单实例主要有单点&#xff0c;容量有…

Spring Cloud Alibaba Nacos作为服务配置中心实践

Nacos官网文档&#xff1a;Nacos 融合 Spring Cloud&#xff0c;成为注册配置中心 【1】服务实例 ① pom依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </de…

使用 Azure AI Document Intelligence 创建智能文档处理

简介 借助 Azure AI 文档智能中的预生成模型&#xff0c;无需自行训练模型&#xff0c;即可从常见表单和文档中提取数据。 公司中&#xff0c;表单种类繁多&#xff0c;如发票、收据、调查表等。你可能想知道&#xff0c;从这些文档中提取姓名、地址、金额等信息需要多少工作…

数字化制造案例分享以及数字化制造能力评估(34页PPT)

资料介绍&#xff1a; 通过全面的数字化企业平台和智能制造技术的应用&#xff0c;制造型企业不仅提升了自身的竞争力&#xff0c;也为整个制造业的数字化转型提供了借鉴。同时&#xff0c;数字化制造能力的评估是企业实现数字化转型的关键环节&#xff0c;需要从技术变革、组…

Linux 并发与竞争基础知识学习

Linux 并发与竞争 并发与竞争 Linux 系统是个多任务操作系统&#xff0c;会存在多个任务同时访问同一片内存区域&#xff0c;这些任务可能会相互覆盖这段内存中的数据&#xff0c;造成内存数据混乱。针对这个问题必须要做处理&#xff0c;严重的话可能会导致系统崩溃。现在的…

Maven:一个下载jar依赖失败的问题解决方案

内部的一个jar包已经上传到了私服上&#xff0c;在私服管理端也能看到该jar包的完整信息&#xff0c;但是springboot项目引入该jar包发现死活下载不下来&#xff0c;报错如图&#xff1a; 从该错误信息中可以看到&#xff0c;找不到服务名是xxl-job这个的&#xff0c;我们要找的…

C语言入门系列:运算符及其优先级

文章目录 一&#xff0c;算术运算符二&#xff0c;自增运算符与自减运算符三&#xff0c;关系运算符四&#xff0c;逻辑运算符逻辑与&#xff08;&&&#xff09;逻辑或&#xff08;||&#xff09;逻辑非&#xff08;!&#xff09;最佳实践&#xff1a;行为单一原则 五&…

最新区块链论文速读--CCF A会议 ICSE 2024 共13篇 附pdf下载 (2/2)

Conference&#xff1a;International Conference on Software Engineering (ICSE) CCF level&#xff1a;CCF A Categories&#xff1a;Software Engineering/System Software/Programming Languages Year&#xff1a;2024 Num&#xff1a;13 第1~7篇区块链文章请点击此处…

【产品经理】订单处理2

本次讲解订单初始化成功到ERP系统过程中的后续环节。 一、根据客服备注更新订单信息 初始化订单过程中&#xff0c;若订单中的客服备注信息对订单进行更新&#xff0c;包括可能改收货信息、改商品、加赠品、指定快递等。 注意&#xff1a;更新订单的过程中要注意订单当前状…

10M速率1553总线终端(RT)模块是依据SAE-AS5652标准设计

10M速率1553总线终端(RT)模块是依据SAE-AS5652标准设计的支持传输速率10Mbps的总线远程终端&#xff08;RT&#xff09;模块&#xff0c;采用SIP封装技术&#xff0c;支持LocalBus接口或UART通信访问&#xff0c;64K*16bits存储空间&#xff0c;灵活的RT数据存储&#xff0c;具…

Android Room数据库使用介绍

1.简介 Room是Google提供的Android架构组件之一&#xff0c;旨在简化数据库操作。它是SQLite的一个抽象层&#xff0c;提供了更易用和安全的API。 Room的总体架构: 2.Room数据库的基础概念 Entity Entity是Room中的数据表&#xff0c;每个Entity类对应一个SQLite表。 DAO …

有什么开放式耳机值得买?六点选购建议你要注意了

作为一名数码爱好者&#xff0c;专业的数码博主&#xff0c;我只想把好的产品介绍给大家&#xff0c;让大家避雷不好用的产品&#xff0c;最近&#xff0c;很多人私信我问我开放式的耳机怎么样&#xff1f;和别的耳机又有什么区别&#xff0c;我发现大家对于开放式耳机的了解少…

什么是计算机技术与软件(初级、中级、高级)考试(软考)?

一、软考是什么&#xff1f; 计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;以下简称计算机软件资格考试&#xff09;是原中国计算机软件专业技术资格和水平考试&#xff08;简称软件考试&#xff09;的完善与发展。计算机软件资格考试是由国家人力…

如何进行敏捷型数据治理?现行的数据治理体系是不是有瑕疵和遗漏?

敏捷型数据治理&#xff08;Agile Data Governance&#xff09;是一种灵活、迭代的方法&#xff0c;旨在快速响应和适应不断变化的业务需求和数据环境。与传统的数据治理方法相比&#xff0c;敏捷型数据治理更注重实践中的灵活性和速度&#xff0c;同时保持数据质量、隐私和安全…

Vue2数据响应式再次理解

今天遇到一个问题吧算是&#xff0c;项目用的vue2&#xff0c;期望把数据的某个数组清空&#xff0c;在组件内部调用this.xxarray [] 没问题&#xff0c;但是把数组引用传递到另外一个函数&#xff0c;执行赋值清空&#xff0c;会失效&#xff1b;大概的复原如下图 分析&#…

直播预约:存内计算加速大模型-未来智能计算的新引擎

直播简介: 在人工智能飞速发展的今天&#xff0c;大模型的训练和推理对计算资源的需求日益增长。传统计算架构已逐渐难以满足其对速度和效率的极致追求。本次直播&#xff0c;我们将深入探讨如何利用存内计算技术&#xff0c;为大模型带来革命性的加速效果。 直播亮点: 技术…

C++ 33 之 const 修饰静态成员

#include <iostream> #include <string.h> using namespace std;// 定义静态const数据成员时&#xff0c;最好在类内部初始化,避免在类外重复初始化&#xff0c;也为了代码的可读性和可维护性class Students03{ public:// 两种写法都可以const static int s_a 10;…