embeded/AVR (ATmega,ATtiny)2009. 10. 28. 00:02

ATMega128의 데이터 시트에 나와있는, IO핀 연결 방법이다.
Pxn내부에는 다이오드와 캐패시터가 달려있고,
외부에는 풀업 저항을 달아주면 된다고 나와 있는데..

실제로 키트에다가 VCC - 스위치 - 풀업저항 - 핀 으로 연결하니
손이 근처에만 가도 눌린것 처럼 인식을 하는데.. 아마 안테나 처럼 민감해져서 그런게 아닐까 싶다.

안정적으로 확실하게 하기 위해서는


이런식으로 구성을 해주면 누를때만 1이 되고 떼면 0 으로 인식하게 된다.

일단 PORTD와 PORTE가 외부 인터럽트로 사용이 가능한데,
PORTE의 0번과 1번 핀은 UART0로 사용되므로,
디버깅을 위해서 printf를 UART0으로 사용할 경우에는 PORTD를 사용하여 테스트를 해보도록 한다.



Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 10. 20. 22:27
#include "stdio.h"

static int uart_putchar(char c, FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
                                         _FDEV_SETUP_WRITE);

static int
uart_putchar(char c, FILE *stream)
{
  if (c == '\n')
    uart_putchar('\r', stream);
  loop_until_bit_is_set(UCSRA, UDRE);
  UDR = c;
  return 0;
}

int
main(void)
{
  init_uart();
  stdout = &mystdout;
  printf("Hello, world!\n");

  return 0;
}
winavr의 설명에 의하면 위의 예제가 printf를 사용하기 위한 초기화라고 나와있다.
(일단 설명서는 잘 읽어야 제맛)

위의 예제는 범용적인 것이고,
실제로 적용하기 위해서는 두부분을 수정해야 한다.

 loop_until_bit_is_set(UCSRA, UDRE);
 UDR = c;

초기화해준 포트에 따라서

UART0를 했다면 UCSR0A / UDR0
UART1을 했다면 UCSR1A / UDR1

로 수정을 해주면된다.


UDRE는 선언상, 비트플래그의 순서로 배열되어 있으므로
굳이 UDRE0 / UDRE1 로 수정해주지 않아도 이상은 없었다.

참고로 stdio.h를 포함하면 3KB 정도 크기가 증가한다(ELF 기준)
"사본"은 아래 소스에서 printf 관련을 전부 삭제한것이다.


atmega128 에서 uart0 를 115200-N-8-1로 16MHz 클럭에서 초기화한 뒤 printf() 하는 예제

Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 10. 16. 00:20
7 segment는 LED를 여러개 한것에 불과하다.

단지, 여러자리로 된 7 segment는
빠른 속도로 여러개를 돌아가면서 출력해야 하기 때문에
타이밍에 민감해져 어려워질 뿐이다.


세븐 세그먼트는 위의 순서대로 폰트를 생성하게 되는데,
어떻게 선을 연결하냐에 따라서 폰트 데이터가 달라지게 된다.

A가 LSB가 될지, MSB가 될지는 결정하기 나름이지만,
일반적으로는 A를 LSB로 쓰는듯 하다.

0번 핀에 A
1번 핀에 B
2번 핀에 C
3번 핀에 D
4번 핀에 E
5번 핀에 F
6번 핀에 G

이런식으로 연결을 한다.


위의 방법으로 세그먼트의 항목을 1로 쓰면 엑셀로 계산해서 10진수로 출력해주는 파일이다.

생성한 결과는 아래와 같다.
                                                    // 1,   2,   3,      4,     5,      6, 7,     8,     9,   0
 unsigned char numeric_font[] = {6, 91, 79, 102, 109, 125, 7, 127, 111, 63};

                                                    // 0,   1,   2,   3,      4,     5,      6, 7,     8,     9
 unsigned char numeric_font[] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111};



그리고 1개가 아닌 여러개의 세그먼트를 제어해야 할 경우에는
AVR에서 A~G + DP의 8bit를 하나의 포트에 연결해주고
다른 포트에 segment select 를 연결해서, Cathod 타입이나 Anode 타입에 따라서
0이나 1로 설정해주면 된다.

단, 이렇게 할경우, 2ms 단위로 4개를 돌리면 상당히 어두운 편이니,
5V를 별도로 TR로 연결해서 사용하는 것이 좋을듯 하다. (밝기가 상관없으면 그냥 연결해도 무방하다)

2ms 정도 되어야지 UART와 동시 사용해도 깜박임이 없었다.
3ms 부터는 7 segment 자체가 깜박이며, UART 입력시에 깜박임이 발생했다.
(UART 는 115200bps로 테스트, ATmega128 16Mhz)
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 10. 9. 11:21
오랫만에 winAVR을 판올림했는데 거의 1년 정도의 버전 차이가 있었다.
그것만으로는 별 문제가 없을줄 알았는데

이상하게 AVR Studio 에서 make 파일과 avr-gcc를 못찾겠다고 떼를 쓴다.
Build started 9.10.2009 at 11:17:02
Build failed... No build tools defined.

Loaded plugin STK500
Loaded plugin AVR GCC
Loaded partfile: C:\Program Files\Atmel\AVR Tools\PartDescriptionFiles\ATmega128.xml

하단의 메시지에는 이런식으로 plugin AVR GCC가 Loaded로 떠야 하는데,
plugin이 검색하지 못할 경우에는 Fail이 나게 되고, 이 플러그인은 레지스트리를 검색하는 것으로 보인다.


이런 경우에 확인을 해보니,
`HKEY_LOCAL_MACHINE\SOFTWARE\WinAVR\{VERSION}`
라는 레지스트리 키가 제대로 등록되어 있지 않아서 생기는 문제로 파악되었다.
(다른 부분에서도 등록되지만, 이 부분만 삭제되어 있었다.)

아마도 신버전을 먼저 설치하고, 구버전을 나중에 삭제하면서
위의 키를 삭제했기 때문에 발생한 문제라고 생각된다.

해결법으로는
1. winAVR을 삭제 후 재설치한다.
2. 위의 레지스트리값만 추가한다.

'embeded > AVR (ATmega,ATtiny)' 카테고리의 다른 글

avr 에서 printf 사용하기  (2) 2009.10.20
7 segment font  (4) 2009.10.16
winAVR outp/inp 매크로  (0) 2009.10.09
ATmega128 UART 에코 서버 만들기 (echo server)  (4) 2009.10.08
ATmega128 USART 사용하기  (0) 2009.10.07
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 10. 9. 10:59
outp() inp()는 매크로이다.
정확한 시기는 모르겠지만, winAVR-20050414 버전 이후 제외된 것으로 보인다.
물론 <compat/deprecated.h> 를 사용하면 호환되도록 작동은 가능할 것으로 보이지만,

문법적으로 깔끔하지 않고, 표준 C를 따르지 않는(이 부분은 좀 이해가 안됨) 이유로 인해서
불편함을 감수하고 위의 매크로가 제외되었다고 한다.

There was a discussion a while back on the avr-gcc mailing list.  Some
"old stuff" has been purged.  Some people are not happy about it.  But
the purged macros were non-standard, had confusing syntax and unclear
semantics, and had been deprecated for over two years, so (IMHO) the
maintainers were justified in purging them.

The quick fix for legacy code is to create a new header (e.g.
"legacy.h") that defines the purged macros for you.  E.g.,

   #define sbi(p,b) (p) |= (1<<(b))
   #define cbi(p,b) (p) &= ~(1<<(b))

etc.  Then #include "legacy.h" in legacy code as a stopgap measure to
get that code to compile with the new compiler.

And be sure to _NOT_ #include "legacy.h" in new code.

Regards,

                               -=Dave

[링크 : http://www.embeddedrelated.com/usenet/embedded/show/25084-1.php]


[링크 : http://winavr.sourceforge.net/]



20091022 추가>
outp(value, PORTn); 은
PORTn = valuel 로 사용하면 된다.

예를들어,
outp(0xff, PORTA); 는
PORTA = 0xff; 로 사용한다.
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 10. 8. 23:13
에코 서버라고 하니 먼가 거창한데,
간단하게 입력하면 그걸 그대로 돌려줘서 화면에 나타나게 하는 프로그램이다.
시리얼로 전송하면, 받는쪽에서 그 값을 돌려주지 않으면 터미널에서 그 값이 출력되지 않는다.
가장 간단하고, 확실한 테스트 방법이라서 일단 echo 하도록 하는데 먼가 험난했다 ㄱ-

아무튼 개인적으로 선호하는 115200bps - N - 8 - 1 로 설정하고, UART0를 통해 UART echo server를 만들어보자





오늘 필요한 녀석은
#include <avr/interrupt.h>

ISR(USART0_RX_vect)
{
    UDR0 = UDR0;
}
요렇게 두 부분이다.

위의 헤더는 ISR() 이라는 매크로를 사용하게 하는 것이고,
ISR은 Interrupt Serive Routine의 약자이다.

예전에는 SIGNAL(SIG_UART0_RECV) 로 사용했을 것이지만,
winAVR 버전이 올라가면서 ISR()로 바뀐 것으로 알고 있다. (물론 사용중인 버전이 20080610 버전으로 좀 오래됐다 ㅠ.ㅠ)

아무튼 USART0_RX_vect 라는 것은 iom128.h의 432 라인에 기술되어있다.
(iom128.h는 <avr/io.h>와 makefile의 cpu 선언에 의해서 자동으로 불려지는 파일이다)
/* USART0, Rx Complete */
#define USART0_RX_vect            _VECTOR(18)
#define SIG_USART0_RECV            _VECTOR(18)
#define SIG_UART0_RECV            _VECTOR(18)

시리얼포트 초기화시에는 당연히 UART RX 인터럽트를 사용하도록 설정을 해야하고,
전역 인터럽트를 사용하도록 해주어야 한다.

UART 인터럽트는 UCSR0A/B/C 레지스터로 조작을 해준다.
    /* for UART */
    /* "BaudRate" related setting */
    UBRR0H = 0;
    UBRR0L = 8; // 115k with U2X = 0
    UCSR0A = 0x00; // U2X = 0;

   /* "Interrupt" related setting */
    UCSR0B = 0x98;

   /* "Sync or Async mode - Parity - stop bits - data bits" related setting*/
    UCSR0C = 0x06; //Asyncronous - no parity - 1bits(stop) - 8bits(data)

UCSR0A  레지스터는 U2X0 를 제외하면 전부 Status Flag 이므로 U2X0를 사용하지 않는다면 0x00으로 설정한다.
UBBR0H 와 UBBR0L 은 BaudRate와 관련된 것으로, 클럭과 원하는 BaudRate에 따라 변하지만,
귀찮으면, 데이터 시트에 나와있는 값으로 입력을 하면된다. (위의 값은 계산하지 않고 그냥 데이터시트 값을 사용한 것이다)

그리고 U2X는 UCSR0A의 비트로, 에러율을 낮추기 위해 2배 속도로 샘플링하는 것이다.
(디바이더(Divider)의 값을 반으로 줄여, 샘플링을 자주해서 값을 놓치지 않도록 한다)

• Bit 1 – U2Xn: Double the USART Transmission Speed
This bit only has effect for the asynchronous operation. Write this bit to zero when using synchronous operation.
Writing this bit to one will reduce the divisor of the baud rate divider from 16 to 8 effectively doubling the transfer rate for asynchronous communication.

UCSR0B  레지스터의 98 값은 인터럽트 관련 설정값이다.
일단 Bit 5를 set 하게 되면, 원하는대로 echo 되지 않으니
    UCSR0B = 0xD8 이나
    UCSR0B = 0x98 로 설정해주면 된다.
(Bit 7 에서 Bit 4까지 1001(2) 이므로 0x90 이고 (RX enable / Receiver Enable)
 Bit 3 으로 인해 0x08, 합쳐서 0x98이 된다.)


UCSR0C  레지스터는 Asynchronous / Synchronous mode 를 고르고,
                어떤 종류의 패리티를 쓸지, 스탑 비트는 몇 비트를 할지, 데이터는 몇 비트로 사용할지 결정한다.
                친숙하게 보는 115200-N-8-1 이러한 설정값에 대한것 중 BaudRate를 제외한 거의 모든것을 결정한다.

그리고 sei() 라는 매크로를 통해, 전역 인터럽트를 사용가능하도록 설정해주어야 한다.
#define sei ()      
#include <avr/interrupt.h>

Enables interrupts by setting the global interrupt mask.
This function actually compiles into a single line of assembly, so there is no function call overhead.

[링크: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html]

머.. sei() 친구로 cli()도 있지만, 어셈블리 명령어인데 명확한 약자로 보기에는 조금 애매함이 있다.
SEtting global Interrupt
CLearing global Interrupt
more <avr/interrupt.h>

#if defined(__DOXYGEN__)
/** \def sei()
    \ingroup avr_interrupts

    \code #include <avr/interrupt.h> \endcode

    Enables interrupts by setting the global interrupt mask. This function
    actually compiles into a single line of assembly, so there is no function
    call overhead. */
#define sei()
#else  /* !DOXYGEN */
# define sei()  __asm__ __volatile__ ("sei" ::)
#endif /* !DOXYGEN */

#if defined(__DOXYGEN__)
/** \def cli()
    \ingroup avr_interrupts

    \code #include <avr/interrupt.h> \endcode

    Disables all interrupts by clearing the global interrupt mask. This function
    actually compiles into a single line of assembly, so there is no function
    call overhead. */
#define cli()
#else  /* !DOXYGEN */
# define cli()  __asm__ __volatile__ ("cli" ::)
#endif /* !DOXYGEN */



[링크: http://blog.yurihan.net/]

Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 10. 7. 23:13
us-tech 사의 제품을 사용해서, 아래 링크의 예제를 사용하려고 했더니.
outp 매크로를 이용하는 구버전이라서 조금 고민하다가 데이터시트를 읽고 시도했다.

    /* for USART */
    UBRR0H = 0;
    UBRR0L = 8; // 115200bps with U2X = 0
    UCSR0A = 0x00; // U2X = 0;
    UCSR0B = 0xF8;
    UCSR0C = 0x06; // Asyncronous - no parity - 1bits(stop) - 8bits(data)


USART Baud Rate Register (UBRR) 은 일종의 divider의 설정값으로, 클럭을 분기하는데 사용하는 값이라고 생각이 된다.
아무튼 16.0MHz 같은녀석은, Error 율이 0% 인녀석이 일반적으로 사용하는 115k 이하에는 없으므로 그리 좋지 않다.

그리고 U2X는
Bit 1 – U2Xn: Double the USART Transmission Speed
This bit only has effect for the asynchronous operation. Write this bit to zero when using synchronous operation.
Writing this bit to one will reduce the divisor of the baud rate divider from 16 to 8 effectively doubling the transfer rate for asynchronous communication
라고 나와있 듯, asynchronous 모드에서만 작동이 되며, 클럭을 두배로 증가시켜 에러율을 줄이는 효과를 보인다.

아무튼, USART / UART를 설정하는데 사용되는 레지스터는
UCSR0A, UCSR0B, UCSR0C 세가지가 있으며

UCSR0A에는 U2X를 제외하면 실질적으로 전부 Status 레지스터이다.
• Bit 7 – RXCn: USART Receive Complete
• Bit 6 – TXCn: USART Transmit Complete
• Bit 5 – UDREn: USART Data Register Empty
• Bit 4 – FEn: Frame Error
• Bit 3 – DORn: Data OverRun
• Bit 2 – UPEn: Parity Error
• Bit 1 – U2Xn: Double the USART Transmission Speed
• Bit 0 – MPCMn: Multi-Processor Communication Mode

UCSR0B에는 인터럽트와 , TX / RX enable 를 설정하며
• Bit 7 – RXCIEn: RX Complete Interrupt Enable
• Bit 6 – TXCIE: TX Complete Interrupt Enable
• Bit 5 – UDRIEn: USART Data Register Empty Interrupt Enable
• Bit 4 – RXENn: Receiver Enable
• Bit 3 – TXENn: Transmitter Enable
• Bit 2 – UCSZn2: Character Size
• Bit 1 – RXB8n: Receive Data Bit 8
• Bit 0 – TXB8n: Transmit Data Bit 8

UCSR0C에는 눈에 익숙한 N-8-1 (No Parity - 8bit data - 1bit stop) 이러한 설정값을 조절한다.
• Bit 7 – Reserved Bit
• Bit 6 – UMSELn: USART Mode Select
• Bit 5:4 – UPMn1:0: Parity Mode
• Bit 3 – USBSn: Stop Bit Select
• Bit 2:1 – UCSZn1:0: Character Size
• Bit 0 – UCPOLn: Clock Polarity


데이터를 TX로 출력하려면 UDR0 = data; 를 하면된다.




[링크 : http://www.us-technology.co.kr/lecture/lecture_main.asp?mode=1&smode=6]
Posted by 구차니

AVR Studio에서 읽은 us-technology.co.kr에서 판매하는 보드의 기본 퓨즈 비트 설정값이다.
CKOPT가 원래 체크 되어 있어야 했던거 같은데 흐음..
Posted by 구차니
embeded/AVR (ATmega,ATtiny)2009. 5. 27. 22:41
ubuntu에는
/dev/paraport0 가 아닌
/dev/parport0 로 장치명이 되어 있었다.



그리고 그냥 패널에서 실행할경우 일반 사용자 모드로 구동이 되므로
아래와 같이 device를 열 수 없다는 에러가 발생한다.

패널에서 실행방법을 변경하거나
아니면 콘솔에서
$ sudo gnome-avrdude &
로 실행을 하면 해결이 된다.



패러럴로 사용시 stk200으로 프로그래머를 설정해주면
ATMega128을 패러럴로 읽을 수 있다.
Posted by 구차니
embeded/80512009. 4. 21. 17:51
신기한 현상을 발견했다.
코드의 위치에 따라 용량이 상당히 많이 변한다는 사실!

for(idx = 0; idx < len; idx++)
{
	tempUnicode = input[idx];
	if(0x0020 <= tempUnicode && tempUnicode < 0x0080)	res = (char)(tempUnicode & 0x00FF);
	else if(tempUnicode == 0x00E1)						res = 0x80;
	else if(tempUnicode == 0x00E0)						res = 0x81;
	...
	else if(0x0400 < tempUnicode && tempUnicode <= 0x045F)
	{
		switch(tempUnicode)
		{
			case 0x0401:	res = 192 +	0;	break;
			case 0x0402:	res = 192 +	1;	break;
			...
		}
	}
	else												res = ' ';
}

Program Size: data=187.7 xdata=0 code=9505

for(idx = 0; idx < len; idx++)
{
	tempUnicode = input[idx];
	if(0x0020 <= tempUnicode && tempUnicode < 0x0080)	res = (char)(tempUnicode & 0x00FF);
	else if(0x0400 < tempUnicode && tempUnicode <= 0x045F)
	{
		switch(tempUnicode)
		{
			case 0x0401:	res = 192 +	0;	break;
			case 0x0402:	res = 192 +	1;	break;
			...
		}
	}
	else if(tempUnicode == 0x00E1)						res = 0x80;
	else if(tempUnicode == 0x00E0)						res = 0x81;
	...
	else												res = ' ';
}

Program Size: data=189.7 xdata=0 code=9698

바뀐건, else if() 내부에 switch()가 있는 경우의 위치가 바뀐 경우이다.
속도 최적화를 위해 빨리빠져 나갈수 있도록 위로 옮겨 주었떠니 용량이 무려!!!
193 바이트나 늘어났다.. OTL

아마도..
코드사이즈가 커지면서 MOV대신 MOVX 라던가..
이런식으로 명령어에 넣어야 하는 주소의 크기가 달라지면서 발생하는 문제가 아닐까 생각이 된다.
Posted by 구차니