CategoriesNotice

저작권 및 라이선스 공지

Notice of License and Copyright

저작권 및 라이선스에 관한 공지

안녕하세요. 로버다인입니다.

로버다인은 펌웨어 개발, 기술 정보, 최신 트렌드에 관한 포스팅 등 다양한 정보를 개발자에게 제공하고자 노력하고 있습니다. 로버다인에서 제공하는 컨텐츠의 모든 저작권은 로버다인의 소유입니다.

로버다인에서 제공하는 컨텐츠는 Creative Commons CC-BY-NC-ND 2.0 KR 라이선스 정책을 채택하고 있습니다.

정책 원문은 다음 사항을 참조하시기 바랍니다.

 

저작자표시-비영리-변경금지 2.0

‘로버다인(Roverdyn)’ 및 ‘Roverdyn Inc.’는 법률사무소 또는 법률회사가 아닙니다. 본 이용허락규약을 배포한다고 해서 법률 서비스가 제공되는 관계가 발생하는 것은 아닙니다. ‘로버다인’ 및 ‘Roverdyn Inc.’는 본 이용허락규약상의 정보를 있는 그대로 제공하는 것이지, 이러한 정보에 관하여 보증을 하거나 이를 이용함으로써 야기되는 손해에 대하여 책임을 부담하지는 않습니다.
이용허락

저작물(본 이용허락에서 정의됨)은 본 ‘Roverdyn Inc.의 일반이용허락(Roverdyn Inc. Public License, 이하 “이용허락”)’의 조건에 따라 제공됩니다. 저작물은 저작권법 및/또는 기타의 법에 의하여 보호됩니다. 본 이용허락 또는 저작권법에 따라 허용된 것 이외의 저작물의 이용은 금지됩니다.

귀하(본 이용허락에서 정의됨)는, 본 이용허락에 따라 저작물을 이용하기 위한 권리를 행사함으로써, 본 이용허락의 조건을 수용하고 이에 동의한 것으로 됩니다. 이용허락자는, 귀하가 본 이용허락의 조건을 수용하는 것을 조건으로 하여, 본 이용허락에 따라 저작물을 이용하기 위한 권리를 부여합니다.

1. 정의

“2차적 저작물” 은 원저작물을 번역·편곡·변형·각색·영상제작 그 밖의 방법으로 작성한 창작물을 의미합니다. 그러나 편집저작물 및 데이터베이스를 구성하는 저작물은 본 이용허락을 적용함에 있어서 2차적 저작물이 되지 않습니다.
“이용허락자” 는 본 이용허락의 조건에 따라 저작물을 제공하는 개인 또는 단체를 의미합니다.
“원저작자” 는 저작물을 창작한 개인 또는 단체를 의미합니다.
“저작물” 은 본 이용허락의 조건에 따라 제공되는 것으로서 저작권에 의하여 보호되는 저작물을 의미합니다.
“저작인접물” 은 저작인접권의 대상인 실연·음반·방송을 의미하며, 본 이용허락이 달리 정하지 않는 한, 저작물에 포함되는 것으로 봅니다.
귀하는 저작물에 관한 본 이용허락의 조건을 이전에 위반하지 않은 자로서 본 이용허락에 따라 권리를 행사하는 개인이나 단체, 또는 이전에 위반을 하였으나 이용허락자로부터 본 이용허락에 따라 권리를 행사하는 것을 명시적으로 허락받은 개인이나 단체를 의미합니다.
본 이용허락은 이용허락자가 선정하고 본 이용허락의 표지에 표시되어 있는 저작자의 표시(Attribution), 비영리(NonCommercial) 및 변경금지(NonDerivation)의 세 요소로 구성되며, 귀하는 이러한 요소들에 바탕을 둔 본 이용허락의 조건에 따라 저작물을 이용할 수 있습니다.

2. 저작권의 제한

본 이용허락의 어떠한 조항도 최초판매의 원칙을 비롯한, 저작권법 또는 기타 법률에 의하여 인정되는 저작권자의 배타적인 권리의 제한에 따르는 귀하의 이익을 축소 또는 제한하거나 금지하지 않습니다.

3. 이용허락

본 이용허락의 조건에 따라 이용허락자는, 다음과 같이 (저작권의 존속기간동안) 귀하가 저작물을 이용하도록, 저작물의 전세계적, 무상, 비배타적, 영구적인 이용을 허락합니다.

저작물의 복제, 편집저작물을 작성하거나 데이터베이스를 제작하기 위한 저작물의 이용, 편집저작물이나 데이터베이스에 포함되어 있는 저작물의 복제
저작물(편집저작물 또는 데이터베이스에 포함된 저작물을 포함) 및 그 복제물의 배포, 전송, 전시, 공연 및 방송
본 이용허락에 따라 저작물을 이용할 수 있는 권리는 현재 알려져 있거나 장래 개발되는 모든 매체 및 형식으로 행하여질 수 있습니다. 이러한 권리에는 저작물을 각기 다른 매체 및 형식으로 이용하기 위하여 기술적으로 수정하는 것도 포함됩니다. 본 이용허락에 의하여 이용허락자가 명시적으로 허락하지 않는 저작물의 이용에 관한 권리는 이용허락자에게 유보됩니다.

4. 이용허락의 제한

제3조에 의하여 허여된 이용허락은 다음의 사항에 의하여 명시적으로 제한을 받습니다.

귀하는 본 이용허락의 조건에 따라서만 저작물을 배포, 전송, 전시, 공연 및 방송할 수 있으며, 귀하가 배포, 전송, 전시, 공연 및 방송하는 모든 저작물의 복제물이나 음반에 본 이용허락서의 복제물이나 이에 대한 통일자원식별부호(Uniform Resource Identifier)를 포함시켜야 합니다. 귀하는 본 이용허락의 조건을 변경·제한하거나 배포 등의 상대방에 의한 본 이용허락상의 권리행사를 변경·제한하는 조건을 제공하거나 부과할 수 없습니다. 귀하는 귀하가 이용허락받은 저작물을 다시 이용허락할 수 없습니다. 귀하는 본 이용허락 및 보증의 부인에 대한 모든 표시를 제거 또는 변경시켜서는 안 됩니다. 귀하는 본 이용허락의 조건을 위반하는 방식으로 저작물에 대한 접근이나 저작물의 이용을 통제하는 기술적 보호조치를 이용하여 저작물을 배포, 전송, 전시, 공연 및 방송하여서는 안 됩니다. 이러한 제한은 편집저작물 또는 데이터베이스에 포함되어 있는 저작물에도 적용되지만, 저작물을 포함하고 있는 편집저작물 또는 데이터베이스가 그 저작물과는 별개로 본 이용허락의 조건에 제한받는 것은 아닙니다. 만약 귀하가 편집저작물을 작성하거나 데이터베이스를 제작하였다면, 이용허락자의 통지가 있는 경우, 귀하는, 실행가능한 한도에서, 이용허락자가 통지에 의하여 요청한 바에 따라서 편집저작물 또는 데이터베이스에서 이용허락자나 원저작자를 나타내는 사항을 삭제하여야 합니다.
귀하는 상업적인 이익 또는 금전적 보상을 받는 것을 주된 목적으로 하거나 이를 얻기 위한 방식으로 제3조에 의하여 귀하에게 부여된 권리를 행사할 수 없습니다. 디지털 파일공유나 기타 방법에 의하여 저작물을 다른 저작물과 교환하는 것은, 저작물을 교환하는 것과 관련하여 금전보상이 이루어지지 않는다면, 상업적인 이익 또는 금전적 보상을 받는 것을 주로 의도하였거나 이를 얻기 위한 것으로 보지 않습니다.
귀하가 저작물을 배포, 전송, 전시, 공연 및 방송하는 경우, 귀하는 저작물에 대한 모든 저작권표시를 제거 또는 변경시켜서는 안 되며, 원저작자의 성명(이명이 있는 경우에는 이명), 저작물의 제호, 합리적으로 가능한 한도에서 이용허락자가 저작물과 연관되는 것을 명기한 통일자원식별부호(통일자원식별부호가 저작물에 대한 저작권표시나 이용허락에 관한 정보와 관련되지 않는 경우에는 제외) 등을 표시함으로써, 귀하가 이용하는 매체와 수단에 적합하게 원저작자 및 원저작물에 관한 사항을 표시하여야 합니다. 이러한 표시는 합리적인 모든 방법에 의하여 가능하지만, 편집저작물, 데이터베이스의 경우에는, 최소한 다른 저작자가 표시되는 곳에 표시되고 적어도 다른 저작자가 표시되는 만큼 눈에 띄는 방법으로 표시되어야 합니다.

5. 보증의 부인 및 책임의 제한

당사자간에 서면에 의하여 달리 합의되지 않는 한, 이용허락자는 저작물을 있는 그대로 제공하며 일체의 보증이나 담보책임을 부담하지 않습니다.

법이 달리 정하는 경우를 제외하고, 이용허락자는, 본 이용허락이나 저작물의 이용으로부터 야기되는 손해에 대하여 책임을 부담하지 않습니다.

6. 이용허락의 종료

본 이용허락 및 이에 의하여 부여되는 권리는 귀하가 본 이용허락의 조건을 위반하는 경우에 자동적으로 종료됩니다. 그러나 본 이용허락에 의하여 귀하로부터 편집저작물, 데이터베이스를 수령한 개인이나 단체에 대해서는, 본 이용허락을 완전히 준수하는 한, 이용허락이 종료되지 않습니다. 제1조, 제2조, 제5조 내지 제8조는 본 이용허락이 종료한 후에도 유효합니다.
이용허락의 종료에 관한 이러한 제한이 적용되는 것을 제외하고는, 본 이용허락에 의하여 허여되는 허락은 저작물의 존속기간동안 유효합니다. 그러나 이용허락자는 언제든지 본 이용허락과 다른 조건으로 저작물에 대하여 이용허락하거나 저작물의 배포를 중단시킬 수 있는 권리를 가집니다. 단 이용허락자가 이와 같은 권리를 행사하여도 본 이용허락(또는 본 이용허락의 조건에 따라 허여되었거나 허여될 것이 요구되는 기타의 이용허락)이 철회되는 것은 아니며, 본 이용허락은, 본 이용허락의 종료규정에 의하여 종료되지 않는 한, 계속하여 완전히 유효합니다.

7. 기타

귀하가 저작물, 편집저작물, 데이터베이스를 배포 또는 전송하는 경우에는 언제든지, 이용허락자는, 배포 또는 전송받는 자에게, 본 이용허락에 의하여 귀하에게 허여된 이용허락과 동일한 조건에 따라, 저작물에 대한 이용허락을 허여합니다.
본 이용허락의 어떠한 규정이 관련법에 의하여 무효이거나 집행할 수 없게 되는 경우, 이에 의하여 본 이용허락에서 무효나 집행할 수 없게 된 조건 외의 다른 조건의 유효성이나 집행가능성이 영향을 받지 않으며, 무효 및 집행할 수 없게 된 규정은, 이용허락 당사자에 의한 별도의 조치 없이, 유효 및 집행 가능한 것으로 하기 위하여 필요한 최소한의 한도에서 개정된 것으로 해석됩니다.
당사자의 서면에 의한 의사표시가 없는 한, 본 이용허락의 조건 또는 규정의 적용을 포기하거나, 위반행위에 대한 권리 주장을 하지 않기로 동의하였다고 간주되지 않습니다.
본 이용허락은 이에 의하여 이용허락된 저작물에 관하여 당사자간에 이루어진 모든 합의를 나타냅니다. 본 이용허락에 명시되지 않은 저작물에 관해서는 아무런 양해나 합의나 설명이 이루어진 것이 아닙니다. 이용허락자는 귀하가 어떠한 추가조항의 적용을 통지하여도 이에 구속받지 않습니다. 본 이용허락은 이용허락자와 귀하 상호간에 서면에 의한 합의에 의하지 않고서는 수정될 수 없습니다.
본 이용허락은 한국어에 의하여 제공되며, 본 이용허락의 영문판은 한국어판을 해석하는 자료가 되는 것에 불과하며 한국어판과 영문판이 일치하지 않는 경우에는 한국어판이 우선합니다.

8. 준거법

본 이용허락은 한국법에 의하여 규율되며 이에 근거하여 해석됩니다.

‘로버다인(Roverdyn)’ 및 ‘Roverdyn Inc.(Roverdyn Korea)’는 본 이용허락의 당사자가 아니며 저작물에 대하여 어떠한 보증도 하지 않습니다. ‘로버다인’ 및 ‘Roverdyn Inc.’는 이용허락과 관련하여 발생하는 어떠한 손해에 대해서도 귀하나 기타의 모든 당사자들에게 책임을 부담하지 않습니다. 그러나 ‘로버다인’ 및 ‘Roverdyn Inc.’가 스스로를 이용허락자라고 명시한 경우에는 이용허락자로서의 권리 및 의무를 가집니다.

저작물이 일반이용허락(CCPL)에 따라 이용허락 되었다는 것을 일반 공중에게 표시하기 위한 목적을 제외하고는, 어느 당사자도, ‘로버다인’ 및 ‘Roverdyn Inc.’의 서면에 의한 사전 허락이 없이는, ‘로버다인’ 및 ‘Roverdyn Inc.’라는 상표나 이와 관련되는 상표, 로고를 이용할 수 없습니다. 허락을 받아 이러한 상표 등을 이용하는 경우, 웹사이트에서 공표되거나 기타 요청에 따라서 제공되는 ‘로버다인’ 및 ‘Roverdyn Inc.’의 상표이용지침을 준수하여야 합니다.

‘로버다인’ 및 ‘Roverdyn Inc.’는 https://www.roverdyn.com 및 http://www.roverdyn.com 에서 접속할 수 있습니다.

CategoriesnRF52 Lecture

Lecture 6. RTC 인터럽트로 초시계 만들기​

Lecture 6. RTC 인터럽트로 초시계 만들기

강의목표

  • Real Time Clock(RTC) 기능을 이용하여 1초 단위로 시간을 계산한다.
  • RTC와 인터럽트를 이용하여 LED를 제어한다.
  • 내장된 버튼을 이용하여 초시계 기능을 시작하거나 중단할 수 있다.

준비물

  • Roverdyn nRF52 개발 보드 × 1 (구매하기)
  • 전원 공급용 Type-C USB 케이블 × 1
  • Windows 데스크톱 혹은 랩톱 × 1
  • VS Code 개발 환경
  • J-Link 디버거

RTC의 정의 및 기본 동작

(위 사진 : 하드웨어 RTC 회로)

RTC는 Real Time Clock의 약자로 말 그대로 실시간(Real Time) 시계(Clock)을 뜻합니다. 따라서 시간을 측정하거나 정해진 시간 간격으로 숫자를 세는(Counting) 등의 동작을 수행할 수 있습니다. 이는 기존의 Timer와 유사한 동작 방식을 가지고 있습니다. 하지만 RTC는 Timer와 하드웨어 구조부터 다르며 개발자는 작성중인 애플리케이션을 좀 더 최적화 하기 위해 RTC와 타이머를 적절히 선택하여 사용할 필요가 있습니다. 타이머와 RTC는 다음과 같은 차이가 있습니다.

  • RTC는 Low Frequency Clock을 사용합니다(32.769kHz)
  • RTC는 동일한 기능을 수행할 때 좀 더 낮은 전력 소모율을 보입니다.(약 1μA)
  • RTC는 낮은 해상도(Resolution)을 가집니다.(Counter Resolutiuon : 최소 30.517μs)
  •  최대 카운팅 가능한 수 : 24 bits (167,777,216)

즉, RTC는 Timer 기능을 대체하여 사용될 수 있지만 동작 방식에 다소 차이가 있으며 좀 더 낮은 해상도를 제공하는 대신 낮은 전력 소모율을 보여주는 것을 알 수 있습니다. RTC는 Timer와 마찬가지로 인터럽트 기능을 제공하고 있습니다. 다만, 전력 소모율을 낮추기 위해 이벤트를 활성화 혹은 비활성화 할 수 있는 레지스터가 추가되어 있습니다.

 RTC는 다양한 용도로 사용됩니다. 특히 mBed나 freeRTOS 등과 같이 임베디드 RTOS는 시스템 작업 스케쥴링을 위해 TICK 이벤트를 사용합니다. 또한 정확하지는 않지만 개략적인 시간이 얼마나 흘렀는지 알려줄 수 있어 보조 타이머로도 많이 사용됩니다.

RTC로 1초 카운트 하기

RTC는 여러 목적으로 사용할 수 있지만, 그 중에서 저전력 시계로도 활용할 수 있습니다. RTC는 24비트 카운터를 지원하므로 최대 0xFFFFFFFF까지 카운트 할 수 있습니다. 따라서 Over Flow가 일어나는 것을 염두하고 펌웨어를 설계하여야 합니다.

 RTC의 카운터는 Prescaler 값에 따라 1초의 단위가 달라집니다. 만약 RTC의 Prescaler를 32로 설정하였다면 다음과 같은 공식으로 1초를 세는데 필요한 카운터 값을 알 수 있습니다.

32760 / (PRESCALER + 1) = 32760/ (32+1) = 992.96

따라서 RTC의 COUNTER 레지스터 값이 993인 경우 1초를 카운트 한다고 할 수 있습니다. 전체 소스코드는 아래와 같습니다.

				
					#include <zephyr/kernel.h>

// RTC0 Interrupt Handler
void RTC2_IRQHandler();


// Global Variables
uint32_t counter = 0;
int main(void)
{
        // Initialize RTC
        NRF_RTC2->TASKS_CLEAR = 0x01;
        NRF_RTC2->INTENSET = RTC_INTENSET_COMPARE0_Enabled << RTC_INTENSET_COMPARE0_Pos;
        NRF_RTC2->EVTENSET = RTC_EVTENSET_COMPARE0_Enabled << RTC_EVTENSET_COMPARE0_Pos;
        NRF_RTC2->PRESCALER = 32;       // 32768/(32+1) = 992.96counts = 1sec
        NRF_RTC2->TASKS_START = 1;

        // Set RTC Compare Register
        counter = NRF_RTC2->COUNTER + 993;
        NRF_RTC2->CC[0] = counter;   // Call RTC1 Compare0 Handler after 1sec

        // Activate IRQ
        IRQ_DIRECT_CONNECT(RTC2_IRQn, 0, RTC2_IRQHandler, 0);
        irq_enable(RTC2_IRQn);
        
        while(true){
                // Main Loop
                //__WFI();
                k_usleep(1);
        }
        return 0;
}

void RTC2_IRQHandler(){
        // Function for RTC0 Interrupt/Events
        if(NRF_RTC2->EVENTS_COMPARE[0] == 1){
                NRF_RTC2->EVENTS_COMPARE[0] = 0;
                
                // Print message
                printk("Elapsed Time : %ds(%08d)\n", counter / 993, counter);        // 992.9 == 1sec

                // Set next compare register for repeat
                counter = NRF_RTC2->COUNTER + 993;
                NRF_RTC2->CC[0] = counter;
        }
}
				
			

RTC를 이용하여 초시계 만들기

				
					/*
        Roverdyn Inc. Timer Interrupt Example.
        2024. 7. 15.

        MIT License

        Copyright (c) 2024. Seonguk Jeong, Roverdyn Inc.

        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
*/

#include <zephyr/kernel.h>

#define GPIO_LED_RED    22
#define GPIO_LED_GREEN  23
#define GPIO_LED_BLUE   24

// Interrupt Handler
void TIMER2_IRQHandler();
int main(void)
{
        // GPIO Configuration
        NRF_GPIO->DIRSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);
        NRF_GPIO->OUTSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);

        /*
                Timer Interrupt Setting
                Timer Bitmode : 32bit => Max. 2^32 counts
                Mode : Timer Mode
                Interrupt Event Channel : EVENT_COMPARE[0]
                Prescaler = 2^9 = 512
                1sec counts : 16000000/512 = 31250 = 1sec
                Comapre Counter(CC) : 15625 -> 31250 / 15625 = 0.5 period 
        */
        NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
        NRF_TIMER2->PRESCALER = 9 << TIMER_PRESCALER_PRESCALER_Pos;
        NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
        NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
        NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
        NRF_TIMER2->CC[0] = 15625;      // Interrupt Period : 0.5sec(31250/2 = 0.5)
        NRF_TIMER2->TASKS_START = 1;
        
        // Enable IRQn
        IRQ_DIRECT_CONNECT(TIMER2_IRQn, 0, TIMER2_IRQHandler, 0);
        irq_enable(TIMER2_IRQn);
        
        while(true){
                k_usleep(1);        // Wait For Interrupt
        }
        return 0;
}

void TIMER2_IRQHandler(){
        // TIMER2 Interrupt Handler
        static bool isLedOn = false;
        if(NRF_TIMER2->EVENTS_COMPARE[0] == 1){
                NRF_TIMER2->EVENTS_COMPARE[0] = 0;
                if(!isLedOn){
                        isLedOn = true;
                        printk("LED On : Green\n");
                        NRF_GPIO->OUTCLR = (1 << GPIO_LED_GREEN);
                }else{
                        isLedOn = false;
                        printk("LED Off : Green\n");
                        NRF_GPIO->OUTSET = (1 << GPIO_LED_GREEN);
                }
        }
}
				
			

빌드 및 컴파일, 다운로드

작성한 소스 코드는 빌드 및 컴파일을 한 후 최종적으로는 디버거 혹은 프로그래머 장비를 이용하여 개발 보드에 다운로드할 수 있습니다. 개발 보드에 관한 설정은 “nRF52  개발환경 구축하기” 튜토리얼을 확인하여 설정할 수 있습니다.

 작성한 코드를 빌드하기 위해서는 우선 다운로드 하고자 하는 보드를 설정해주어야 합니다. 대상 보드를 정의하기 위하여 좌측 패널의 메뉴 중 “Run and Debug” 메뉴를 클릭한 후 “NRF CONNECT:WELCOME” 패널 내부의 “Create a new board” 메뉴를 클릭합니다.

화면 상단에 패널이 나타나면 새로운 보드의 이름을 작성한 후 엔터키를 눌러줍니다. 보드의 이름은 영문으로 작성하여야 합니다.

다음으로 보드의 이름을 한번 더 작성합니다. 다만 이 이름은 기계가 인식할 수 있는 방법으로 작성합니다. 대게 자동으로 작성되어 있으므로 엔터키를 눌러 다음으로 넘어갑니다.

보드가 사용하는 MCU의 종류를 입력합니다. nRF52 개발 보드는 nRF52810-QFAA 혹은 nRF52832-QFAA 두 종류를 사용합니다.

새로 작성한 보드의 정보가 저장될 위치를 설정합니다. 기본적으로 프로젝트 내부의 “board” 폴더가 지정되어 있습니다.

마지막으로 보드의 제조사를 설정합니다. 해당 내용은 작성하지 않아도 동작에 지장이 없습니다.

위와 같이 새 보드의 정의 및 파일 생성이 완료되었다면 빌드 환경을 구성할 수 있습니다. 빌드 환경은 위의 보드 추가 방법과 같이 동일한 “Run & Debug” 패널의 “NRF CONNECT: APPLICATION” 항목에서 설정할 수 있습니다.

 APPLICATION 패널 중 우측에 위치한 “Add Build Configuration” 아이콘을 눌러 설정창을 열어줍니다.

빌드 환경 설정 창이 나타나면 위 그림과 같이 “Custom board” 항목을 눌러준 다음 이전에 생성한 보드를 선택합니다. 위 예제에서는 “nrf52_devboard_52832” 항목을 선택하였습니다. 이는 사용자가 만든 보드 이름에 따라 달라질 수 있습니다. 또한 Configuration 항목을 prj.conf 로 선택합니다. 이후 우측 하단의 “Build configuration” 버튼을 눌러 빌드 환경을 구성합니다.

이상 없이 빌드가 완료되었다면 다시 APPLICATION  패널로 이동하여 “Flash All Linked Devices” 항목을 눌러 컴파일된 펌웨어의 다운로드를 시작합니다. 이 때, 타겟 보드는 컴퓨터와 Jlink 혹은 기타 디버거, 프로그래머와 연결이 되어 있어야 합니다.

위와 같이 빌드를 시작하며 컴파일이 완료된 후 자동으로 컴파일된 펌웨어를 개발 보드로 전송합니다. 전송이 완료되면 개발 보드를 재부팅 하거나 전원을 분리하였다가 다시 꽂으면 새로운 펌웨어로 동작합니다.

동작 시켜보기

이 예제는 별다른 소프트웨어 없이 동작할 수 있습니다. 컴파일 및 다운로드 후 전원을 제거했다가 다시 연결하거나 개발 보드의 리셋 버튼을 이용하여 동작시킬 수 있습니다. 동작 시 SEGGER RTT Viewer를 이용하여 디버깅 메시지를 출력할 수 있으며, 0.5초 주기로 LED On 및 Off 문구가 출력됩니다. 또한, 보드 상에서는 초록색 LED가 0.5초를 주기로 켜짐과 꺼짐을 반복함을 확인할 수 있습니다.

CategoriesnRF52 Lecture

Lecture 5. Timer Interrupt 사용하기

Lecture 5. Timer Interrupt 사용하기

강의목표

  • nRF52 개발 보드에 내장된 RGB LED를 타이머 인터럽트를 이용하여 제어할 수 있다.
  • nRF52832 개발 보드를 사용하여 타이머 인터럽트의 사용 설정을 할 수 있다.
  • 타이머 레지스터에 관해 다양한 설정 방법을 파악한다.

준비물

  • Roverdyn nRF52 개발 보드 × 1 (구매하기)
  • 전원 공급용 Type-C USB 케이블 × 1
  • Windows 데스크톱 혹은 랩톱 × 1
  • VS Code 개발 환경
  • J-Link 디버거

타이머-카운터 인터럽트의 정의 및 동작

타이머-카운터 인터럽트(Timer-Counter Interrupt)는 MCU의 내외부 클럭을 활용하여 정확한 시간 단위로 어떠한 동작을 수행하거나 횟수를 셀 수 있는(=Count) 기능을 말합니다. 또한 인터럽트(Interrupt)는 사전적 의미 그대로 어떠한 작업을 잠시 중단 시키고(=Interrupt) 정해진 작업을 수행하는 기능을 말합니다. 타이머-카운터 인터럽트는 타이머 혹은 카운터 기능과 인터럽트가 결합한 MCU의 기능을 말합니다. nRF 시리즈에서 제공하는 타이머와 카운트는 다음과 같은 동작을 수행할 수 있습니다.

  • 타이머 : 정해진 시간 간격으로 특정 기능을 동작시킴
  • 카운터 : 정해진 시간 간격으로 숫자를 하나씩 더하거나 뺌

위의 두 특성을 이용하여 개발자는 정확한 시간 간격으로 다양한 동작을 정의하여 실행시킬 수 있으며 여기에 더해 기존 작업을 잠시 중지하고 타이머/카운터 인터럽트가 정의한 작업을 수행하는 인터럽트 기능을 추가하여 개발자의 의도대로 작업을 스케쥴링할 수 있습니다. nRF52시리즈는 총 3개 ~ 5개의 타이머/카운터 인스턴스를 지원합니다. 이 중 nRF52832 시리즈는 총 5개의 타이머 레지스터를 지원합니다. 각각의 타이머는 Compare Channel(CC) 이라고 하는 비교 기준 값을 설정하는 레지스터를 가지고 있으며, CC 레지스터는 타이머의 인스턴스에 따라 지원되는 갯수가 다르며 nRF52832 MCU의 경우에는 다음 사항을 참조하기 바랍니다.

  • NRF_TIMER0 : 총 4개의 CC
  • NRF_TIMER1 : 총 4개의 CC
  • NRF_TIMER2 :  총 6개의 CC
  • NRF_TIMER3 :  총 6개의 CC
  • NRF_TIMER4 :  총 6개의 CC

각 타이머가 지원하는 CC의 갯수는 MCU의 종류와 타입에 따라 달라질 수 있으므로 데이터 시트를 반드시 참조하여야 합니다.

타이머 인터럽트 설정하여 사용하기

타이머/카운터 인터럽트중 타이머 인터럽트는 일정한 주기로 작업을 실행시키는 용도로 자주 사용되는 기능입니다. 예를들면 특정 주기로 데이터를 보내거나, LED를 동작시키거나 혹은 외부 신호를 확인하는 등의 동작을 수행 할 수 있으며 스탑 워치등의 기능으로 활용할 수 있습니다. nRF52시리즈 MCU는 타이머/카운터 기능을 내부 레지스터로 설정하여 사용할 수 있으며 총 세 개의 모드(Counter, LowPowerCounter, Timer)를 지원합니다. 우리는 이 중 Timer 모드를 활용하여 LED를 정해진 주기로 제어하려고 합니다. 이를 위해서 먼저 TIMER 레지스터를 사용하여 몇 가지 설정을 해주어야 합니다.

  • BITMODE : 타이머/카운터가 셀 수 있는 총 갯수를 설정합니다. 8/16/24/32Bit를 설정할 수 있습니다.
  • PRESCALER : 시스템 클럭(=16MHz)을 나눌 수 있는 설정값입니다. Prescaler는 0~9까지 설정할 수 있으며 각각 2^0 ~ 2^9(512)를 의미합니다.
  • PRESCALER는 1초가 몇 개의 카운트인지 결정합니다. 예를 들어 PRESCALER를 9로 설정할 경우 다음 공식으로 1초에 해당하는 카운터 값을 계산할 수 있습니다 : 16000000/2^9 = 16MHz/512 = 31250 = 1초
  • MODE : 타이머/카운터 동작 모드를 설정할 수 있습니다. Timer, Counter, LowPowerCounter를 지원합니다.
  • INTENSET : 인터럽트를 설정하는 레지스터입니다.
  • SHORTS : 특정 동작 후 별다른 명령 없이 정해진 동작을 수행하도록 설정할 수 있습니다.
  • CC : Compare Channel의 약자로서 기준이 되는 카운터/타이머 값을 설정할 수 있으며 EVENTS_COMPARE 레지스터는 이 값을 기준으로 호출됩니다.

위의 설명대로 작성한 위 이미지의 설정 값은 다음과 같습니다.

  • Bitmode : 32Bit
  • Prescaler : 512
  • 1초 카운터 : 16000000/512 = 31250
  • 인터럽트 채널 : EVENTS_COMPARE[0]
  • 인터럽트 호출 주기 : 31250 / 15625 = 0.5초
  • SHOTS : EVENTS_COMPARE[0] 호출 후 TIMER/COUNTER 값이 0으로 자동으로 초기화
  • 인터럽트 호출 시 TIMER2_IRQHandler 함수를 호출함

소스 코드

				
					/*
        Roverdyn Inc. Timer Interrupt Example.
        2024. 7. 15.

        MIT License

        Copyright (c) 2024. Seonguk Jeong, Roverdyn Inc.

        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
*/

#include <zephyr/kernel.h>

#define GPIO_LED_RED    22
#define GPIO_LED_GREEN  23
#define GPIO_LED_BLUE   24

// Interrupt Handler
void TIMER2_IRQHandler();
int main(void)
{
        // GPIO Configuration
        NRF_GPIO->DIRSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);
        NRF_GPIO->OUTSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);

        /*
                Timer Interrupt Setting
                Timer Bitmode : 32bit => Max. 2^32 counts
                Mode : Timer Mode
                Interrupt Event Channel : EVENT_COMPARE[0]
                Prescaler = 2^9 = 512
                1sec counts : 16000000/512 = 31250 = 1sec
                Comapre Counter(CC) : 15625 -> 31250 / 15625 = 0.5 period 
        */
        NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;
        NRF_TIMER2->PRESCALER = 9 << TIMER_PRESCALER_PRESCALER_Pos;
        NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
        NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
        NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
        NRF_TIMER2->CC[0] = 15625;      // Interrupt Period : 0.5sec(31250/2 = 0.5)
        NRF_TIMER2->TASKS_START = 1;
        
        // Enable IRQn
        IRQ_DIRECT_CONNECT(TIMER2_IRQn, 0, TIMER2_IRQHandler, 0);
        irq_enable(TIMER2_IRQn);
        
        while(true){
                k_usleep(1);        // Wait For Interrupt
        }
        return 0;
}

void TIMER2_IRQHandler(){
        // TIMER2 Interrupt Handler
        static bool isLedOn = false;
        if(NRF_TIMER2->EVENTS_COMPARE[0] == 1){
                NRF_TIMER2->EVENTS_COMPARE[0] = 0;
                if(!isLedOn){
                        isLedOn = true;
                        printk("LED On : Green\n");
                        NRF_GPIO->OUTCLR = (1 << GPIO_LED_GREEN);
                }else{
                        isLedOn = false;
                        printk("LED Off : Green\n");
                        NRF_GPIO->OUTSET = (1 << GPIO_LED_GREEN);
                }
        }
}
				
			

빌드 및 컴파일, 다운로드

작성한 소스 코드는 빌드 및 컴파일을 한 후 최종적으로는 디버거 혹은 프로그래머 장비를 이용하여 개발 보드에 다운로드할 수 있습니다. 개발 보드에 관한 설정은 “nRF52  개발환경 구축하기” 튜토리얼을 확인하여 설정할 수 있습니다.

 작성한 코드를 빌드하기 위해서는 우선 다운로드 하고자 하는 보드를 설정해주어야 합니다. 대상 보드를 정의하기 위하여 좌측 패널의 메뉴 중 “Run and Debug” 메뉴를 클릭한 후 “NRF CONNECT:WELCOME” 패널 내부의 “Create a new board” 메뉴를 클릭합니다.

화면 상단에 패널이 나타나면 새로운 보드의 이름을 작성한 후 엔터키를 눌러줍니다. 보드의 이름은 영문으로 작성하여야 합니다.

다음으로 보드의 이름을 한번 더 작성합니다. 다만 이 이름은 기계가 인식할 수 있는 방법으로 작성합니다. 대게 자동으로 작성되어 있으므로 엔터키를 눌러 다음으로 넘어갑니다.

보드가 사용하는 MCU의 종류를 입력합니다. nRF52 개발 보드는 nRF52810-QFAA 혹은 nRF52832-QFAA 두 종류를 사용합니다.

새로 작성한 보드의 정보가 저장될 위치를 설정합니다. 기본적으로 프로젝트 내부의 “board” 폴더가 지정되어 있습니다.

마지막으로 보드의 제조사를 설정합니다. 해당 내용은 작성하지 않아도 동작에 지장이 없습니다.

위와 같이 새 보드의 정의 및 파일 생성이 완료되었다면 빌드 환경을 구성할 수 있습니다. 빌드 환경은 위의 보드 추가 방법과 같이 동일한 “Run & Debug” 패널의 “NRF CONNECT: APPLICATION” 항목에서 설정할 수 있습니다.

 APPLICATION 패널 중 우측에 위치한 “Add Build Configuration” 아이콘을 눌러 설정창을 열어줍니다.

빌드 환경 설정 창이 나타나면 위 그림과 같이 “Custom board” 항목을 눌러준 다음 이전에 생성한 보드를 선택합니다. 위 예제에서는 “nrf52_devboard_52832” 항목을 선택하였습니다. 이는 사용자가 만든 보드 이름에 따라 달라질 수 있습니다. 또한 Configuration 항목을 prj.conf 로 선택합니다. 이후 우측 하단의 “Build configuration” 버튼을 눌러 빌드 환경을 구성합니다.

이상 없이 빌드가 완료되었다면 다시 APPLICATION  패널로 이동하여 “Flash All Linked Devices” 항목을 눌러 컴파일된 펌웨어의 다운로드를 시작합니다. 이 때, 타겟 보드는 컴퓨터와 Jlink 혹은 기타 디버거, 프로그래머와 연결이 되어 있어야 합니다.

위와 같이 빌드를 시작하며 컴파일이 완료된 후 자동으로 컴파일된 펌웨어를 개발 보드로 전송합니다. 전송이 완료되면 개발 보드를 재부팅 하거나 전원을 분리하였다가 다시 꽂으면 새로운 펌웨어로 동작합니다.

동작 시켜보기

이 예제는 별다른 소프트웨어 없이 동작할 수 있습니다. 컴파일 및 다운로드 후 전원을 제거했다가 다시 연결하거나 개발 보드의 리셋 버튼을 이용하여 동작시킬 수 있습니다. 동작 시 SEGGER RTT Viewer를 이용하여 디버깅 메시지를 출력할 수 있으며, 0.5초 주기로 LED On 및 Off 문구가 출력됩니다. 또한, 보드 상에서는 초록색 LED가 0.5초를 주기로 켜짐과 꺼짐을 반복함을 확인할 수 있습니다.

CategoriesnRF52 Lecture

Lecture 4. UART로 PC와 통신하기

Lecture 4. UART로 PC와 통신하기

강의목표

  • nRF52 개발 보드에 내장된 UARTE-USB Birdge를 사용하여  PC와 Serial 통신을 할 수 있다.
  •  UARTE 통신으로 PC에서 보드의 RGB LED를 켜고 끌 수 있다.
  • UARTE에 관한 다양한 설정과 핀 설정 등 사용법을 익힌다.

준비물

  • Roverdyn nRF52 개발 보드 × 1 (구매하기)
  • 전원 공급용 Type-C USB 케이블 × 1
  • Windows 데스크톱 혹은 랩톱 × 1
  • VS Code 개발 환경
  • PuTTY

UARTE 통신 및 기본 설정

UARTE 통신은 Universal asynchronous receiver/transmitter with EasyDMA의 약자로 일반적인 UART 통신에 MCU의 동적 메모리에 손쉽게 접근할 수 있는 Nordic 사의 고유 기능인 EasyDMA를 추가하여 손쉽게 UARTE 통신 및 인터럽트 기반 통신을 수행할 수 있도록 구성한 것입니다. 실제 물리적인 동작은 기존의 UART와 동일합니다. 각각 RX, TX 선과 CTS, RTS 선을 이용하여 통신을 수행하며 Parity Bit, Flow Control 등의 기능 또한 활용할 수 있습니다. 

 nRF52 시리즈의 UARTE 기능은 기본적으로 HAL(Hardware Access Layer)를 이용하여 설정하고 사용할 수 있습니다. 위 이미지는 nRF52 시리즈에서 UARTE를 사용하는 간단한 방법에 대한 예시입니다. UARTE를 사용하기 위해서는 기본적으로 RX, TX 핀을 설정하고 각각의 데이터를 저장할 버퍼를 설정하며 통신 속도(Baudrate)를 설정하여 사용할 수 있습니다. 뿐만 아니라 TX와 RX에 관한 다양한 이벤트가 있으며 각 이벤트는 인터럽트와 연동되어 사용할 수 있습니다. UARTE 는 기본적으로 다른 IC 혹은 MCU 등과 연결되어서 사용할 수 있으며, 특히 UART to USB Bridge IC를 이용하면 컴퓨터의 COM 포트를 통하여 직접 컴퓨터와 통신할 수 있습니다.

Roverdyn의 nRF52 개발 보드는 버전에 따라 두 가지 버전의 UART to USB Bridge IC를 지원합니다. Revision 1의 경우 SiliconLabs 사의 CP2104 브릿지 IC를 내장하였으며 Revision 2의 경우 CH340BN 브릿지 IC를 내장하였습니다. 두 IC 모두 nRF52시리즈 MCU가 지원하는 최대 속도인 1Mbps 이상의 통신 속도를 지원하며 두 버전의 개발 보드 모두 동일한 RX, TX 핀을 사용하고 있습니다. 사용하는 핀은 다음과 같습니다.

  • RX핀 : P0.07
  • TX핀 : P0.08

개발 보드의 버전에 따라 브릿지 IC의 종류와 연결되는 핀은 달라질 수 있으니 반드시 데이터시트를 사전에 확인하시기 바랍니다.

UARTE 설정 및 사용하기

UARTE를 사용하기 위해서는 기본적인 설정을 해주어야 합니다. 다음은 필수로 설정하여야 하는 설정입니다.

  • NRF_UARTE0->BAUTEDATE : 통신 속도 설정
  • NRF_UARTE0->RXD.PTR : 수신 데이터 버퍼
  • NRF_UARTE0->TXD.PTR : 송신 데이터 버퍼
  • NRF_UARTE0->PSEL.RXD : 수신 핀 번호
  • NRF_UARTE0->PSEL.TXD : 송신 핀 번호
  • NRF_UARTE0->ENABLE : UARTE 기능 활성화

위 항목 중 Baudrate는 통신 속도를 설정할 수 있습니다. Baudrate의 범위는 9600bps ~ 1MBaud까지 지원합니다. RXD.PTR, TXD.PTR은 송수신 데이터 버퍼를 지정하며, 데이터를 저장할 버퍼의 포인터 주소를 지정하는 방법으로 사용할 수 있습니다. PSEL.RXD와 PSEL.TXD는 각각 Bridge IC와 연결된 RX핀과 TX핀의 번호를 입력하면 됩니다. 마지막으로 ENABLE은 해당 모듈을 활성화 할 것인지 결정하는 것으로서, 활성화 하기 위해서는 0x08 값을 넣어주면 됩니다.

만약 인터럽트 기능을 이용하고자 한다면 다음 항목을 설정하여야 합니다.

  • NRF_UARTE0->INTENSET
  • NRF_UARTE0->SHORTS

INTENSET은 사용하고자 하는 인터럽트 종류를 설정하는데 사용됩니다. 다양한 인터럽트 이벤트가 있으며 이 튜토리얼에서는 ENDTX, ENDRX, RXDRDY 이벤트의 인터럽트를 사용합니다. SHORTS는 말 그대로 지름길을 설정하는 레지스터로서,  ENDRX_STARTRX 혹은 ENDRX_STOPRX를 설정할 수 있습니다. 이 레지스터를 설정하게 되면 ENDRX 이벤트가 생성되면 자동으로 STARTRX 태스크를 수행하거나 STOPRX 태스크를 수행합니다.

또한 인터럽트는 Zephyr RTOS의 인스턴스를 활성화하여야 사용할 수 있으므로 다음 함수를 이용하여 인터럽트를 활성화 할 수 있습니다.

  • IRQ_DIRECT_CONNECT
  • irq_enable

IRQ_DIRECT_CONNECT 함수는 매개변수로 각각 인터럽트 인스턴스, 인터럽트 Priority, 리스너 함수, IRQ 설정 플래그를 입력하면 됩니다. 대개, 인터럽트 우선순위나 IRQ 설정 플래그는 0으로 설정하여 사용할 수 있습니다. irq_enable은 인터럽트 인스턴스를 활성화 시키는 함수이며, 이 튜토리얼에서는 UARTE0_UART0_IRQn 인스턴스를 사용하였습니다.

 

소스 코드

				
					/*
        MIT License

        Copyright (c) 2024. Seonguk Jeong, Roverdyn Inc.

        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
*/

#include <zephyr/kernel.h>

/* Pin definition */
#define GPIO_LED_RED            22
#define GPIO_LED_GREEN          23
#define GPIO_LED_BLUE           24
#define UARTE_PIN_RX            8
#define UARTE_PIN_TX            7

/* UARTE Buffer */
uint8_t rxBuffer[255] = {0}, txBuffer[255] = {0};

/* UARTE Functions */
void write(uint8_t *data, uint8_t length);
void UARTE_Listener();
int main(void)
{
        // GPIO Configuration
        NRF_GPIO->DIRSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);
        NRF_GPIO->OUTSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);

        // UARTE Configuration
        NRF_UARTE0->BAUDRATE = UARTE_BAUDRATE_BAUDRATE_Baud115200;
        NRF_UARTE0->PSEL.RXD = UARTE_PIN_RX;
        NRF_UARTE0->PSEL.TXD = UARTE_PIN_TX;
        NRF_UARTE0->TXD.PTR = (uint32_t)txBuffer;
        NRF_UARTE0->RXD.PTR = (uint32_t)rxBuffer;
        NRF_UARTE0->SHORTS = UARTE_SHORTS_ENDRX_STARTRX_Enabled << UARTE_SHORTS_ENDRX_STARTRX_Pos;
        NRF_UARTE0->INTENSET = UARTE_INTEN_RXDRDY_Enabled << UARTE_INTEN_RXDRDY_Pos;
        NRF_UARTE0->INTENSET = UARTE_INTEN_ENDRX_Enabled << UARTE_INTEN_ENDRX_Pos;
        NRF_UARTE0->INTENSET = UARTE_INTEN_ENDTX_Enabled << NFCT_INTEN_ENDTX_Pos;
        NRF_UARTE0->ENABLE = 0x08;
        NRF_UARTE0->RXD.MAXCNT = 255;
        NRF_UARTE0->TASKS_STARTRX = 1;
        
        // Enable IRQ Handler
        IRQ_DIRECT_CONNECT(UARTE0_UART0_IRQn, 0, UARTE_Listener, 0);
        irq_enable(UARTE0_UART0_IRQn);

        while(true){
                k_usleep(10);
        }
        return 0;
}

void write(uint8_t *data, uint8_t length){
        // Function for UARTE Write
        memcpy(txBuffer, data, length);
        NRF_UARTE0->TXD.MAXCNT = length;
        NRF_UARTE0->TASKS_STARTTX = 1;
}

void UARTE_Listener(){
        // Function for UARTE RXDRDY interrupt
        static uint8_t order = 0;
        if(NRF_UARTE0->EVENTS_ENDTX == 1){
                // Clear Tx Buffer
                NRF_UARTE0->EVENTS_ENDTX = 0;
                memset(txBuffer, 0x00, sizeof(uint8_t));
        }

        if(NRF_UARTE0->EVENTS_RXDRDY == 1){
                // Clear and Stop RxBuffer
                printk("RX data received : %c\r\n", rxBuffer[order]);
                write(&rxBuffer[order], 1);
                if(rxBuffer[order] == 0x0D){
                        NRF_UARTE0->TASKS_STOPRX = 1;
                }else{
                        order++;
                }
                NRF_UARTE0->EVENTS_RXDRDY = 0;
        }

        if(NRF_UARTE0->EVENTS_ENDRX == 1){
                // Clear and Stop RxBuffer
                printk("%d byte received.\r\n", strlen(rxBuffer));
                write(rxBuffer, strlen(rxBuffer));

                // Control LED
                if(strncmp(rxBuffer, "off", 3) == 0){
                        NRF_GPIO->OUTSET = (1 << GPIO_LED_RED) | (1 << GPIO_LED_GREEN) | (1 << GPIO_LED_BLUE);
                }else if(strncmp(rxBuffer, "red", 3) == 0){
                        NRF_GPIO->OUTCLR = 1 << GPIO_LED_RED;
                }else if(strncmp(rxBuffer, "green", 3) == 0){
                        NRF_GPIO->OUTCLR = 1 << GPIO_LED_GREEN;
                }else if(strncmp(rxBuffer, "blue", 3) == 0){
                        NRF_GPIO->OUTCLR = 1 << GPIO_LED_BLUE;
                }

                // Clear parameter
                order = 0;
                memset(rxBuffer, 0x00, sizeof(uint8_t));
                NRF_UARTE0->EVENTS_ENDRX = 0;
        }
}
				
			

빌드 및 컴파일, 다운로드

작성한 소스 코드는 빌드 및 컴파일을 한 후 최종적으로는 디버거 혹은 프로그래머 장비를 이용하여 개발 보드에 다운로드할 수 있습니다. 개발 보드에 관한 설정은 “nRF52  개발환경 구축하기” 튜토리얼을 확인하여 설정할 수 있습니다.

 작성한 코드를 빌드하기 위해서는 우선 다운로드 하고자 하는 보드를 설정해주어야 합니다. 대상 보드를 정의하기 위하여 좌측 패널의 메뉴 중 “Run and Debug” 메뉴를 클릭한 후 “NRF CONNECT:WELCOME” 패널 내부의 “Create a new board” 메뉴를 클릭합니다.

화면 상단에 패널이 나타나면 새로운 보드의 이름을 작성한 후 엔터키를 눌러줍니다. 보드의 이름은 영문으로 작성하여야 합니다.

다음으로 보드의 이름을 한번 더 작성합니다. 다만 이 이름은 기계가 인식할 수 있는 방법으로 작성합니다. 대게 자동으로 작성되어 있으므로 엔터키를 눌러 다음으로 넘어갑니다.

보드가 사용하는 MCU의 종류를 입력합니다. nRF52 개발 보드는 nRF52810-QFAA 혹은 nRF52832-QFAA 두 종류를 사용합니다.

새로 작성한 보드의 정보가 저장될 위치를 설정합니다. 기본적으로 프로젝트 내부의 “board” 폴더가 지정되어 있습니다.

마지막으로 보드의 제조사를 설정합니다. 해당 내용은 작성하지 않아도 동작에 지장이 없습니다.

위와 같이 새 보드의 정의 및 파일 생성이 완료되었다면 빌드 환경을 구성할 수 있습니다. 빌드 환경은 위의 보드 추가 방법과 같이 동일한 “Run & Debug” 패널의 “NRF CONNECT: APPLICATION” 항목에서 설정할 수 있습니다.

 APPLICATION 패널 중 우측에 위치한 “Add Build Configuration” 아이콘을 눌러 설정창을 열어줍니다.

빌드 환경 설정 창이 나타나면 위 그림과 같이 “Custom board” 항목을 눌러준 다음 이전에 생성한 보드를 선택합니다. 위 예제에서는 “nrf52_devboard_52832” 항목을 선택하였습니다. 이는 사용자가 만든 보드 이름에 따라 달라질 수 있습니다. 또한 Configuration 항목을 prj.conf 로 선택합니다. 이후 우측 하단의 “Build configuration” 버튼을 눌러 빌드 환경을 구성합니다.

이상 없이 빌드가 완료되었다면 다시 APPLICATION  패널로 이동하여 “Flash All Linked Devices” 항목을 눌러 컴파일된 펌웨어의 다운로드를 시작합니다. 이 때, 타겟 보드는 컴퓨터와 Jlink 혹은 기타 디버거, 프로그래머와 연결이 되어 있어야 합니다.

위와 같이 빌드를 시작하며 컴파일이 완료된 후 자동으로 컴파일된 펌웨어를 개발 보드로 전송합니다. 전송이 완료되면 개발 보드를 재부팅 하거나 전원을 분리하였다가 다시 꽂으면 새로운 펌웨어로 동작합니다.

동작 시켜보기

이 예제를 실행하기 위해서는 먼저 PuTTY 프로그램을 이용하여 동작 시킬 수 있습니다. PuTTY는 공식 홈페이지에서 다운로드 할 수 있습니다. PuTTY를 실행시킨 후 “Connection type” 항목에서 “Serial”을 선택한 후 상단의 Serial Line에서 COM포트 번호와 Speed를 입력합니다. 연결되어 있는 COM포트 번호는 운영체제의 “장치관리자” 혹은 각 운영체제에 맞는 방법으로 확인할 수 있으며 사용하는 환경에 따라 포트 번호는 달라질 수 있습니다. 위 이미지에서는 COM4 포트에 개발 보드가 연결되어 있으며 통신 속도는 115200으로 설정하였습니다. 설정한 후 “Open” 버튼을 눌러 개발 보드와 연결합니다.

정상적으로 연결되었다면 위와 같이 소문자로 “green” 이라고 입력한 후 엔터 키를 누르면 개발 보드의 초록색 LED가 켜지는 것을 확인 할 수 있습니다. 마찬가지로 “off” 글자를 입력하면 모든 LED가 꺼지는 것을 확인할 수 있습니다. 이 튜토리얼은 백스페이스키를 지원하지 않으므로 백스페이스 키를 이용하여 입력 명령어를 수정할 수 없습니다.

 Red, Green, Blue LED를 각각 켜고 꺼서 3색 이외에도 조합된 색상을 얻을 수 있습니다.