동영상으로 보는 엔코더의 작동 원리

임베디드 2019. 12. 16. 00:43


 이전에 작성하였던 엔코더의 작동 원리에 대한 글이 지금까지도 많은 분들께서 찾아와주시는 것을 보면서 제 글이 많은 사람들에게 도움을 드리고 있다는 것에 상당한 뿌듯함을 느꼇습니다. 지금도 댓글로 질문을 달아주시는 분들이 계시는 것을 보면서 많은 분들께서 엔코더에 대해 궁금해 하시는 것이 많다는 것을 알게 되었습니다.


 어떻게 하면 엔코더의 작동 과정을 직관적으로 설명할 수 있을까 하다가 유튜브에서 좋은 영상 자료를 구하게 되어 여러분들께 보여드리고자 합니다. 먼저 동영상을 보신 다음 아래의 설명을 읽어주신다면 이해하는데 많은 도움이 되시리라 믿습니다.


Absolute(절대)방식과 Incremental(증분)방식 엔코더의 차이점





 엔코더의 구조로 크게 선형(Linear)엔코더와 로터리(Rotary)엔코더가 있습니다. 선형엔코더는 이름 그대로 직선으로 이동하며 위치를 측정하는 용도로 사용되며 로터리엔코더는 회전 정보를 측정하는 용도로 사용됩니다.



 선형엔코더는 트랜스듀서(Transducer)를 사용하여 위치 변화를 측정합니다. 로터리(샤프트)엔코더의 경우 샤프트 축을 기준으로 회전 과정에서 얻게 되는 정보를 측정합니다. 위의 로터리엔코더는 Absolute 방식으로 회전 각도에 대한 정보를 출력합니다.



 그렇다면 로터리엔코더의 Absolute 방식과 Incremental 방식은 어떠한 차이가 있을까요? 두 엔코더는 사용 목적에 따라 크게 다릅니다. 측정하고자 하는 대상이 샤프트를 중심으로 어느 정도 회전했는지를 360도 이내에서 알아내기 위해서는 Absolute 방식이 적합하고, 회전 속도를 측정하는 것이 목적이라면 Incremental 방식이 적합합니다.

 Absolute 방식은 어느 정도 회전 했는지의 각도 정보(Angular Position)을 제공하며 Incremental 방식은 엔코더의 회전횟수에 따른 물체의 속도와 이동거리를 측정할 수 있습니다.



 Incremental 방식의 엔코더의 회전 속도를 측정하는 방법은 위의 그림과 같이 엔코더 내부의 슬릿(틈새)사이로 빛을 쏘는 부분과 빛은 수신하는 부분이 맞물린 구조에서 이루어집니다. 엔코더가 회전할 때 슬릿이 지나갈 때 마다 수신하는 부분에서는 빛이 차단되다 다시 수신되는 과정을 거치게 됩니다.



 Absolute 방식의 엔코더는 특정한 각도만큼 회전하였을 때 출력값이 위에서 보는 바와 같이 다르게 나타납니다. 이는 엔코더의 광수신 부분 갯수에 따라 각을 나타낼 수 있는 값이 더 미세해집니다. 위의 예제의 경우 3개의 광수신기가 있으므로 3^2=8개의 위치를 파악할 수 있는 것입니다.



 Absolute 엔코더는 구조에 따라 싱글턴(Single-turn) 방식과 멀티턴(Multi-turn) 방식이 있습니다. 싱글턴 방식의 경우 엔코더가 회전할 수 있는 360º 범위를 측정할 수 있습니다. 쉽게 말해 Absolute 엔코더가 15º 만큼 돌았는지 375º 만큼 한바퀴를 더 돌았는지 아닌지를 알 수 없다는 것입니다.

 이러한 싱글턴 엔코더의 한계를 해결하고자 한 것이 멀티턴 엔코더입니다. Absolute 엔코더의 광수신 부분을 위의 그림과 같이 하나 더 설치하여 엔코더의 회전수를 체크할 수 있도록 하여 각도의 변화량 측정 범위를 360º 이상의 범위에서 측정할 수 있게 됩니다.



 Incremental 엔코더의 경우 회전할 때 마다 광수신부의 빛이 차단과 수신을 반복하게 되면서 출력으로 Rising edge trigger가 수신될 때 마다 값을 1씩 증가시켜 엔코더의 회전 여부 및 속도를 나타낼 수 있습니다.


 그렇다면 엔코더의 회전 방향이 샤프트를 기준으로 시계방향(CW)인지 시계반대방향(CCW)인지 확인할 수 있는 방법은 어떤 것이 있을까요? 아래의 동영상을 통해 이해해보도록 합니다.


Incremental 방식 엔코더의 A상과 B상





 위에서 설명드렸듯이 Incremental 엔코더가 회전할 때 counting disc를 지날 때 마다 카운터가 1씩 증가되는 과정을 위 동영상에서 다시 확인하실 수 있습니다.



 이러한 특성의 Incremental 엔코더에 counting disc를 두 개로 만들어 두 개의 상이 90º 차이가 나도록 설계합니다. 이렇게 되면 A상과 B상이 서로 90º 위상 차이로 출력되고 있는 것을 보실 수 있습니다.



 지속적으로 회전을 해보면 A상이 90º 차이로 B상보다 먼저 출력되고 있음을 확인하실 수 있습니다.



 반대로 이번에는 엔코더의 회전 방향을 반대로 돌려봅니다. 이 경우 B상이 A상보다 90º 빠르게 돌아가고 있음을 확인하실 수 있습니다. 이러한 두 상의 위상차를 통해 엔코더의 회전 방향을 파악할 수 있음을 알 수 있습니다.


 엔코더의 작동 원리에 대해 좀 더 자세히 알아보고자 하시는 분들은 이전에 정리하였던 제 글을 참조해 주셨으면 합니다!


2016/07/31 - [임베디드] - [로터리 엔코더] 엔코더의 작동 원리 및 사용 방법


300x250

Infineon AURIX TC237 사용기(3) - PC와 시리얼통신을 위한 VCP(가상컴포트) 설정방법

임베디드/MCU 2016. 8. 8. 00:37

 일반적으로 MCU 보드를 제공하는 회사 내의 소프트웨어 툴 내에는 USB를 통해 PC와 시리얼통신을 할 수 있도록 해주는 드라이버를 기본적으로 제공합니다. 보통은 USB를 연결하자마자 바로 가상의 포트(VCP, Virtual Com Port)가 설치되어 MCU와 통신이 가능하게 설정됩니다. 그러나 몇몇 제품의 경우 우리들이 직접 VCP를 설정해줘야 하는 경우가 있습니다. Infineon에서 제공하는 보드의 경우 PC에 연결하기 위해 Infineon에서 제공하는 ASCLIN(Asyncronous Syncronous Communication Local Interconnect Network, 보편적으로는 UART통신이라 부름)통신을 사용하여야 하는데 이를 위해 PC에 VCP드라이버를 직접 설치해주어야 합니다.



 Infineon TC237과 PC와 시리얼통신을 하기 위해서는 Infineon에서 제공하는 DAS Tool Interface를 설치해야 합니다. 이전에 TriCore™ Entry Tool Chain을 설치하는 과정에서 DAS도 함께 설치되므로 TriCore™ Entry Tool Chain을 설치하셨을 경우 아래 DAS Tool Interface를 설치하는 과정을 생략하여도 됩니다.

 


1. DAS Tool Interface를 설치하기 위해 아래 링크에 접속합니다.


http://www.infineon.com/cms/en/product/promopages/das/




2. DAS 최신버전을 다운로드 받습니다. 위의 회면에서 보았을 때 DAS v5.0.0을 클릭합니다.



3. 위 화면에서 붉은 네모칸 부분을 클릭하여 DAS를 다운로드 합니다. 압축파일을 열었을 경우 아래와 같이 DAS_v500_setup.exe 파일을 확인하실 수 있습니다.



 4. DAS 설치파일을 실행합니다. 실행 후 'Next' 버튼을 클릭합니다.



5. a 버튼을 눌러 체크한 후 'Next' 버튼을 클릭합니다. 이후 나오는 경로 설정 등을 자신의 컴퓨터에 맞게 설정해줍니다.



6. 설치가 완료되면 아래와 같은 화면을 보실 수 있습니다. 'Finish'버튼을 클릭하여 설치를 완료합니다.

(몇몇 컴퓨터의 경우 DLL에러로 더이상 진행이 되지 않는 경우가 있습니다. 이 경우 운영체제를 다시 설치하여 진행하시는 것이 건강에 매우 이롭습니다. 그 이외의 방법은 상당히 많은 시간이 소요될 것으로 예상됩니다.)



7. 이제 MCU 보드와 PC를 USB로 연결해줍니다. 잠시후 USB 드라이버가 자동으로 설치됩니다.



8. USB 드라이버가 제대로 설치되었는지 확인합니다. 만약 제대로 설치되었을 경우 아래와 같은 화면으로 확인이 가능할 것입니다.(Windows 10 기준)



9,  Windows+Pause 키를 눌러 시스템 화면으로 진입합니다. 또는 windows 탐색기에 '시스템'을 검색하여 시스템 화면을 엽니다. 그 다음 '장치 관리자'를 클릭합니다.



10. '범용 직렬 버스 컨트롤러' 메뉴를 연 후 이전에 확인하였던 드라이브명을 찾아봅니다. 다음 오른쪽 클릭 후 '속성(Property)'을 선택합니다.



11. '고급' 탭 선택 후 'VCP드라이버 설치'를 클릭한 후 '확인'버튼을 클릭합니다.



12. 연결된 USB를 컴퓨터에서 분리한 후 다시 연결하면 다시 드라이버 설치가 진행됩니다. 설치가 완료된 후 장치 관리자에서 '포트(COM & LPT)' 메뉴를 열어보면 가상 시리얼포트가 설정된 것을 확인하실 수 있습니다.




 이제 시리얼통신 프로그램(ComPortMaster 또는 Teraterm)을 사용하여 보드와 PC간의 Serial 통신을 사용해보시길 바랍니다!

300x250

[로터리 엔코더] 엔코더의 작동 원리 및 사용 방법

임베디드 2016. 7. 31. 19:25


 모종의 일로 엔코더를 접하게 된 기회가 생겨 관련 내용을 조사해 보았는데 엔코더를 완전히 처음 접하게 되는 저의 입장에서 인터넷 상에 올라온 엔코더에 대한 정보를 이해하는데 상당히 많은 시간이 들어 애를 먹었던 기억이 있어 이후 저와 같이 엔코더에 대해 알아보고자 하는 분들에게 좀 더 쉬운 이해를 드리고자 나름의 방법으로 엔코더의 원리와 사용법에 대해 간단히 설명해보고자 이 포스팅을 작성하게 되었습니다. 초심자의 입장에서 이해를 할 수 있도록 하는 방향으로 포스팅을 작성하였으나 여전히 궁금한 점이 있으신 분이라면 부담없이 이 포스팅의 답글로 질문을 해주신다면 환영합니다!


 -2019년 12월 16일 추가사항

 엔코더의 동작 원리를 시각적으로 쉽게 설명하는 동영상 자료를 추가하였습니다. 아래의 포스팅에서 동영상을 보실 수 있습니다.

2019/12/16 - [임베디드] - 동영상으로 보는 엔코더의 작동 원리



 ※이 포스팅은 오토닉스社의 로터리 엔코더인 E20S시리즈(E20S-2-360-3-N-5-S)를 기준으로 작성하였으며 엔코더 제작사에 따라 회로 구조 및 동작 방식이 다소 차이가 있을 수 있음을 알립니다.


  엔코더는 회전하는 물체의 회전속도(각속도 등)을 측정하기 위해 사용되는 기기로서 엔코더의 회전축에 측정하고자 하는 회전체의 축을 서로 연결하여 돌아가는 방향과 횟수를 정밀하게 측정하는 것을 목표로 사용됩니다.(전자공학에서 디지털 논리 과목에서 듣게되는 Encoder와는 철자만 같을 뿐 전혀 다릅니다. 여기서 설명하는 엔코더는 주로 '로터리 엔코더'로 칭합니다.)


1. 엔코더의 종류

 회전축이 돌아가는 정도를 측정하는 방식으로는 인크리멘탈(Incremental, 증분) 방식과 앱솔루트(Absolute, 절대) 방식이 존재합니다.
 인크리멘탈 방식은 말 그대로 점진적으로 증가하는(더하는) 형식을 쓰는 것으로 엔코더가 돌아갈 때 발생되는 파형의 횟수를 통해 회전축의 회전 속도를 측정합니다. 이는 일정한 방향으로 회전하는 기기에 사용하기 적합한 방식으로 DC모터와 같이 돌아가는 기기의 속도를 정밀하게 측정하기에 적합한 방식입니다.

위 그림은 인크리멘탈 방식의 원리를 간단한 그림으로 나타낸 것입니다. 각 발광소자를 통해 나오는 빛이 A상, B상, Z상을 주기적으로 비추게 되는데 엔코더가 회전을 하게 되었을 때 회전 슬릿으로 나오는 빛이 각 상에 비추었다가 가려지는 식으로 회전축이 돌아가는 속도를 측정하는 방식이라 할 수 있겠습니다.

 한편, 앱솔루트 방식은 이름 그대로 각 지점의 절대값을 설정하여 엔코더가 축을 중심으로 돌던 도중 측정되는 해당 위치에서의 값을 전달하는 방식입니다. 이 방식은 인크리멘탈 방식과는 달리 1바퀴 이상 돌아가지 않는 기기, 즉 특정 각도로 미세하게 움직여야 하는 기기에 사용하기 적합한 방식이라 할 수 있습니다.

앱솔루트 방식의 원리를 그림으로 나타내었을 때 회전 슬릿이 인크리멘탈 방식과 확연히 다르다는 것을 알 수 있습니다. 회전축이 움직이던 도중 특정 위치에서 이동한 만큼의 위치값이 전달되는데 해당 각도에 대한 값이 회전 슬릿의 구멍을 통해 나타내었으며 해당 슬릿을 통과한 빛의 위치 및 가중치를 고려하여 해당 엔코더가 회전한 위치값을 전달하게 됩니다.


2. 분해능

 분해능은 엔코더의 성능 중 가장 중요한 요소로서 사용되는 기기의 특성 및 사양에 따라 달리 사용될 수 있습니다. 분해능이 높을수록 축의 회전 속도 및 위치를 미세하게 측정할 수 있는데 엔코더가 1회 회전하였을 때 발생신호는 분해능의 갯수만큼 출력됩니다.


 예를 들어 인크리멘탈형 엔코더의 경우 분해능이 360인 엔코더에 연결된 기기가 1바퀴를 정확히 돌았을 때 총 360개의 펄스가 발생합니다. 즉, 한 바퀴를 정확히 회전하였을 때 360°이므로 360/360 =1° 이동할 때 마다 1개의 펄스가 발생되는 것이지요. MCU에 연결된 기기에 타이머를 설정하여 특정 시간동안 MCU에 입력된 횟수를 토대로 엔코더의 회전 각속도를 측정해낼 수 있습니다.


 반면 앱솔루트형 엔코더의 경우 회전체가 회전한 위치를 알아내는 것이 목표로서 만약 분해능이 360일 경우 현재 회전체가 회전한 정도를 실제 도수 단위인 1° 단위로 위치를 측정합니다. 만약 90° 정도에 위치했던 회전체가 시계 방향으로 30° 이동하게 되면 엔코더의 출력값이 90°에서 120°로 출력되는 방식입니다.


3. 출력 방식

 인크리멘탈형 엔코더의 경우 증분 방식으로 회전수를 측정하는 것이 목표이므로 MCU 측에서는 Rising-Edge 입력 인터럽트를 통해 회전율을 측정하게 됩니다.

 위 그림은 인크리멘탈형 엔코더의 출력 방식을 그림으로 나타낸 것으로 시계방향(CW : Clockwise)으로 회전시의 모습입니다. A상과 B상의 주기는 같으나 회전 방향에 따라 위상차가 생겨 이를 사용하여 엔코더의 회전 방향을 예측할 수 있습니다. 반면 Z상의 경우 B상보다 주기가 2배이며 회전 방향을 식별하지 않아도 되는 경우, 즉 엔코더가 한쪽 방향으로만 돌기 때문에 이를 굳이 구분할 필요가 없을 경우 Z상만 사용해도 될 듯 합니다.


시계방향(CW)

반시계방향(CCW)

  위 그림은 A상과 B상의 위상을 통해 엔코더의 회전 방향을 분석하는 방법을 타나낸 것입니다. 엔코더의 축이 시계방향(CW)으로 돌 경우 A상이 B상보다 90° 앞서고 있으며 반시계방향(CCW)으로 돌 경우 반대로 B상이 A상보다 90° 앞서게 되는 것을 보실 수 있습니다. 이러한 A상과 B상의 위상차를 사용하여 엔코더의 축이 돌아가는 방향을 알아내는 방법은 다음과 같습니다.


1) 소트프웨어 방식

 A상을 GPIO Input 모드로 연결하고 B상을 Rising Edge 방식의 Interrupt로 설정합니다. B상에 의해 Interrupt 발생시 A상의 입력값이 1일 경우 시계방향(CW)으로, 0일 경우 반시계방향(CCW)으로 회전함을 확인할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
unsigned char rotate_direction;
 
void Interrupt_InputB(){
    unsigned char state = IfxPort_getPinState(&MODULE_P33, 0); // identify phase A
    if(state){
        rotate_direction = 1;
    }else{
        rotate_direction = 0;
    }
}
cs


2) 하드웨어 방식

 간단한 D플립플롭을 사용하여 회전 방향을 알 수 있는 회로를 보도록 합니다.

 위 그림은 A상을 입력 D에, B상을 클록에 연결하여 출력 Q값을 통해 방향을 확인할 수 있습니다. D 플립플롭의 특성상 클록이 rising edge가 입력될 때 까지 출력값 Q가 고정되었다가 rising edge가 입력된 순간 A상의 위상을 출력하게 됩니다. 축의 회전방향에 따라 A상과 B상의 위상이 바뀌는 특성을 이용하여 위에서 보시는 바와 같이 회전방향을 출력해 내는 것을 확인하실 수 있습니다.


 한편, 앱솔루트 방식의 엔코더를 사용할 경우 엔코더의 위치값이 그대로 출력되므로 MCU의 GPIO Input모드로 각 값을 받아들여 값을 처리하면 됩니다.

위 그림은 앱솔루트형 엔코더의 파형을 나타낸 것입니다. 이 엔코더의 분해능은 6으로 빨간색으로 표시한 부분을 통해 엔코더가 회전한 위치를 알 수 있습니다. 분해능이 6인 앱솔루트형 엔코더를 통해 기기의 회전체가 60°, 120°, 180°, 240°, 300°, 360° 위치로 움직였음을 알 수 있습니다.


4. 회로 설계방법

 엔코더의 물리적 사용법에 따라 인크리멘탈형과 앱솔루트형을 선택한후 다음으로 엔코더를 설치할 회로의 특성에 따라 토템폴 방식, NPN오픈콜렉터 방식, PNP오픈콜렉터 방식 라인드라이버 방식이 있습니다. 각 방식의 장점은 다음과 같습니다.


토템폴(Totem Pole) 방식       - 파형의 왜곡 및 노이즈의 영향을 적게 받고 엔코더와 회로의 거리가 멀 때 사용하기 좋다.

NPN(PNP)오픈콜렉터 방식     - 엔코더의 전원전압과 회로의 전원전압이 다를 경우 사용하기 좋다.

라인드라이버(Line Driver)방식 - 엔코더로부터 회로의 위치가 멀리 떨어져있을 경우 빠른 응답속도로 동작할수 있다.


 엔코더를 사용하고자 하는 목적에 따라 회전횟수를 측정하여야 하는 경우 인크리멘탈형으로, 회전체의 미세한 이동각도를 측정하고자 하는 경우 앱솔루트형 엔코더를 사용하며 자신의 회로에 맞는 특성을 고려하여 엔코더를 고르신다면 제작에 큰 도움이 되시리라 기대합니다.


참고자료 : 오토닉스社 제품 사용 설명서
http://autonics.co.kr/products/products_2.php?big=01&mid=01/06


동영상자료: 

2019/12/16 - [임베디드] - 동영상으로 보는 엔코더의 작동 원리

https://elecs.tistory.com/346


300x250

Infineon AURIX TC237 사용기(2) - TriCore™ 컴파일 후 프로그램 실행

임베디드/MCU 2016. 6. 26. 22:49

 지난 포스팅에서 Infineon사의 TC23x 시리즈를 사용하기 위해 사용되는 IDE인 TriCore™ Entry Tool Chain을 설치하는 과정을 진행하였습니다. 이어서 프로그램을 컴파일한 후 실행하는 과정을 살펴보도록 하겠습니다.

 시작하기에 앞서 아래 예제 프로젝트를 다운로드 받아 주시길 바랍니다.


TC237L_Example.zip



1. 위 프로젝트 파일을 받으신 후 IDE를 실행한 다음 아래의 화면과 같이 HighTec Project Explorer 화면 위에서 마우스 오른쪽 버튼을 클릭한 후 'Import' 버튼울 눌러줍니다.




2. 아래와 같은 창이 나타났다면 General -> Existing Projects into Workspace 를 선택해줍니다.



3. 'Select archive file'을 선택해주신 후 'Browse' 버튼을 클릭하여 다운로드 받았던 프로젝트 파일을 선택합니다. 아래와 같은 화면이 나타난다면 아래에 있는 'Finish' 버튼을 눌러줍니다.



3. 완료시 아래와 같이 프로젝트가 import된 것을 확인하실 수 있습니다. 이제 바로 해당 프로젝트 파일을 컴파일해 보도록 하겠습니다. 프로젝트를 선택해주신 후 아래 그림에서 붉은 색으로 표시한 아래화살표 부분을 클릭해줍니다.



4. build 방식을 선택하는 메뉴입니다. 프로젝트를 컴파일 하기 위해 'Build project...'을 클릭합니다. 만약 컴파일이 제대로 이루어지지 않는 경우 아래칸의 'Clean project...'을 실행한 후 다시 컴파일을 시도합니다.



5. 컴파일이 완료되었다면 생성된 바이너리를 MCU에 다운로드 해보도록 하겠습니다. 아래 화면에서 디버그(벌레그림)버튼의 오른쪽에 있는 아래화살표를 클릭한 후 'Debug Configurations...'을 클릭합니다.



6. 아래와 같이 'Debug Configurations' 창이 뜨면 메뉴 맨 아래에 있는 'Universal Debug Engine'을 클릭한 후 붉은 표시를 한 부분을 눌러 새로운 환경을 추가시켜줍니다.



7. 해당 예제를 디버그할 수 있는 환경을 만들어준 후 생기는 오른쪽 창 메뉴 중 'UDE Startup'을 클릭한 후 두 번째 빈칸 오른쪽에 있는 'Create Configuration'을 클릭합니다.



8. 'Use a default target configuration'을 클릭한 후 'TriCore -> Infineon -> TC23x StarterKit -> Triboard with TC23x (DAS)'를 선택 후 '마침' 버튼을 클릭합니다.



9. 선택한 설정파일을 저장합니다. 이후 다른 프로젝트를 실행할 때 선택하여 사용할 수 있도록 적당한 곳에 저장해둡니다.



10. 이제 디버그를 할 수 있는 환경이 모두 구축되었습니다. 아래 붉은 색으로 표시한 'Debug' 버튼을 클릭하여 디버그 모드로 진입합니다.



11. 디버그 모드에 진입하게 되면 아래와 같이 MCU에 프로그램을 올릴 수 있는 단계에 도달하게 됩니다. 붉은 색으로 표시된 'Program All' 버튼을 클릭하여 컴파일 된 프로그램을 MCU에 다운로드 해줍니다.



12. 컴파일된 프로그램이 MCU에 다운로드가 완료되면 아래와 같이 초록색 칸이 모두 채워집니다. 'Exit' 버튼을 클릭하여 메뉴를 닫으면 디버그를 수행할 수 있습니다.



13. 이제 TC237의 RESET 버튼을 누르면 내장된 프로그램이 동작하는 것을 확인하실 수 있습니다.


300x250

Infineon AURIX TC237 사용기(1) - TriCore™ Entry Tool Chain 설치하기

임베디드/MCU 2016. 4. 26. 00:31

 이번에 기회가 되어 Infeneon의 AURIX TC23x 시리즈 MCU를 만져보게 되면서 이와 관련된 자료들을 블로그로 포스팅 해볼까 합니다. 이전에 TI사의 Tiva C 시리즈를 다루던 당시처럼 관련 내용을 다룬 국내의 포스팅이 없어 TI 콘테스트를 준비하던 당시처럼 맨땅에 해딩하는 듯한 기분이 없지않아 느껴집니다.


 TI사의 MCU를 사용하기 위해 Code Composer Studio를 사용하듯이 이번에 다루는 Infineon사의 AURIX TC23x 시리즈의 MCU를 사용하기 위한 통합개발환경인 TriCore™ Entry Tool Chain이 필요합니다. 이를 얻기 위해 HIGHTEC이라는 사이트에서 TriCore™ Entry Tool Chain의 컴파일러를 사용할 수 있는 라이센스를 무료로 발급받으시면 됩니다.


http://free-entry-toolchain.hightec-rt.com/



 위 사이트의 화면에서 보시는 바와 같이 오른쪽 부분에 이름, 이메일주소 등의 신상정보를 입력하신 후 TriCore™ Entry Tool Chain을 사용하고자 하는 PC의 MAC어드레스를 입력해야 합니다.

 컴퓨터의 MAC어드레스를 알아내기 위해 CMD를 통해 명령어를 입력하여야 합니다. '윈도키+R'를 누른 후 cmd를 입력하시어 명령 프롬포트를 실행합니다.


위 화면의 경우 Windows 10 작업표시줄에 있는 검색창을 통해 cmd를 입력한 모습입니다.


 명령 프롬포트를 실행하신 후 다음과 같이 명령어를 입력해줍니다.

> ipconfig/all



 실행하시면 보시는 바와 같이 자신의 컴퓨터에 할당된 MAC어드래스(물리적 주소)를 확인하실 수 있습니다. 만약 자신의 PC가 랜선을 연결하여 인터넷을 하는 경우 '이더넷'을, 와이파이를 통해 인터넷을 하시는 경우 'Wi-Fi'에 있는 MAC어드래스를 입력하시면 되겠습니다. 만약 가상머신을 사용하여 인터넷을 사용하시는 경우 해당 가상머신에 할당된 MAC어드래스를 사용하시면 되겠습니다.



 자신의 신상정보를 모두 입력하셨을 경우 위와 같이 라이센스가 성공적으로 발급되었음을 확인하실 수 있습니다. 발급된 라이센스는 'Download "license.lic"'를 통해 다운받으시거나 자신의 이메일을 통해 다운받으실 수 있으며 설치 패키지 또한 메일 주소로 다운로드 경로를 제공합니다.



 다운로드가 설치를 진행하도록 합니다. 첫 화면에서 License에 동의함을 선택하신 후 'Next'버튼을 클릭합니다.



 설치 모드를 선택합니다. 자신이 선호하는 모드를 선택하신 후 'Next'를 클릭합니다.



 TriCore™ Entry Tool Chain를 설치하고자 하는 경로를 설정합니다.



 Product Selection Key를 입력하는 부분입니다. 이 부분에서 라이센스 부여 여부가 결정되는 것으로 보이며 보통은 초기에 Product Selection Key가 미리 설정되어 있어서 그냥 'next'버튼을 누르고 넘어가시면 되겠습니다.



 설치가 진행중입니다. 설치가 완료되면 바탕화면에 'TriCore™ Entry Tool Chain'의 바로가기가 설치되었음을 확인하실 수 있습니다.


※TriCore™ Entry Tool Chain은 Eclipse를 기반으로 만들어진 IDE(통합 개발 환경)이며, Eclipse는 Java가 설치된 환경에서 동작합니다. 만약 자신의 컴퓨터에 JDK가 설치되어 있지 않을 경우 아래의 화면과 같은 오류가 발생합니다. 이 경우 Oracle에서 제공하는 JDK(32-bit)를 설치해 주시기 바랍니다.


http://www.oracle.com/technetwork/java/javase/downloads/index.html



※64-bit 환경의 운영체제를 사용하시는 경우 JDK가 설치되어 있음에도 아래와 같은 오류가 발생하는 경우가 있습니다. 이는 TriCore™ Entry Tool Chain가 32-bit 기반의 프로그램이기 때문에 64-bit 환경의 JDK에서는 실행할 수 없는 겁니다. 이 경우 Oracle에서 제공하는 JDK(32-bit)를 설치해 주시기 바랍니다.


http://www.oracle.com/technetwork/java/javase/downloads/index.html




 설치가 완료된 후 TriCore™ Entry Tool Chain을 실행하면 위와 같은 화면이 나타며 IDE가 실행됩니다.



 TriCore™ Entry Tool Chain를 처음 실행하였을 경우 사용자의 라이센스를 확인하여야 한다는 경고문이 등장합니다. Yes를 눌러줍니다.



 위와 같이 'Add license'이 등장하면 홈페이지에 입력하였던 정보를 그대로 입력해줍니다. 'Finish'버튼을 누르면 인증이 완료되며 Infineon의 AURIX TC23x 시리즈를 개발할 수 있는 환경을 구축하실 수 있습니다.


 설치과정에서 발생하였던 몇몇 이슈들에 대해 알아봅니다.


Q1.설치 후 인증과정에서 라이센스를 발급받았던 신상정보를 그대로 입력했음에도 컴파일러가 작동하지 않습니다.

->TriCore™ Entry Tool Chain의 라이센스를 최종으로 획득하기 위해서는 해당 MAC어드래스를 통해 인터넷이 연결되어 있어야 합니다. 만약 다운로드 당시 LAN의 MAC어드래스로 라이센스를 받아두고 Wi-Fi를 통해 인증을 시도하는 경우 인증이 되지 않는 경우가 발생합니다.


Q2.위의 방법대로 인터넷에 연결된 상태에서 라이센스 인증을 시도하였으나 여전히 컴파일러가 작동하지 않습니다.

->만약 라이센스 인증을 여러 번 시도하였을 경우 최근에 수행하였던 라이센스만 인증이 됩니다. 이 경우 자신의 이메일에 있는 가장 최근에 도착한 license.lic파일을 다운로드 받으신 후 C:/HIGHTEC/licenses 폴더에 삽입합니다. 이 때 기존의 lic파일을 삭제해야 TriCore™ Entry Tool Chain IDE가 단 하나의 라이센스만 인식할 수 있습니다.

300x250

[Tiva] GPIOIntTypeSet()

임베디드/TI 2015. 7. 13. 10:55

void GPIOIntTypeSet(uint32_t ui32Port, uint8_t ui8Pins, uint32_t ui32IntType)

설명 : 특정한 핀에 대한 인터럽트 방식을 설정합니다.


uint32_t ui32Port

GPIO의 포트를 설정합니다.


uint8_t ui8Pins

설정하고자 하는 해당 포트의 핀번호를 선택합니다.


uint32_t ui32IntType

자신이 원하는 인터럽트의 신호를 선택합니다.


 여기서 ui32IntType를 통하여 다음과 같은 인터럽트 신호들을 감지할 수 있도록 설정할 수 있습니다.


GPIO_FALLING_EDGE

핀의 입력이 1에서 0으로 내려가는 순간에 인터럽트를 발생시킵니다.


GPIO_RISING_EDGE

핀의 입력이 0에서 1로 올라가는 순간에 인터럽트를 발생시킵니다.


GPIO_BOTH_EDGE

위의 GPIO_FALLING_EDGE와 GPIO_RISING_EDGE가 발생시 인터럽트를 발생시킵니다.


GPIO_LOW_LEVEL

핀의 입력이 0이 되었을 때 인터럽트를 발생시킵니다.


GPIO_HIGH_LEVEL

핀의 입력이 1이 되었을 때 인터럽트를 발생시킵니다.


GPIO_DISCRETE_INT

GPIO 포트에서의 각 핀에 대한 별개의 인터럽트를 설정합니다.



 인터럽트를 설정할 때 의도치 않은 인터럽트 설정을 피하기 위해 위의 함수를 사용할 시에 GPIO의 입력이 안정된 상태어야 합니다. 즉, Floating 현상으로 인해 의도치 않은 인터럽트가 발생할 수 있다는 점을 유의해야 합니다. Floating에 대한 자세한 설명은 아래 포스팅을 참조해 주시기 바랍니다.


http://elecs.tistory.com/15

300x250

Timer를 활용하여 특정 파형간 간격 측정방법

임베디드/MCU 2015. 3. 25. 00:02

 아날로그 회로를 사용할 때 알고 싶은 정보들 중 하나로 특정 파형 간의 간격을 시간으로 구하는 것일겁니다. 그런데 이 파형이 간헐적이라면 사람의 감으로 대략적으로 알 수 있겠습니다만 1MHz 정도 되는 파형으로는 절대 사람의 힘으로는 알 수 없을 것입니다. 이러한 파형을 측정하기 위해 사용되는 것이 바로 MCU에서 사용되는 Timer와 Counter이지요.


 2015년 현재 웨어러블이 주목받고 있습니다. 사람의 몸에 직접 착용하여 사용하는 기기이다 보니 사람의 생체를 활용한 기능들이 속속 선보이고 있습니다. 삼성전자의 갤럭시워치에는 심전도 측정 기능이 등장하였는데요 심박수를 측정할 때도 이 Timer가 쓰이는 것이지요.



  

 2015년 현재의 대표적인 상징물이라 할 수 있는 스마트워치

심전도, 만보계 등 생체를 활용한 기능들이 활용되고 있다.


 이번 포스팅에서는 특정 파형에서 원하는 구간을 측정하여 해당 구간의 시간 간격을 타이머로 구하는 방법에 대해 이야기하려 합니다. 파형으로 심전도 측정값을 활용하여 진행해 보도록 하겠습니다.




 다음과 같이 특정한 파형이 있다고 가정해 봅시다. 우리는 위 파형에서 보이고 있는 Peak 값을 구해볼 것입니다. MCU에서 해당 부분만 검출하기 위해서 아날로그 비교기(Analog Comparator)를 통해 검출해내 보겠습니다.


 여기서 잠시 Analog Comparator의 동작 방식에 대해 간단하게 이해를 하고 넘어가겠습니다.


 Analog Comparator은 기본적으로 2개의 입력과 1개의 출력으로 구성되어 있습니다. 이 때 Vin+을 Input1로, Vin-을 Input2라 가정합니다. 쉽게 설명하자면 Input1과 Input2의 전압차이가 +일 경우 Output의 값은 1이 되며 Input1과 Input2의 전압차이가 -가 될 경우 Output의 값은 0이 됩니다. 아래는 Analog Comparator을 사용한 입출력값과 결과값을 나타냅니다.




 출력결과를 확인하시면 우리들이 흔히 접하는 0과 1의 디지털 파형이 되는 것을 보실 수 있습니다. 이제 이 Output값을 이용해서 우리는 각 1이되는 값 사이의 간격을 측정해 볼 것입니다. 여기서 Output의 파형을 상세하게 보도록 하겠습니다.



 아날로그 파형에서 자신이 측정하고자 하던 파형 사이의 간격은 다음과 같이 측정하면 될 것입니다. 이 때 파형을 측정하는 방법을 다음과 같이 4가지로 보실 수 있습니다.


1. 파형이 1이 될 때

2. 파형이 0이 될 때

3. 파형이 Positive Edge(0에서 1로 올라가는 순간)이 될 때

4. 파형이 Negative Edge(1에서 0으로 내려가는 순간)이 될 때


 Interrupt를 공부하신 분이라면 이 부분에서 '아하!'하고 이해하실 수 있을 것입니다. 그렇습니다. 출력 부분을 Interrupt 처리가 가능한 입력 부분에 연결하실 후 Positive Edge가 발생하는 순간부터 Timer를 동작시켜 시간을 측정하신 후 그 다음 Interrupt가 들어오는 순간 Timer의 동작을 종료시킨 후 해당 값을 확인하시면 파형간 간격을 측정하실 수 있으실 것입니다.

300x250

[Tiva] Tiva 기반 MCU로 블루투스 모듈을 활용하여 UART 통신하기

임베디드/TI 2014. 9. 13. 02:04

 MCU를 활용하여 다른 기기와의 통신으로 UART를 많이 사용할 겁니다. 이러한 MCU에 블루투스 모듈을 사용하면 간단한 설정으로 무선으로 UART를 활용할 수 있다는 점은 상당히 매력적이지요.

 다만 아쉬운 점이라면 블루투스 모듈을 사용시 AT 커맨드 등 기본적인 활용 지식이 없는 상태에서 입문하기에는 공부할 것이 많다는 점이 블루투스에 입문하는데 장벽이 되고 있기도 하지요.


 아래의 코드는 MCU와 블루투스 모듈이 연결되어 있을 때 해당 코드를 활용하면 바로 다른 기기와 연결모드에 진입할 수 있습니다. 이후 다른 기기와 블루투스를 연결하면 UART 통신을 통해 블루투스와 연결된 기기간에 통신을 할 수 있게 됩니다.


 해당 코드는 TI사의 TM4C123GH6PM MCU를 활용하였으며 소스코드는 TI사의 Tivaware 라이브러리 내의 소스코드를 활용하였습니다. 블루투스 모듈은 FirmTech 사의 FB155BC를 사용하였음을 알립니다.


※UART0은 PC와 연결되어 있으며 UART7은 블루투스 모듈과 연결되어 있습니다.

※블루투스 모듈의 모드는 AT COMMAND를 받는 모드로 설정되어 있습니다.

※블루투스 모듈에 UART로 'AT+BTSCAN'을 전송하면 블루투스 모듈이 다른 기기의 연결을 기다리게 됩니다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/adc.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
 
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
 
void ConfigureUART(void) {
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
 
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART7);
 
    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    ROM_GPIOPinConfigure(GPIO_PE0_U7RX);
    ROM_GPIOPinConfigure(GPIO_PE1_U7TX);
    ROM_GPIOPinTypeUART(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1);
 
    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
    UARTClockSourceSet(UART7_BASE, UART_CLOCK_PIOSC);
 
    //
    // Initialize the UART for console I/O.
    //
    ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
            UART_CONFIG_PAR_NONE));
    ROM_UARTConfigSetExpClk(UART7_BASE, ROM_SysCtlClockGet(), 9600,
            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
            UART_CONFIG_PAR_NONE));
}
 
void findDevice() {
    UARTCharPut(UART7_BASE, 'A');
    UARTCharPut(UART7_BASE, 'T');
    UARTCharPut(UART7_BASE, '+');
    UARTCharPut(UART7_BASE, 'B');
    UARTCharPut(UART7_BASE, 'T');
    UARTCharPut(UART7_BASE, 'S');
    UARTCharPut(UART7_BASE, 'C');
    UARTCharPut(UART7_BASE, 'A');
    UARTCharPut(UART7_BASE, 'N');
    UARTCharPut(UART7_BASE, 0x0D);
}
 
void AT() {
    UARTCharPut(UART7_BASE, 'A');
    UARTCharPut(UART7_BASE, 'T');
    UARTCharPut(UART7_BASE, 0x0D);
    UARTCharPut(UART0_BASE, '0');
}
 
void UARTIntHandler() {
    unsigned char get;
    get = UARTCharGet(UART7_BASE);
    if (get == '\r') {
        UARTCharPut(UART0_BASE, '\n');
        UARTCharPut(UART0_BASE, '\r');
    } else
        UARTCharPut(UART0_BASE, get);
}
 
void InsertUART2() {
    unsigned char get;
    get = UARTCharGet(UART0_BASE);
    
    if (get == '\r') {
        UARTCharPut(UART7_BASE, '\r');
        UARTCharPut(UART7_BASE, '\n');
    } else
        UARTCharPut(UART7_BASE, get);
}
 
void SendString(char *str) {
    while (*str) {
        UARTCharPut(UART7_BASE, *str);
        SysCtlDelay(SysCtlClockGet() / 100);
        str++;
    }
    
}
 
int main(void) {
    ROM_FPULazyStackingEnable();
 
    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
 
    //
    // Enable the GPIO port that is used for the on-board LED.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
 
    //
    // Enable the GPIO pins for the LED (PF2 & PF3).
    //
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
 
    //
    // Initialize the UART.
    //
    ConfigureUART();
 
    IntMasterEnable();
 
    IntEnable(79);
    UARTIntEnable(UART7_BASE, UART_INT_RX | UART_INT_RT);
    UARTIntRegister(UART7_BASE, UARTIntHandler);
 
    IntEnable(21);
    UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
    UARTIntRegister(UART0_BASE, InsertUART2);
 
    SysCtlDelay(SysCtlClockGet() / 4);
    findDevice();
 
    while (1) {
    
    UARTCharPut(UART7_BASE, 'H');
    UARTCharPut(UART7_BASE, 'e');
    UARTCharPut(UART7_BASE, 'l');
    UARTCharPut(UART7_BASE, 'l');
    UARTCharPut(UART7_BASE, 'o');
    UARTCharPut(UART7_BASE, ',');
    UARTCharPut(UART7_BASE, 'W');
    UARTCharPut(UART7_BASE, 'o');
    UARTCharPut(UART7_BASE, 'r');
    UARTCharPut(UART7_BASE, 'l');
    UARTCharPut(UART7_BASE, 'd');
    UARTCharPut(UART7_BASE, '!');
    UARTCharPut(UART7_BASE, '\n');
    UARTCharPut(UART7_BASE, '\r');
    SysCtlDelay(SysCtlClockGet());
    
    }
}
 


300x250

[Tiva] Tiva C 기반의 MCU로 초음파센서 SRF-10 활용하기

임베디드/TI 2014. 9. 12. 23:51

[SRF-10 source code using tm4c123g]


본 소스코드는 TI 사에서 제공하는 TivaWare 기반으로 작성되었으며

TI 사의 tm4c123gh6pm MCU에서 동작을 확안하였음을 알립니다.


기타 문의사항이 있으시거나 코드에 문제가 있을 경우 알려주시면 감사하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/i2c.h"
#include "utils/uartstdio.h"
 
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
 
void ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
 
    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
 
    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
 
    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
 
    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}
 
void DelaySoft(volatile unsigned long ulDelay) {
    SysCtlDelay((SysCtlClockGet() / 10000) * ulDelay);
}
 
#define    SLAVE_ADDRESS    0xE0 / 2
 
void ChangeAddress(int old, int new) {
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, old, false);
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x00);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0xA0);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    //SysCtlDelay(SysCtlClockGet() / 1000000 * 2);
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x00);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0xAA);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    //SysCtlDelay(SysCtlClockGet() / 1000000 * 2);
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x00);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0xA5);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    //SysCtlDelay(SysCtlClockGet() / 1000000 * 2);
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x00);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterDataPut(I2C1_BASE, new);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
}
 
int getI2CValue(int ADDR) {
    uint32_t rcv1 = 0;
    uint32_t rcv2 = 0;
    uint32_t rcv = 0;
 
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, ADDR, false);
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x00);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x51);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    SysCtlDelay(SysCtlClockGet() / 1000000 * 2);
 
    ROM_I2CMasterDataPut(I2C1_BASE, 0x02);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterDataPut(I2C1_BASE, 93);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    DelaySoft(115);
 
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, ADDR, false);
    ROM_I2CMasterDataPut(I2C1_BASE, 0x02);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, ADDR, true);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    rcv1 = ROM_I2CMasterDataGet(I2C1_BASE);
    rcv = rcv1 << 8;
 
    SysCtlDelay(SysCtlClockGet() / 1000000 * 2);
 
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, ADDR, false);
    ROM_I2CMasterDataPut(I2C1_BASE, 0x03);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, ADDR, true);
    ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    rcv2 = ROM_I2CMasterDataGet(I2C1_BASE);
    rcv += rcv2;
 
    //ROM_I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true);
    //ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    //rcv = ROM_I2CMasterDataGet(I2C0_BASE);
 
    while (ROM_I2CMasterBusy(I2C1_BASE)) {
 
    }
 
    //DelaySoft(500);
    DelaySoft(300);
 
    return rcv;
}
 
int main(void) {
    //volatile uint32_t ui32Loop;
    uint32_t var1, var2;
 
    //
    // Enable lazy stacking for interrupt handlers.  This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPULazyStackingEnable();
 
    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
    SYSCTL_OSC_MAIN);
 
    //
    // Enable the GPIO port that is used for the on-board LED.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);
 
    ROM_GPIOPinConfigure(GPIO_PA6_I2C1SCL);
    ROM_GPIOPinConfigure(GPIO_PA7_I2C1SDA);
 
    ROM_GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6);
    ROM_GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7);
 
    ROM_I2CMasterInitExpClk(I2C1_BASE, SysCtlClockGet(), false);
 
    ROM_I2CMasterSlaveAddrSet(I2C1_BASE, SLAVE_ADDRESS, false);
 
    ROM_I2CMasterEnable(I2C1_BASE);
 
 ConfigureUART();
 
 //I2C Slave의 주소를 바꿀 때 사용합니다.
 //이 때, ChangeAddress의 첫 번째 인자는 원래 주소, 두 번째 인자는 바꾸기를 원하는 주소를 입력합니다.
 //단, 첫 번째 인자의 경우 7비트로 전송해야 하므로 원래 주소 / 2 를 하여 전송하고
 //두 번째 인자의 경우 변경하기 원하는 주소를 그대로 입력해줍니다.
    //ChangeAddress(0xE0 / 2, 0xE2);
 
    //
    // We are finished.  Hang around doing nothing.
    //
    while (1) {
 
        //I2C를 통해 SRF10 초음파 거리측정 센서와 통신하여 거리를 측정합니다.
             //getI2CValue() 함수 사용시 인자는 측정을 원하는 센서의 주소를 입력합니다.
             //단, 7비트로 전송해야 하므로 원래주소 / 2 를 하여 전송합니다.
        var1 = getI2CValue(0xE0 / 2);
        var2 = getI2CValue(0xE2 / 2);
 
        UARTprintf("LEFT : %5d, RIGHT : %5d\r", var1, var2);
    }
}
 


참고 자료 : http://www.robot-electronics.co.uk/htm/srf10tech.htm

300x250

[CCS] The program generated is not compatible with any of the CPUs in your target configuration.

임베디드/TI 2014. 8. 28. 14:04

 Code Composer Studio를 활용하여 MCU를 실행하기 위해 프로젝트 파일을 디버그를 시도하려 할 때 이러한 경고 메시지가 뜨면서 작동이 되지 않는 경우기 있습니다.


 The program generated by "프로젝트명" is not compatible with any of the CPUs in your target configuration. The program will not be looaded.





 위의 경우를 해결하는 방법은 다음과 같습니다.



1. 해당 프로젝트에서 오른쪽 버튼을 누른 후 Properties -> General 메뉴로 들어가면 다음과 같은 화면을 보실 수 있습니다.



Main 탭에서 Connection 란이 비어있는 것을 확인하실 수 있습니다.


2. 설정되어 있지 않은 Connection을 클릭하신 후 MCU와 USB 사이에 연결하는 방식을 설정합니다.

Tiva 시리즈의 경우 "Stellaris In-Circuit Debug Interface"를 선택하시면 되겠습니다.



다음과 같이 설정하신 후 디버그를 시도하면 프로그램이 정상적으로 동작됨을 확인하실 수 있습니다.


참고 : http://e2e.ti.com/support/development_tools/code_composer_studio/f/81/t/319982.aspx

300x250

[Tiva] TM4C MCU와 ECHO UART 통신

임베디드/TI 2014. 8. 27. 21:30

 Tiva MCU를 활용하여 UART의 RX와 TX의 동작을 간단하게 확인할 수 있는 코드입니다.

 MCU가 키보드로부터 입력받은 값을 다시 TX로 출력하는 코드입니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
 
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
void ConfigureUART(void) {
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
 
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
 
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    UARTStdioConfig(0, 115200, 16000000);
}
 
int main(void) {
    unsigned char getChar;
    ROM_FPULazyStackingEnable();
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
    SYSCTL_OSC_MAIN);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
 
    ConfigureUART();
    while (1) {
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
        SysCtlDelay(SysCtlClockGet() / 10 / 3);
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
        SysCtlDelay(SysCtlClockGet() / 10 / 3);
 
        getChar = UARTCharGet(UART0_BASE);
        if(getChar=='\r'){
            UARTCharPut(UART0_BASE, '\n');
            UARTCharPut(UART0_BASE, '\r');
        }else{
            UARTCharPut(UART0_BASE, getChar);
        }
    }
}



 위의 코드를 적용한 후 Port 통신을 실행하여 키보드로 값을 입력하면 그 값을 그대로 컴퓨터로 다시 전송하여 값을 출력한다.




300x250

[Tiva] I2CMasterDataGet()

임베디드/TI 2014. 8. 26. 00:23

 uint32_t I2CMasterDataGet(uint32_t ui32Base)

 설명 : I2C 통신을 통해 Slave로부터 받아온 값을 return값으로 받습니다.


 uint32_t ui32Base

 Slave와 통신을 했던 I2C의 Base Address를 설정합니다.


 위 함수를 사용하기 위해 I2CMasterControl() 함수를 사용하에 Slave로부터 값을 받아야 합니다.


 다음은 위의 함수를 실행하기 위한 코드와 그 결과입니다.



unsigned int rcv = 0;

ROM_I2CMasterSlaveAddrSet(I2C0_BASE, 0xE0 / 2, true);

ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

rcv = ROM_I2CMasterDataGet(I2C0_BASE);


while (ROM_I2CMasterBusy(I2C0_BASE)) {


}



① : START

② : Slave address
7비트로 전송된 Slave의 address값은 7비트이므로 0xE0 / 2 입니다.

③ : R/S
HIGH 상태이므로 SLAVE로부터 DATA를 전달받게 됩니다.

④ : ACK

⑤ : DATA
Slave로부터 DATA를 전달받습니다. 전달받게된 DATA의 값은 0x00입니다.

⑥ : ACK

⑦ : STOP


300x250