28.1 初学者重要提示
学习本章节前,务必优先学习第25章,了解TCM,SRAM等五块内存区的基础知识,比较重要。
TCM : Tightly-Coupled Memory 紧密耦合内存 。ITCM用于指令,DTCM用于数据,特点是跟内核速度一样(400MHz),而片上RAM的速度基本都达不到这个速度(200MHz)。很多时候我们希望将需要实时性的程序和变量分别放在ITCM和DTCM里面执行,本章就是解决这个问题。
实现方法比较简单,基于MDK的Option选项设置下即可,无需操作分散加载。使用分散加载的好处是灵活,在设置复杂工程的内存映射方面比较方便。
实现这个功能的关键是要把所有程序都下载到Flash,系统上电后让MDK中的库函数去将所需的程序加载到RAM里面,用户不要自己去加载,太麻烦。如果用户自己去加载就得搞个bootloader加载应用程序到ITCM。这里所说的库函数是MDK里面的__main封装起来了。
28.2 简单实现方法
28.2.1 第1步,设置DTCM
设置DTCM空间,前0x400大小的空间用于中断向量表,所以这里从0x20000400开始,用于各种变量需求:
28.2.2 第2步,添加ITCM
ITCM的首地址是0x0000 0000,大小64KB:
28.2.3 第3步,选择在ITCM执行的代码
右击MDK分组,选择使用ITCM,这里设置了APP分组、BSP分组和SEGGER/HardFault分组。
以APP分组为例,设置方法如下:
BSP分组和SEGGER/HardFault分组也设置完毕后,可以看到小雪花标识
而进入main函数之前的所有代码,含main函数所在的文件main.c切不要设置,这个之前的代码我们都需要在flash里面执行。这些代码仅执行一次以后不会执行,所以不用管他们,之后的所有代码都可以放在ITCM里面。
28.2.4 第4步,复制中断向量表到DTCM
前面三步设置完毕后,将中断向量表从flash中复制到DTCM,主要存储的DTCM地址要0x200对齐。
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: 标准c程序入口。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
int main(void)
{
uint32_t *SouceAddr = (uint32_t *)FLASH_BANK1_BASE;
uint32_t *DestAddr = (uint32_t *)D1_DTCMRAM_BASE;
memcpy(DestAddr, SouceAddr, 0x400);
/* 设置中断向量表到ITCM里面 */
SCB->VTOR = D1_DTCMRAM_BASE;
MainRAM();
}
至此就设置完毕了,另外注意以下两点:
不限制设置分组,单独设置一个C文件也是可以的。
如果大家将HAL_Driver分组也放在了ITCM里面,会有如下警告,这个不用管,是删除了冗余函数。
28.3 实验例程说明(MDK)
配套例子:
V7-007_时间关键代码在ITCM执行的超简单方法
实验目的:
学习时间关键代码在ITCM执行的超简单方法,同时中断向量表和变量放DTCM。
实验内容:
系统上电后驱动了1个软件定时器,每100ms翻转一次LED2。
启动1个TIM6周期性中断,频率10KHz,在中断服务程序里面翻转FMC扩展引脚20和23。
实验操作:
K1按键按下,开启TIM6的周期性中断。
K2按键按下,关闭TIM6的周期性中断。
上电后串口打印的信息:
波特率 115200,数据位 8,奇偶校验位无,停止位 1
程序设计:
系统栈大小分配:
RAM空间用的DTCM:
硬件外设初始化
硬件外设的初始化是在 bsp.c 文件实现:
/*
*********************************************************************************************************
* 函 数 名: bsp_Init
* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
/* 配置MPU */
MPU_Config();
/* 使能L1 Cache */
CPU_CACHE_Enable();
/*
STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
- 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
- 设置NVIV优先级分组为4。
*/
HAL_Init();
/*
配置系统时钟到400MHz
- 切换使用HSE。
- 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
*/
SystemClock_Config();
/*
Event Recorder:
- 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
- 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章
*/
#if Enable_EventRecorder == 1
/* 初始化EventRecorder并开启 */
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
#endif
bsp_InitKey(); /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
bsp_InitTimer(); /* 初始化滴答定时器 */
bsp_InitUart(); /* 初始化串口 */
bsp_InitExtIO(); /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */
bsp_InitLed(); /* 初始化LED */
}
MPU配置和Cache配置:
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。
/*
*********************************************************************************************************
* 函 数 名: MPU_Config
* 功能说明: 配置MPU
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* 禁止 MPU */
HAL_MPU_Disable();
/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x60000000;
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/*使能 MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/*
*********************************************************************************************************
* 函 数 名: CPU_CACHE_Enable
* 功能说明: 使能L1 Cache
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
/* 使能 I-Cache */
SCB_EnableICache();
/* 使能 D-Cache */
SCB_EnableDCache();
}
主功能:
主程序实现如下操作:
系统上电后驱动了1个软件定时器,每100ms翻转一次LED2。
启动1个TIM6周期性中断,频率10KHz,在中断服务程序里面翻转FMC扩展引脚20和23。
K1按键按下,开启TIM6的周期性中断。
K2按键按下,关闭TIM6的周期性中断。
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: 标准c程序入口。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
int main(void)
{
uint32_t *SouceAddr = (uint32_t *)FLASH_BANK1_BASE;
uint32_t *DestAddr = (uint32_t *)D1_DTCMRAM_BASE;
memcpy(DestAddr, SouceAddr, 0x400);
/* 设置中断向量表到ITCM里面 */
SCB->VTOR = D1_DTCMRAM_BASE;
MainRAM();
}
/*
*********************************************************************************************************
* 函 数 名: MainRAM
* 功能说明: c程序入口
* 形 参: 无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int MainRAM(void)
{
uint8_t ucKeyCode; /* 按键代码 */
bsp_Init(); /* 硬件初始化 */
PrintfLogo(); /* 打印例程名称和版本等信息 */
PrintfHelp(); /* 打印操作提示 */
bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */
bsp_SetTIMforInt(TIM6, 10000, 2, 0); /* 设置为10KHz频率定时器中断*/
/* 进入主程序循环体 */
while (1)
{
bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
/* 判断定时器超时时间 */
if (bsp_CheckTimer(0))
{
/* 每隔100ms 进来一次 */
bsp_LedToggle(2);
}
/* 按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。 */
ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1键按下,开启TIM6的周期性中断*/
TIM6->DIER |= TIM_IT_UPDATE;
break;
case KEY_DOWN_K2: /* K2键按下,关闭TIM6的周期性中断*/
TIM6->DIER &= ~TIM_IT_UPDATE;
break;
default:
/* 其它的键值不处理 */
break;
}
}
}
}
/*
*********************************************************************************************************
* 函 数 名: TIM6_DAC_IRQHandler
* 功能说明: TIM6定时中断服务程序
* 返 回 值: 无
*********************************************************************************************************
*/
void TIM6_DAC_IRQHandler(void)
{
if((TIM6->SR & TIM_FLAG_UPDATE) != RESET)
{
/* 清除更新标志 */
TIM6->SR = ~ TIM_FLAG_UPDATE;
/* 翻转FMC扩展引脚20和23脚 */
HC574_TogglePin(GPIO_PIN_23);
HC574_TogglePin(GPIO_PIN_20);
}
}
28.4 总结
本章节就为大家交流这么多,对速度有要求的应用部分,建议使用ITCM和DTCM来达到最高性能。
上一篇:【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API
下一篇:【STM32H7教程】第27章 STM32H7的TCM,SRAM等动态内存分配实现
推荐阅读
史海拾趣
随着国内市场的饱和,Bedford Opto公司开始寻求国际化扩张的机会。通过与国外知名企业的合作,公司成功打入国际市场,并获得了更多的业务机会。同时,公司还积极参与国际技术交流与合作,不断提升自身的技术水平和创新能力。
随着电子行业的快速发展,客户对电容器的需求日益多样化。CDE公司积极应对市场变化,致力于定制化电容器的研发与应用。公司利用数学建模和定制化的仿真App对电容器的设计进行微调,以满足不同客户的特定需求。这一举措不仅提升了CDE的市场竞争力,也为公司在定制化电容器领域树立了领先地位。
近年来,随着电子行业的不断发展壮大,FARNELL公司也开始向多元化方向发展。除了电子元器件分销业务外,公司还涉足了工业自动化、智能制造等领域。这种多元化的发展战略使FARNELL公司的业务范围更加广泛,也为公司带来了新的发展机遇。
以上五个故事概述了FARNELL公司在电子行业中的发展历程和主要成就。这些故事展示了FARNELL公司不断创新、积极应对市场挑战的精神以及其在电子行业中的重要地位。
为了更好地服务全球客户,COILCRAFT公司在北美、亚洲和欧洲等地建立了制造、分销和工程设施。这一全球布局使得公司能够快速地响应客户需求,提供高效的服务和运输。同时,COILCRAFT还拥有丰富的网络工具库和免费评估样品政策,这些措施简化了部件选择过程,提高了客户的满意度。
COILCRAFT公司成立于1945年,是美国较早的磁性元件制造商。在创立初期,公司以生产高频电感器和变压器为主,凭借着卓越的技术和稳定的质量,逐渐在电子元器件市场中崭露头角。公司总部位于伊利诺伊州卡里,这个地理位置为其提供了便捷的物流和人才资源,为其后续的发展奠定了坚实的基础。
随着技术创新的不断推进,Eagle Plastic Devices公司开始积极拓展国内外市场。公司通过参加国际电子展会、与知名电子制造商建立战略合作关系等方式,不断提高品牌知名度和市场份额。同时,公司还注重产品质量的提升和售后服务的完善,赢得了客户的信任和好评。在短短几年内,Eagle Plastic Devices公司便成为了电子行业内知名的塑料电子部件供应商。
摘要:利用EDA工具和硬件描述语言(HDL),根据产品的特定要求设计性能价格比高的片上系统,是目前国际上广泛使用的方法。与传统的设计方法不同,在设计开始阶段并不一定需要具体的单片微控制器(MCU)和开发系统(仿真器)以及带有外围电路的线路板 ...… 查看全部问答∨ |
北京恒润科技,做车身网络,AFS等(提供+dspace、CAN开发工具,mathworks公司国内的代理) 山东济南捷特,做ABS等产品 广东那边有不少汽车音响、仪表产品的供应商,但因为和真正意义上的汽车电子产品(动力,安全)还有些差别,没有去罗列。 ...… 查看全部问答∨ |
我现在只是一个大一新生,对机器人特别感兴趣,但对这个领域了解甚少.想知道作为初学者应该从哪些基础方面着手.对了我学的专业是信息安全,也不知道有哪些专业课对此爱好有用. … 查看全部问答∨ |
|
我用的是Keil uVision4版本,和ULINK2 编译正确后,调试时,弹出一个窗口:JTAG communication failure!点击确定后出现ERROR:Target DLL has been cancelled debug 和Utilities 哩也选了Ulink Cotex Debugger 选项 之前也调试过 可以成功下载 ...… 查看全部问答∨ |