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.,
/* Copyright (c) 2005,2006 Joerg Wunsch
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
/* $Id: deprecated.h,v 1.6.2.2 2008/07/30 21:39:21 arcanum Exp $ */
#ifndef _COMPAT_DEPRECATED_H_
#define _COMPAT_DEPRECATED_H_
/** \defgroup deprecated_items "compat/deprecated.h": Deprecated items
This header file contains several items that used to be available
in previous versions of this library, but have eventually been
deprecated over time.
\code #include "compat/deprecated.h" \endcode
These items are supplied within that header file for backward
compatibility reasons only, so old source code that has been
written for previous library versions could easily be maintained
until its end-of-life. Use of any of these items in new code is
strongly discouraged.
*/
/** \name Allowing specific system-wide interrupts
In addition to globally enabling interrupts, each device's particular
interrupt needs to be enabled separately if interrupts for this device are
desired. While some devices maintain their interrupt enable bit inside
the device's register set, external and timer interrupts have system-wide
configuration registers.
Example:
\code
// Enable timer 1 overflow interrupts.
timer_enable_int(_BV(TOIE1));
// Do some work...
// Disable all timer interrupts.
timer_enable_int(0);
\endcode
\note Be careful when you use these functions. If you already have a
different interrupt enabled, you could inadvertantly disable it by
enabling another intterupt. */
/*@{*/
/** \ingroup deprecated_items
\def enable_external_int(mask)
\deprecated
This macro gives access to the \c GIMSK register (or \c EIMSK register
if using an AVR Mega device or \c GICR register for others). Although this
macro is essentially the same as assigning to the register, it does
adapt slightly to the type of device being used. This macro is
unavailable if none of the registers listed above are defined. */
/* Define common register definition if available. */
#if defined(EIMSK)
# define __EICR EIMSK
#elif defined(GIMSK)
# define __EICR GIMSK
#elif defined(GICR)
# define __EICR GICR
#endif
/* If common register defined, define macro. */
#if defined(__EICR) || defined(__DOXYGEN__)
#define enable_external_int(mask) (__EICR = mask)
#endif
/** \ingroup deprecated_items
\deprecated
This function modifies the \c timsk register.
The value you pass via \c ints is device specific. */
static __inline__ void timer_enable_int (unsigned char ints)
{
#ifdef TIMSK
TIMSK = ints;
#endif
}
/** \def INTERRUPT(signame)
\ingroup deprecated_items
\deprecated
Introduces an interrupt handler function that runs with global interrupts
initially enabled. This allows interrupt handlers to be interrupted.
As this macro has been used by too many unsuspecting people in the
past, it has been deprecated, and will be removed in a future
version of the library. Users who want to legitimately re-enable
interrupts in their interrupt handlers as quickly as possible are
encouraged to explicitly declare their handlers as described
\ref attr_interrupt "above".
*/
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
# define __INTR_ATTRS used, externally_visible
#else /* GCC < 4.1 */
# define __INTR_ATTRS used
#endif
#ifdef __cplusplus
#define INTERRUPT(signame) \
extern "C" void signame(void); \
void signame (void) __attribute__ ((interrupt,__INTR_ATTRS)); \
void signame (void)
#else
#define INTERRUPT(signame) \
void signame (void) __attribute__ ((interrupt,__INTR_ATTRS)); \
void signame (void)
#endif
/*@}*/
/**
\name Obsolete IO macros
Back in a time when AVR-GCC and avr-libc could not handle IO port
access in the direct assignment form as they are handled now, all
IO port access had to be done through specific macros that
eventually resulted in inline assembly instructions performing the
desired action.
These macros became obsolete, as reading and writing IO ports can
be done by simply using the IO port name in an expression, and all
bit manipulation (including those on IO ports) can be done using
generic C bit manipulation operators.
The macros in this group simulate the historical behaviour. While
they are supposed to be applied to IO ports, the emulation actually
uses standard C methods, so they could be applied to arbitrary
memory locations as well.
*/
/*@{*/
/**
\ingroup deprecated_items
\def inp(port)
\deprecated
Read a value from an IO port \c port.
*/
#define inp(port) (port)
/**
\ingroup deprecated_items
\def outp(val, port)
\deprecated
Write \c val to IO port \c port.
*/
#define outp(val, port) (port) = (val)
/**
\ingroup deprecated_items
\def inb(port)
\deprecated
Read a value from an IO port \c port.
*/
#define inb(port) (port)
/**
\ingroup deprecated_items
\def outb(port, val)
\deprecated
Write \c val to IO port \c port.
*/
#define outb(port, val) (port) = (val)
/**
\ingroup deprecated_items
\def sbi(port, bit)
\deprecated
Set \c bit in IO port \c port.
*/
#define sbi(port, bit) (port) |= (1 << (bit))
/**
\ingroup deprecated_items
\def cbi(port, bit)
\deprecated
Clear \c bit in IO port \c port.
*/
#define cbi(port, bit) (port) &= ~(1 << (bit))
/*@}*/
#endif /* _COMPAT_DEPRECATED_H_ */
에코 서버라고 하니 먼가 거창한데,
간단하게 입력하면 그걸 그대로 돌려줘서 화면에 나타나게 하는 프로그램이다.
시리얼로 전송하면, 받는쪽에서 그 값을 돌려주지 않으면 터미널에서 그 값이 출력되지 않는다.
가장 간단하고, 확실한 테스트 방법이라서 일단 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 선언에 의해서 자동으로 불려지는 파일이다)
시리얼포트 초기화시에는 당연히 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.
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 */
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 */
몇일 전, 평소가던 식당이 아닌 다른 식당에서 저녁을 먹다가
애 아버지들의 이야기를 듣게 되었는데
이야기 중에, 대안학교로 남한산성쪽 학교 이야기가 나왔다.
공부도 잘하고, 하고 싶은대로 하고
애들이 가장 좋아하는거 머냐고 물으면 강에서 놀기 이런거 적어 낸다고 하면서
성적도 좋아 좋은 대학교 갔고
처음에는 적응못하다가 금세 따라간다고 이야기를 하는데
웬지 모르게, 결과론적인 모습에 치중을 하는게 아닐까? 라는 아쉬움이 들었다.
공부를 잘한다.
좋은 대학 갓다.
금세 따라가서 더 잘한다.
그러다가 이야기가 계속 진행되었는데
그런 학교 보내고 마음대로 하고 싶긴한데, 문제는
거기는 로또라는 것이다. 잘되면 대박이고 안되면 쪽박 아니냐
"내가 아이 책임져줄 만큼 잘살면 모르겠지만 그게 아니니
그래서 그냥 무난하게 보통 교육을 하는게 좋을것 같다."라는 이야기가 나왔다.
아.. 그래서 요즘 애들이 더더욱 안전빵으로 교육을 받아야만 하고
그것에 최적화가 되어있구나 싶었다.
그 이야기를 하시던 애 딸린 분들의 시대에는 알아서 먹고 살아라, 그래도 부모가 해줄수 있는 최대의 교육은 해주마 였을꺼고
그 부모들은, 넓은 벌판에서 배고프고 힘들지만 공부에 대한 걱정없이 살았고, 그분들의 부모 역시
알아서 굶어죽진 않고 잘 살겠지 하는 마음에 마음놓고 풀어서 키웠을텐데
이제는 그러지 못하고,
내 아이는 그래도 남들만큼은 해야 한다라는 강박관념과
대학도 못가면 인간 구실도 못한다.
대기업은 가야 한다 라는 생각으로 인해서 더더욱 각박한 세상이 되어가는게 아닐까라는 생각이 들었다.
잔인한 말일 수도 있지만,
그 아이가 밥 벌어 먹고 사는건 그 아이 자신이 결정할 일이겠지만
역설적으로... 부모가 이렇게 아이를 생각하는 마음으로 인해 아이를 망치는구나 라는 생각이 들었다.