티스토리 뷰
직비 칩에서 시리얼 통신 코드 구현에 관하여
자꾸만 잊어버리는 건망증에 대비하여 이 글을 남긴다. 내공이 부족하여 오류가 있음을 충분히 감안하고 보아야 할 것이다. (뭐냐 이 대책 없는 무모함은 ㅡ..ㅡ) 어쨌든 이 포스팅에서는 cc2530의 UART 설정 방법에 대해 살펴보고자 한다. 본 포스팅을 읽기 전에 CC2530에서 UART가 어떻게 동작하는가에 대한 기본 이해를 돕는 Design Note DN112를 먼저 읽어볼 것을 추천한다.
기본적인 준비는 되었겠지?
cc2530 개발환경과 TIMAC이 잘 준비된 상태라고 가정한다. 안 되어있으면 그것부터 해놓자. 이 부분도 좀 삽질을 해야하지만 그것까지 적으려니 좀 귀찮다. 언제 시간 날때 정리하도록 하자. 자~ 그럼 UART를 사용하기 위해 다음의 과정을 밟아가 보자.
preprocessor 옵션
먼저 UART 옵션들을 설정한다. UART를 사용하기 위해 프로젝트 옵션의 C/C++ Compiler 항목의 Preprocessor의 Defined symbols에 몇 가지 항목을 추가 혹은 수정한다. HAL_UART = TRUE로 넣고 POWER_SAVING은 xPOWER_SAVING로 변경하자. hal_board_cfg.h에 관련 옵션들이 나오는데 내가 쓴 옵션은 다음과 같다. 처음 하드웨어 환경 설정할 때 hal_board_cfg.h의 전 부분을 꼼꼼히 설정했다면 아래 부분들이 제대로 맞춰져 있을것이다.
HAL_UART = TRUE
인터럽트를 사용하는 경우 : HAL_UART_ISR = ( 1 또는 2 ), HAL_UART_DMA = FALSE
* HAL_UART_ISR = 1 ( UART 0을 사용 ), HAL_UART_ISR = 2 ( UART 1을 사용 )
DMA를 사용하는 경우 : HAL_UART_ISR = 0, HAL_UART_DMA = (1 또는 2 )
UART 초기화
애플리케이션이 시작되면 UART 관련 초기화를 하고 콜백함수도 맹글어 준다. 참고로 printf에서 0x0d(\r)는 커서 제일 앞으로, 0x0a(\n)는 줄바꿈이다. 가끔 생각이 안나서 적어놓는다. ㅡ..ㅡ);;;
//UART test variable uint8 *rxBuffer; uint8 rxBufferIndex = 0; static void uartCallback(uint8 port, uint8 event) { uint16 len; uint8 buf[8]; uint8 i; switch(event) { case HAL_UART_RX_FULL: case HAL_UART_RX_ABOUT_FULL: case HAL_UART_RX_TIMEOUT: len = Hal_UART_RxBufLen(HAL_UART_PORT_0); HalUARTRead(HAL_UART_PORT_0, buf, len); for(i = 0; i < len; i++) { //in this application, all lines sent to CC2540 ends with a carriage return (0x0D) if(buf[i] != 0x0D) rxBuffer[rxBufferIndex++] = buf[i]; printf("%c", buf[i]); // echo else { //processBuffer(); //do stuff with rxBuffer using rxBufferIndex as the length of the rxBuffer rxBuffer[rxBufferIndex] = 0; printf("\r\n%s\r\n", rxBuffer); memset(rxBuffer, 0x00, sizeof(rxBuffer)); rxBufferIndex = 0; break; } } break; } } static void setupUART(void) { //HalUARTInit(); halUARTCfg_t uartConfig; // configure UART uartConfig.configured = TRUE; uartConfig.baudRate = HAL_UART_BR_115200; uartConfig.flowControl = HAL_UART_FLOW_OFF; uartConfig.flowControlThreshold = 0; uartConfig.rx.maxBufSize = 128; uartConfig.tx.maxBufSize = 128; uartConfig.idleTimeout = 1; //1ms timeout uartConfig.intEnable = TRUE; uartConfig.callBackFunc = (halUARTCBack_t)uartCallback; //start UART //assumes no issues with starting UART (void)HalUARTOpen(HAL_UART_PORT_0, &uartConfig); rxBuffer = osal_mem_alloc(128); //assumes there is no problem with getting this block of memory }
memset함수 때문에 헤더에 #include
setupUART는 어디에 두어야 할까?
setupUART는 다른 모든 초기화가 끝난 이후에 맹글은 본인의 애플리케이션의 Init() 함수 내에 위치시키도록 한다.
UART 상에 printf 구현하기
oPossum’s tiny printf()를 기초로한 printf 샘플이다. 이걸로 UART상에서 손쉽게 데이터를 전송하는 디버깅 코드를 구현할 수 있다. printf.c 라고 대략 이름을 붙여줬다. 싫으면 다른 이름도 괜찮겠지.. 그런데 머리가 굳어서인지 다른 이름은 생각나지 않네. 흠..
#include "stdarg.h" #include "hal_uart.h" #include#include "hal_types.h" void printf(char *format, ...); static void sendByte(unsigned char byte) { HalUARTWrite(HAL_UART_PORT_0, &byte, 1); //change port to suit your needs } static void putc(unsigned char c) { sendByte(c); } static void puts(uint8 *str) { HalUARTWrite(HAL_UART_PORT_0, str, strlen((const char*)str)); //change port to suit your needs } static const unsigned long dv[] = { // 4294967296 // 32 bit unsigned max 1000000000,// +0 100000000, // +1 10000000, // +2 1000000, // +3 100000, // +4 // 65535 // 16 bit unsigned max 10000, // +5 1000, // +6 100, // +7 10, // +8 1, // +9 }; static void xtoa(unsigned long x, const unsigned long *dp) { char c; unsigned long d; if (x) { while (x < *dp) ++dp; do { d = *dp++; c = '0'; while (x >= d) ++c, x -= d; putc(c); } while (!(d & 1)); } else putc('0'); } static void puth(unsigned n) { static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; putc(hex[n & 15]); } void printf(char *format, ...) { char c; int i; long n; va_list a; va_start(a, format); while(c = *format++) { if(c == '%') { switch(c = *format++) { case 's': // String puts(va_arg(a, char*)); break; case 'c':// Char putc(va_arg(a, char)); break; case 'i':// 16 bit Integer case 'u':// 16 bit Unsigned i = va_arg(a, int); if(c == 'i' && i < 0) i = -i, putc('-'); xtoa((unsigned)i, dv + 5); break; case 'l':// 32 bit Long case 'n':// 32 bit uNsigned loNg n = va_arg(a, long); if(c == 'l' && n < 0) n = -n, putc('-'); xtoa((unsigned long)n, dv); break; case 'x':// 16 bit heXadecimal i = va_arg(a, int); puth(i >> 12); puth(i >> 8); puth(i >> 4); puth(i); break; case 0: return; default: goto bad_fmt; } } else bad_fmt: putc(c); } va_end(a); }
extern void printf(char *format, ...); 코드를 사용하고자 하는 애플리케이션 헤더에 추가해서 사용토록 하자.
더 해볼것들
앞서 이야기 했다시피 이 코드는 인터럽트를 썼다. DMA를 이용해서 사용하는 것도 해보자. 끝.
- Total
- Today
- Yesterday
- Ai
- 소니 AXP35
- CSS
- 박근혜
- 서평
- 오블완
- 팅크웨어
- 블로그
- 캠코더
- c언어
- SM5
- 한빛미디어
- 독후감
- 아이나비 태블릿
- 아이나비 Tab XD9
- 소니 핸디캠
- 티스토리
- qxd1000a
- 소니 캠코더
- 아이나비 패드
- 아이나비 탭 xd9
- 티스토리챌린지
- 소니
- 아이나비
- 독서
- X1 DASH
- Sony
- AXP35
- 아이나비 탭 XD11 Pro
- 블랙박스
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |