해보기는 했어?

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

MEGAWIN

MG82F6D SPI Master

롬돌이 2022. 12. 26. 09:18
반응형

1. 프로그램 개요

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

SPI 통신은 송/수신이 동시에 이루어진다. 송신 데이터와 수신 데이터가 서로 틀리면 LED_RON 시킨다.

데이터 송신 전에 LED_ROFF 시킨다.

 

2. 회로도

 

 

3. Code

main routine

void main()

{

         u8 x,y;

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

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

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

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

         x++;                                                // x 증가

while(1)

{

                  DelayXms(50);                           // 50ms 딜레이

                  LED_G_1 = !LED_G_1;                  // LED_G_1 토글

                  LED_R=1;                                 // LED_R OFF

                  SPI_nSS=0;                               // SPI_nSS 핀을 Low로 설정, 연결된 Slave통신 활성화

                  y=SPITransceiver(x);                    // x를 송신하고, 수신되는 값을 y에 저장함

                  SPI_nSS=1;                               // SPI_nSS 핀을 High로 설정, 연결된 Slave 통신 비 활성화

                  if(x!=y) LED_R=0;                        // x y가 서로 다르면 LED_R ON

                  x++;                                       // x 증가

}

}

 

⑵ 시스템 초기화 루틴

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

*Function:   void InitSystem(void)

*Description:           Initialize MCU

*Input:  

*Output:    

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

void InitSystem(void)

{

           InitPort();

           InitClock();

           InitSPI();

}

- 포트 초기화

- 클럭 초기화

- SPI 초기화

 

 

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_Master\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();

}

 

 

SPI 통신 초기화 – SPI 마스터 설정

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

*Function:   void InitSPI(void)

*Description:   Initialize SPI Master

*Input:  

*Output:    

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

void InitSPI(void)

{

           SPI_Enable();                                                                                       // Enable SPI

           SPI_SelectMASTERByMSTRbit();                                                 // Set to MASTER

           SPI_SetClock(SPI_CLK_SYSCLK_8);                                             // Set Clock SYSCLK/8 48M/8=6M

           SPI_SetCPOL_0();                                                                                 // CPOL=0

           SPI_SetDataMSB();                                                                               // Data MSB

           SPI_SetCPHA_0();                                                                                 // CPHA=0

           SPI_SetUseP14P15P16P17();                                                       // IO Port: nSS/P14,MOSI/P15,MISO/P16,SPICLK/P17

}

- SPI 활성화

#define SPI_Enable()                                                      SPCON=SPCON|(SPEN)

SPCON 레지스터의 SPEN비트를 셋 시켜서 SPI를 동작 시킨다.

 

- 마스터 선택 및 nSS 동작 방법 선택

#define SPI_SelectMASTERByMSTRbit()                           SPCON=SPCON|(SSIG|MSTR)                            

SPCON 레지스터의 MSTR 비트를 셋 시켜서 SPI MASTER MODE를 선택하고, SSIG를 셋 시킴으로써 마스터 또는 슬레이브로 선택되어 있더라도 nSS 핀은 마스터가 동작시킨다.(자동으로 동작하지 않는다.)

 

- SPI Clock 설정

#define SPI_SetClock(x)                                                  SPCON=(SPCON&B11111100)|(x&0x03);SPSTAT=(x>>2)

SPCON 레지스터의 1, 0 비트와 SPSTAT 레지스터의 0번 비트를 이용해서 총 8가지의 클럭을 선택해서 사용할 수 있다.

본 예제에서는 SYSCLK/8을 사용하기로하였다. SYSCLK48MHz이므로 SPI Clock6MHz가 된다.

 

 

 

 

SPI 송수신

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

*Function:   u8 SPITransceiver(u8 SPI_DATA)

*Description:   SPI Master transmit

*Input:                     u8 SPI_DATA: Data to be send

*Output:                  u8:  Received data

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

u8 SPITransceiver(u8 SPI_DATA)

{

           SPI_SendData(SPI_DATA);                                                                     // Send data

           while(SPI_ChkCompleteFlag()==0);                                    // Wait complete

           SPI_ClearCompleteFlag();                                                           // Clear flag

           return SPI_GetData();                                                                 // Return data

}

- SPI 데이터 송신

#define SPI_SendData(x)                 SPDAT=x

설정이 완료되면 SPDAT 레지스터에 전송하고자 하는 데이터를 저장한다.

 

- 데이터 송수신 완료 플래그 확인

#define SPI_ChkCompleteFlag()                  (SPSTAT&SPIF)

데이터가 송신이 완료될 때까지 대기한다.

 

- 송수신 완료 플래그 초기화

#define SPI_ClearCompleteFlag()                SPSTAT=SPSTAT|SPIF

SPIF 플래그를 클리어 하기 위해서 해당 비트에 “1”을 써 준다.

 

 

 

- 수신된 데이터 반환

#define SPI_GetData()                     SPDAT

SPI 통신으로 수신된 데이터를 반환한다.

 

è (EN)MG82F6D16_Datasheet_V051.PDF18. Serial Peripheral Interface(SPI)를 참조한다.

è (EN)MG82F6D17_Datasheet_V051.PDF19. Serial Peripheral Interface(SPI)를 참조한다.

è (EN)MG82F6D64/32_Datasheet_V051.PDF19. Serial Peripheral Interface(SPI)를 참조한다.

 

 

4. 프로그램 실행

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

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

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

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

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

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

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

 

5. 동작 영상

 

https://youtu.be/eSYj5uG6-RY

 

 

 

반응형

'MEGAWIN' 카테고리의 다른 글

MG82F6D Series TIM_T2_Mode4_PWM  (0) 2022.12.28
MG82F6D Series TIM_T2_Mode0_AutoRL_AndEXI  (0) 2022.12.27
MG82F6D SPI Flash-2  (0) 2022.12.22
MG82F6D SPI Flash-1  (0) 2022.12.22
MG82F6D Series PCA COPM Buf  (0) 2022.12.21