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

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

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

안녕하세요.

오늘은 지난번에 쓴 글에 이어서, Flash Driver 코드와

Flash 메모리를 상세히 분석해 보는 시간을 가져 보도록 하겠습니다.

 

지난시간에 쓴글은 아래 링크 글을 참고해 주시기 바랍니다.

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

 

그러면 이어서 글을 한번 써보도록 하겠습니다.

아래는 이제 Write를 수행하는 Flash Program 함수입니다.

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

여기서 보시면 알겠지만 Page 크기 만큼 반복해서 쓰고 있는것을 볼수 있습니다.

1 Page의 크기가 32바이트니

32바이트 배수로 Wirte를 수행하고 있는 것입니다.

그러면 이제 Reference Manual을 한번 확인해 보도록 하겠습니다.

아래 메뉴얼은 TC275 Reference Manual입니다.

여기서 Flash Memory 관련된 부분인데

32바이트 페이지를 가지고 있다는 것을 볼 수 있습니다.

즉 32바이트씩 쓰고 있다는 것입니다.

 

만일 page가 5라고 한다면

32바이트 x 5 = 160바이트를 Flash에 Write하는 것이 되는 것입니다.

 

​그리고 sector_address를 가지고 오는데,

아래와 같이 가져옵니다.

uint32 sector_addr = IfxFlash_pFlashTableLog[g_Pflash.sector].start;

 

pflash의 sector는 27개로 이루어져 있습니다.

S0~S26 이렇게 27개로 나누어져 있습니다.

그리고 Erase를 수행하면

Sector 별로 Erase가 됩니다.

예제 코드에서는 Sector가 22라고 적혀 있습니다.

따라서  offset이 0xe0000 이고

Base Address는 0x80000000 이기 때문에

0x800e0000에 Erase 및 Write가 되는 것을 알 수 있습니다.

 

그리고 아래 코드와 같이

/* program the given no of pages */

for (page = start_page; page < no_of_pages; ++page) start_page :

0x800e0000 에서부터 시작됩니다. 여기서 1page씩 (32바이트) write가 되고 있는 것입니다.

 

그렇다면 한번 이제

아래의 arry[24] 의 데이터를 0x800e000에 써보도록 하겠습니다.

4바이트 x 24 = 96바이트가 될것입니다.

32바이트씩 쓰게 되니까

32 + 32 + 32 = 96바이트

따라서 3page를 쓸것이고

for구문을 3번 돌겠네요!

그렇다면 Sector 주소는 아래와 같이

sector_addr = 0x800e000가 될것이고

g_Pflash.startPage = 0

g_Pflash.numberOfPages = 3

이렇게 설정을 하게 될것입니다.

 

&arry[0]는 Flash에 Write할 배열의 주소값이 될 것입니다.

그렇기 때문에 코드는 아래와 같습니다.

static void PFlashDemo(void)
{
    uint32  errors      = 0;
    uint32  offset;
    uint32  page        = 0;
    uint32  flash       = 0;
    uint32  sector_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();

    /* Copy the erase and program routines to PSPR memory */
    copyFlashRoutinesToPspr();

    g_Pflash.numberOfPages = sizeof(arry)/32u;

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

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

따라서 페이지의 수를 구하기 위하여 32바이트를 나누어서 

g_Pflash.numberOfPages = sizeof(arry)/32u;

위와 같은 수식을 넣었습니다.

그럼!

원하는 데이터가 Write가 되는지 확인해 보도록 하겠습니다.

이렇게 96바이트가 정상적으로 write가 되는것을 확인할수 있습니다.

​이렇게 Flash Driver를 이용해서 Write를 수행하는 것이네요!!

이제 API에 대해서는 어느정도 분석이 되었습니다.

그러면 이제 RAM에서 도는 함수에 대해서 생각해 볼게요!

g_Pflash.command.eraseSector(sector_addr);

g_Pflash.command.writePage(pageAddr);

이것은 함수포인터로서, 아래와 같은 함수를 RAM으로 복사된 함수를 Call하게 되어 있습니다.

IFX_INLINE void IfxFlash_eraseSector(uint32 sectorAddr)
{
    volatile uint32 *addr1 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaa50);
    volatile uint32 *addr2 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaa58);
    volatile uint32 *addr3 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaaa8);
    volatile uint32 *addr4 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaaa8);

    *addr1 = sectorAddr;
    *addr2 = 1;
    *addr3 = 0x80;
    *addr4 = 0x50;

    __dsync();
}
IFX_INLINE void IfxFlash_writePage(uint32 pageAddr)
{
    volatile uint32 *addr1 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaa50);
    volatile uint32 *addr2 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaa58);
    volatile uint32 *addr3 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaaa8);
    volatile uint32 *addr4 = (volatile uint32 *)(IFXFLASH_CMD_BASE_ADDRESS | 0xaaa8);

    *addr1 = pageAddr;
    *addr2 = 0x00;
    *addr3 = 0xa0;
    *addr4 = 0xaa;

    __dsync();
}

이것은

결국Flash erase wirte를 control 하는 레지스터에 값을 넣는 부분입니다.

 

메뉴얼을 읽어보시면 더 많은 정보를 얻을 수 있습니다.

즉, Flash를 관장하는 모듈에 값을 채워넣어서

erase 또는 write동작을 수행하도록 하는 것입니다.

아래에서 Write를 할때, Erase를 할때가 보이시나요?

다시 설명드리면

g_Pflash.command.eraseSector(sector_addr); 이 함수포인터에

IfxFlash_eraseSector 이 함수를 직접연결하는 것이아니라

아래와 같이 memcpy하여 ram 영역에 복사하는 것을 볼 수 있습니다.

memcpy((void *)FLASHDEMO_ERASESECTOR_ADDR, (const void *)IfxFlash_eraseSector, FLASHDEMO_ERASESECTOR_LEN);

g_Pflash.command.eraseSector = (void *)FLASHDEMO_RELOC_START_ADDR;

왜 이 함수를 ram에 복사하여, ram에서 돌리는 것일까요?

그 이유는 이 함수가 Flash에서 CPU가 Read를 하여 동작​해서는 안되기 때문입니다.

2M Flash는 section이 나누어져 있지만 하나의 덩어리 입니다.

따라서, erase 를 수행할때

동시에 Code를 읽으면 문제가 생기게 됩니다.

따라서 해당 API는 RAM에 복사하여 동작을 수행해야 한다고 메뉴얼에 나와 있습니다.

​한번 메뉴얼에서 찾아보세요 ^^

 

이상으로 Flash Driver Code, Flash 메모리 Reference Manual 분석을 마치도록 하겠습니다.

반응형

댓글