322 lines
10 KiB
C
322 lines
10 KiB
C
//系统初始化
|
||
|
||
#include "sys.h"
|
||
|
||
/**
|
||
* @brief 配置 MPU
|
||
*/
|
||
void MPU_Config(void)
|
||
{
|
||
MPU_Region_InitTypeDef MPU_InitStruct;
|
||
|
||
/* 禁止 MPU */
|
||
HAL_MPU_Disable();
|
||
|
||
/* 配置AXI SRAM的MPU属性为Write through, read allocate,no 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_NOT_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_LEVEL0;
|
||
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_ACCESS_CACHEABLE;会出现2次CS、WE信号 */
|
||
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);
|
||
|
||
/* 配置SRAM4的属性为Write through, read allocate,no write allocate */
|
||
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
|
||
MPU_InitStruct.BaseAddress = 0x38000000;
|
||
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
|
||
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
|
||
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
|
||
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
|
||
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
|
||
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* @brief 使能 L1-Cache
|
||
*/
|
||
void Cache_Enable(void)
|
||
{
|
||
SCB_EnableICache(); //使能 I-Cache
|
||
SCB_EnableDCache(); //使能 D-Cache
|
||
SCB->CACR |= 1 << 2; //强制 D-Cache透写
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化系统时钟
|
||
* @param plln: PLL1 倍频系数(PLL倍频),取值范围:4~512
|
||
* @param pllm: PLL1 预分频系数(进PLL之前的分频),取值范围:2~63
|
||
* @param pllp: PLL1 的 p 分频系数(PLL之后的分频),分频后作为系统时钟,取值范围:2~128(且必须是 2 的倍数)
|
||
* @param pllq: PLL1 的 q 分频系数(PLL之后的分频),取值范围:1~128.
|
||
* @retval 成功返回 0,失败返回 1
|
||
*/
|
||
uint8_t Clock_Init(uint32_t plln, uint32_t pllm, uint32_t pllp, uint32_t pllq)
|
||
{
|
||
HAL_StatusTypeDef ret = HAL_OK;
|
||
RCC_ClkInitTypeDef RCC_ClkInitStruct;
|
||
RCC_OscInitTypeDef RCC_OscInitStruct;
|
||
|
||
MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
|
||
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||
|
||
while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY)
|
||
{
|
||
}
|
||
|
||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
|
||
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
|
||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||
|
||
RCC_OscInitStruct.PLL.PLLN = plln;
|
||
RCC_OscInitStruct.PLL.PLLM = pllm;
|
||
RCC_OscInitStruct.PLL.PLLP = pllp;
|
||
RCC_OscInitStruct.PLL.PLLQ = pllq;
|
||
|
||
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
|
||
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
|
||
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
|
||
if (ret != HAL_OK)
|
||
return 1;
|
||
|
||
// QSPI_Enable_Memmapmode(); //QSPI内存映射模式,需要在时钟初始化之前开启,否则会有各种问题
|
||
|
||
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
|
||
RCC_CLOCKTYPE_HCLK |
|
||
RCC_CLOCKTYPE_D1PCLK1 |
|
||
RCC_CLOCKTYPE_PCLK1 |
|
||
RCC_CLOCKTYPE_PCLK2 |
|
||
RCC_CLOCKTYPE_D3PCLK1);
|
||
|
||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
|
||
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
|
||
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
|
||
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
|
||
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
|
||
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV4;
|
||
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
|
||
if (ret != HAL_OK)
|
||
return 1;
|
||
|
||
__HAL_RCC_CSI_ENABLE();
|
||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||
HAL_EnableCompensationCell();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 判断 I_Cache 是否打开
|
||
* @retval 关闭返回 0,打开返回 1
|
||
*/
|
||
uint8_t Get_ICacheSta(void)
|
||
{
|
||
uint8_t sta;
|
||
sta = ((SCB->CCR) >> 17) & 0X01;
|
||
return sta;
|
||
}
|
||
|
||
/**
|
||
* @brief 判断 I_Dache 是否打开
|
||
* @retval 关闭返回 0,打开返回 1
|
||
*/
|
||
uint8_t Get_DCacheSta(void)
|
||
{
|
||
uint8_t sta;
|
||
sta = ((SCB->CCR) >> 16) & 0X01;
|
||
return sta;
|
||
}
|
||
|
||
/**
|
||
* @brief QSPI 进入内存映射模式
|
||
*/
|
||
void QSPI_Enable_Memmapmode(void)
|
||
{
|
||
uint32_t tempreg = 0;
|
||
volatile uint32_t *data_reg = &QUADSPI->DR;
|
||
GPIO_InitTypeDef qspi_gpio;
|
||
|
||
RCC->AHB4ENR |= 1 << 1; //使能 PORTB 时钟
|
||
RCC->AHB4ENR |= 1 << 5; //使能 PORTF 时钟
|
||
RCC->AHB3ENR |= 1 << 14; //QSPI 时钟使能
|
||
|
||
qspi_gpio.Pin = GPIO_PIN_6; //PB6 AF10
|
||
qspi_gpio.Mode = GPIO_MODE_AF_PP;
|
||
qspi_gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||
qspi_gpio.Pull = GPIO_NOPULL;
|
||
qspi_gpio.Alternate = GPIO_AF10_QUADSPI;
|
||
HAL_GPIO_Init(GPIOB, &qspi_gpio);
|
||
|
||
qspi_gpio.Pin = GPIO_PIN_2; //PB2 AF9
|
||
qspi_gpio.Alternate = GPIO_AF9_QUADSPI;
|
||
HAL_GPIO_Init(GPIOB, &qspi_gpio);
|
||
|
||
qspi_gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7; //PF6 7 AF9
|
||
qspi_gpio.Alternate = GPIO_AF9_QUADSPI;
|
||
HAL_GPIO_Init(GPIOF, &qspi_gpio);
|
||
|
||
qspi_gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9; //PF8 9 AF10
|
||
qspi_gpio.Alternate = GPIO_AF10_QUADSPI;
|
||
HAL_GPIO_Init(GPIOF, &qspi_gpio);
|
||
|
||
//QSPI 设置,参考 QSPI 实验的 QSPI_Init 函数
|
||
RCC->AHB3RSTR |= 1 << 14; //复位 QSPI
|
||
RCC->AHB3RSTR &= ~(1 << 14); //停止复位 QSPI
|
||
while (QUADSPI->SR & (1 << 5))
|
||
; //等待 BUSY 位清零
|
||
QUADSPI->CR = 0X01000310; //设置 CR 寄存器
|
||
QUADSPI->DCR = 0X00160401; //设置 DCR 寄存器
|
||
QUADSPI->CR |= 1 << 0; //使能 QSPI
|
||
|
||
//注意:QSPI QE 位的使能,在 QSPI 烧写算法里面,就已经设置了
|
||
//所以,这里可以不用设置 QE 位,否则需要加入对 QE 位置 1 的代码
|
||
//不过,代码必须通过仿真器下载,直接烧录到外部 QSPI FLASH,是不可用的
|
||
//如果想直接烧录到外部 QSPI FLASH 也可以用,则需要在这里添加 QE 位置 1 的代码
|
||
|
||
//W25QXX 进入 QPI 模式(0X38指令)
|
||
while (QUADSPI->SR & (1 << 5))
|
||
; //等待 BUSY 位清零
|
||
QUADSPI->CCR = 0X00000138; //发送 0X38 指令,W25QXX 进入 QPI 模式
|
||
while ((QUADSPI->SR & (1 << 1)) == 0)
|
||
; //等待指令发送完成
|
||
QUADSPI->FCR |= 1 << 1; //清除发送完成标志位
|
||
|
||
//W25QXX 写使能(0X06指令)
|
||
while (QUADSPI->SR & (1 << 5))
|
||
; //等待 BUSY 位清零
|
||
QUADSPI->CCR = 0X00000106; //发送 0X06 指令,W25QXX 写使能
|
||
while ((QUADSPI->SR & (1 << 1)) == 0)
|
||
; //等待指令发送完成
|
||
QUADSPI->FCR |= 1 << 1; //清除发送完成标志位
|
||
|
||
//W25QXX 设置 QPI 相关读参数(0XC0)
|
||
while (QUADSPI->SR & (1 << 5))
|
||
; //等待 BUSY 位清零
|
||
QUADSPI->CCR = 0X030003C0; //发送 0XC0 指令,W25QXX 读参数设置
|
||
QUADSPI->DLR = 0;
|
||
while ((QUADSPI->SR & (1 << 2)) == 0)
|
||
; //等待 FTF
|
||
*(volatile uint8_t *)data_reg = 3 << 4; //设置 P4&P5=11,8 个 dummy clocks,104M
|
||
QUADSPI->CR |= 1 << 2; //终止传输
|
||
while ((QUADSPI->SR & (1 << 1)) == 0)
|
||
; //等待数据发送完成
|
||
QUADSPI->FCR |= 1 << 1; //清除发送完成标志位
|
||
while (QUADSPI->SR & (1 << 5))
|
||
; //等待 BUSY 位清零
|
||
|
||
//MemroyMap 模式设置
|
||
while (QUADSPI->SR & (1 << 5))
|
||
; //等待 BUSY 位清零
|
||
QUADSPI->ABR = 0; //交替字节设置为 0,实际上就是 W25Q 0XEB 指令的 M0~M7=0
|
||
tempreg = 0XEB; //INSTRUCTION[7:0]=0XEB,发送 0XEB 指令(Fast Read QUAD I/O)
|
||
tempreg |= 3 << 8; //IMODE[1:0]=3,四线传输指令
|
||
tempreg |= 3 << 10; //ADDRESS[1:0]=3,四线传输地址
|
||
tempreg |= 2 << 12; //ADSIZE[1:0]=2,24位地址长度
|
||
tempreg |= 3 << 14; //ABMODE[1:0]=3,四线传输交替字节
|
||
tempreg |= 0 << 16; //ABSIZE[1:0]=0,8位交替字节 (M0~M7)
|
||
tempreg |= 6 << 18; //DCYC[4:0]=6,6个dummy周期
|
||
tempreg |= 3 << 24; //DMODE[1:0]=3,四线传输数据
|
||
tempreg |= 3 << 26; //FMODE[1:0]=3,内存映射模式
|
||
QUADSPI->CCR = tempreg; //设置CCR寄存器
|
||
|
||
//设置 QSPI FLASH 空间的MPU保护
|
||
SCB->SHCSR &= ~(1 << 16); //禁止 MemManage
|
||
MPU->CTRL &= ~(1 << 0); //禁止 MPU
|
||
MPU->RNR = 0; //设置保护区域编号为 0 (1~7 可以给其他内存用)
|
||
MPU->RBAR = 0X90000000; //基地址为 0X9000 000,即 QSPI 的起始地址
|
||
MPU->RASR = 0X0303002D; //设置相关保护参数(禁止共用,允许 cache,允许缓冲)
|
||
MPU->CTRL = (1 << 2) | (1 << 0); //使能 PRIVDEFENA,使能 MPU
|
||
SCB->SHCSR |= 1 << 16; //使能 MemManage
|
||
}
|
||
|
||
#if defined(__clang__) //使用V6编译器(clang)
|
||
//THUMB指令不支持汇编内联
|
||
//采用如下方法实现执行汇编指令WFI
|
||
void __attribute__((noinline)) WFI_SET(void)
|
||
{
|
||
__asm__("wfi");
|
||
}
|
||
|
||
//关闭所有中断(但是不包括fault和NMI中断)
|
||
void __attribute__((noinline)) INTX_DISABLE(void)
|
||
{
|
||
__asm__("cpsid i \t\n"
|
||
"bx lr");
|
||
}
|
||
|
||
//开启所有中断
|
||
void __attribute__((noinline)) INTX_ENABLE(void)
|
||
{
|
||
__asm__("cpsie i \t\n"
|
||
"bx lr");
|
||
}
|
||
|
||
//设置栈顶地址
|
||
//addr:栈顶地址
|
||
void __attribute__((noinline)) MSR_MSP(uint32_t addr)
|
||
{
|
||
__asm__("msr msp, r0 \t\n"
|
||
"bx r14");
|
||
}
|
||
#elif defined(__CC_ARM) //使用V5编译器(ARMCC)
|
||
|
||
//THUMB指令不支持汇编内联
|
||
//采用如下方法实现执行汇编指令WFI
|
||
__asm void WFI_SET(void)
|
||
{
|
||
WFI;
|
||
}
|
||
//关闭所有中断(但是不包括fault和NMI中断)
|
||
__asm void INTX_DISABLE(void)
|
||
{
|
||
CPSID I
|
||
BX LR
|
||
}
|
||
//开启所有中断
|
||
__asm void INTX_ENABLE(void)
|
||
{
|
||
CPSIE I
|
||
BX LR
|
||
}
|
||
//设置栈顶地址
|
||
//addr:栈顶地址
|
||
__asm void MSR_MSP(uint32_t addr)
|
||
{
|
||
MSR MSP, r0 //set Main Stack value
|
||
BX r14
|
||
}
|
||
|
||
#endif
|