7월22일 arm(직렬 통신)
2010. 7. 22. 10:41ㆍ2010년/7월
시리얼 통신에 대한내용이다 사실 너무 어렵다 ㅠ
일단 통신에 기본은 바로 Rx와 Tx에 대한 내용이다
순서대로 설명하자면 바로 이것이다
1. RCC 통해 Rx Tx 포트 열기 USART1 열기
2. Rx Tx를 input output 설정(arm입장에서 전송이 output 수신이 input이다)
3. USART의 통신설정하기 ( 전송속도, 패리티, 데이터비트 정지비트 흐름제어)
4. 전송하기
5. 잘전송되었나 확인하기
언제나 늘 사용하는 RCC이다
자 회로도를 보게 되면 UART1과 UART2가있다. 일단 UART1를 통해서 사용하며
PORTA에 연결되어있음 알수있다. 그것도 PA9와 PA10에 대해서
그렇기 때문에 RCC에서 PORTA와 USART1를 열어야한다.
당연히 RCC 주소인 0x4002 1018에서 USART1EN 과 IOPAEN 에 값을 1을 지정하면
본격적으로 사용할수가 있다.
그리고 다시 PORTA를 보자
회로도에서 본것처럼 TX가 PA9이고 RX가 PA10이다.
자이 이제 TX는 당연히 output모드 Rx는 intput모드로 해야한다.
Tx는 output이기때문에 당연히 MODE9에 00이 아닌 01 이나 10 11 을 넣어서 output mode로 설정해야한다 그리고 CNF10에 값을 넣어야하는데 00이면 일반적인 output이고 alternate function은 대충 변화되는 내용을 output인데 사실 저것을 보고 00으로 했다가 당연히... 깜깜무소식에 ㅠ 울다가 10을 통해서 Alternate function을 사용했다 사실... 영어실력이 떨어져서 겨우겨우 해석하면서 하는데 어렵긴하다.
사실 그안에 내용은 전부 메뉴얼에 나와있다 못찾아서 -_-;;; 그렇지
사실 메뉴얼에서 몇쪽만 올라가게되면 바로 USART를 사용할때 RX와 TX의 사용법에대해서 나와있다. 당연히 전이중통신이므로 RX에서는 입력모드의 input floation을 사용하고 TX에서 Alternate function push-pull을 사용하게 한다.
그래서 (*(volatile unsigned *)0x40010804) 값에 0x4B를넣게 되면 제대로 RX와 TX에서값이 들어가게된다.(이거찾는동안 고생했다 ㅠㅠ)
자 이제 PORTA에 대한 설정이 모두 끝이 났다. 하지만
더어려운 USART1에 대한 통신 프로토콜 설정이 남아있다.
메모리 맵을 보게 되면 0x4001 3800 에서 부터 USART1에 대한 내용이 다있다.
그리고 USART에 대한 register map 대한 내용이다 일단 기본적으로 빨간색을 밑줄을 친 4개가 제일 필요하다 주요구성요소는 하나하나 다알려면 어렵기때문에 엑기스만 쪼옥 뽑아서 사용해 본다.
USART에 대한 register 레지스터에 대해서 알아보자
일단 USART에 처음부터 여러 레지스터가 있지만 가장 기본인 Status resigter이다
이것은 바로 USART에서 시리얼통신에 관한 상태를 읽을수가 있다 여기 값은 전부다 R값이다 그렇기때문에 자동으로 변화하는 값이라고 보면된다. 빨간색을 칠한 TXE인 7번째 비트는 대한 내용은
바로 전송한 데이터 다보냈느지 비었는지를 확인할수 있다. 그래서 1인경우 비었다는 것이다.
그래서 flag상태라든지 error가 떳는지등의 상태를 알수 있다 그래서 나중에 전송후에 전송하는 버퍼가 0이 되었는가에대한 확인을 TXE에서 한다.
다은 Data register이다 사실 여기에 data를 저장하고 전송한다고 보면된다 한번 전송단위가 8비트이다 그래서 총 9비트로 이루어져있다 이는 제일 앞 비트가 바로 시작비트인 USART_CR1에서 PCE값에 따라서 자동으로 들어간다고 보면된다. 그래서 제일 앞 비트를 뺀 나머지 8비트에 데이터를 넣게 되면 전송이 하고 한후에 전송이 완료되었거나 이 버퍼가 비어있을경우 위 USART_SR에 TXE와 TC에 값이 변하게 된다.
다음은 USART_BRR인데 이것은 제일 마지막에 설명하겠다. (제일어려움 ㅠ)
다음은 Control register 1 USART CR1에 대한 내용이다.
말그대로 동작관련에 대한 내용이 나와있다 실질적으로 사용하는것은 UE, M PCE,PS,TE,RE이다.
나머지도 중요하지만 시리얼통신에 대한 설정은 저 곳에서 할수있다.
아까 다한것 같지만 USART enabled 슬프게도 여기서도 만져줘야한다 물론 presclaers and outputs가 default이므로 1을 넣어줘야한다.
그리고 M:Word length 뭐 보다시피우리가 사용하는 1시작 비트에 8데이터비트 그리고 n Stop bit를 설정이다 뭐 이것은 보다시 당연히 8비트씩 전송하고 시작비트는 1이며 설정한다 default가 0이기때문에 이런게 있다고 봐두면된다.
자 다음은 패리티 비트에 설정이다
뭐사실 패리티 비스에 설정인데 알다시피 짝수나 홀수도 할수도 있지만 우린 사용안하게 해버렸다 그래서 당연히 PCE에 0이고 PS는 자동으로 안쓰게 된다.
자 다음은 다시 전송과 수신 설정이다
전송은 설정하고 이는 클락이나 전송하는 속도가틀리 때문에 약간 동기화 느낌도 있다.
그리고 수신같은경우 받을때 시작비트른 검색하는거나 대해서 이기때문에 역시 enabled 되어야한다.
보다 보니깐 너무 내용이 어렵고 많기도 하다.
그리고 통신설정에 제일 마지막인 stop bit에 대한 설정이 있는 USART_CR2이다
우리가 사용하는 STOP bits는 1이다 그래서 저값이 00을 넣으면 되는데 기본이 00이기때문에 값을 안넣어도 된다. 하지만 어디에 무엇이 있고 어떻게 사용하는건지 알아둬야 나중에 기억할수 있다. 이로써 시리얼 통신에 대한 설정이 끝이다 (이후 BRR 설명... 전송속도)
우습게도 CR1,CR2,CR3 ,Guard time and prescaler register 까지 여러가지 설정이들이 많다 하지만 전부다 설명하게 되면 어렵고 영어실력에 아쉬움으로 여기까지 찾아낸것이 대견하다 ㅠㅠ 물론 약간 빠진내용도 있지만 통신설정에 가장중요한 속도,시작비트, 패러티비트, 정지비트 대한 설정 그리고 수신송신 설정 송신 버퍼상태확인등 으로 통신에 기본이 알수있다.
자다음은 아까부터 계속 미루어온 BRR 즉 통신 속도에 관한 내용이다.
뭐 사실 BRR하면 생소해보지만 우리가 전송속도를 맞출때 115200이라는 속도 즉 bps로 맞추게 된다.
그것을 Baud rate 로 바꾸게 되면 좀 절차나 모든면이 아주 까다롭다. 단지 16비트라는 공간에서 속도를 넣기도 힘들다. 최고 65536밖에 되지않고 ARM과 일반 컴퓨터사이의 CPU에대한 클럭속도도 전부 확연하게 차이가 나게 된다 그래서 BRR을 지수부 가수부로 나누게 된다. 뜬금없이 지수부 가수부로 나누니깐 어려운데 이것은 BRR로 바꾸는 과정에서 ARM에 속도에 따라서 clock속도와 전송에 대한 오류율을 최소화시키고(전송햇는데 오류가 10%만되어도 그것은 쓰레기통신....)
내용을 보게되면 사실 어렵다. 뭐 사실 오류율을 약간 네트워크통신의 개념도 있긴하다.
자 기본 공식이다 fck/16*USARTDIV 참 보기에 생소하고 어렵다.. 뭐 사실 이것보고 이해한다면 그사람은 천재일지도 모른다 바로 수학적 공식에 느낌도 가능하다
USARTDIV 구하기
일단 fck는 8Mhz이기때문에 8000000 입니다 그리고 16*115200(전송속도) 를 하게 되면 기본적인 값이
4.3402777778 이라는값이 나온다. 간단하다 앞에 4를 넣고 뒤에 3402777778을 넣으면 끝이다 하지만 이것을 프로그램적으로 설명해서 나타내게 되면 일단 4를 먼저 빼내야한다. 그것은 간단하다 그냥 일단 100을 곱한후에 100을 나누어서 나머지를 버리면 된다. 그리고 지수에 넣어야하기때문에 <<4를 shift하게 되면 바로 지수부에 넣을 4가 나온다.. 다음은 가수부에 넣어야할 값인데 뒷자리는 조금 빼고 0.340인데 아까 구한 100을 곱한부분에서 434가 나왓다. 거기서 가수부인 34을 빼낸다 그리고
가수부에 값인 34을 저장하기위해서 16을 곱하게 된다. 이는 16*USARTDIV이기때문에 미리 곱해둔다 뭐 구한후에 나중에 곱해도 상관없지만. 이미 지수부는 <<4를 했기때무네 16을 곱햇고 이제 가수부를 곱하면 된다. 그래서 34에서 16을 곱하고면 544가 나온다.. 컴퓨터에서 일정이상 크기 빼고는 반올림을 해야하는데 반올림의 기본은 그냥 50을 더하면된다. 그러면 594가 되고 아까 제일처음에 구할때 4.340을 100을 곱했기때문에 다시 100으로 나누게 되면.. 5가 남고 그것이 가수부에 넣게 된다.
사실 4.340 를 4따로 16을 곱하고 0.34를 따로 16을 곱하면 그냥 64 +5.44 가 나오기때문에.. 64를에 값을 넣고 5를 값을 넣게 되면... 간단하다 11520같은경우 0x45라는 값이 나오게된다.~!
예제로 9600을 구하게 되면..
52.0833 정도 나오는데 52를 따로때고
0.833을 따로 뺀후 16을 곱하고 구하면.. 값이 나온다...
/*---------------------------- USART BRR Configuration -----------------------*/
/* Configure the USART Baud Rate -------------------------------------------*/
/* Determine the integer part */
integerdivider = ((0x19 * apbclock) / (0x04 * (USART_InitStruct->USART_BaudRate)));
// integerdivider = 0x19 * 8000000 = 200,000,000 / 0x04 * 115200 = 460800 //19는 오류율
// 200,000,000 / 460,800 = 434
// integerdivider = 0x0000 01B2
tmpreg = (integerdivider / 0x64) << 0x04;
// 0x01B2/0x64 << 0x04;
// 0x04 << 0x04 = 0b 0000 0000 0000 0100 << 4; //16을 곱함, 지수부 구함
// 0b 0000 0000 0100 0000;
/* Determine the fractional part */
fractionaldivider = integerdivider - (0x64 * (tmpreg >> 0x04)); //가수부분리
//fractionaldivider = 0x01B2 - (0x64 * (tmpreg >> 0x04));
//0x1B2 - (0x64 * 0b0000 0000 0000 0100)
//0x0000 01B2 - 0x0000 0190
//0x22
tmpreg |= ((((fractionaldivider * 0x10) + 0x32) / 0x64)) & ((uint8_t)0x0F); //0x10은 16을 곱한것
//tmpreg |= ((0x220+0x32)/64)&0x0F
//tmpreg |= 0x05 & 0x0F
// tmpreg |= 0x05
// 0x45
/* Write to USART BRR */
USARTx->BRR = (uint16_t)tmpreg;
그에 대한 소스코드 설명인데... 뭐 사실.. 어렵게 보면 어렵고 쉽게 보면 쉽다.!
USART에 대한 설명이 모두 끝이 났다.
그럼 본격적으로 프로그램을 만들어서 보자
#define RCC_APB2 (*(volatile unsigned*)0x40021018)
#define PORTA_H (*(volatile unsigned*)0x40010804)
#define PORTB_H (*(volatile unsigned*)0x40010C04)
#define USART_SR (*(volatile unsigned*)0x40013800)
#define USART_DR (*(volatile unsigned*)0x40013804)
#define USART_BRR (*(volatile unsigned*)0x40013808)
#define USART_CR1 (*(volatile unsigned*)0x4001380C)
static void delay(volatile double a)
{
for(;a>0;--a)
{
;
}
}
int R(){
if((USART_SR&0x80)!=0){ //USART_SR TXE의 값이 1 이면 전송버퍼가 비었기에
return 0; //값을 0리턴
}
else
{
return 1; //아니면 1을 리턴해서 무한 반복문형성
}
}
void Uart_send_byte(unsigned char byte)
{
USART_DR=byte; //전송할 8비트(문자)를 DR에넣고
while(R());
}
void Uart_send_String(unsigned char *buf)
{
while(*buf!='\0') //들어온 buf값이 마지막이 아닐때까지... 반복문
{
Uart_send_byte(*buf); //들어온 문자열을 8비트단위전송하기위해서 값을 보냄
buf++; //char기때문에 1바이트씩 이동
}
}
int main(void)
{
RCC_APB2=0x4004|0x8; //PORTA, USART1 enable
PORTA_H =0x4B0; //PA9 CNF9 10 MODE9 11 PA10 CNF10 10 MODE10 00
USART_BRR =0x45; //BRR 계산식
USART_CR1=0x200C; // UE=1 TE=1 RE=1
while(1)
{
Uart_send_String("Hello\r\n"); //전송
delay(30000);
}
}
===================================================
while(R());
사실 이부분에서 함수로 구현햇는데 그냥 무한 반복문에서 while(1)
USART_SR의 0x80 즉 TXE의 값이 1이 변할때까지 기다렸다가 다시 전송하고
무한반복문이 1이 변할때까지 도는거였는데... 생각보다 구현이 안되어서
함수로 했는데 되었다. 망할 이제 직렬통신에 뭔가좀 가닥이 잡히는데
송신했으니깐 수신해서... LED와 FND를 만져볼까 생각중이다 ㅠ
'2010년 > 7월' 카테고리의 다른 글
7월23일 JAVA(채팅) (0) | 2010.07.23 |
---|---|
7월21일 JAVA(동기화) ARM(7-segment,USART1) (0) | 2010.07.21 |
7월20일 JAVA(Thread),ARM( (0) | 2010.07.20 |
7월19일 Mango-m32(7-segment) java(FileInputStrem,문자스트림) (0) | 2010.07.19 |
7월16일 Mango-M32(LED 켜기,7-segment) (0) | 2010.07.16 |