-------- 转载请注明出处
-------- 更多笔记请访问:merafour.blog.163.com
-------- 2015-6-15.冷月追风
-------- email:
:
USBS最初是笔者基于 STM32F103系列开发出来的一个 bootloader,通过把设备做成一个USB接口的存储设备即U盘从而摆脱以往升级固件过程中所需要的上位机跟驱动(即免驱)。USBS全称是:"USB Storage",具有一下特点:
一、只要你的操作系统支持 U盘原则上都可以使用,目前已经测试了 Windows、Ubuntu跟苹果;
二、可通过 PC端软件配置所使用的 IO并设置其余 IO的默认输出,也就是说检测 IO跟 LED指示 IO用户可以自定义;
三、自带不依赖外部 EEPROM的加密算法, 32B加密数据确保程序读到另外一颗 IC上不能运行;
四、为 App提供单独的加密算法(32B),用户可通过 PC软件设置加密 "licence"。
解压下载到的 ST的库,我用的是 V2.1版本,于是得到 "STM32_USB-Host-Device_Lib_V2.1.0"目录。其目录结构如下:
我们是在 MSC例程的基础上进心修改的。而 DFU例程其实也值得我们去参考,通过 DFU我们可以知道怎么去引导 App。那么我们不妨先给 "STM32_USB-Host-Device_Lib_V2.1.0"改个名字,如 "USBS_V0.1.21",其中 ".21"表示所使用的 ST库的版本。当然你们在移植的时候可以另外在解压一份库作为对比。
然后我们到 MSC工程目录新建一个 "QiFreeUSBS"目录,用来存放我们的源码(包括我们修改过的相关文件),如下:
接下来我们就可以到 "MDK-ARM"目录下打开工程了(我用的是keil编译器)。打开工程之后的第一件事就是选择 "STM324xG-EVAL_USBD-FS",记住不能是 "STM324xG-EVAL_USBD-HS",因为 H表示 host,作为主机使用的,我们要作为一个磁盘存储设备不能是主机!
然后我们再配置一下工程,配置如下:
我们不用 Debug所以 Debug不配置,Utilities中根据自己所使用的下载器自行配置,我个人习惯于使用 Jlink。不过用 ST-Link的就要注意了,我之前发现用 ST-Link烧录程序必须是连续的,因为在加密的时候我们会手动把一些代码放在指定的位置所以直接使用 hex文件代码就是不连续的。
配置好之后我们就可以点击 "build"把工程编译一遍。但是我们把程序 Download到板子里边去的时候连上 USB线电脑上根本就没有反应。LED是不要指望了,除非你所使用的端口恰好跟 ST的 dome板是一样的。电脑没有发现我们的设备不是代码有 bug什么的,而是时钟不一样。 ST使用的是 25M外振,如果你的晶振不是 25M或者你的板子根本就没有外振那肯定是跑不起来的。于是我们需要修改时钟。为了通用性我们选择使用 16M内振。在修改之前我们需要把 STM32F4xx手册中时钟那一章完整地看一遍,熟悉 F4的时钟。读者请自行查阅手册,这里我就不截图了。
然后我们将 "system_stm32f4xx.c"源文件从工程中删除,再将源文件剪切到 USBS目录。这就是我们 QiFreeUSBS目录下的第一个源文件。然后在工程中新建一个 "Group"名为:"QiFreeUSBS"用来存放我们的源文件。在源文件 "system_stm32f4xx.c"中找到 SetSysClock函数:
static void SetSysClock(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
我们参考这个函数并对照手册写一个 SetSysClock_HSI函数:
static void SetSysClock_HSI(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSI */
RCC->CR |= ((uint32_t)RCC_CR_HSION);
/* Wait till HSI is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSIRDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSIRDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24);
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
这样我们就可以把 SystemInit函数中对 SetSysClock的调用改为对 SetSysClock_HSI的调用:
//SetSysClock();
SetSysClock_HSI();
但此时我们把程序 Download到板子里电脑还是没有反应,原因是我们只修改了时钟源,而没有修改 PLL系数:
/************************* PLL Parameters *************************************/
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M 25
#define PLL_N 336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 2
/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
#define PLL_Q 7
简单计算一下我们就会发现只需将 PLL_M的值改为 16即可。再次 Download到板子里边电脑就可以识别到一个 "Mass Storage",这就是我们的板子。
然后我们把 inc目录下的头文件 usb_conf.h移动到 USBS目录,并在工程配置 "C/C++"中添加头文件路径。然后再打开头文件 usb_conf.h找到宏 "VBUS_SENSING_ENABLED"将其注释掉:
/****************** USB OTG MISC CONFIGURATION ********************************/
//#define VBUS_SENSING_ENABLED
因为我们不需要 VBUS。然后再 build并 Download确保没有问题。
当你做到这里时,我们的第一个任务算是做完了。