QQ:971586331
软件环境:
操作系统:windows 10
IDE:CCS7.4
代码生成工具:HALCoGen 04.07.01
Flash操作库:F021FlashApi-02.01.01
硬件环境:
目标板:TMDS570LS31HDK
本文内容:描述了TMS570系统芯片内部flash编程方法
1.新建CCS工程
按TMS570学习1中的流程新建工程boot_test。
2.安装F021库
在TI官网下载F021库,HERCULES F021FLASHAPI,下载后是一个exe,安装完后是下面这样
include:API接口的头文件
source:用户自定义的回调,只有一个Fapi_UserDefinedFunctions.c文件,文件中只有一个函数Fapi_serviceWatchdogTimer,根据描述,这个函数会在擦除,写和读时被调用,可以在函数中喂狗,防止flash操作时间太长导致复位。
lib文件:lib文件分三类,M3_BE,R4_BE和R4_LE,BE是大端模式,LE是小端模式,我们用的TMS570是大端模式(可以通过读ENDIAN_REG寄存器得知),所以我们使用R4_BE。
SPNA148.pdf:这个文档是操作flash的例子,里面有操作代码和流程图
SPNU501G.pdf:这个文档是API说明
3.移植F021库
将include目录,source目录,R4_BE后缀的lib文件拷贝到工程中,在工程中添加头文件路径
参考SPNA148.pdf中第三章的程序模板和SPNU501G.pdf中第5章的流程图编写flash操作函数,如下是flash操作的程序模板:
扇区擦除流程:
块擦流程:
编程流程:
4.编写flash操作函数
根据上一节的操作流程,编写flash操作接口,主要实现下列4个接口:
Flash_EraseSector:擦除扇区
Flash_EraseBanks:擦除块
Flash_WriteData:写数据
Flash_ReadData:读数据
/*
* flash_handle.h
*
* Created on: 2019年8月15日
* Author: shiyu
*/
#ifndef USER_FLASH_HANDLE_H_
#define USER_FLASH_HANDLE_H_
#include "F021.h"
enum e_flash_status
{
flash_succeed,
flash_failure,
};
struct Sector_List
{
Fapi_FlashBankType banks_num;
uint32_t sector_num;
uint32_t low_addr;
uint32_t size;
};
#define SECTOR_NUM (15+12+4)
enum e_flash_status Flash_EraseSector(Fapi_FlashBankType oNewFlashBank, uint32_t sector);
enum e_flash_status Flash_EraseBanks(Fapi_FlashBankType oNewFlashBank);
enum e_flash_status Flash_WriteData(Fapi_FlashBankType oNewFlashBank, uint32_t sector, uint32_t offset, uint8_t * buff, uint32_t len);
void Flash_ReadData(Fapi_FlashBankType oNewFlashBank, uint32_t sector, uint32_t offset, uint8_t * buff, uint32_t len);
#endif /* USER_FLASH_HANDLE_H_ */
/*
* flash_handle.c
*
* Created on: 2019年8月15日
* Author: shiyu
*/
#include "F021.h"
#include "flash_handle.h"
//TMS570LS3137的flash分区表
struct Sector_List gSector_List[SECTOR_NUM] =
{
// 块编号 扇区编号 扇区起始地址 扇区大小
{Fapi_FlashBank0, 0, 0x00000000, 32*1024},
{Fapi_FlashBank0, 1, 0x00008000, 32*1024},
{Fapi_FlashBank0, 2, 0x00010000, 32*1024},
{Fapi_FlashBank0, 3, 0x00018000, 32*1024},
{Fapi_FlashBank0, 4, 0x00020000, 128*1024},
{Fapi_FlashBank0, 5, 0x00040000, 128*1024},
{Fapi_FlashBank0, 6, 0x00060000, 128*1024},
{Fapi_FlashBank0, 7, 0x00080000, 128*1024},
{Fapi_FlashBank0, 8, 0x000A0000, 128*1024},
{Fapi_FlashBank0, 9, 0x000C0000, 128*1024},
{Fapi_FlashBank0, 10, 0x000E0000, 128*1024},
{Fapi_FlashBank0, 11, 0x00100000, 128*1024},
{Fapi_FlashBank0, 12, 0x00012000, 128*1024},
{Fapi_FlashBank0, 13, 0x00014000, 128*1024},
{Fapi_FlashBank0, 14, 0x00016000, 128*1024},
{Fapi_FlashBank1, 0, 0x00018000, 128*1024},
{Fapi_FlashBank1, 1, 0x0001A000, 128*1024},
{Fapi_FlashBank1, 2, 0x0001C000, 128*1024},
{Fapi_FlashBank1, 3, 0x0001E000, 128*1024},
{Fapi_FlashBank1, 4, 0x00020000, 128*1024},
{Fapi_FlashBank1, 5, 0x00022000, 128*1024},
{Fapi_FlashBank1, 6, 0x00024000, 128*1024},
{Fapi_FlashBank1, 7, 0x00026000, 128*1024},
{Fapi_FlashBank1, 8, 0x00028000, 128*1024},
{Fapi_FlashBank1, 9, 0x0002A000, 128*1024},
{Fapi_FlashBank1, 10, 0x0002C000, 128*1024},
{Fapi_FlashBank1, 11, 0x0002E000, 128*1024},
{Fapi_FlashBank7, 0, 0xF0200000, 16*1024},
{Fapi_FlashBank7, 1, 0xF0204000, 16*1024},
{Fapi_FlashBank7, 2, 0xF0208000, 16*1024},
{Fapi_FlashBank7, 3, 0xF020C000, 16*1024},
};
/* @brief 查找扇区信息
* @param[in] oNewFlashBank:块编号
* @param[in] sector:扇区编号
*
* return:扇区在数据结构中的位置
*/
uint32_t find_sector(Fapi_FlashBankType oNewFlashBank, uint32_t sector)
{
int i=0;
for(i=0; iFmStat.FMSTAT_BITS.BUSY != Fapi_Status_FsmBusy))
{
oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank); //设置活动的Flash Bank
if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) )
oReturnCheck = Fapi_enableMainBankSectors( 1<<(sector+1) ); //设置EEPROM存储区中可用的扇区以进行擦除和编程
else if( oNewFlashBank == Fapi_FlashBank7 )
oReturnCheck = Fapi_enableEepromBankSectors(1<<(sector+1) ,1<<((sector+1)%32)); //设置EEPROM存储区中可用的扇区以进行擦除和编程
while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, gSector_List[num].low_addr); //向Flash状态机发出命令
/* Place specific example code here */
/* Wait for FSM to finish */
while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
/* Check the FSM Status to see if there were no errors */
if (FLASH_CONTROL_REGISTER->FmStat.u32Register != 0)
{
/* Put Error handling code here */
return flash_failure;
}
}
return flash_succeed;
}
/* @brief 擦除块
* @param[in] oNewFlashBank:块编号
*
* return:
*/
enum e_flash_status Flash_EraseBanks(Fapi_FlashBankType oNewFlashBank)
{
int num = 0;
Fapi_StatusType oReturnCheck = Fapi_Status_Success;
num = find_sector(oNewFlashBank, 0);
oReturnCheck = Fapi_initializeFlashBanks(180); //初始化Flash Bank以进行API操作
if((oReturnCheck == Fapi_Status_Success) && (FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY != Fapi_Status_FsmBusy))
{
oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank); //设置活动的Flash Bank
if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) )
oReturnCheck = Fapi_enableMainBankSectors( 0xffffffff ); //设置EEPROM存储区中可用的扇区以进行擦除和编程
else if( oNewFlashBank == Fapi_FlashBank7 )
oReturnCheck = Fapi_enableEepromBankSectors(0xffffffff, 0xffffffff); //设置EEPROM存储区中可用的扇区以进行擦除和编程
while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
Fapi_issueAsyncCommandWithAddress(Fapi_EraseBank, gSector_List[num].low_addr); //向Flash状态机发出命令
/* Place specific example code here */
/* Wait for FSM to finish */
while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
/* Check the FSM Status to see if there were no errors */
if (FLASH_CONTROL_REGISTER->FmStat.u32Register != 0)
{
/* Put Error handling code here */
return flash_failure;
}
}
return flash_succeed;
}
/* @brief 写扇区数据
* @param[in] oNewFlashBank:块编号
* @param[in] sector:扇区编号
* @param[in] offset:扇区偏移地址
* @param[in] buff:数据
* @param[in] len:数据长度
*
* return:
*/
enum e_flash_status Flash_WriteData(Fapi_FlashBankType oNewFlashBank, uint32_t sector, uint32_t offset, uint8_t * buff, uint32_t len)
{
int num = 0;
Fapi_StatusType oReturnCheck = Fapi_Status_Success;
num = find_sector(oNewFlashBank, sector);
//如果写的大小起过扇区的大小
if( (offset+len) > gSector_List[num].size )
{
return flash_failure;
}
oReturnCheck = Fapi_initializeFlashBanks(180); //初始化Flash Bank以进行API操作
if((oReturnCheck == Fapi_Status_Success) && (FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY != Fapi_Status_FsmBusy))
{
oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank); //设置活动的Flash Bank
if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) )
oReturnCheck = Fapi_enableMainBankSectors( 0xffffffff ); //设置EEPROM存储区中可用的扇区以进行擦除和编程
else if( oNewFlashBank == Fapi_FlashBank7 )
oReturnCheck = Fapi_enableEepromBankSectors(0xffffffff ,0xffffffff); //设置EEPROM存储区中可用的扇区以进行擦除和编程
while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset, buff, len, 0, 0, Fapi_DataOnly); //设置数据并将程序命令发送到有效的闪存地址
/* Place specific example code here */
/* Wait for FSM to finish */
while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
/* Check the FSM Status to see if there were no errors */
if (FLASH_CONTROL_REGISTER->FmStat.u32Register != 0)
{
/* Put Error handling code here */
return flash_failure;
}
}
return flash_succeed;
}
/* @brief 读扇区数据
* @param[in] oNewFlashBank:块编号
* @param[in] sector:扇区编号
* @param[in] offset:扇区偏移地址
* @param[in] buff:数据
* @param[in] len:数据长度
*
* return:
*/
void Flash_ReadData(Fapi_FlashBankType oNewFlashBank, uint32_t sector, uint32_t offset, uint8_t * buff, uint32_t len)
{
int num = 0;
num = find_sector(oNewFlashBank, sector);
//如果读的大小超过扇区的大小
if( (offset+len) > gSector_List[num].size )
{
return flash_failure;
}
memcpy(buff, gSector_List[num].low_addr+offset, len);
}
/* USER CODE BEGIN (0) */
#include "sys_common.h"
#include "gio.h"
#include "rti.h"
#include "delay.h"
#include "het.h"
#include "pinmux.h"
#include "F021.h"
/* USER CODE END */
/* Include Files */
#include "sys_common.h"
/* USER CODE BEGIN (1) */
/* USER CODE END */
/** @fn void main(void)
* @brief Application main function
* @note This function is empty by default.
*
* This function is called after startup.
* The user can use this function to implement the application.
*/
/* USER CODE BEGIN (2) */
uint32 g_ulTransferAddress;
uint8 flash_write_buf0[10] = {0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x10};
uint8 flash_write_buf1[10] = {0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x10};
uint8 flash_write_buf2[10] = {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x10};
uint8 flash_write_buf3[10] = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x10};
uint8 flash_read_buf[10];
/* USER CODE END */
uint8 emacAddress[6U] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};
uint32 emacPhyAddress = 1U;
int main(void)
{
/* USER CODE BEGIN (3) */
int i = 0;
gioInit();
muxInit();
rtiInit();
/* Set high end timer GIO port hetPort pin direction to all output */
gioSetDirection(hetPORT1, 0xFFFFFFFF);
/* Enable RTI Compare 0 interrupt notification */
rtiEnableNotification(rtiNOTIFICATION_COMPARE0);
/* Enable IRQ - Clear I flag in CPS register */
/* Note: This is usually done by the OS or in an svc dispatcher */
_enable_IRQ();
/* Start RTI Counter Block 0 */
rtiStartCounter(rtiCOUNTER_BLOCK0);
printf("ENDIAN_REG = %x\n", ENDIAN_REG);
//擦除整个块
Flash_EraseBanks(Fapi_FlashBank7);
//读数据,这时读出来的全是FF
Flash_ReadData(Fapi_FlashBank7, 0, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 1, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 2, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 3, 0, flash_read_buf, 10);
//向4个扇区写不同的数据
Flash_WriteData(Fapi_FlashBank7, 0, 0, flash_write_buf0, 10);
Flash_WriteData(Fapi_FlashBank7, 1, 0, flash_write_buf1, 10);
Flash_WriteData(Fapi_FlashBank7, 2, 0, flash_write_buf2, 10);
Flash_WriteData(Fapi_FlashBank7, 3, 0, flash_write_buf3, 10);
//读数据,这时读出来的是刚才写入的数据
Flash_ReadData(Fapi_FlashBank7, 0, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 1, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 2, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 3, 0, flash_read_buf, 10);
//擦除整个块
Flash_EraseBanks(Fapi_FlashBank7);
//读数据,这时读出来的全是FF
Flash_ReadData(Fapi_FlashBank7, 0, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 1, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 2, 0, flash_read_buf, 10);
Flash_ReadData(Fapi_FlashBank7, 3, 0, flash_read_buf, 10);
while(1)
{
}
/* USER CODE END */
return 0;
}
/* USER CODE BEGIN (4) */
/* Note-You need to remove rtiNotification from notification.c to avoid redefinition */
void rtiNotification(uint32 notification)
{
/* enter user code between the USER CODE BEGIN and USER CODE END. */
/* Toggle HET pin 5 */
gioSetPort(hetPORT1, gioGetPort(hetPORT1) ^ (1<<5));
}
/* USER CODE END */
在sys_main.c中验证读写擦除操作是否生效
1.先擦除Fapi_FlashBank7
2.然后读Fapi_FlashBank7的4个扇区,读出来应该全为FF
3.然后向Fapi_FlashBank7的4个扇区分别写入不同的数据
4.再次读Fapi_FlashBank7的4个扇区,读出来应该刚才写入的数据
5.再擦除Fapi_FlashBank7
6.再次读Fapi_FlashBank7的4个扇区,读出来应该全为FF
以上证明flash读写擦除都正常