前言
软件版本信息:Keil MDK v5.26
硬件开发板:STM32F429I-Discovery
工程创建
下载STM32F4系列的pack包https://www.keil.com/dd2/pack/
新建工程
利用Manage Run-Time Environment配置工程
- 添加Keil RTX实时操作系统
具体需要添加的
Board Support | LED |
CMSIS | CORE |
Keil RTX | |
Compiler | Event Recorder |
File | |
Device | Startup |
Classic | |
USART | |
SPI | |
SDRAM | |
RCC | |
PWR | |
I2C | |
GPIO | |
DMA | |
Cortex | |
Common | |
File System | CORE |
RAM |
将stm32f4xx_it.c文件中三个函数注释了,因为这三个函数被Keil RTX实时操作系统占用了
void SysTick_Handler(void)
void PendSV_Handler(void)
void SVC_Handler(void)
管理工程
创建多个Groups用于区分不同部分代码使工程结构更加清晰
添加stm32f429I中的SDRAM实例文件stm32f429i_discovery_sdram.c文件。这里不再讲如何初始化SDRAM直接用别人程序就行
这里需要使用void BSP_SDRAM_Init(void)来初始化开发上的SDRAM
添加线程
选择工程结构的Threads文件夹,右键Add new items into Groups。然后选择CMSIS-RTOS thread模板
向文件中添加以下代码——线程创建、文件系统创建:
注意:保存文件系统的设备(Flash、SD卡、SDRAM等)需要格式化!
#include "cmsis_os.h" // CMSIS RTOS header file
#include "rl_fs.h" // Keil.MDK-Plus::File System:CORE
#include "Board_LED.h" // ::Board Support:LED
#include <stdio.h>
/*----------------------------------------------------------------------------
* Thread 1 'Thread_Name': Sample thread
*---------------------------------------------------------------------------*/
void Thread (void const *argument); // thread function
osThreadId tid_Thread; // thread id
osThreadDef (Thread, osPriorityNormal, 1, 0); // thread object
static char *get_drive (char *src, char *dst, uint32_t dst_sz) {
uint32_t i, n;
i = 0;
n = 0;
while (!n && src && src[i] && (i < dst_sz)) {
dst[i] = src[i];
if (dst[i] == ':') {
n = i + 1;
}
i++;
}
if (n == dst_sz) {
n = 0;
}
dst[n] = '\0';
return (src + n);
}
static void cmd_format (char *par) {
char label[12];
char drive[4];
//int retv;
char *opt;
// Set formatting options
opt = "/W /L RAMDRIVE"; // Do not use /FAT32, ram drive space is too small
par = get_drive (par, drive, 4); //多余的代码
printf ("\nProceed with Format [Y/N]\n");
//格式化设备这行代码非常重要,如果驱动正常。初始化一直失败说没有“文件系统卷宗”。那么就是这里出问题了即没有格式化!!!
if (fformat (drive, opt) == fsOK) { // file:///C:/Keil_v5/ARM/PACK/Keil/MDK-Middleware/7.9.0-dev4/Doc/FileSystem/html/group__utility__routines.html#gaea20173a589e298b86791f1cc661731b
printf ("Format completed.\n");
if (fvol (drive, label, NULL) == 0) {
if (label[0] != '\0') {
printf ("Volume label is \"%s\"\n", label);
}
}
}
else {
printf ("Formatting failed.\n");
}
/*}
else {
printf ("Formatting canceled.\n");
}*/
}
static void init_filesystem (void) {
fsStatus stat;
printf ("Initializing and mounting enabled drives...\n\n");
stat = finit ("R0:");
if (stat == fsOK) {
stat = fmount ("R0:");
if (stat == fsOK) {
printf ("Drive R0 ready!\n");
}
else if (stat == fsNoFileSystem) {
// Format the drive
printf ("Drive R0 not formatted!\n");
cmd_format ("R0:");
stat = fmount ("R0:");
if (stat != fsOK) {
LED_On(0);
}
}
else {
printf ("Drive R0 mount failed with error code %d\n", stat);
}
}
else {
printf ("Drive R0 initialization failed!\n");
}
printf ("\nDone!\n");
}
int Init_Thread (void) {
FILE *f;
tid_Thread = osThreadCreate (osThread(Thread), NULL);
if (!tid_Thread) return(-1);
init_filesystem();
// if(finit("R0:") != fsOK)
// {
// LED_On(0);
// }
// fstat = fmount("R0:");
f = fopen("R0:\\Test.log","w");
if(f == NULL)
{
LED_On(1);
}
else
{
fclose(f);
}
return(0);
}
void Thread (void const *argument) {
while (1) {
; // Insert thread code here...
osThreadYield (); // suspend thread
}
}
注意:文件系统中间件的使用,请参考MDK中Manage Run-Time Environment相应的帮助文档
点击“蓝色”链接文字即可打开帮助文档。文档中有API使用以及相关例程
编写主程序中的代码。主要功能:初始化SDRAM设备
/**
******************************************************************************
* @file Templates/Src/main.c
* @author MCD Application Team
* @version V1.2.4
* @date 06-May-2016
* @brief Main program body
*
* @note modified by ARM
* The modifications allow to use this file as User Code Template
* within the Device Family Pack.
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f429i_discovery.h"
#include "stm32f429i_discovery_sdram.h"
#include "Board_LED.h" // ::Board Support:LED
#ifdef RTE_Compiler_EventRecorder
#include "EventRecorder.h"
#endif
#ifdef _RTE_
#include "RTE_Components.h" /* Component selection */
#endif
#ifdef RTE_CMSIS_RTOS // when RTE component CMSIS RTOS is used
#include "cmsis_os.h" // CMSIS RTOS header file
#endif
#ifdef RTE_CMSIS_RTOS_RTX
extern uint32_t os_time;
uint32_t HAL_GetTick(void) {
return os_time;
}
#endif
/** @addtogroup STM32F4xx_HAL_Examples
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define BUFFER_SIZE ((uint32_t)0x0100)
#define WRITE_READ_ADDR ((uint32_t)0x0800)
/** @addtogroup Templates
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program
* @param None
* @retval None
*/
/**
* @brief Fills buffer with user predefined data.
* @param pBuffer: pointer on the buffer to fill
* @param uwBufferLenght: size of the buffer to fill
* @param uwOffset: first value to fill on the buffer
* @retval None
*/
static void Fill_Buffer(uint32_t *pBuffer, uint32_t uwBufferLenght, uint32_t uwOffset)
{
uint32_t tmpIndex = 0;
/* Put in global buffer different values */
for (tmpIndex = 0; tmpIndex < uwBufferLenght; tmpIndex++ )
{
pBuffer[tmpIndex] = tmpIndex + uwOffset;
}
}
extern int Init_Thread (void);
/* Counter index */
uint32_t uwIndex = 0;
/* Read/Write Buffers */
uint32_t aTxBuffer[BUFFER_SIZE];
uint32_t aRxBuffer[BUFFER_SIZE];
/* Status variables */
__IO uint32_t uwWriteReadStatus = 0;
int main(void)
{
uint32_t data_test = 123456;
uint32_t data_test_rec = 0;
#ifdef RTE_CMSIS_RTOS // when using CMSIS RTOS
osKernelInitialize(); // initialize CMSIS-RTOS
#endif
/* STM32F4xx HAL library initialization:
- Configure the Flash prefetch, Flash preread and Buffer caches
- Systick timer is configured by default as source of time base, but user
can eventually implement his proper time base source (a general purpose
timer for example or other time source), keeping in mind that Time base
duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
handled in milliseconds basis.
- Low Level Initialization
*/
HAL_Init();
/* Configure the system clock to 168 MHz */
SystemClock_Config();
/* Add your application code here
*/
LED_Initialize();
BSP_SDRAM_Init();//初始化SDRAM
//KRB
#ifdef RTE_Compiler_EventRecorder
EventRecorderInitialize(0, 1);
EventRecorderEnable (EventRecordError, 0x80U, 0x87U); /* FS Error Events */
EventRecorderEnable (EventRecordAll , 0x81U, 0x81U); /* FAT Events */
#endif
Init_Thread();
BSP_SDRAM_WriteData(SDRAM_DEVICE_ADDR,&data_test,1);
BSP_SDRAM_ReadData(SDRAM_DEVICE_ADDR,&data_test_rec,1);
if(data_test == data_test_rec)
{
LED_On(0);
}
else
{
LED_On(1);
}
#if 0
/* Fill the buffer to write */
Fill_Buffer(aTxBuffer, BUFFER_SIZE, 0xA244250F);
/* Write data to the SDRAM memory */
for (uwIndex = 0; uwIndex < BUFFER_SIZE; uwIndex++)
{
*(__IO uint32_t*) (SDRAM_DEVICE_ADDR + WRITE_READ_ADDR + 4*uwIndex) = aTxBuffer[uwIndex];
}
/* Read back data from the SDRAM memory */
for (uwIndex = 0; uwIndex < BUFFER_SIZE; uwIndex++)
{
aRxBuffer[uwIndex] = *(__IO uint32_t*) (SDRAM_DEVICE_ADDR + WRITE_READ_ADDR + 4*uwIndex);
}
/* Read back data from the SDRAM memory */
for (uwIndex = 0; uwIndex < BUFFER_SIZE; uwIndex++)
{
aRxBuffer[uwIndex] = *(__IO uint32_t*) (SDRAM_DEVICE_ADDR + WRITE_READ_ADDR + 4*uwIndex);
}
/*##-3- Checking data integrity ############################################*/
for (uwIndex = 0; (uwIndex < BUFFER_SIZE) && (uwWriteReadStatus == 0); uwIndex++)
{
if (aRxBuffer[uwIndex] != aTxBuffer[uwIndex])
{
uwWriteReadStatus++;
}
}
if (uwWriteReadStatus)
{
/* KO */
/* Turn on LED4 */
LED_On(0);//绿灯
// BSP_LED_On(LED4);
}
else
{
/* OK */
/* Turn on LED3 */
LED_On(1);//红灯
// BSP_LED_On(LED3);
}
// LED_On(0);
// BSP_SDRAM_Init();//初始化SDRAM
// BSP_SDRAM_WriteData(SDRAM_DEVICE_ADDR,&data_test,1);//写数据
// BSP_SDRAM_ReadData(SDRAM_DEVICE_ADDR,&data_test_rec,1);//读数据
// if(data_test == data_test_rec)
// {
// LED_On(1);
// }
#endif
#ifdef RTE_CMSIS_RTOS // when using CMSIS RTOS
// create 'thread' functions that start executing,
// example: tid_name = osThreadCreate (osThread(name), NULL);
osKernelStart(); // start thread execution
#endif
/* Infinite loop */
while (1)
{
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 168000000
* HCLK(Hz) = 168000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 336
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
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 = 8;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 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)
{
/* Initialization Error */
Error_Handler();
}
/* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported */
if (HAL_GetREVID() == 0x1001)
{
/* Enable the Flash prefetch */
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
}
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* User may add here some code to deal with this error */
while(1)
{
}
}
#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 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) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
调试程序
在cmd_format函数中添加断点,观察是否会进入格式化成功的逻辑中