[原创] TMS570学习3-内部Flash编程

石玉   2019-8-16 14:56 楼主

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},
};


/*  [url=home.php?mod=space&uid=159083]@brief[/url]  查找扇区信息
*   @param[in] oNewFlashBank:块编号
*   @param[in] sector:扇区编号
*
*   return:扇区在数据结构中的位置
*/
uint32_t find_sector(Fapi_FlashBankType oNewFlashBank, uint32_t sector)
{
    int i=0;

    for(i=0; i<SECTOR_NUM; i++)
    {
        if( (gSector_List[i].banks_num == oNewFlashBank) && (gSector_List[i].sector_num == sector) )
        {
            return i;
        }
    }
}

/*  @brief  擦除扇区
*   @param[in] oNewFlashBank:块编号
*   @param[in] sector:扇区编号
*
*   return:
*/
enum e_flash_status Flash_EraseSector(Fapi_FlashBankType oNewFlashBank, uint32_t sector)
{
    int num = 0;
    Fapi_StatusType oReturnCheck = Fapi_Status_Success;

    num = find_sector(oNewFlashBank, sector);   //根据块ID和扇区ID查找扇区信息
    printf("addr = %x\n", gSector_List[num].low_addr);

    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( 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( 1<<sector );  //设置EEPROM存储区中可用的扇区以进行擦除和编程
        else if( oNewFlashBank == Fapi_FlashBank7 )
            oReturnCheck = Fapi_enableEepromBankSectors(1<<sector ,1<<(sector%32));  //设置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读写擦除都正常




此内容由EEWORLD论坛网友石玉原创,如需转载或用于商业用途需征得作者同意并注明出处

回复评论 (2)

顶一下

很好的学习例程

点赞  2019-8-16 17:15

真心不错的分享啦。

点赞  2019-8-19 07:56
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复