해보기는 했어?

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

MEGAWIN

MG82F6D Series IAP LOOP

롬돌이 2022. 12. 15. 13:10
반응형

1. 프로그램 개요

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

IAP 영역에 특정 시스템 파라미터 영역을 할당한다.

P10 키가 눌리면 해당 영역을 리셋 시키고, P11 키가 눌리면 While 문에서 100us 마다 증가하는 값, P11 키가 눌렸을 때에만 증가하는 값을 저장하고 UART로 전송한다.

 

2. 회로도

      

 

3. Code

main routine

idata u8 TrapFlag[3];                            // 전역변수

void main()

{

u8 i;

TrapFlag[0]='W';                         // TrapFlag[0]‘W’ 문자 저장

InitSystem();                             // 시스템 초기화 루틴, 포트설정, UART0설정, TrapFlag[1]‘I’ 문자 입력

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

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

         printf("\nStart IAP DEMO!");         // “Start IAP DEMO!” 문자 전송, 프로그램 시작임을 알려줌

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

         TrapFlag[1]='i';                                   // TrapFlag[1]‘I’, TrapFlag[2] ‘n’ 저장

         TrapFlag[2]='n';

         //read IAP low boundary

         i=IAP_ReadPPage(IAPLB_P);           // IAP Low boundary 영역읽기, 0x03

printf("\nRead IAPLB:%02bX",i);     // IAP Low boundary 영역의 데이터를 읽고 전송한다.

 

         // set IAP low boundary to IAP_END_ADDRESS,IAP size none

         IAP_WritePPage(IAPLB_P,IAP_END_ADDRESS/256); // (0x3C00/256 = 60)IAP Low boundary 영역에 IAP 페이지 수 입력, 60

         i=IAP_ReadPPage(IAPLB_P);           // IAP Low boundary 영역읽기

printf("\nNOW IAPLB:%02bX  ",i);  // IAP Low boundary 영역의 데이터를 읽고 전송한다.

         TrapFlag[1]=0xFF;                       // 플래그 클리어

         TrapFlag[2]=0xFF;                       //

ReadSysParaFromIAP();                // IAP에서 시스템 파라미터 읽기

         printf("\nRead SysPara: ");            // 시스템 파라미터를

         for(i=0;i<(sizeof(SysParaDef));i++)   // 시리얼 데이터로 전송함, SysParaDef의 크기는 8, I = 0 ~ 7

         {

                  printf("%02bX ",SysPara.BUF[i]);

         }

printf("\nWrite cnt:%ld",SysPara.B.Para2);   // Write cnt : SysParaa.B.Para2 를 시리얼로 전송,

 

while(1)                                   //

{

SysPara.B.Para1++;             // SysPara.B.Para1 증가

                  LED_G_0=!LED_G_0;           // LED_G Toggle

                 DelayXms(100);                 // 100ms Delay

                  if(P10==0)                       // P10이 눌려져 있으면

                  {       

i=0;                               // i 0으로 클리어

                           do{                               // do-while start

DelayXus(100);                 // 100us Delay

                                   if(P10==0)     // P10Low이면

                                   {

                                            i++;    // I 증가

                                   }

                                   else             // 아니면

                                   {

                                            break; // do-while 문탈출

                                   }

                           }while (i<200);         // i200이상이면 do-while 문 탈출

                           // P10이 눌려있으면 20ms 정도 딜레이를 시키는 구문임

                           // 만약 P10이 눌렸다가 바로 떼어지면 이 딜레이도 탈출

                           // 스위치 댐핑노이즈를 제거하기 위한 루틴

 

                           if(i>=200)                       // i200이상이면

                           {

                                   RestoreSysPara();             // 시스템 파라미터를 다시 저장한다.

                                   TrapFlag[1]='i';                          // TrapFlag[1]에 다시 ‘i’ 저장

                                   printf("\nSave SysPara: ");            // 저장된 파라미터를 다시 시리얼로 보낸다.

                                   for(i=0;i<(sizeof(SysParaDef));i++)

                                   {

                                            printf("%02bX ",SysPara.BUF[i]);

                                   }

                                   LED_G_1=1;LED_R=1;                  // LEG_G_11, LED_R1 저장, LED OFF

                                   if(SaveSysParaToIAP()==0)             // 시스템 파라미터를 IAP에 저장하는 것이 성공하면

                                   { // success

                                            printf(" ---OK!");                // ---OK!를 출력

                                            LED_G_1=0;                     // LED_G_1 clear, LED ON

                                   }

                                   else   

                                   { // fail                                    // 실패하면

                                            printf(" ---Fail!");               // ---Fail!를 프린트하고

                                            LED_R=0;                        // LED_R clear, LED ON

                                            while(1)                          // 실패시 무한루프를 돈다.

                                            {                                  

                                                     CLRWDT();              // 와치도그 클리어, 와치도그에 의해 리셋되지않게한다.

                                            }

                                   }

                                   TrapFlag[1]=0xFF;                       // TrapFlag[1]0xFF 저장

 

                                   i=0;                                        // i를 클리어시키고

                                   do{                                        // do-while문을 시작한다

                                            DelayXus(100);                          // 100us 딜레이

                                            if(P10==1)                       // P10 High(1)이면

                                            {

                                                     i++;                      // i를 증가시키고

                                             }

                                            else                               // 그렇지않으면(i = 0)

                                            {                                   //

                                                     i=0;                      // i0으로 클리어한다.

                                            }

                                   }while (i<200);                           // i200미만이면 계속 돈다

                           }

                  }

 

                  if(P11==0)                                        // P11 Low이면

                  {

                           i=0;                                        // i = 0

                           do{                               // do-while 시작

                                   DelayXus(100);                 // 100us delay

                                    if(P11==0)              // P11 Low이면

                                   {

                                            i++;             // i 증가

                                   }

                                   else

                                   {

                                            break;          // P11High이면 do-while 문 탈출

                                   }

                           }while (i<200);                  // i200이상이면 while문 탈출

                 

                           if(i>=200)                                // i200이상이면

                           {

                                   SysPara.B.Para2++;                      // SysPara.B.Para2를 증가시키고

                                   TrapFlag[1]='i';                                   // TrapFlag[1] i 를 저장

                                   printf("\nSave SysPara: ");            // 저장된 시스템 파라미터를 출력시킴

                                   for(i=0;i<(sizeof(SysParaDef));i++)

                                   {

                                            printf("%02bX ",SysPara.BUF[i]);

                                   }

                                   LED_G_1=1;LED_R=1;                  // LEG_G, LED_R OFF

                                   if(SaveSysParaToIAP()==0)             // IAP로 파라미터 저장이

                                   { // success                              // 성공하면

                                            printf(" ---OK!");                // ---OK를 전송하고

                                            LED_G_1=0;                     // LEG_G_1ON

                                   }

                                   else

                                   { // fail                                    // 실패하면

                                            printf(" ---Fail!");               // ---Fail을 전송하고

                                            LED_R=0;                        // LED_RON

                                            while(1)                          // 무한루프로 들어감

                                            {

                                                     CLRWDT();              // 와치도그 클리어

                                            }

                                   }                

                                   TrapFlag[1]=0xFF;                       // TrapFlag0xFF 입력

                 

                           }

                  }

 

    }

 

}

 

* SysPara 구조

0 1 2 3 4 5 6 7
SysPara.B.Para1 SysPara.B.Para2 SysPara.B.Para3 SysPara.B.Flag

⑵ 시스템 초기화 루틴

void InitSystem(void)

{

 

           InitPort();

           InitUart0_T1();

 

           TrapFlag[1]='i';

 

}

- 포트 설정을 수행한다.

- UART0을 설정한다.

- TrapFlag[1]‘i’를 저장한다.

 

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, P26LED 구동을 위하여 Push-Pull type로 설정한다.

           PORT_SetP1OpenDrainPu(BIT0|BIT1);                                                    // Set P10 as open-drain with pull-high,For KEY input.

è P10, P11 Pull-Up이 추가된 Open Drain으로 설정하고 Key 입력으로 사용한다.

           P10=1;            // P10, P11 High를 출력시켜 입력 핀으로 사용할 준비를 한다.

           P11=1;

}

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

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

UART0초기화 èTimer 1 Overflow를 이용한 Baud Rate 설정

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

*Function:   void InitUart0_T1(void)

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

*Input:  

*Output:    

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

void InitUart0_T1(void)

{

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

         UART0_EnReception();                                            // Enable reception

         UART0_SetBRGFromT1();                                // B.R. source:T1

         UART0_SetT1BaudRateX2();                             // B.R. x2

 

         TM_SetT1Mode_2_8BIT_AUTORELOAD();

         TM_SetT1Clock_SYSCLK();

         TM_SetT1Gate_Disable();

 

    // Sets B.R. value

         TM_SetT1HighByte(T1_BRGRL_9600_2X_12000000_1T);

         TM_SetT1LowByte(T1_BRGRL_9600_2X_12000000_1T);

 

         TM_EnableT1();

}

 

- UART0 MODE 설정

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

S0CFG 레지스터의 SM30bit, S0CON 레지스터의 SM00/FE, SM10 비트의 조합으로 여러가지 시리얼 포트 동작 모드를 설정할 수 있다. 그 중 본 예제는 8-bit UART, Variable Baud Rate 특성인 MODE 1을 사용한다.

 

- UART0 Receive Enable

#define UART0_EnReception()                                           REN0=1

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

- UART0 Baud RateTimer 1을 이용해서 만든다.

#define UART0_SetBRGFromT1()                                        SFRPI=1;T2MOD1=T2MOD1&(~TL2IS);SFRPI=0;RCLK_TF2L=0;TCLK_TL2IE=0

SFR PAGE 1에 위치한 T2MOD1 레지스터의 TL2IS 플래그를 클리어 시켜 T2CON5, 4번 비트가 RCLK, TCLK 제어 비트로 동작 할 수 있도록 한다.

RCLK 비트를 0으로 만들어 Timer 1 Overflow UART0의 수신 Clock으로 사용될 수 있도록 설정한다.

TCLK 비트를 0으로 만들어 Timer 1OverflowUART0의 송신 Clock으로 사용될 수 있도록 설정한다.

 

- Double Baud Rate 설정

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

PCON0 레지스터의 SMOD1 플래그를 셋 시켜 UART0 MODE 1, 2, 3Double Baud RateEnable 시킨다.

S0CFG 레지스터의 SMOD2 플래그를 클리어 시켜 USRT0 Extra Double Baud Rate Disable 시킨다.

 

- Timer 1을 모드 2 8-bit Auto Reload 모드로 설정.

#define TM_SetT1Mode_2_8BIT_AUTORELOAD()            TMOD=(TMOD&(~(T1M0|T1M1)))|(T1M1)

타이머 1을 모드 2로 설정한다.(T1M0 = 0, T1M1 = 1) 8-bit 타이머로 자동 재적재 기능(Automatic Reload)으로 동작한다.

 

- Timer 1의 클럭 설정

#define TM_SetT1Clock_SYSCLK()                                       AUXR2=(AUXR2|(T1X12));TMOD=(TMOD&(~T1C_T))

AUXR2 레지스터의 T1X12를 셋, TMOD 레지스터의 T1C/TClear 시킴으로써 Timer 1Clock Source SYSCLK로 설정한다.

- Gate Disable(타이머클럭선택, 타이머 트리거 방법 선택)

#define TM_SetT1Gate_Disable()                                        TMOD=TMOD&(~T1GATE)

TMOD레지스터의 T1GATE 비트는 TIMER 1의 클럭 소스를 결정하는 곳과 TIMER 1의 트리거 방법을 설정하는 곳에 사용된다. T1GATE Clear 시킴으로써 TIMER 1 클럭 소스를 System Clock or (System Clock/12) 중 하나로 선택할 수 있고, 클럭이 타이머에 입력되는 것(트리거시그널)을 제어하는 것을 TR1비트로 설정할 수도 있다.

 

- 타이머 1의 상/하위 레지스터의 값을 저장

TM_SetT1HighByte(T1_BRGRL_9600_2X_12000000_1T);

TM_SetT1LowByte(T1_BRGRL_9600_2X_12000000_1T);

타이머 1 UP Counter로 동작하고 0xFF에서 0x00으로 바뀔 때 Overflow 이벤트가 발생한다.

자동 재적재 기능을 갖는 Mode 2 8-bit timer로 설정하였기 때문에 실제 동작하는 카운터는 TL1레지스터이고, TH1은 재적재할 카운터 값을 저장한다. TL1레지스터의 값이 0xFF에서 0x00으로 변하면서 Overflow 이벤트가 발생하면 TH1에 저장되어 있는 데이터가 자동으로 TL1에 재적재 된다.

12MHz 클럭을 사용하고, T1X12=1, SMOD2=0, SMOD1 = 1으로 설정하였으므로 재적재 될 값은 178(0xB2)이다.(데이터시트상의 표 참조)

 

- 타이머 1 Enable(시작)

TM_EnableT1();

마지막으로 TR1 비트를 셋 시켜 타이머 1을 동작 시킨다.

 

è (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)를 참조한다.

 

 

 

IAP_ReadPPage

 

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

*Function:   u8 IAP_ReadPPage(u8 PsfrAddr)

*Description:   read P page sfr

*Input:  

*                                        u8 PsfrAddr: sfr Address

*Output:    

*                                        u8: sfr data

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

u8 IAP_ReadPPage(u8 PsfrAddr)

{

           bit bEA=EA;                          // bit 변수 bEA EA 의 값을 저장하고

           EA = 0;                                // EA 0을 저장해서 모든 인터럽트를 Disable 시킨다.

           IFADRH = 0;                         // IFADRH must be 0

           IFADRL= PsfrAddr;                // sfr Address, SFR 주소를 저장하고

           IFMT = ISP_READ_P;              // read P page sfr, 동작구분을 READ로 저장한다.

           ISPCR = 0x80;            // Enable ISP/IAP, ISP/IAP 기능을 동작시키고

           CheckTrapFlag();                 // TrapFlag를 검사하고

           SCMD = 0x46;           

           CheckTrapFlag();

           SCMD = 0xB9;           // IAP 기능 종료를 시킨다.

           nop();

           IFMT=0;                               // IAP 동작을 클리어 시키고

           ISPCR = 0;                           // clear, IAP/ISP 기능을 정지시킨다.

           EA = bEA;                            // EA의 데이터를 복워시키고

           return IFD;                            // return sfr data, 해당영역의 SFR 데이터 값을 반환한다.

                                                     // Read 시에도 IFD에 데이터가 저장된다.

}

 

- PAGE P, 보조 SFR 맵은 SFR 맵의 보조영역으로 사용되므로 주소는 0x0000 ~ 0x00FF까지이다. 그래서 IFADRH는 항상 0이어야한다.

- IAPLB(IAP Low Boundary, IAP의 하위 경계) 레지스터는 Page P에서 제어가 가능하다. 이 값은 IAP 최하위 어드레스의 상위 바이트를 표시하고, 그 값은 리셋 시 0x36으로 저장된다.

 

IAP_WritePPage

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

*Function:                 void IAP_WritePPage(u8 PsfrAddr,u8 PsfrData)

*Description:   write P page sfr

*Input:  

*                                        u8 PsfrAddr: sfr Address

*                                        u8 PsfrData: sfr data

*Output:    

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

void IAP_WritePPage(u8 PsfrAddr,u8 PsfrData)

{

           bit bEA=EA;                                    // global interrupt Enable bit 저장

           EA = 0;                                          // Global interrupt Disable

           IFADRH = 0;                                    // IFADRH must be 0

           IFADRL= PsfrAddr;                           // sfr Address, 쓰기 할 레지스터의 주소 저장

           IFD= PsfrData;                      // sfr data, 쓰기 할 데이터 저장

           IFMT = ISP_WRITE_P;             // write P page sfr, Page P 제어 동작 설정

           ISPCR = 0x80;                      // Enable ISP/IAP, ISP/IAP 동작 시작

           CheckTrapFlag();                            //

           SCMD = 0x46;                      // 동작 마무리

           CheckTrapFlag();

           SCMD = 0xB9;                      // 동작 마무리

           nop();

           IFMT=0;                                          // Page P 제어 동작 클리어

           ISPCR = 0;                                      // clear, Disable ISP/IAP

           EA = bEA;                                       // restore Global Interrupt Enable bit

}

- Page P 레지스터에 쓰기 동작을 하기 위한 루틴

- IAP 시작 주소를 0x36에서 0x3C로 변경했음

 

è (EN)MG82F6D16_Datasheet_V051.PDF29. Page P SFR Access를 참조한다.

è (EN)MG82F6D17_Datasheet_V051.PDF30. Page P SFR Access를 참조한다.

è (EN)MG82F6D64/32_Datasheet_V051.PDF30. Page P SFR Access를 참조한다.

 

 

CheckTrapFlag

 

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

*Function:   void CheckTrapFlag(void)

*Description:          

*                                         If TrapFlag != Win, means illegal entry and soft reset of MCU

*Input:         

*Output:    

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

void CheckTrapFlag(void)

{

           if ((TrapFlag[0]!='W')||(TrapFlag[1]!='i')||(TrapFlag[2]!='n'))

           {

                     // Softwave Reset

                     ISPCR=SRST;

           }

}

 

- TrapFlag레지스터의 값이 ‘W’, ‘i’, ‘n’와 틀린 것이있으면 소프트웨어리셋을 수행한다.

 

ReadSysParaFromIAP

 

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

*Function:       void ReadSysParaFromIAP(void)

*Description:    Read system para from IAP

*Input:  

*Output:    

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

void ReadSysParaFromIAP(void)

{

           u8 i;

           u16 wAddr;

           wAddr=0;

           for(i=0;i<(512/(sizeof(SysParaDef)));i++)      // i=0 ~ 63까지

           { //

                     if(CBYTE[(SYS_PARA_ADDR)+(sizeof(SysParaDef)-1)+wAddr]==IAP_SYS_PARA_FLAG)

                     {         // SYS_PARA_ADDR = 0x3800

                                // 파라미터를 읽어오는데 8번째 데이터가 0xA5이면 이 루틴을 탈출하고

                                break;

                     }

                     wAddr=wAddr+(sizeof(SysParaDef));

           }

           if(i<(512/(sizeof(SysParaDef))))       // i64보다 작으면

           { //

                     for(i=0;i<(sizeof(SysParaDef));i++)

                     { //

                                SysPara.BUF[i]= CBYTE[(SYS_PARA_ADDR)+wAddr+i];      // 시스템 파라미터에 그 값들을 저장한다.

                     }

           }

           else     // 만약 i64이상이면

           {//     

                     RestoreSysPara();     // 시스템 파라미터를 재설정한다.

           }

}

 

* CBYTE

CBYTE8051의 프로그램 메모리의 바이트들을 개별적으로 접근할 수 있는 매크로이다. 다음과 같이 사용이 가능하다.

#include <absacc.h>    /* Include Macro Definitions */
.
.
.
rval = CBYTE [0x0002];
.
.
.

 

위 예제는 프로그램 메모리 0002H의 내용을 읽는 것이다. 인덱스 값의 범위는 0~ 65535이다.

참조 : https://www.keil.com/support/man/docs/c51/c51_cbyte.htm

typedef struct{

           u16 Para1;                           // 2

           u32 Para2;                           // 4

           u8 Para3;                             // 1

           u8 Flag;                               // 1, 0xA5

}SysParaDef;

 

sizeof(SysParaDef) = 8

 

 

RestoreSysPara

 

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

*Function:   void RestoreSysPara(void)

*Description:    reset System para

*Input:         

*Output:    

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

void RestoreSysPara(void)

{

           // reset System para

           SysPara.B.Para1=0x0000;

           SysPara.B.Para2=0x00000000;

           SysPara.B.Para3=0x00;

           SysPara.B.Flag=IAP_SYS_PARA_FLAG;

}

- SysPara에 기본 데이터를 저장한다. 이 후 루틴에서 이 데이터를 IAP영역에 저장한다.

 

4. 프로그램 실행

*** Keil compiler가 인스톨되어 있어야함 ***

해당 Example 폴더를 찾아가 KeilPrj폴더를 Open 한다.

\Megawin 8051\(EN)MG82F6D16_SampleCode_v1.20\ MG82F6D16_IAP_LOOP\KeilPrj

 

해당 폴더의 Keil project 파일을 더블 클릭하여 실행시킨다.(MG82F6D16_DEMO.uvproj)

 

Rebuild 아이콘을 클릭하여 프로젝트를 컴파일 한다.

 

Demo BoardUSB Connector를 연결하여 전원을 인가하고, 전원 스위치를 ON시키고, OCD ICE를 연결한 상태에서 위 이미지의 Start/Stop Debug Session(Ctrl+F5) 버튼을 눌러 컴파일된 프로젝트의 디버그 데이터를 다운로드 시킨다.(컴파일 시 에러가 발생하지 않아야함)

 

 

다운로드 후 Run(F5) 버튼을 클릭하면 프로그램이 동작한다.

 

5. 동작 영상

https://www.youtube.com/watch?v=0QJCjsP-oH0

 

 

 

 

 

 

반응형

'MEGAWIN' 카테고리의 다른 글

MG82F6D Series INT KBI Wake UP  (0) 2022.12.19
MG82F6D Series IAP Sample  (0) 2022.12.16
MG82F6D Series TIM_T2_Mode4_PWM  (0) 2022.12.13
MG82F6D Series I2C Slave Int  (0) 2022.12.09
MG82F6D시리즈 GPIO MODE  (0) 2022.12.08