DSP

TMS320C6748 을 활용한 DSP_ SYS/BIOS 설치 (LAB3)

알 수 없는 사용자 2019. 10. 3. 15:06
반응형

<이 내용은 강원대학교 전자공학과 실시간 신호처리 과목에서 진행된 내용을 기반으로 작성되었습니다.>

 

 

 

 Lab2까지가 bare metal에서 펌웨어를 만드는 기본적인 과정이었다. , OS가 없는 상태에서 진행되는 과정이었다. 그렇다면 과연 실제로도 OS없이 시스템을 짤까?

 

예전에는 시스템의 성능이 그리 좋지 않았고, 가격도 비쌌으며 메모리의 크기도 매우 작았다. 이러한 요인들에 의해 임베디드 시스템에서는 실제로 OS를 쓰지 않았었다. 하지만 요즘을 생각해보자. 과거와 달리 임베디드 시스템에게 요구되는 기능도 많아졌고, 성능대비 가격이 많이 내려가 좋은 프로세서를 싼 가격에 사용할 수 있게 되었다. 메모리 기술의 발달은 부족한 메모리 용량의 문제도 탈피시켜 주었다. 이런 상황에서 OS를 외면하는 것은 점점 힘들어진다.

 

여기서 말하는 OS는 윈도우와는 조금 다른 개념이다. 앞서 언급하였듯이 임베디드 시스템에게 요구되는 기능이 많아짐에 따라 임베디스 시스템에서도 Task가 여러 개 돌아갈 수 있게 만들어야 한다. 하지만 이 시스템이 표준화된 제품을 배포해야 하는 케이스는 아니다. 임베디드 시스템이란 말 그대로 특화된 시스템이다. 모두에게 표준화된 윈도우와 같은 개념을 장착시키기엔 그 규모가 너무 작다. 따라서 개발자는 필요한 기능이 있으면 다 만들어 낼 수 있다. 하지만 task가 많으면 많을 수록 개발을 혼자 하기 힘들어진다.

 

여러 개의 task를 작동시킬 때 OS가 없으면 작동시키기 어렵다는 점은 우선순위를 정하는 과정 때문이다. PC에서보다 임베디드 시스템에서 여러 개의 task가 돌아갈 때 애플리케이션의 우선순위는 매우 중요하다. – 요즘 나오는 자동차를 예를 들면 자동차를 네비게이션, 음악, 자율주행, 카메라 등등 여러 기능들을 복합적으로 가지고 있는 IT기기라고 할 수 있다. 이 때 우선순위는 무조건 자율주행이다. 당연하다. 특히 돌발상황이 발생하면 이를 처리할 수 있는 일을 더 빨리 수행하여야 한다. 음악이 잠깐 멈추는 한이 있더라도 CPU의 연산을 자율주행에서 가져가야 하는 것이다. 마찬가지로 임베디드 시스템에서도 많은 task를 돌리되 우선순위를 선정할 수 있는 OS가 필요하다. 이를 real time OS라고 한다.

 

Real time OS를 직역하자면 실시간 OS라 할 수 있다. 실시간에서 가장 중요한 것은 속도이다. 이 속도는 상대적이다. 주어진 시간 안에 어떠한 일을 처리할 수 있어야 한다. 만약 주어진 시간이 길다면 속도가 엄청 빠를 필요는 없을 것이다. 하지만 무조건 주어진 시간 안에는 일을 처리해야 한다. 그리고 실시간 OS는 정해진 task가 반드시 실시간으로 처리되는 것을 보장해주는 OS이다. (물론 이를 위해서 Performance가 받혀줘야 하는 것은 당연하다.) 실시간 OSTask들에게 각각의 우선순위를 부여한다. 그리고 특정 상황에 마주했을 때 우선순위가 높은 task 순서대로 실시간 처리를 해준다.

간단한 상황을 통해 실시간 처리에 대해 이해해 보자.


사진은 오디오와 키패드가 동시에 작동중인 상황을 표현하고 있다. 우리의 시스템은 이 두 가지 동작을 동시에 처리해야 한다. 어떻게 해야 할까?

가장 초보적인 생각은 while문을 활용하여 2개의 task를 계속 작동시키는 것이다.

 

문제에 조건을 하나 추가해 보자. 오디오는 10us마다 계속 수행되어야 하고 키패드는 100ms의 주기로 체크해야 한다고 해보자. 처리해야 하는 두 taskdelay가 달라졌다. 어떻게 작동시키는 것이 가장 효과적일까?

 

이럴 때 사용할 수 있는 방법들 중 하나가 타이머이다. 타이머를 사용하면 각각의 동작을 일정 시간마다 한번씩 실행되게 할 수 있다.

그런데 다음과 같은 상황이 발생했다고 생각해보자. 일반적인 인터럽트에 대해 (ti같은 경우) 하드웨어 인터럽트는 rest가 되지 않는다. , 인터럽트에 들어가면 그 인터럽트가 끝나기 전에는 다른 인터럽트가 동작하지 않는다. 따라서 키패드가 동작하는 1ms 사이에 오디오 1um가 겹치면 오디오 인터럽트는 missed되는 것이다. Cpu의 퍼포먼스는 상대적으로 좋아 전체의 51%밖에 사용하지 못하는데 비해 처리 과정에서 제대로 실행되지 못하는 문제가 발생하게 된다.

 

위 예시를 통해 느꼈듯이 문제는 우선순위이다. Delay가 긴 B를 나눠서 처리하면 해결될 것이다.

 

이와 같이 task에 우선순위를 할당함으로써 task를 시행할 수 있다. 개발자는 여러 개의 task에대해 이런 식으로 짜면 된다! 하지만 일이 아주 많고 우선순위가 복잡해지면 이렇게 일일이 코드화하여 짜기가 점점 힘들어진다. 어떻게 이걸 표준적이고 일관성 있는 방식으로 짤 수 있을까? 이 문제를 해결해 주는 것이 real time OS의 일이다.

우리는 SYS/BIOS라는 OS를 사용할 것이다. OSTI에서 무료로 제공해준다. 보통 대부분의 real time OS는 매우 비싸다. 실시간 OS들은 한번 OS를 장착하면 OS자체를 변경을 잘 하지 않는다. 따라서 안정성이 매우 중요하며 이가 검증된 OS들은 높은 가격을 지닌다.

 

SYS/BIOS는 무료이지만 TI에서 직접 만든 것이 아니라 과거 TIreal time OS기술이 있는 sparks라는 회사를 인수하면서 만든 것이기 때문에 상당히 전문성 있는 OS이다. 대부분의 real time OS가 유사하고 컨셉도 비슷하기 때문에 SYS/BIOS를 알면 VS works와 같은 다른 실시간 OS에 대한 이해도 쉬워질 것이다. 한번 알아보자.

 

RTOs 4개의 분류로 나눌 수 있다. 하드웨어 인터럽트, 소프트웨어 인터럽트, Task, Idle 4개로 나눠진다. 이 때 우선순위는 하드웨어 인터럽트가 가장 높다. , 모든 하드웨어 인터럽트는 모든 소프트웨어 인터럽트보다 우선순위가 높다. 마찬가지로 모든 소프트웨어 인터럽트는 모든 Task보다 우선순위가 높다. 그리고 사실 idle task중에서 가장 우선순위가 낮은 것을 표현하기 위한 명칭에 가깝다.

 

여기서 언급된 task는 프로그램 개시와 동시에 뜨는 그 task이다. , 평상시에 항상 돌아가는 일들이다. 따라서 일종의 백그라운드 작업을 하는 성격을 지니고 있다.

 

소프트웨어 인터럽트와 task는 각각 32개의 우선순위 설정이 가능하다. 만약 우선순위가 같은 일을 처리해야 하면 round running으로 작동한다.

 

Idle은 위에 애들이 다 할 일이 없을 때 돌아간다. 여러 개가 있다면 round moving으로 순서대로 하나씩 시간 남을 때 마다 작동된다. Idle의 보편적인 예를 들자면 cpu 점유율을 알고 싶다면 Idle에 넣으면 된다. 우리가 cpu의 점유율을 알기 위해서 다른 작업에 지장을 주면 안되기 때문에 사용하지 않을 때에만 작동하도록 idle에 넣어주는 것이다.

 

대부분의 사람들이 하드웨어 인터럽트와 소프트웨어 인터럽트의 차이를 잘 모른다. 인터럽트란 이벤트가 발생 했을 때 수행되는 일이다. 병원으로 예시를 들어보자. 환자가 병원에 들어와 접수를 하는 것이 것이 하드웨어 인터럽트이다. 의사가 다른 환자를 진찰 중이라면 환자는 접수 후 환자 대기실로 가 의사를 기다린다. 이 대기실로 가는 것이 소프트웨어 인터럽트 포스팅이다. 만약 접수 단계에서 환자가 응급환자임이 밝혀지면 의사는 그 환자를 먼저 진찰할 것이다. 접수하는 과정에서 환자의 심각성을 판단한 뒤 대기실로 옮기는 것이다. 하드웨어 인터럽트 과정에서 우선순위를 판단하여 소프트웨어 인터럽트 포스팅을 진행하는 것이다.

 

 앞으로 진행할 DSP를 위해서 이제부터는 sys/bios를 기반으로 코드를 작성할 것이다. 이론적인 설명은 여기까지 하고 CSS에서 어떻게 OS를 다뤄야 하는지 차근차근 나아가보자.

가장 먼저 SYS/BIOS를 다운받아야 한다. HELP->APP Center에 들어가면 SYS/BIOS가 보일 것이다. 다운로드를 클릭해주자. 2019-10-03 기준 BIOS 6_76_02_02 버전을 사용하였다

 

이런 창이 뜨면 실행을 눌러 프로그램을 설치하자.

 

다운로드 사이트에서 자세히 보면 XDCtools라는게 있다. xdc tools RTSC라고 하는 것인데, real time OS와는 관계 없으나 임베디드 개발 시 유명한 유틸리티라고 생각하면 된다. 우리가 real time 임베디드 시스템 개발을 하면 디버깅 할 때 불편한 점이 많다. 디버깅 시 가장 많이 사용하는 방식인 체크 코드에 대해 주어진 시간 안에 뭔가를 수행하지 않으면 의미가 없는데 코드 중간중간에 체크를 위한 코드를 심어 놓으면 그것 자체가 real time을 방해한다. 이런 문제들을 해결해주는 것이 바로 RTSC이다. 이 컴포넌트를 통해 편리한 함수를 쓸 수 있다. 대부분 실시간으로 돌아가는 데 아주 유용한 코드들이다.

 

예를 들면 System_printf이다. 보통 개발자들은 디버깅을 진행 할 때 printf함수를 애용한다. 하지만 임베디드 시스템에서는 printf가 코드사이즈가 크고 시행시간이 길기 때문에 실시간 단위에서는 무의미하다. xdc tools에서 제공해주는 System_printf는 코드사이즈가 아아아아주 작고, 실행 속도도 굉장히 빠르게 해놨다. printf가 느린 이유 중에 출력장치를 들 수 있다. 그 장치의 느린 속도에 의해서 짧은 시간 안에 작동하기 힘든 것이다. System_printf는 이 문제를 모니터가 아니라 메모리에 출력을 함으로써 해결했다(따라서 약간의 버퍼를 잡는다.). 프로그램 실행이 끝난 뒤 메모리에서 해당 출력을 읽어와 언제든 볼 수 있는 방식이다. 이런 식으로 XDCtools는 사용하기 편한 함수들을 제공해준다.

 

BIOS 6_76_02_02에 매칭되는 XDCtools 3_51_03_28 버전을 다운받아 압축을 풀고 C:\ti 디렉토리에 사진과 같이 넣어준다.

모든 설치가 끝났다면 다음과 같은 순서로 CSS단에서 설정한다.

Window -> Preferences -> Code Composer Studio -> Products 클릭 Rediscover 클릭.

설치가 잘 되었다면 다음과 같은 화면이 뜰 것이다. Install 후 뜨는 창에 따라 재 시작을 해주면 SYS/BIOS의 설치가 끝난다.

 

설치가 끝났으면 이제 사용을 해야 될 것이다. 프로젝트를 만들어 보자.

기존과 같이 CCS 프로젝트를 생성하면 기존에는 없던 SYS/BIOS 메뉴가 하나 있을 것이다. 사진과 같이 Typical로 생성하면 앞으로 만들어 볼 SYS/BIOS 프로젝트 생성이 완료된다.

 

이때 다음 화면에서 플랫폼 설정을 잊지 말자.


이제 동작을 잘 하는지 알아보기 위해 간단한 코드 한 줄을 실행시켜보았다.

 

바로 System_printf()를 사용한 출력이다. 이 출력을 위해서는 #include <xdc/std.h>, #include <xdc/runtime/System.h>, #include <ti/sysbios/BIOS.h> 3줄이 필요하다. 아까 설명한 동작이 어떤 식으로 이루어지는지를 알아보기 위해 Runtime Object View를 이용해 보았다. 실행 과정에서 return 전 줄에 스탑을 걸어놓고(클릭을 하면 설정 가능하다) 아직 return이 되지 않은 상태에서 본 버퍼이다.


확대하여 보면 버퍼에 출력문이 저장되어있는 것을 볼 수 있다. System_printf()는 메모리에 출력하는 방식을 사용하기 때문에 버퍼에 저장이 되어 있는 것이다. 이게 무슨 차이인지 잘 모를 수도 있다. 다음 사진을 보면 알 수 있을 것이다.

메인문과 출력문의 차이를 보자. 분명 System_printf()가 먼저 쓰였는데 콘솔창의 출력은 Printf!!가 먼저 출력되었다. Printf 는 바로 출력을 하는 반면 System_printf()는 메모리에 출력 후 프로그램 종료 후 읽어오는 방식을 사용하기 때문에 나타나는 현상이다.

 

 

System_printf()처럼 디버깅 시 유용하게 사용되는 함수를 하나 더 소개한다. 바로 Log이다.

몇 가지 include를 더 해준 뒤 다음과 같은 코드를 실행시켜 ROV를 통해 보면 사진과 같이 나온다.


로그는 타임스탬프와 함께 기록되기 때문에 코드를 분석하고 고칠 때 유용하게 사용 할 수 있다. 이 로그를 출력문을 통해 보고 싶으면 LoggerBuf_flush()를 사용하면 된다. Flush는 보통 버퍼에 저장되어있는 내용을 강제로 클라이언트에게 전송하고 버퍼를 비우는 역할을 한다. , 로그버퍼에 있는 내용을 전송해주는 함수이다.

 

 이를 위해서는 로그버퍼를 설정해줘야 한다. SYS/BIOS의 설정은 대부분 app.cfg 파일에서 이루어진다.

 

app.cfg를 그냥 열면 어지러운 내용들이 우리를 혼란스럽게 한다. 이를 조금 더 사용하기 쉽게 GUI형태로 보여주는 것이 XGCONF이다. 열어보자.


outline에서 LoggerBuf를 클릭해보면 logger0라는 이름의 버퍼가 하나 있을 것이다. 우리가 기록하는 로그는 해당 버퍼에 저장된다.

 

따라서 출력을 하고 싶으면 다음 사진처럼 코드를 작성하면 된다.

LAB3_A


 자 이제 본격적으로 연산을 해보자. 연산을 위해 Sine을 계산하는 함수를 만들었다.

sin.h 를 보면 함수는 array에다가 주파수, 샘플링, 배열의 길이, 시작 값을 넣어주면 루프를 돌면서 사인값을 버퍼에 담아 리턴한다.

View -> Expressions 에 들어가면 계산된 sine을 볼 수 있다.


 계산된 결과값을 그래프로 보고자 한다면 Tools -> Graph -> Single time에 들어가 다음과 같이 설정해준다.

 

그러면 그래프를 볼 수 있을 것이다. 여기에 조금 더 보기 좋게 다음과 같은 설정을 추가하는 것을 권장한다.


해당 코드는 SYS/BIOS를 사용하지 않는다. 하지만 SYS/BIOS기반으로 작성하였기 때문에 빌드시간이 오래 걸린다. 그런데 여기서 한가지 의문을 품을 수 있다. LAB2에서는 C6748.cmd라는 파일을 통해 기기를 찾아 들어갔다. 지금은 어떻게 작동하는 것일까? 바로 프로젝트 생성 시 Platform 설정에서 ti.platforms.evm6748을 선택하여서 linker.cmd 파일이 자동 생성된 것이다. 이 파일을 커스텀마이징하기 위해 우리가 새로 만들어볼 필요가 있다.

사진과 같이 따라 들어가보자.


위 설정과 같이 찾아 들어가면

사진과 같은 화면이 나올 것이다. 이게 현재 설정되어있는 파일이다. 이 파일을 복사하여 우리가 사용할 새로운 파일을 만들어보자. 아까와 같은 방식으로 이번에는 NEW를 클릭하여 새로운 플랫폼을 만들자.

 

설정은 이렇게 한다.

다음 화면에서 Import버튼을 눌러 복사를 해오자. 이 플랫폼은 이제 우리가 사용할 수 있는 복사본이 되었다.


이제 프로젝트 우클릭 -> Properties -> General 클릭, 화면 내 Products 탭으로 이동 -> Add 클릭


다음과 같이 설정해준 후

 

플랫폼을 myBoard로 바꾸어 Apply해주면 된다.

 


Edit Platform은 기존에 C6748.cmd 파일에서 설정했던 사항들을 GUI적으로 설정 가능하게 도와준다. 한번 설정을 바꾸어보자.

 


기존에 DDR이었던 메모리 섹션들을 IRAM으로 변경하였다. 이전 글에서 설명하였듯이 IRAM이 더 빠르다! 바뀐 섹션들은 Debug파일 내에 있는 map파일을 통해 어떻게 사용되고 있는지 확인할 수 있다.


헌데 DDR에서 IRAM으로 메모리 변경을 하여도 느껴지는 속도차이가 그리 크지 않다. 비교를 위해 연산을 for문으로 1000번 돌려도 체감되는 속도차이는 거의 없다. 왜냐하면 싸인을 계산하는 코드 정도는 캐시에 다 올라갈 수 있기 때문이다. 캐시 사용을 안하고 DDR을 사용하면 속도차이가 느껴질 것이다.

 

캐시를 0K로 만들면 캐시 사용을 안 할 것이다. 그리고 나서 코드를 실행시키면 속도차이가 엄청나게 체감된다. 궁금하면 한번 시도해 보는것도 나쁘지 않다.

 

 

마지막으로 코드 하나를 소개하고 마치도록 하겠다.

사진의 코드는 싸인을 한번에 200개씩 만드는 코드로 변경한 것이다.

 

기존 소스코드와의 차이는 200개씩 만들면 2000개가 다 안 만들어진 상태에서도 소스코드가 돌아갈 수 있다는 점이다.

즉 버퍼링이 적은 것처럼 될 수 있다.

반응형