해보기는 했어?

오늘 안됐다고 포기하지 말고 용기내서 내일 다시 해 보자.

MEGAWIN

MG82F6D SPI Flash-1

롬돌이 2022. 12. 22. 09:50
반응형

1. 프로그램 개요

P22Green 0 LED, P24 Red LED, P26Green 1 LED가 연결되어 있다.

SPI 통신으로 MX25L3206 ICRead/Write 테스트함.

- Flash ID 읽기

- Flash Erase

- Flash Write

- Flash Read

 

2. 회로도

3. Code

main routine

void main()

{

         u32 i;

         bit bOK;

         DWordTypeDef dwTemp;

InitSystem();                                      // 시스템 초기화

INT_EnAll();                                       // EA = 1,

        

         SendStr("\nHello!");                            // 시리얼로 Hello 전송, program start

         LED_G_0=0;LED_G_1=0;LED_R=0;             // LED ALL ON

         DelayXms(1000);                                 // 1초 딜레이

         LED_G_0=0;LED_G_1=1;LED_R=1;             // LED ALL OFF

 

         dwTemp.DW=SPI_Flash_Read_ID();           // dwTemp.DWFlash ID 읽은 것을 저장

         SendStr("\nFlash ID: ");                        // 시리얼로 Flash ID 전송

         SendHex(dwTemp.B.BMHigh);            // RDID1byte Manufacture ID, 2byte Memory ID(type, density)로 구성

         SendHex(dwTemp.B.BMLow);                           // 0xC2, 0x20, 0x16

         SendHex(dwTemp.B.BLow);

 

 

// Clear write protect

         SPI_Flash_Write_Status(0x00);         // Flash Status 초기화

         if(dwTemp.DW == FLASH_ID)                 // 읽은 Flash ID0x00C22016 이 맞으면

         {

                  bOK=TRUE;                      // bOK플래그에 TRUE를 저장

                  // Test

                  SendStr("\nFlash Erase...");            // Flash를 지운다.

                  i=FLASH_TEST_SIZE_MAX/FLASH_BLOCK_SIZE;      // (용량최대1024*1024)/(블록크기64kB 64*1024)

                  // Erase Flash                                              // i = 16이 된다.

                  dwTemp.DW=FLASH_TEST_START_ADDRESS;       // Flash의 시작 주소는 0x00000000 이다.

                  ResetCounter();                                           // timer 0, 1의 카운터를 0으로 클리어시킴

                  while(i!=0)

                  {

                           LED_G_1 = !LED_G_1;                           // LED_G_1을 토글시킴

                           if(SPI_Flash_Block_Erase(dwTemp.DW)!=0)   // 블록 Erase

                           {

                                   bOK=FALSE;

                                   break;

                           }

                           dwTemp.DW=dwTemp.DW+FLASH_BLOCK_SIZE;   // Erase 후 다음 블록 주소를 저장

                           i--;                                                          // 블록 카운트를 1 감소 시킴

                  }

                  SendCounter();                                                    // Erase에 소요된 시간을 시리얼로 전송함

                  for(i=0;i<256;i++)                                                 // 테스트 버퍼에 0 ~ 255까지 저장

                  {

                           TestBuf[i]=i;

                  }

                  // Write Flash

                  SendStr("\nFlash Write 1M");                                           

                  i=FLASH_TEST_SIZE_MAX/256;                                  // (용량최대1024*1024)/256 = 4096

                  dwTemp.DW=FLASH_TEST_START_ADDRESS;                // Flash start address = 0DW에 저장

                  ResetCounter();                                                    // 카운터를 초기화 시킴

                  while(i!=0)

                  {

                           LED_G_1 = !LED_G_1;                                    // LED_G_1을 토글

                           if(SPI_Flash_Page_Program(dwTemp.DW,&TestBuf[0],256)!=0)      // 선택된 페이지 어드레스에서부터 테스트 버퍼의

                           {                                                                               // 데이터를 256바이트 저장한다.

                                   bOK=FALSE;                                                        //

                                   break;

                           }

                           dwTemp.DW=dwTemp.DW+256;                      // 저장을 시작할 주소에 +256을 하고

                           i--;                                                          // 저장 회수를 -1한다.

                  }

                  SendCounter();                                                    // 저장이 끝나면 소요된 시간을 시리얼로 전송한다.

                  // Read Flash

                  SendStr("\nFlash Read 1M");

                  i=FLASH_TEST_SIZE_MAX/512;                                  // (용량최대1024*1024)/512 = 2048

                  dwTemp.DW=FLASH_TEST_START_ADDRESS;                // Flash start address = 0

                  ResetCounter();                                                    // 카운터 초기화

                  while(i!=0)

                  {

                           LED_G_1 = !LED_G_1;                                    // LED_G_1토글

                           SPI_Flash_MultiBytesRead(dwTemp.DW,&TestBuf[0],512); // 지정된 주소로부터 512바이트를 읽어 테스트 버퍼에저장

                           dwTemp.DW=dwTemp.DW+512;    // 주소에 +512

                           i--;                                         // 블록 카운트 -1

                  }

                  SendCounter();                                                    // 읽기에 소요된 시간을 시리얼로 전송함

         }

         else

         {

                  SendStr("\nFlash isn't MX25L3206! ");                        // 연결된 플래시가 틀리면

                  bOK=FALSE;

         }

         while(1)

         {                                                    // Erase-Write-Read 동작이 모두 완료되면 LED_G_0을 토글 시키고

                  DelayXms(100);                         // 에러가 있었으면 LED_R을 토글 시킨다.

                  if(bOK)

                  {

                           LED_G_0 = !LED_G_0;

                  }

                  else

                  {

                           LED_R = !LED_R;

                  }

         }

}

 

⑵ 시스템 초기화 루틴

/***********************************************************************************

*Function:   void InitSystem(void)

*Description:           Initialize MCU

*Input:  

*Output:    

*************************************************************************************/

void InitSystem(void)

{

           InitPort();

           InitClock();

           InitSPI_Master();

           InitUart0_S0BRG();

           InitTimer0();

           InitTimer1();

           InitTimer2();

           InitInterrupt();

}

- 포트 초기화

- 클럭 초기화

- SPI 초기화

- S0BRG를 이용한 UART0 설정

- 타이머 0, 1, 2, 초기화

- 인터럽트 초기화

 

 

 

Port 초기화

/***********************************************************************************

*Function:   void InitPort(void)

*Description:            Initialize IO Port

*Input:  

*Output:    

*************************************************************************************/

void InitPort(void)

{

           PORT_SetP2PushPull(BIT2|BIT4|BIT6);                   // Set P22,P24,P26 as Push-Pull,For LED.

è P22, P24, P26에는 LED 연결 

           PORT_SetP3PushPull(BIT3);                                  // Set P33 as Push-Pull, For nSS

è P33Push-Pull type으로 설정. nSS 핀으로 사용된다. Slave 통신을 활성화 시키는 핀

           PORT_SetP1PushPull(BIT4|BIT5|BIT7);                  // Set P14(nSS),P15(MOSI),P17(SPICLK) as push-pull for output.

è P14, P15, P17PushPull type으로 설정하고, SPI 통신 핀으로 사용한다. P33은 뭐지?

           PORT_SetP1OpenDrainPu(BIT6);                            // Set P16(MISO) as open-drain with pull-high for digital input

è P16 Pull Up을 가지는 Open Drain으로 설정한다. P16은 입력(MISO)핀이다.

}

 

*** 사용된 매크로함수는 “API_Macro_MG82FG6D16.H”에서 찾아볼 수 있다.

\Megawin 8051\(EN)MG82F6D16_SampleCode_v1.20\MG82F6D16_SPI_Flash\code\include

 

⑷ 클럭 초기화 루틴 è 시스템 클럭 및 내부 클럭을 설정한다.

프로그램의 루틴 자체는 복잡하게 많이 설정해 두었으나 그 구조는 아래와 같다.

MCU_SYSCLK의 값은 11059200, 12000000, 22118400, 24000000, 29491200, 32000000, 44236800, 48000000로 설정이 가능하며, 각각 프로그램 상단에

#define        MCU_SYSCLK          48000000

와 같이 선언해주었다. 그리고, 바로

#define        MCU_CPUCLK          (MCU_SYSCLK/2)

로 선언하여 (System 클럭/2)CPU 클럭을 동일하게 사용하기로 선언하였다. 물론 사용자의 선택에 따라 틀려질 수 있으므로 어플리케이션에 따라 선언하면 된다.

#if (MCU_SYSCLK==48000000)

         // SysClk=48MHz CpuClk=24MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx8, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X8|OSCIn_IHRCO);

#endif

 

- CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

CKCON0 레지스터의 각 비트를 설정한다.

CKCON0.7 : AFS, Alternated Frequency Selection, 내부 클럭 IHRCO12MHz(AFS = 0), 또는 11.059MHz(AFS = 1)로 설정함

CKCON0.6 : ENCKM, X8 클럭 멀티플라이어를 동작시킴

CKCON0.5~4 : OSCin12MHz이므로 01을 입력한다.

CKCON0.3 : CCKS, CPU Clock Select, 0:CPU CLOCK = System Clock, 1:CPU CLOCK = System Clock/2

CKCON0.0 ~ 2 : Programable System Clock Select. SYSCLK_MCKDO_DIV_1(System Clock = Master Clock Divider Output)

 

- CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X8|OSCIn_IHRCO);

IHRCO를 동작시키고, CKMI x8을 동작 시키고, OSCInIHRCO로 선택한다.

 

/***********************************************************************************

*Function:   void InitClock(void)

*Description: 

*                                  Initialize clock

*Input:  

*Output:    

*************************************************************************************/

void InitClock(void)

{

{

#if (MCU_SYSCLK==11059200)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=11.0592MHz CpuClk=11.0592MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1);

        

#else

         // SysClk=11.0592MHz CpuClk=5.5296MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1);

#endif

#endif

 

#if (MCU_SYSCLK==12000000)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=12MHz CpuClk=12MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1);

        

#else

         // SysClk=12MHz CpuClk=6MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1);

#endif

#endif

 

#if (MCU_SYSCLK==22118400)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=22.1184MHz CpuClk=22.1184MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#else

         // SysClk=22.1184MHz CpuClk=11.0592MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==24000000)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // SysClk=24MHz CpuClk=24MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#else

         // SysClk=24MHz CpuClk=12MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx4, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X4|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==29491200)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // Cpuclk high speed

         CLK_SetCpuCLK_HighSpeed();

         // SysClk=29.491200MHz CpuClk=29.491200MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#else

         // SysClk=29.491200MHz CpuClk=14.7456MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==32000000)

#if (MCU_CPUCLK==MCU_SYSCLK)

         // Cpuclk high speed

         CLK_SetCpuCLK_HighSpeed();

         // SysClk=32MHz CpuClk=32MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#else

         // SysClk=32MHz CpuClk=16MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx5.33, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X533|OSCIn_IHRCO);

#endif

#endif

 

#if (MCU_SYSCLK==44236800)

         // SysClk=44.2368MHz CpuClk=22.1184MHz

         CLK_SetCKCON0(IHRCO_110592MHz|CPUCLK_SYSCLK_DIV_1|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx8, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X8|OSCIn_IHRCO);

#endif

 

#if (MCU_SYSCLK==48000000)

         // SysClk=48MHz CpuClk=24MHz

         CLK_SetCKCON0(IHRCO_12MHz|CPUCLK_SYSCLK_DIV_2|SYSCLK_MCKDO_DIV_1|ENABLE_CKM|CKM_OSCIN_DIV_2);

         DelayXus(100);

         // IHRCO, MCK=CKMIx8, OSCin=IHRCO

         CLK_SetCKCON2(ENABLE_IHRCO|MCK_CKMI_X8|OSCIn_IHRCO);

#endif

 

         // P60 Output MCK/4

         //CLK_P60OC_MCKDiv4();

}

UART0초기화 èS0를 이용해서 UART0Baud Rate를 설정한다.

/***********************************************************************************

*Function:              void InitUart0_S0BRG(void)

*Description:          Initialize Uart0, The source of baud rate was S0BRG

*Input:  

*Output:    

*************************************************************************************/

void InitUart0_S0BRG(void)

{       

         UART0_SetAccess_S0CR1();                    // Enable access S0CR1

         UART0_SetMode8bitUARTVar();              // UART0 Mode: 8-bit, Variable B.R.

         UART0_EnReception();                                   // Enable reception

         UART0_SetBRGFromS0BRG();                  // B.R. source:S0BRG

         UART0_SetS0BRGBaudRateX2();                       // B.R. x2

         UART0_SetS0BRGSelSYSCLK();                         // S0BRG clock source: SYSCLK

 

    // Sets B.R. value

         UART0_SetS0BRGValue(S0BRG_BRGRL_9600_2X_12000000_1T);

        

         UART0_EnS0BRG();                                       // Enable S0BRG

}

- UART0 MODE 설정

#define UART0_SetAccess_S0CR1()                            S0CFG=S0CFG|(SMOD3)

S0CFG 레지스터의 0번 비트인 SMOD3을 셋 시킴으로써 S0CR1을 제어가능하게 된다. CPU S0CR1을 읽고 쓰기 위해SFR어드레스 0xB9을 제어한다.

- UART0MODE 1으로 설정한다.

#define UART0_SetMode8bitUARTVar()                       S0CFG=S0CFG&(~SM30);SM00_FE=0;SM10=1

SM30 비트 클리어, SM00비트 클리어, SM10 비트 셋 시킴으로서 MODE 1으로 설정한다. Mode 18-bit UART이고, Baud Rate는 가변이 된다.

 

- UART0 Receive Enable

#define UART0_EnReception()                                           REN0=1

UART0이 시리얼 통신으로 데이터를 받아들일 수 있도록 설정한다. S0CON 레지스터의 REN0를 셋(=1) 시킨다.

 

- UART0 Baud Rate S0BRG를 이용한다.

#define UART0_SetBRGFromS0BRG()                                            S0CR1=S0CR1|(S0TCK|S0RCK)                

앞서 S0CR1을 제어 가능하도록 설정해 두었으며, S0TCK, S0RCK를 셋 시킴으로써 S0BRGOverflowUART0의 송신/수신 클럭으로 사용하도록 설정한다.

 

- Baud Rate2배로 설정한다.

#define UART0_SetS0BRGBaudRateX2()                       PCON0=PCON0&(~SMOD1);S0CFG=S0CFG|(SMOD2)

SMOD1을 클리어 시켜 Double Baud RateDisable 시키고, SMOD2를 셋 시켜 향상된 기능의 UART를 사용한다. Baud RateDouble Baud Rate x 2가 된다.

 

- S0BRG의 클럭 설정

#define UART0_SetS0BRGSelSYSCLK()                         S0CR1=S0CR1|(S0TX12)

S0BRG의 클럭을 SYSCLK를 사용하도록 한다.

 

 

- Baud Rate : 9600 설정

#define S0BRG_BRGRL_9600_2X_12000000_1T             0xB2        // 0.16%

#define UART0_SetS0BRGValue(x)                              S0BRT=x;S0BRC=x

 

위의 수식으로 계산 시 S0BRT 177.875가 나온다. 따라서 9600 Baud Rate를 위해서는 178(0xB2)S0BRT, S0BRC에 초기값으로 저장한다.

 

- S0BRG를 동작시킨다.

#define UART0_EnS0BRG()                                               S0CR1=S0CR1|S0TR

 

è (EN)MG82F6D16_Datasheet_V051.PDF17. Serial Port 0(UART0)를 참조한다.

è (EN)MG82F6D17_Datasheet_V051.PDF18. Serial Port 0(UART0)를 참조한다.

è (EN)MG82F6D64/32_Datasheet_V051.PDF18. Serial Port 0(UART0)를 참조한다.

 

 

* 길게써서 그런건지...내 컴이 구형이라 그런건지 일정 용량 이상으로 글을 쓰면 Tistory 에디터가 먹통이 된다.

** 그래서 내용이 긴 것은 중간에 짤라야겠다.

 

 

 

 

반응형

'MEGAWIN' 카테고리의 다른 글

MG82F6D SPI Master  (1) 2022.12.26
MG82F6D SPI Flash-2  (0) 2022.12.22
MG82F6D Series PCA COPM Buf  (0) 2022.12.21
MG82F6D Series PCA Capture Buf  (0) 2022.12.20
MG82F6D Series INT KBI Wake UP  (0) 2022.12.19