Cortex-M3 LM8962의 경우 적절한 가이드북이 아직 없더군요. 그런 경우 뭐 예제를 분석해보는 수 밖에요. 일단 복적은 제목에도 나와있지만, 일정시간간격(Timer Interrupt)을 가지고 엔코더를 해석해서 그 결과를 시리얼통신으로 전송하는 걸로 하겠습니다. 이미 myCortexM3 LM8962보드를 설치해서 사용하신 분들이라면 딱 예제3개를 한 덩어리로 묶었구만뭐~~ 하시겠지만, 사실 예제를 그대로 파는건 별로 재미없으니까 그냥 한번 합쳐본것도 있구요. 또 제가 수행할려고하는 목표가 딱 위 예제 3개에를 합쳐서 출발해야하기도 하거든요... 그런데, 물론 제가 다뤄봤다던지 공부했다는 프로세서가 얼마안되지만, (80c196, AVR, DSP2812) 이 CortexM3의 예제는 뭐라할까 좀 어색하더군요.... 음.. 역시 어색하다는 말이 맞는듯합니다. 일단 제가 (만든건 아니고, 수정했다고 하기도 좀 민망한) 편집한 예제에서 main문을 보시면
int main(void) { SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ); InitTIMERINT(); InitUART(); InitQEI(); // Loop Start. while(1) { } }
그래서 예제폴더의 인클루드된 헤더화일들을 찾아보니 있긴 하더군요...
저렇게...
저렇게 인자들은 찾았습니다. 뭐 주석만 봐도 대충이해되긴 하더군요. 그러나 정작 SysCtlClockSet 저게 하는 일이 코딩된 부분은 없더군요. 그래도 또 찾아봤는데요. API라는 저 글자...
마이크로프로세서가 진화 하면서 같이 변화된 것이 있다. 8비트 MPU에서 데이터시트를 보고 비트 제어를 하는 원시적인 코딩을 주로 했다면 32비트 특히 Cortex-M3로 오면서 전달 인수와 리턴값과 변수, define 정의 등을 요약해 놓은 API(Application Program Interface)를 이용하여 프로그램 하는 것으로 바뀌었다. 제공된 API는 데이터 시트를 일일이 분석하여 코딩 하지 않아도 하드웨어 제어에 손쉽게 입문 할 수 있으며 코딩 적응을 빠르게 하는 장점이 있다. 또한 PC에서 운영되었던 C/C++ 언어로 프로그램 수정을 극히 적게 하여 Cortex-M3 알고리듬으로 옮겨 올 수 있다.
ARM Processor의 특성 및 최신동향 08.11.14. 디지털 파워. 김형태 발췌
음.. API는 저런거인 모양입니다. 뭐 편하다고 하니(사실 잘 모르겠지만, 그냥 사용하지요. 틈틈히 그 의미를 공부해야겠습니다.) 일단 아까 그 메인문에서 시스템클럭을 8Mhz로 설정하고 -ㅎ~ 여기서 또 의문이 하나 생기긴 했습니다. Withrobot이 제공하는 설명서에는 50MHz로 동작한다고 되어있거든요. 그런데 왜 클럭은 8MHz일까요?... 2분주, 4분주 등등을 해도 50MHz로는 안가지 않습니까?^^ ㅎ... 모르는게 너무 많습니다... 쩝... 그리고 나서 타이머인터럽트와 시리얼통신, 엔코더해석부분을 초기화시키는 부분이 필요할 것입니다.
static void InitTIMERINT(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); TimerConfigure( TIMER0_BASE, TIMER_CFG_32_BIT_PER ); TimerLoadSet( TIMER0_BASE, TIMER_A, SysCtlClockGet() / 100 ); // 10ms TimerIntRegister( TIMER0_BASE, TIMER_A, TimerIntHandler ); IntMasterEnable(); TimerIntEnable( TIMER0_BASE, TIMER_TIMA_TIMEOUT ); TimerEnable( TIMER0_BASE, TIMER_A ); }
근데 희한하게 하드웨어 설정은 뭐 잘 모르겠지만, 해석은 또 대충되긴합니다. 일단 5번줄의 끝부분에 있는 숫자 '100'은 1/100의 시간 즉 10ms의 시간마다 인터럽트가 걸리도록 설정한 겁니다. 그리고, 그 인터럽트가 걸렸을때 수행할 함수가 6번줄 끝의 TimerIntHander로 설정되어있습니다.
다음으로 시리얼통신부분을 초기화합니다.
static void InitUART(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); }
6번줄의 115200이 Baud Rate를 맞춰준 부분입니다. 뭐 8비트고 어쩌고하는 설정도 있네요. 5번줄은 Withrobot의 설명서에 있는 회로도를 보면 시리얼통신의 Tx/Rx핀이 PA0/PA1에 연결되어있습니다. 아마 그걸 설정하는 듯합니다.
그 다음... 엔코더를 해석한다는 QEI설정이 필요하겠네요.
static void InitQEI(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); GPIOPinTypeQEI(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_6); QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), 0xffffffff); QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, SysCtlClockGet() / 100); QEIEnable(QEI0_BASE); QEIVelocityEnable(QEI0_BASE); }
위 내용에서 엔코더의 A,B상은 PC4, PC6번 핀에 연결되도록하고, 4분주해서 사용한다는 말도 확인이 됩니다. 또한 엔코더에서 들어온 카운터값 뿐만 아니라 방향과 속도성분까지 주어진다는 설정도 확인할수있습니다.
위의 3개의 초기화코드를 보더라도 사실 포기(^^)하고 그냥 사용하겠다고 생각하면 뭐 편해보입니다. 게으름에 대한 변명입니다...ㅜ.ㅜ 이제 타이머인터럽트가 걸리면 수행할 TimerIntHandler 구문을 보겠습니다.
static void TimerIntHandler(void) { unsigned long vel, pos; long dir; char buffer[BUFFER_LEN]; // Clear interrupt flag TimerIntClear( TIMER0_BASE, TIMER_TIMA_TIMEOUT ); dir = QEIDirectionGet(QEI0_BASE); vel = QEIVelocityGet(QEI0_BASE); pos = QEIPositionGet(QEI0_BASE); usnprintf(buffer, BUFFER_LEN, "%d, %d, %d; \n", dir, vel, pos); buffer[BUFFER_LEN - 1] = 0; UARTPutString(buffer); }
음 위 코드에서는 방향(dir), 속도(vel), 위치(pos)를 시리얼로 보내는 것입니다. 13번행에 있는 데로 구성한 이유는 제가 데이터를 받아서 처리할 PC쪽 프로그램이 MATLAB이라서 그렇습니다. 받을 때부터 (Data1, Data2, Data3;) 의 형태로 받으면 아주 편하거든요.
저렇게 꾸몄습니다. JTAG부분의 선이 짧더군요..ㅜ.ㅜ... 그래서 중간에 선을 좀 더 길게 할려고했는데 때마침 제 주위에 저 커넥터가 없더군요.. 그래서 저런 좀 지저분한 작업을 했습니다. 그리고, 전원공급장치로는
그리고 test = load('123.txt'); 라고 명령어를 주면
test = load('123.txt'); ts = 0.01; scaleEnc = 360/2000; test = [test(:,1), [test(:,2), test(:,3)]*scaleEnc]; [sizeTest, temp] = size(test); t = [0:ts:ts*(sizeTest-1)]'; figure plot(t,test(:,3)) grid on hold on xlabel('s (Second)'); ylabel('degree / degree per sencond'); plot(t,test(:,2).*test(:,1)/ts,'r') plot(t,[0; diff(test(:,3))/ts],'c')
나머진 그렸네요^^
아래는 프로세서쪽 전체 코드입니다.
//***************************************************************************** // // Withrobot에서 배포하는 엔코더 테스트화일에 시리얼 통신 예제와 타이머 인터럽트 사용예를 // 통합해서 PinkWink가 수정함. 2009.06.04 // // 일정 시간간격(Sampling Time)으로 엔코더에서 해석한 방향, 속도, 위치값 을 // 시리얼 통신으로 전송함. // //***************************************************************************** #include "../../../hw_types.h" #include "../../../hw_memmap.h" #include "sysctl.h" #include "gpio.h" #include "uart.h" #include "qei.h" #include "ustdlib.h" #include "timer.h" #include "interrupt.h" #ifdef DEBUG void __error__(char *pcFilename, unsigned long ulLine) { } #endif #define BUFFER_LEN 32 static void UARTPutString(char * str); static void InitTIMERINT(void); static void InitUART(void); static void InitQEI(void); static void TimerIntHandler(void); int main(void) { SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ); InitTIMERINT(); InitUART(); InitQEI(); // Loop Start. while(1) { } } static void TimerIntHandler(void) { unsigned long vel, pos; long dir; char buffer[BUFFER_LEN]; // Clear interrupt flag TimerIntClear( TIMER0_BASE, TIMER_TIMA_TIMEOUT ); dir = QEIDirectionGet(QEI0_BASE); vel = QEIVelocityGet(QEI0_BASE); pos = QEIPositionGet(QEI0_BASE); usnprintf(buffer, BUFFER_LEN, "%d, %d, %d; \n", dir, vel, pos); buffer[BUFFER_LEN - 1] = 0; UARTPutString(buffer); } static void UARTPutString(char * str) { while(*str) UARTCharPut(UART0_BASE, *str++); } static void InitTIMERINT(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); TimerConfigure( TIMER0_BASE, TIMER_CFG_32_BIT_PER ); TimerLoadSet( TIMER0_BASE, TIMER_A, SysCtlClockGet() / 100 ); // 10ms TimerIntRegister( TIMER0_BASE, TIMER_A, TimerIntHandler ); IntMasterEnable(); TimerIntEnable( TIMER0_BASE, TIMER_TIMA_TIMEOUT ); TimerEnable( TIMER0_BASE, TIMER_A ); } static void InitUART(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); } static void InitQEI(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); GPIOPinTypeQEI(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_6); QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), 0xffffffff); QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, SysCtlClockGet() / 100); QEIEnable(QEI0_BASE); QEIVelocityEnable(QEI0_BASE); }
'Hardware > MCU' 카테고리의 다른 글
[28335] TI 공식 홈페이지에서 28335용 예제와 라이브러리를 다운받자 - controlSUITE - (6) | 2016.04.27 |
---|---|
[28335] Code Composer Studio (CCS) V6에서 28335 프로젝트 시작해보기 (20) | 2016.04.22 |
DC 모터의 모션(서보)제어 (Servo Control - Motion Control) (68) | 2011.07.06 |
[Cortex M3] 단순 시리얼통신 테스트 ComPortMaster (4) | 2009.06.04 |
Cortex M3 LM8962 왕초보 설치기.... 헉헉 (10) | 2009.05.29 |
WinARM에서 작업폴더 바꾸기 (0) | 2009.05.01 |
ARM7과 텍스트형 LCD (0) | 2009.04.15 |