因为公司项目功能需求,网上购买了UNCLED-F070RB开发板,摸索实现TF卡IAP升级用户程序。拿到UNCLED-F070RB开发板后,参考官网的库文件,很快就调通了TF卡和移植了FatFs文件系统;
并在官网USART串口IAP范例下,也很快就实现了TF卡IAP升级用户程序。
接下来就大概介绍下实现过程:
1、UNCLED-F070RB开发板由于自带ST-LINK,所以给PC电脑安装ST-LINK驱动(备注:驱动KEIL 5安装路径下就有);
2、参照官网库工程,设置好硬件SPI的初始化设置,基本设置如下所示:
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
/*!< Enable the SPI clock */
SPI_CLK_INIT(SPI_CLK, ENABLE);
/*!< Enable GPIO clocks */
RCC_AHBPeriphClockCmd_Boot(SPI_SCK_GPIO_CLK | SPI_MISO_GPIO_CLK |
SPI_MOSI_GPIO_CLK | SPI_CS_GPIO_CLK, ENABLE);
/*!< SPI pins configuration *************************************************/
/*!< Connect SPI pins to AF6 */
GPIO_PinAFConfig_Boot(SPI_SCK_GPIO_PORT, SPI_SCK_SOURCE, SPI_SCK_AF);
GPIO_PinAFConfig_Boot(SPI_MISO_GPIO_PORT, SPI_MISO_SOURCE, SPI_MISO_AF);
GPIO_PinAFConfig_Boot(SPI_MOSI_GPIO_PORT, SPI_MOSI_SOURCE, SPI_MOSI_AF);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
/*!< SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_SCK_PIN;
GPIO_Init_Boot(SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN;
GPIO_Init_Boot(SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< SPI MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN;
GPIO_Init_Boot(SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sd Card CS pin in output pushpull mode ********************/
GPIO_InitStructure.GPIO_Pin = SPI_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init_Boot(SPI_CS_GPIO_PORT, &GPIO_InitStructure);
SPI_StructInit_Boot(&SPI_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init_Boot(SPI, &SPI_InitStructure);
SPI_RxFIFOThresholdConfig_Boot(SPI, SPI_RxFIFOThreshold_QF);
//< Enable the sFLASH_SPI
SPI_Cmd_Boot(SPI, ENABLE);
其中加粗部分是需要跟STM32F207/STM32F407不同,需要注意的。
3、TF卡初始化等操作部分直接移植的官网的(可直接参考官方代码);
4、移植FatFs文件系统,修改底层diskio.C文件内的disk_initialize、disk_read和disk_write函数,具体如下所示:
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
INT8U res=0;
switch (pdrv)
{
case SD_CARD://SD¿¨
res = SD_Initialize();//SD_Initialize()
if(res)//STM32 SPIµÄbug,ÔÚsd¿¨²Ù×÷ʧ°ÜµÄʱºòÈç¹û²»Ö´ÐÐÏÂÃæµÄÓï¾ä,¿ÉÄܵ¼ÖÂSPI¶ÁдÒì³£
{
SD_SPI_SpeedLow();
SD_SPI_ReadWriteByte(0xff);//Ìṩ¶îÍâµÄ8¸öʱÖÓ
SD_SPI_SpeedHigh();
}
break;
default:
break;
}
if(res==0x00)
return RES_OK;
else
return RES_ERROR;
}
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
INT8U res=0;
if (!count)
return RES_PARERR;//count²»ÄܵÈÓÚ0£¬·ñÔò·µ»Ø²ÎÊý´íÎó
switch (pdrv)
{
case SD_CARD://SD¿¨
res=SD_ReadDisk(buff,sector,count);
if(res)//STM32 SPIµÄbug,ÔÚsd¿¨²Ù×÷ʧ°ÜµÄʱºòÈç¹û²»Ö´ÐÐÏÂÃæµÄÓï¾ä,¿ÉÄܵ¼ÖÂSPI¶ÁдÒì³£
{
SD_SPI_SpeedLow();
SD_SPI_ReadWriteByte(0xff);//Ìṩ¶îÍâµÄ8¸öʱÖÓ
SD_SPI_SpeedHigh();
}
break;
default:
break;
}
if(res==0x00)
return RES_OK;
else
return RES_ERROR;
}
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
INT8U res=0;
if (!count)
return RES_PARERR;//count²»ÄܵÈÓÚ0£¬·ñÔò·µ»Ø²ÎÊý´íÎó
switch (pdrv)
{
case SD_CARD:
res=SD_WriteDisk((INT8U*)buff,sector,count);
res = RES_OK;
break;
default:
break;
}
if(res==0x00)
return RES_OK;
else
return RES_ERROR;
}
5、接下来就是移植IAP部分的FLASH擦除和烧录操作,具体如下所示:
static INT8U sIAPUpdate(void)
{
INT8U lubRecv = 1;
INT8U lucArray[12];
INT8U i;
INT32U lulData;
switch( lubTaskID )
{
case 0:
{
if( sCreateFileSystem() )
{
lubTaskID = 1;
}
break;
}
case 1:
{
if( sCheckUpdateFile() )
{
lubTaskID = 2;
}
else
{
lubTaskID = 6;
}
break;
}
case 2:
{
if( sOpenUpdateFile1(cAppFileName1String) )
{
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR | FLASH_FLAG_BSY);
for(i = PAGE_START; i < PAGE_NUM; i++)
{
if(FLASH_ErasePage(0x8000000 + i * PAGE_SIZE) != FLASH_COMPLETE)
{
FLASH_Lock();
NVIC_SystemReset_Boot();
}
}
FLASH_Lock();
lubTaskID = 3;
}
else
{
lubTaskID = 6;
}
break;
}
case 3:
{
if( sProgramFlashFromUpdateFile() )
{
lubTaskID = 4;
}
else
{
lubTaskID = 3;
}
break;
}
case 4:
{
if( sOpenUpdateFile2(cAppFileName2String) )
{
lulDataAddr = cAppSecondAddr;
lubTaskID = 5;
}
else
{
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR | FLASH_FLAG_BSY);
for(i = PAGE_START; i < PAGE_NUM; i++)
{
if(FLASH_ErasePage(0x8000000 + i * PAGE_SIZE) != FLASH_COMPLETE)
{
FLASH_Lock();
NVIC_SystemReset_Boot();
}
}
FLASH_Lock();
NVIC_SystemReset_Boot();
}
break;
}
case 5:
{
if( sProgramFlashFromUpdateFile() )
{
lulDataAddr = cAppAddress;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR | FLASH_FLAG_BSY);
for(i = 0;i < 0x40;i++)
{
lulData = (INT32U)lubFirstAppData[4 * i + 3] << 24;
lulData += (INT32U)lubFirstAppData[4 * i + 2] << 16;
lulData += (INT32U)lubFirstAppData[4 * i + 1] << 8;
lulData += (INT32U)lubFirstAppData[4 * i];
lubFaultCnt = 0;
while(FLASH_ProgramWord(lulDataAddr,lulData) != FLASH_COMPLETE)
{
if(++lubFaultCnt >= 5)
{
FLASH_Lock();
NVIC_SystemReset_Boot();
}
}
lulDataAddr += 4;
}
FLASH_Lock();
NVIC_SystemReset_Boot();
}
lubTaskID = 5;
break;
}
case 6:
{
sDeleteFileSystem();
lubRecv = 0;
break;
}
default:
break;
}
return (lubRecv);
}
IAP实现步骤描述具体为:
第一步:SPI和TF卡初始化,并创建文件系统;
第二步:扫描判断TF卡内是否存在待升级文件(BIN格式);
第三步:打开升级文件,并擦除用户区FLASH;
第四步:读取升级文件内容,烧录到用户区FLASH内;
第五步:烧录完成关闭文件系统;
第六步:跳转到用户区FLASH内运行;
第一次整理,各位见谅描述的可能粗糙了。
|