본문 바로가기
Embedded SW/Embedded SW Introduction

Flash Driver API 최적화 작업 (TC275 인피니언)

by 방구석 임베디드 2022. 9. 16.
반응형

안녕하세요.

지난시간에 이어서 계속

MCU의 Flash Driver에 대해서 글을 써보도록 하겠습니다.

 

Flash 관련하여 이전글을 아래와 같이 첨부하오니

참고해 주시기 바랍니다.

Flash Driver 포팅 및 Erase, Write 동작 확인 정리 (TC275 인피니언 MCU)

Flash Driver Code, Flash 메모리 Reference Manual 분석 (TC275 인피니언)

 

그러면 계속 진행해 보도록 하겠습니다.

저는 현재 TC275 MCU 개발 보드를 이용하여

Flash Driver를 포팅하고,

Flash에 Erase, Write를 하는 기능을 구현하고 있습니다.

 

하지만, 예제 코드를 사용하자고 하니, 

너무 불필요한 매개변수가 많이 있네요.

 

그래서 이제 예제코드의 Flash Erase, Write API를 최적화해 보는 작업을 

수행해 보도록 하겠습니다.

 

먼저 우리에게 필요한 것은

RAM 주소영역 (Flash에 Wirte하려고 하는 주소영역)

을 알아야 합니다.

그리고 이제 Flash에 Write할 주소를 알아야 합니다.

 

Origin Address -> Write Address

이렇게 2가지 주소이렇게 표현해 보도록 하겠습니다.

 

또한 얼마만큼의 size를 쓸것인지도 알아야 합니다.

 

총 이렇게 3가지 정보를 알면 되겠네요.

Origin address, Write address, size

memcpy 함수이 매개변수가 비슷해 보입니다.

 

flash은 P0(2M),P1(2M) 이렇게 2가지가 있는데

IfxFlash_FlashType_P0 = 3, /**< \brief program flash #0 */

이니까 그대로 이것을 사용하겠습니다.

 

static void PFlashProgram(uint32 flash, uint32 sector_addr, uint32 start_page, uint32 no_of_pages, uint32_t* pDataAddress)
{
    uint32 offset;
    uint32 page;
    uint16 endinitSfty_pw;
    uint32_t temp = 0u;

    endinitSfty_pw = IfxScuWdt_getSafetyWatchdogPasswordInline();

    temp = 0u;

    /* program the given no of pages */
    for (page = start_page; page < no_of_pages; ++page)
    {
        uint32 pageAddr = sector_addr + page * FLASHDEMO_PFLASH_PAGE_LENGTH;
        g_Pflash.command.enterPageMode(pageAddr);

        /* wait until unbusy */
        g_Pflash.command.waitUnbusy(flash, g_Pflash.flashType);

        /* write 32 bytes (8 doublewords) into assembly buffer */
        for (offset = 0; offset < FLASHDEMO_PFLASH_PAGE_LENGTH; offset += 8)
        {
            g_Pflash.command.loadPage2X32(pageAddr, pDataAddress[temp], pDataAddress[temp+1]);
            temp += 2u;
        }

        /* write page */
        IfxScuWdt_clearSafetyEndinitInline(endinitSfty_pw);
        g_Pflash.command.writePage(pageAddr);
        IfxScuWdt_setSafetyEndinitInline(endinitSfty_pw);

        /* wait until unbusy */
        g_Pflash.command.waitUnbusy(flash, g_Pflash.flashType);
    }
}

그러면  지금부터 API를 수정해 할게요!

아래와 같이 수정해 보겠습니다.

orin address data를 pflash wirte address에 쓸것이고

wirte할 크기는 size입니다!

static void PFlashProgram(uint32_t write_addr, uint32_t ori_addr, uint32_t size)
{
    uint32 offset;
    uint32 page;
    uint16 endinitSfty_pw;
    uint32_t no_of_pages = size/FLASHDEMO_PFLASH_PAGE_LENGTH;
    uint32_t* pDataAddress = (uint32_t*)ori_addr;
    uint32_t temp = 0u;

    endinitSfty_pw = IfxScuWdt_getSafetyWatchdogPasswordInline();

    temp = 0u;

    /* program the given no of pages */
    for (page = 0u; page < no_of_pages; ++page)
    {
        write_addr = write_addr + page * FLASHDEMO_PFLASH_PAGE_LENGTH;
        g_Pflash.command.enterPageMode(write_addr);

        /* wait until unbusy */
        g_Pflash.command.waitUnbusy(0u, g_Pflash.flashType);

        /* write 32 bytes (8 doublewords) into assembly buffer */
        for (offset = 0; offset < FLASHDEMO_PFLASH_PAGE_LENGTH; offset += 8)
        {
            g_Pflash.command.loadPage2X32(write_addr, pDataAddress[temp], pDataAddress[temp+1]);
            temp += 2u;
        }

        /* write page */
        IfxScuWdt_clearSafetyEndinitInline(endinitSfty_pw);
        g_Pflash.command.writePage(write_addr);
        IfxScuWdt_setSafetyEndinitInline(endinitSfty_pw);

        /* wait until unbusy */
        g_Pflash.command.waitUnbusy(0u, g_Pflash.flashType);
    }
}

 

그러면, 몇가지만 더 생각해 보겠습니다.

지금 demo 함수가 돌고 있는데

erase 함수와 program 함수를 분리해서 API를 만들어 보도록 하겠습니다.

static void PFlashDemo(void)
{
    uint32  errors      = 0;
    uint32  offset;
    uint32  page        = 0;
    uint32  flash       = 0;
    uint32  write_addr = IfxFlash_pFlashTableLog[g_Pflash.sector].start;
    static uint32_t arry[24]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};

    /* disable interrupts */
    boolean interruptState = IfxCpu_disableInterrupts();

    /* erase & program flash (execute from relocated memory)*/
    g_Pflash.command.pFlashErase(write_addr);
    g_Pflash.command.pFlashProgram(write_addr, (uint32_t)&arry[0], sizeof(arry));

    /* enable interrupts again */
    IfxCpu_restoreInterrupts(interruptState);
}

위이 데모코드를

아래와 같이 Erase, Write API를 만들어서 사용해 Refactoring 해보도록 하겠습니다.

static void PFlashDemo(void)
{
    static uint32_t arry[24]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};

    Driver_Flash_Erase(0xA00E0000u);
    Driver_Flash_Write(0xA00E0000u, (uint32_t)&arry[0], sizeof(arry));
}

void Driver_Flash_Erase(uint32_t erase_addr)
{
    boolean interruptState = IfxCpu_disableInterrupts();
    g_Pflash.command.pFlashErase(erase_addr);
    IfxCpu_restoreInterrupts(interruptState);
}

void Driver_Flash_Write(uint32_t write_addr, uint32_t ori_addr, uint32_t size)
{
    boolean interruptState = IfxCpu_disableInterrupts();
    g_Pflash.command.pFlashProgram(write_addr, ori_addr, size);
    IfxCpu_restoreInterrupts(interruptState);
}

 

Driver_Flash_Erase 함수는 Flash의 sector를 지우는 함수이며

Driver_Flash_Write 함수는 Flash에 Write를 하는 함수입니다.

Flash는 항상 지우고 써야합니다.

RAM처럼 바로 쓸수가 없습니다.

이렇게 두 기능을 나누어서 독립적으로 API를 만드는 것이 User입장에서는 더 편합니다.

아래는 Erase 기능을 수행했을때 살펴 보도록 하겠습니다.

그리고 아래는 Write 기능을 수행했을때를

Flash가 잘 써지는 확인해 보도록 하겠습니다.

헉 그런데 버그가 있는것 같습니다.

지금 저 빨강색 부분에서부터 데이터가 채워져야 하는데

무슨 문제가 있는것 같습니다.

​확인을 해보니,

주소를 더하는 부분에서 문제가 있었습니다.

아래와 같이 수정하면 문제는 해결됩니다.

static void PFlashProgram(uint32_t write_addr, uint32_t ori_addr, uint32_t size)
{
    uint32 offset;
    uint32 page;
    uint16 endinitSfty_pw;
    uint32_t no_of_pages = size/FLASHDEMO_PFLASH_PAGE_LENGTH;
    uint32_t* pDataAddress = (uint32_t*)ori_addr;
    uint32_t temp_addr;
    uint32_t temp = 0u;

    endinitSfty_pw = IfxScuWdt_getSafetyWatchdogPasswordInline();

    temp = 0u;

    /* program the given no of pages */
    for (page = 0u; page < no_of_pages; ++page)
    {
        temp_addr = write_addr + page * FLASHDEMO_PFLASH_PAGE_LENGTH;
        g_Pflash.command.enterPageMode(temp_addr);

        /* wait until unbusy */
        g_Pflash.command.waitUnbusy(0u, g_Pflash.flashType);

        /* write 32 bytes (8 doublewords) into assembly buffer */
        for (offset = 0; offset < FLASHDEMO_PFLASH_PAGE_LENGTH; offset += 8)
        {
            g_Pflash.command.loadPage2X32(temp_addr, pDataAddress[temp], pDataAddress[temp+1]);
            temp += 2u;
        }

        /* write page */
        IfxScuWdt_clearSafetyEndinitInline(endinitSfty_pw);
        g_Pflash.command.writePage(temp_addr);
        IfxScuWdt_setSafetyEndinitInline(endinitSfty_pw);

        /* wait until unbusy */
        g_Pflash.command.waitUnbusy(0u, g_Pflash.flashType);
    }
}

잘써지는 것을 확인하실 수 있으시죠?

 

그런데, 이제 마지막으로 하나가 더 남아 있습니다.

static uint32_t arry[24]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};

데이터를 쓸대 저는 32바이트의 배수로 데이터를 썼습니다.

​이유는 페이즈가 32바이트로 구성이되어 있기 때문인데요.

 

우리가 쓰고싶은 데이터가 32바이트의 배수로 구성되지 않는다면

이것을 호환할수 있도록 API 수정이 필요합니다.

 

예를 들면 arr[22] 일때 32배수가 아니기 때문에 수정이 필요합니다.

이제, 다음장에서 이것에대한 수정을 해보겠습니다.

반응형

댓글