DynE
Stewart Platform Project
2015-02-15
#if defined (ARDUINO) && ARDUINO >= 100 ? 어디서 비교하는지 궁금합니다.
아두이노 호환 구문 관련 질문을 정리한 글입니다.
출처 : cafe.naver.com/laydigital/
공개용 코드들을 참조하기 위해 살펴보다가 유독 아래와 같은 구문들이 자주 보여서 검색해보니 버젼 호환과 관련된 내용이라는 것을 알게 되었습니다.
http://forum.arduino.cc/index.php?topic=61764.5;wap2
if (ARDUINO < 100)
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
------------------------------------------
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
그런데 여기서 한가지 궁금한 점이 있어 질문드립니다.
ARDUINO 를 100 이란 상수값과 비교한다는건 ARDUINO가 numeric value라는 얘기인데
이값이 정의된 곳이 어디인지 찾아보기가 힘들어서 질문드립니다 현재 ARDUINO는 사용하고 있지 않고 있어서
전체 lib파일들을 전부 흝어 볼수가 없고 지금 참고용으로 살펴보고 있는 코드와 관련된 공개용 소스만 보고 있다가
궁금해서 질문 드립니다.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
C:\Program Files\Arduino\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=106 -IC
컴파일될때 -DARDUINO=106
이렇게 전달되네요.
IDE 내부에서 전달할 수도 있을듯 합니다.
16BIT-TIMMER 관련 질문
서보를 사용하면서 16비트 타이머 관련 질문을 정리한 내용입니다.
출처 : cafe.naver.com/laydigital/
안녕하세여, 오랜만에 질문을 드리네요.
현재 프로젝트로 6DOF - stewart platform을 만들고 있는데요, 16bit timer를 쓸려고 살펴보는 중에 다음과 같은
부분이 이해가 좀 않되서 질문 드립니다.
위의 그림에서 Duty를 주는 부분이 8bit 에서는 TOP값이 고정되어 OCRn이었는데 16bit에서는 WGMn3:0 값에 따라 달라진다고
나와 있는데요,
질문1) TOP값이 FIXED일 경우, ICRnA의 경우 Duty값으로 비교되는 값이 아래 지문처럼 OCRnA reg를 자유롭게 사용하여 PWM파형을 출력하여 사용한다고 나와 있는데 OCRnA의 경우에 Duty값으로 비교되는 값이 어떤값으로 되는지 어느부분에 명시된건지 잘 파악되지 않아 질문드립니다.
질문2) Figure 52. FAST PWM모드에서 OCRnA이 non fixed TOP일경우 TOP value를 바꿔주므로써 기본 PWM주파수를 의도적으로 바꾸는데 좋은 장점이 있다는 부분이 위 지문에 언급되어 나오는데 이부분이 OCRnA값을 TOP으로 주고 duty값도 OCRnA값으로 비교한다는 말인지, 어떤지 실제로 코드로 구현하면 16bit 타이머1을 시작할때 한번 TOP값을 set 하고 이후에 다시 어떻게 TOP값을 주는다는건지 이해가 않되서 이부분도 질문드립니다.
servo 모터는 skyholic DGS-1188 http://www.servodatabase.com/servo/skyholic/dgs-1188 6개를 구매해서
http://www.youtube.com/watch?v=ezp4ZvfJv0g 이 친구들처럼 제작해보고자 하는데 진행하면서 질문 좀 드리겠습니다 ㅎ; servo 모터는 8bit timer로 FAST PWM 모드로 61HZ 파형으로 duty를 변경해서 테스트 해본결과 작동은 하는데 50hz 안에서 20ms 주기로 fast pwm으로 6개의 OCn pin을 사용 출력으로 이용해보고자 16bit timer를 살펴보게 됐습니다.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
1) 만약 제가 정상적으로 이해를 했다면
ICRn을 사용하는 경우는 이해를 하신거구
OCRnA를 TOP 값으로 사용한 경우의 비교 값을 말씀하시는 거죠?
OCRnA는 OCR1A,OCR3A 둘중 하나이고(타이머에 따라)
OCR1A 라면 정상적으로 만들 수 있는 PWM 신호는 두개(OCR1B,OCR1C에 의한) 이죠.
2)
그냥 TOP 에 해당하는 레지스터는 동적으로 바꾸셔도 되는데, 다음의 경우는 조심해야 합니다.
내부 카운터가 이전 TOP을 지나가고 있을떄, 만약 해당 TOP값을 낮은 값으로 바꾸면, 이전에 진행하던
CNT 값이 이미 비교 레지스터를 지나버려서 MAX값까지 올라갔다 오는게 한번 생깁니다.
동작은 내부 TCNT가 있고, 어디까지(TOP)을 설정하는 레지스터(ICRn,OCRnA)와 그 pwm의 듀티
(OCRnA,OCRnB,OCRnC where ICRn을 TOP으로 한 경우,
OCRnB,OCRnC where OCRnA가 TOP인 경우)
출처 : cafe.naver.com/laydigital/
안녕하세여, 오랜만에 질문을 드리네요.
현재 프로젝트로 6DOF - stewart platform을 만들고 있는데요, 16bit timer를 쓸려고 살펴보는 중에 다음과 같은
부분이 이해가 좀 않되서 질문 드립니다.
위의 그림에서 Duty를 주는 부분이 8bit 에서는 TOP값이 고정되어 OCRn이었는데 16bit에서는 WGMn3:0 값에 따라 달라진다고
나와 있는데요,
질문1) TOP값이 FIXED일 경우, ICRnA의 경우 Duty값으로 비교되는 값이 아래 지문처럼 OCRnA reg를 자유롭게 사용하여 PWM파형을 출력하여 사용한다고 나와 있는데 OCRnA의 경우에 Duty값으로 비교되는 값이 어떤값으로 되는지 어느부분에 명시된건지 잘 파악되지 않아 질문드립니다.
질문2) Figure 52. FAST PWM모드에서 OCRnA이 non fixed TOP일경우 TOP value를 바꿔주므로써 기본 PWM주파수를 의도적으로 바꾸는데 좋은 장점이 있다는 부분이 위 지문에 언급되어 나오는데 이부분이 OCRnA값을 TOP으로 주고 duty값도 OCRnA값으로 비교한다는 말인지, 어떤지 실제로 코드로 구현하면 16bit 타이머1을 시작할때 한번 TOP값을 set 하고 이후에 다시 어떻게 TOP값을 주는다는건지 이해가 않되서 이부분도 질문드립니다.
servo 모터는 skyholic DGS-1188 http://www.servodatabase.com/servo/skyholic/dgs-1188 6개를 구매해서
http://www.youtube.com/watch?v=ezp4ZvfJv0g 이 친구들처럼 제작해보고자 하는데 진행하면서 질문 좀 드리겠습니다 ㅎ; servo 모터는 8bit timer로 FAST PWM 모드로 61HZ 파형으로 duty를 변경해서 테스트 해본결과 작동은 하는데 50hz 안에서 20ms 주기로 fast pwm으로 6개의 OCn pin을 사용 출력으로 이용해보고자 16bit timer를 살펴보게 됐습니다.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
1) 만약 제가 정상적으로 이해를 했다면
ICRn을 사용하는 경우는 이해를 하신거구
OCRnA를 TOP 값으로 사용한 경우의 비교 값을 말씀하시는 거죠?
OCRnA는 OCR1A,OCR3A 둘중 하나이고(타이머에 따라)
OCR1A 라면 정상적으로 만들 수 있는 PWM 신호는 두개(OCR1B,OCR1C에 의한) 이죠.
2)
그냥 TOP 에 해당하는 레지스터는 동적으로 바꾸셔도 되는데, 다음의 경우는 조심해야 합니다.
내부 카운터가 이전 TOP을 지나가고 있을떄, 만약 해당 TOP값을 낮은 값으로 바꾸면, 이전에 진행하던
CNT 값이 이미 비교 레지스터를 지나버려서 MAX값까지 올라갔다 오는게 한번 생깁니다.
동작은 내부 TCNT가 있고, 어디까지(TOP)을 설정하는 레지스터(ICRn,OCRnA)와 그 pwm의 듀티
(OCRnA,OCRnB,OCRnC where ICRn을 TOP으로 한 경우,
OCRnB,OCRnC where OCRnA가 TOP인 경우)
JKIT-128-1 : failed to enter programming mode!
Failed to enter programming mode!
출처 : cafe.naver.com/laydigital/
안녕하세요, 오늘 마지막 강좌 연습을 하던도중 다음과 같은 Error가 발생하여 문의 드립니당.
첫번째와 두번째 사진까지 정상 진입하였습니다.. 아무런 에러도 없었는데
두번째 사진에서 ISP 모드에서 memory -> program을 클릭 하면 아래 3번째 사진과 같이 에러 메세지와 함께 세번째 사진과
같은 팝업 안내창 출력됩니다. 지금까지 아무 문제 없다가 오늘 갑자기 그래서 COM3 ->5로 바꿔도 보고 재부팅도 해보고 재실행도 해봤지만 현상이 계속 지속되서 문의 드립니당.
제품은 jkit-128-1
프로그램 atmel studio 6.1
일단 기본적인 해결책은 모듈 및 키트에 연결된 외부 모듈 들을 전부 제거하여 avr-kit 와 컴퓨터 사이에 서로 연결이 원할한지 다시 체크 해보는게 첫째 입니다. 킷트에 문제가 없다면
현재 연결하려는 선의 port pin들이 ISP와 과련된 핀에 연결되는지 체크 해보시면 큰 무리없이 해결 될 것입니다. 이렇게 해도 상황이 개선 되지 않는다면 일단 프로그램을 재설치 해보시고 이후에도 상황이 변화가 없다면 chip에 문제가 있을 수 있으니 모듈 미치 킷트 제조사에 문의 해보시기를 추천합니다.
Dot-matrix 연습 영상
전광판 출력 연습 강좌란에 나오는 내용을 연습한 코드 및 정리 자료 입니다.
출처 : cafe.naver.com/laydigital/
안녕하세요, 어느덧 강좌가 2개만 남았습니다.... 남은 강좌도 마무리까지 열심히 달려서 보충자료에 있는 과제와 연습 코드까지 다룰수 있도록 힘내봐야겠네요. youtube도 시작할겸 강좌 구동영상을 연습삼아 올려봅니다. 2 color dot matrix 품명은 BVD-8518SG1 이고 datasheet가 없다네요 ;; 하드웨어 연결은 강좌에 나온 사항을 토대로 연결하였습니당.
// CODE
#include <avr/io.h>
#define Kilo 1000UL
#define Mega Kilo * Kilo
#define F_CPU 16*Mega
#include <util/delay.h>
void dsp(uint8_t *p,uint8_t);
uint8_t prr[]= {
0,0,0,0,0,0,0,
0b00111100, //I
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00111100,
0,0,
0b01100110, //♥
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b01111110,
0b00111100,
0b00011000,
0,0,
0b01100110, //Y
0b01100110,
0b01100110,
0b01111110,
0b01111110,
0b00011000,
0b00011000,
0b00011000,
0,0,
0b00111100, //O
0b01111110,
0b11100111,
0b11000011,
0b11000011,
0b11100111,
0b01111110,
0b00111100,
0,0,
0b01100110, //U
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01111110,
0b00111100,
0,0,0,0,0,0,0,0
};
int main(void)
{
DDRA = 0xff;
DDRE = 0xff; //red
DDRF = 0xff; //green
uint8_t i,j=0;
while(1)
{
for(i=0; i<((sizeof(prr)/sizeof(prr[0]))-8); i++)
{
for(j=0; j<80; j++)
{
dsp(prr,i);
}
}
}
}
void dsp(uint8_t *p,uint8_t t)
{
uint8_t i=0;
for(i=0; i<8; i++)
{
PORTA = (1<<PA7)>>i;
PORTF = *((p++)+t); //green
PORTE = PORTF&0xf0; //red
_delay_us(500);
}
}
출처 : cafe.naver.com/laydigital/
안녕하세요, 어느덧 강좌가 2개만 남았습니다.... 남은 강좌도 마무리까지 열심히 달려서 보충자료에 있는 과제와 연습 코드까지 다룰수 있도록 힘내봐야겠네요. youtube도 시작할겸 강좌 구동영상을 연습삼아 올려봅니다. 2 color dot matrix 품명은 BVD-8518SG1 이고 datasheet가 없다네요 ;; 하드웨어 연결은 강좌에 나온 사항을 토대로 연결하였습니당.
Code simulation video
// CODE
#include <avr/io.h>
#define Kilo 1000UL
#define Mega Kilo * Kilo
#define F_CPU 16*Mega
#include <util/delay.h>
void dsp(uint8_t *p,uint8_t);
uint8_t prr[]= {
0,0,0,0,0,0,0,
0b00111100, //I
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00011000,
0b00111100,
0,0,
0b01100110, //♥
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b01111110,
0b00111100,
0b00011000,
0,0,
0b01100110, //Y
0b01100110,
0b01100110,
0b01111110,
0b01111110,
0b00011000,
0b00011000,
0b00011000,
0,0,
0b00111100, //O
0b01111110,
0b11100111,
0b11000011,
0b11000011,
0b11100111,
0b01111110,
0b00111100,
0,0,
0b01100110, //U
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01100110,
0b01111110,
0b00111100,
0,0,0,0,0,0,0,0
};
int main(void)
{
DDRA = 0xff;
DDRE = 0xff; //red
DDRF = 0xff; //green
uint8_t i,j=0;
while(1)
{
for(i=0; i<((sizeof(prr)/sizeof(prr[0]))-8); i++)
{
for(j=0; j<80; j++)
{
dsp(prr,i);
}
}
}
}
void dsp(uint8_t *p,uint8_t t)
{
uint8_t i=0;
for(i=0; i<8; i++)
{
PORTA = (1<<PA7)>>i;
PORTF = *((p++)+t); //green
PORTE = PORTF&0xf0; //red
_delay_us(500);
}
}
CLCD + AVR 을 이용하여 문자 쓰기.
CLCD를 사용하여 좌우명 새기기 라는 강좌를 진행하며 정리한 글입니다.
출처 : cafe.naver.com/laydigital/
안녕하세요 8.2 Clcd 강좌를 진행후 궁금증이 생겨서 질문드립니다.
강좌에서 Write timing diagram을 토대로 timing 에따라 코드를 작성하다 실제로 제가 주는 _delay(sec)시간이 과연
정확한 시간인가하고 의아해졌습니다.
실제로 init_clcd 에서는 그대로 _delay()라이브러리 함수의 기능을사용하여 값을 datasheet value 그대로 주었고,
_delay_ms(1.53) or _delay_ms(2), _delay_us(39).. 등등 Write timing diagram에서는 시간단위가 ns 인데 MPU: 16MHZ
1clock당 62.5ns 로 계산하면 기본적으로 1clock에서 ~? clock 까지 한코드를 실행하는데 드는 clock 만 가지고도 딜레이 없이 사용해도 괜찮은건지 궁금합니당. 제가 작성한 코드는 아래와 같이.. write_dsp_timing 에서 table 순서대로만 코드를 적고 마지막에 data를 입력 시키는 delay만 길게 잡고 실행해서 data를 화면에 표시를 했습니다. 마지막 delay 값을 ns 단위로 줬는데 data가 다 입력되지 않고 잘려서 들어갑니다.
여기서 궁금증을 정리하면..
질문1) 정확히 확인해보지는 못했지만 사실 방법도 아직 잘 모르지만 코드가 컴파일되면 1clock당 수행되는 코드형태로
바뀐다고 알고 있는데요 (assembly형태) 순서대로 딜레이 함수 추가 하지않고 기본적으로 한코드문 실행할경우
1clock~ 3clcok(16MHz = 62.5ns/1clock )으로 가정하고 순서대로 코드하여 사용해도 괜찮은건지 일단 궁금합니다.
여기서 좀 문제되는건 제가 작성한 코드가 각코드문에서 몇 clock씩 소요되는지 아직 확인 방법을 몰라 좀 애매합니다..
질문2) write_dsp_timing 마지막 delay값으로 그냥 적당한 값을 넣어주었는데요 (몇번 해보고 되는 값으로..) 실제로
delay 함수를 사용하여 write_dsp_timing 함수상에서 마지막으로 넣어줘야 하는 delay 값을 어림잡아서라도 계산값 으로 해보고
싶은데 영 어떻게 계산할지 방법이 않떠오릅니다 어떤식으로 계산해서 넣어주면 괜찮을지 힌트라도 주시면 감사하겠습니다.
질문3) datasheet 상에서 E Rise/Fall time 이값의 의미는 강좌에 설명되어져 있는데요, 실제로 이값은
어떤식으로 사용되는건지 궁금합니다. Max 20 (ns), 설명은 있는데 활용하는 경우가 없어서(?), 몰라서 이해하기 좀 난해합니다.
코딩할때나 하드웨어를 구성할때나 어떤경우에 이용되는건지 아니면 그냥 참고사항인지, 실제로 wiki나 각종블로그에는
화려한 공식들이 등장하는데요 이값이 어떤 쓰임이 있는지 알려주시면 감사하겠습니다.
-------------------------------------------------------------------------------------------------
아래는 연습용으로 첫번째 줄의 문자열이 한칸씩 >> 쉬프트하는 연습을 코드로 해보았습니다. 더 괜찮은 방법이 있다면 알려주시면 감사하겠습니다. 쉬프트하면 전에 있던 첫주소의 문자가 계속 중첩되서 다시 지우고 새로 쓰는 형태로 해보았습니다.
-----------------------------------------------------------------------------------------------------------------
#include <avr/io.h>
#define kilo 1000UL
#define Mega kilo*kilo
#define F_CPU 16*Mega // 1/16us = 1clock=0.0625(us), 1clock=62.5(ns)
#include <util/delay.h>
#define Enable PG4 //1: Enable , 0:disable
#define R_W PG3 //1: Read, 0: Write , normal: 0 (write)
#define RS PG2 //1: DR(Data reg), 0: IR(Instruction reg)
#define DB0 PA0
#define DB1 PA1
#define DB2 PA2
#define DB3 PA3
#define DB4 PA4
#define DB5 PA5
#define DB6 PA6
#define DB7 PA7
#define IR 0
#define DR 1
#define READ 1
#define WRITE 0
void init_clcd(void);
void write_dsp_timing(int8_t,int8_t,uint8_t); //1cycle: 500ns = 8clock (upper)
void write_string(uint8_t *p);
uint8_t arr[]="Dyne Practice";
uint8_t brr[]="Good job !";
uint8_t crr[]={20,20,20,20,20,20,20,20,20,20,20,20};
int main(void)
{
DDRA = 0xff;
DDRG = 0xff;
init_clcd();
uint8_t i=0;
//write_dsp_timing(DR,WRITE,'D');
while(1)
{ /*--set ADD---*/
write_dsp_timing(IR,WRITE,(3<<DB6)); //2-line first address.
write_string(brr);
for(i=0; i<8; i++)
{
write_dsp_timing(IR,WRITE,((2<<DB6)+i)); //1-line first address.
write_string(arr);
/*--set ADD---*/
_delay_ms(400);
write_dsp_timing(IR,WRITE,((2<<DB6)+i)); //clear.
write_string(crr); //disp clear.
}
}
}
void init_clcd(void)
{
/*----wait more 30ms, minimum (30ms) -----*/
_delay_ms(30);
/*---funcition set 2-line mode(1), 5x7dot mode(0)----*/
write_dsp_timing(IR,WRITE,(7<<DB3)); // PORTA = (7<<DB3);
/*----wait more 39us, minimum (39us) -----*/
_delay_us(39);
/*----Display on(1), curs off(0), Blink off(0)---*/
write_dsp_timing(IR,WRITE,(3<<DB2));//PORTA = (3<<DB2);
/*----wait more 39us, minimum (39us) -----*/
_delay_us(30);
/*----Display clear(1)-----*/
write_dsp_timing(IR,WRITE,(1<<DB0));//PORTA = (1<<DB0);
/*----wait more 1.53ms, minimum (1.53ms) -----*/
_delay_ms(2);
/*----Entry mode set -----*/
write_dsp_timing(IR,WRITE,(3<<DB1));//PORTA = (3<<DB2);
}
void write_dsp_timing(int8_t rs, int8_t r_w, uint8_t Data)
{
PORTG = (rs<<RS); //IR
PORTG |= (r_w<<R_W); //Write
PORTG |= (1<<Enable); //1
PORTA = Data; //Data
PORTG &= ~(1<<Enable); //0
_delay_ms(1); //valid data timing
}
void write_string(uint8_t *p)
{
while(*p)
{
write_dsp_timing(DR,WRITE,*p++);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
질문1) 정확히 확인해보지는 못했지만 사실 방법도 아직 잘 모르지만 코드가 컴파일되면 1clock당 수행되는 코드형태로
바뀐다고 알고 있는데요 (assembly형태) 순서대로 딜레이 함수 추가 하지않고 기본적으로 한코드문 실행할경우
1clock~ 3clcok(16MHz = 62.5ns/1clock )으로 가정하고 순서대로 코드하여 사용해도 괜찮은건지 일단 궁금합니다.
그렇게 가정해서 하셔도 상관없습니다.
단 C로 만든 코드가 assembly 몇개 명령어로 만들어질지, 기계어를 보면서(lss화일) 확인 하시면 됩니다.
PORTA = 1;
PORTA = 0;
적어도 포트 A의 핀 0는 62.5 * 2 이상의 high pulse를 가집니다.(io register에 쓰기 assembly code
가 2 clock을 먹으므로)
타이밍상 100ns high 라면 위 두개의 assembly를 바로 사용해서도 delay가 만족합니다.
일반적으로는 IO핀의 변화에 대한 최소 시간이 있습니다.
특정포트의 핀을 0으로 만듬
특정포트의 핀을 1로 만듬
의 두 기계어가 있다고 하고 위 두 명령어 각각이 2 clock의 실행시간이 소요된다고 해서
실제로 IO핀이 해당 시간만큼만큼 따라주지 경우도 맣습니다.
(예를 들어 1Ghz cpu 가 bus 가 200Mhz 를 통해서 io 레지스터에 200MHz로 쓰기가 가능하다고 해서
io핀이 100Mhz(토글을 하므로 bus 속도의 반)이 되지 못합니다.
핀은 최대 움직일수 있는 속도가 있습니다.
만약 60ns 보다 작은 setup 타임이 필요한 타이밍이라면
PORTy = data; // 데이타를 싣고
PORTx = 0;
PORTx = 1; // 제어신호가 ->0->1 로 바뀌어야 하고 data의 setup 타임이 60ns 라면
// 위 같이 delay 없이도 충분함... io register에 쓰기/읽기 최소 2clock이라 최소 130 ns 이상은 나옴.
와 같이 하셔도 충분히 0인 시간이 위 조건을 만족합니다.(따로 delay가 필요없음)
C 로 작성한 코드가 asembly로 생성되는 걸 보시고 필요한 경우
asm("nop");// 62.5 ns 추가
와 같은 assembly를 C 에 삽입하면 됩니다.
PORTG = (rs<<RS); //IR
PORTG |= (r_w<<R_W); //Write
PORTG |= (1<<Enable); //1
PORTA = Data; //Data
PORTG &= ~(1<<Enable); //0
_delay_ms(1); //valid data timing
[출처] 8.2 CLCD에 내 좌우명을 새겨라 [강좌]질문. (임베디드홀릭) |작성자 다인
위는
시작
RS신호만 1로 만듬
최소 62.5 * 2 이상 대기
R_W 신호 1로 만듬
최소 62.6 * 2 이상 대기
Enable 신호를 1로 만듬
최소 62.5 * 2 이상 대기
data를 씀
최소 62.5 * 2 이상 대기
Enable 신호 0으로 만듬
최소 62.5 * 2 이상 대기
---여기에서 더 필요한 시간은
Enable이 0이 된후 다시 위 과정이 반복되는걸 cycle time 이라고 하는데
위 시간을 다 합한것과 cycle time의 차(cycle 타임이 더 적으면 delay 필요없음,
cycle타임이 더 크면 해당 시간만큼 대기)
그런데 위에서
atmega128의 경우 PORTG는 io read write(비트 세트/clear) 명령어가 제공되지 않는 레지스터입니다.
즉 메모리 읽기/쓰기로 일어납니다.
PORTG |= 1 << Enable
이건
reg = PORTG;
reg = reg | (1 << Enable);
PORTG = reg
이렇게 세 단계로 이루어집니다.
메모리에서 데티아 읽기, 쓰기, 그리고 레지스터에 OR 시키는 시간만큼 소요됩니다.
따라서 io bit set/clear 가 되는
PORTA |= 1 << Enable ;
가 sbis 같은 2cycle 명령어로 변환되는것도 다르게 시간이 훨씬 더 걸립니다.
기계어 생성된걸 봐야 하며 컴파일 옵션(옵티마이저)에 따라 다르므로
제가 위에서 최소라고 적은 겁니다. 실제 시간은 더 걸림.
강좌에 있는 CLCD 타이밍으로 본다면
RS와 R/W는 같은 타이밍에 쓸수 있음
E가 1로 바뀔때까지 RS, R/W는 Tsu1 시간이 필요하며, 예의 경우 40ns 이므로 delay 필요없음
E의 high 시간은 Tw이며 230 ns 이므로 명령어 실행시간 62.5 * 2 = 130과의 차 100ns 이므로 두개의 기계어
asm("nop"); // 62.5
asm("nop"); // 62.5
다시 E를 0으로 하면 130ns(최소 62.5 * 2) 인데
새로 E를 high 할 수 있는 시간 Tc (cycle이 500 ns 이므로)
500 - (62.5 * 2 + 62.5 * 2(nop) + 62.5 * 2(0으로 쓰기)) =
500 - (130 + 130 + 130) = 500 - 390 = 110
그런데 새로 시작할때, 다시 RS/RW를 쓰기 하고 다시 E를 1로 올리므로 이미 시간에 다 포함.
(또한 함수로 구현되어 있어서 함수 리턴 및 call 시간이 추가로 붙음)
Tr/Tf 은 길어야 20ns 입니다. 일반적으로 회로에서 mcu에 바로 clcd를 연결할 경우 mcu가 특정 핀을 쓰기 하면 신호가 바로 올라가므로 별로 신경 쓸 필요는 없는데,
혹시라도 해당 핀에 cap같은걸 달아서 천천히 올라가는 완만한 신호가 생성된다면 해당 규격에 어긋나죠
만약 clcd를 긴 케이블을 통해서 구동한다면 선이 길어지면서
저항과 cap 성분이 크져서 신호가 완만히 올라갈경우 위 시간이 meet하지 않는다면 다른
방안(케이블을 좋은걸 사용하거나, 길이를 줄이거나) 을 강구해야 겠죠.
데이타쉬트 보시면
테이블 6에
bus timing (bus상에서 시간) 말고 명령어별로 delay시간이 우측에 있습니다.
즉 명령어에 따라 추가 시간이 필요합니다.
예를 들어 RS가 0인 것중에서도
clear display 명령어가 보낸후에는 최소 1.53 ms 까지 대기해야 하고
entry mode는 39 us 등
각 동작에 따른 delay 테이블을 두시거나,
해당 갑중 가능 큰값을 일괄 적용하시면 되겠죠.
bus 의 타이밍은 물리적은(전기적은) 규격이고, 그것을 통해 lcd에 명령이 전달되어서
해당 명령이 실행될때까지의 시간은 lcd 에서 내부적으로 더 필요한 시간입니다.
아 그래서 8-bit Initialization의 표와 같이 중간마다 명령어 수행후 최소 delay 값을 명시한거군요
그렇죠.
bus 타이밍은 전기적으로 상대편이 신호를 잘 받기 위한 규격이고
그렇게 전달된 명령/데이타가 내부에서 처리하는 시간이 있는거죠.
출처 : cafe.naver.com/laydigital/
안녕하세요 8.2 Clcd 강좌를 진행후 궁금증이 생겨서 질문드립니다.
강좌에서 Write timing diagram을 토대로 timing 에따라 코드를 작성하다 실제로 제가 주는 _delay(sec)시간이 과연
정확한 시간인가하고 의아해졌습니다.
실제로 init_clcd 에서는 그대로 _delay()라이브러리 함수의 기능을사용하여 값을 datasheet value 그대로 주었고,
_delay_ms(1.53) or _delay_ms(2), _delay_us(39).. 등등 Write timing diagram에서는 시간단위가 ns 인데 MPU: 16MHZ
1clock당 62.5ns 로 계산하면 기본적으로 1clock에서 ~? clock 까지 한코드를 실행하는데 드는 clock 만 가지고도 딜레이 없이 사용해도 괜찮은건지 궁금합니당. 제가 작성한 코드는 아래와 같이.. write_dsp_timing 에서 table 순서대로만 코드를 적고 마지막에 data를 입력 시키는 delay만 길게 잡고 실행해서 data를 화면에 표시를 했습니다. 마지막 delay 값을 ns 단위로 줬는데 data가 다 입력되지 않고 잘려서 들어갑니다.
여기서 궁금증을 정리하면..
질문1) 정확히 확인해보지는 못했지만 사실 방법도 아직 잘 모르지만 코드가 컴파일되면 1clock당 수행되는 코드형태로
바뀐다고 알고 있는데요 (assembly형태) 순서대로 딜레이 함수 추가 하지않고 기본적으로 한코드문 실행할경우
1clock~ 3clcok(16MHz = 62.5ns/1clock )으로 가정하고 순서대로 코드하여 사용해도 괜찮은건지 일단 궁금합니다.
여기서 좀 문제되는건 제가 작성한 코드가 각코드문에서 몇 clock씩 소요되는지 아직 확인 방법을 몰라 좀 애매합니다..
질문2) write_dsp_timing 마지막 delay값으로 그냥 적당한 값을 넣어주었는데요 (몇번 해보고 되는 값으로..) 실제로
delay 함수를 사용하여 write_dsp_timing 함수상에서 마지막으로 넣어줘야 하는 delay 값을 어림잡아서라도 계산값 으로 해보고
싶은데 영 어떻게 계산할지 방법이 않떠오릅니다 어떤식으로 계산해서 넣어주면 괜찮을지 힌트라도 주시면 감사하겠습니다.
질문3) datasheet 상에서 E Rise/Fall time 이값의 의미는 강좌에 설명되어져 있는데요, 실제로 이값은
어떤식으로 사용되는건지 궁금합니다. Max 20 (ns), 설명은 있는데 활용하는 경우가 없어서(?), 몰라서 이해하기 좀 난해합니다.
코딩할때나 하드웨어를 구성할때나 어떤경우에 이용되는건지 아니면 그냥 참고사항인지, 실제로 wiki나 각종블로그에는
화려한 공식들이 등장하는데요 이값이 어떤 쓰임이 있는지 알려주시면 감사하겠습니다.
-------------------------------------------------------------------------------------------------
아래는 연습용으로 첫번째 줄의 문자열이 한칸씩 >> 쉬프트하는 연습을 코드로 해보았습니다. 더 괜찮은 방법이 있다면 알려주시면 감사하겠습니다. 쉬프트하면 전에 있던 첫주소의 문자가 계속 중첩되서 다시 지우고 새로 쓰는 형태로 해보았습니다.
-----------------------------------------------------------------------------------------------------------------
#include <avr/io.h>
#define kilo 1000UL
#define Mega kilo*kilo
#define F_CPU 16*Mega // 1/16us = 1clock=0.0625(us), 1clock=62.5(ns)
#include <util/delay.h>
#define Enable PG4 //1: Enable , 0:disable
#define R_W PG3 //1: Read, 0: Write , normal: 0 (write)
#define RS PG2 //1: DR(Data reg), 0: IR(Instruction reg)
#define DB0 PA0
#define DB1 PA1
#define DB2 PA2
#define DB3 PA3
#define DB4 PA4
#define DB5 PA5
#define DB6 PA6
#define DB7 PA7
#define IR 0
#define DR 1
#define READ 1
#define WRITE 0
void init_clcd(void);
void write_dsp_timing(int8_t,int8_t,uint8_t); //1cycle: 500ns = 8clock (upper)
void write_string(uint8_t *p);
uint8_t arr[]="Dyne Practice";
uint8_t brr[]="Good job !";
uint8_t crr[]={20,20,20,20,20,20,20,20,20,20,20,20};
int main(void)
{
DDRA = 0xff;
DDRG = 0xff;
init_clcd();
uint8_t i=0;
//write_dsp_timing(DR,WRITE,'D');
while(1)
{ /*--set ADD---*/
write_dsp_timing(IR,WRITE,(3<<DB6)); //2-line first address.
write_string(brr);
for(i=0; i<8; i++)
{
write_dsp_timing(IR,WRITE,((2<<DB6)+i)); //1-line first address.
write_string(arr);
/*--set ADD---*/
_delay_ms(400);
write_dsp_timing(IR,WRITE,((2<<DB6)+i)); //clear.
write_string(crr); //disp clear.
}
}
}
void init_clcd(void)
{
/*----wait more 30ms, minimum (30ms) -----*/
_delay_ms(30);
/*---funcition set 2-line mode(1), 5x7dot mode(0)----*/
write_dsp_timing(IR,WRITE,(7<<DB3)); // PORTA = (7<<DB3);
/*----wait more 39us, minimum (39us) -----*/
_delay_us(39);
/*----Display on(1), curs off(0), Blink off(0)---*/
write_dsp_timing(IR,WRITE,(3<<DB2));//PORTA = (3<<DB2);
/*----wait more 39us, minimum (39us) -----*/
_delay_us(30);
/*----Display clear(1)-----*/
write_dsp_timing(IR,WRITE,(1<<DB0));//PORTA = (1<<DB0);
/*----wait more 1.53ms, minimum (1.53ms) -----*/
_delay_ms(2);
/*----Entry mode set -----*/
write_dsp_timing(IR,WRITE,(3<<DB1));//PORTA = (3<<DB2);
}
void write_dsp_timing(int8_t rs, int8_t r_w, uint8_t Data)
{
PORTG = (rs<<RS); //IR
PORTG |= (r_w<<R_W); //Write
PORTG |= (1<<Enable); //1
PORTA = Data; //Data
PORTG &= ~(1<<Enable); //0
_delay_ms(1); //valid data timing
}
void write_string(uint8_t *p)
{
while(*p)
{
write_dsp_timing(DR,WRITE,*p++);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
질문1) 정확히 확인해보지는 못했지만 사실 방법도 아직 잘 모르지만 코드가 컴파일되면 1clock당 수행되는 코드형태로
바뀐다고 알고 있는데요 (assembly형태) 순서대로 딜레이 함수 추가 하지않고 기본적으로 한코드문 실행할경우
1clock~ 3clcok(16MHz = 62.5ns/1clock )으로 가정하고 순서대로 코드하여 사용해도 괜찮은건지 일단 궁금합니다.
그렇게 가정해서 하셔도 상관없습니다.
단 C로 만든 코드가 assembly 몇개 명령어로 만들어질지, 기계어를 보면서(lss화일) 확인 하시면 됩니다.
PORTA = 1;
PORTA = 0;
적어도 포트 A의 핀 0는 62.5 * 2 이상의 high pulse를 가집니다.(io register에 쓰기 assembly code
가 2 clock을 먹으므로)
타이밍상 100ns high 라면 위 두개의 assembly를 바로 사용해서도 delay가 만족합니다.
일반적으로는 IO핀의 변화에 대한 최소 시간이 있습니다.
특정포트의 핀을 0으로 만듬
특정포트의 핀을 1로 만듬
의 두 기계어가 있다고 하고 위 두 명령어 각각이 2 clock의 실행시간이 소요된다고 해서
실제로 IO핀이 해당 시간만큼만큼 따라주지 경우도 맣습니다.
(예를 들어 1Ghz cpu 가 bus 가 200Mhz 를 통해서 io 레지스터에 200MHz로 쓰기가 가능하다고 해서
io핀이 100Mhz(토글을 하므로 bus 속도의 반)이 되지 못합니다.
핀은 최대 움직일수 있는 속도가 있습니다.
만약 60ns 보다 작은 setup 타임이 필요한 타이밍이라면
PORTy = data; // 데이타를 싣고
PORTx = 0;
PORTx = 1; // 제어신호가 ->0->1 로 바뀌어야 하고 data의 setup 타임이 60ns 라면
// 위 같이 delay 없이도 충분함... io register에 쓰기/읽기 최소 2clock이라 최소 130 ns 이상은 나옴.
와 같이 하셔도 충분히 0인 시간이 위 조건을 만족합니다.(따로 delay가 필요없음)
C 로 작성한 코드가 asembly로 생성되는 걸 보시고 필요한 경우
asm("nop");// 62.5 ns 추가
와 같은 assembly를 C 에 삽입하면 됩니다.
PORTG = (rs<<RS); //IR
PORTG |= (r_w<<R_W); //Write
PORTG |= (1<<Enable); //1
PORTA = Data; //Data
PORTG &= ~(1<<Enable); //0
_delay_ms(1); //valid data timing
[출처] 8.2 CLCD에 내 좌우명을 새겨라 [강좌]질문. (임베디드홀릭) |작성자 다인
위는
시작
RS신호만 1로 만듬
최소 62.5 * 2 이상 대기
R_W 신호 1로 만듬
최소 62.6 * 2 이상 대기
Enable 신호를 1로 만듬
최소 62.5 * 2 이상 대기
data를 씀
최소 62.5 * 2 이상 대기
Enable 신호 0으로 만듬
최소 62.5 * 2 이상 대기
---여기에서 더 필요한 시간은
Enable이 0이 된후 다시 위 과정이 반복되는걸 cycle time 이라고 하는데
위 시간을 다 합한것과 cycle time의 차(cycle 타임이 더 적으면 delay 필요없음,
cycle타임이 더 크면 해당 시간만큼 대기)
그런데 위에서
atmega128의 경우 PORTG는 io read write(비트 세트/clear) 명령어가 제공되지 않는 레지스터입니다.
즉 메모리 읽기/쓰기로 일어납니다.
PORTG |= 1 << Enable
이건
reg = PORTG;
reg = reg | (1 << Enable);
PORTG = reg
이렇게 세 단계로 이루어집니다.
메모리에서 데티아 읽기, 쓰기, 그리고 레지스터에 OR 시키는 시간만큼 소요됩니다.
따라서 io bit set/clear 가 되는
PORTA |= 1 << Enable ;
가 sbis 같은 2cycle 명령어로 변환되는것도 다르게 시간이 훨씬 더 걸립니다.
기계어 생성된걸 봐야 하며 컴파일 옵션(옵티마이저)에 따라 다르므로
제가 위에서 최소라고 적은 겁니다. 실제 시간은 더 걸림.
강좌에 있는 CLCD 타이밍으로 본다면
RS와 R/W는 같은 타이밍에 쓸수 있음
E가 1로 바뀔때까지 RS, R/W는 Tsu1 시간이 필요하며, 예의 경우 40ns 이므로 delay 필요없음
E의 high 시간은 Tw이며 230 ns 이므로 명령어 실행시간 62.5 * 2 = 130과의 차 100ns 이므로 두개의 기계어
asm("nop"); // 62.5
asm("nop"); // 62.5
다시 E를 0으로 하면 130ns(최소 62.5 * 2) 인데
새로 E를 high 할 수 있는 시간 Tc (cycle이 500 ns 이므로)
500 - (62.5 * 2 + 62.5 * 2(nop) + 62.5 * 2(0으로 쓰기)) =
500 - (130 + 130 + 130) = 500 - 390 = 110
그런데 새로 시작할때, 다시 RS/RW를 쓰기 하고 다시 E를 1로 올리므로 이미 시간에 다 포함.
(또한 함수로 구현되어 있어서 함수 리턴 및 call 시간이 추가로 붙음)
Tr/Tf 은 길어야 20ns 입니다. 일반적으로 회로에서 mcu에 바로 clcd를 연결할 경우 mcu가 특정 핀을 쓰기 하면 신호가 바로 올라가므로 별로 신경 쓸 필요는 없는데,
혹시라도 해당 핀에 cap같은걸 달아서 천천히 올라가는 완만한 신호가 생성된다면 해당 규격에 어긋나죠
만약 clcd를 긴 케이블을 통해서 구동한다면 선이 길어지면서
저항과 cap 성분이 크져서 신호가 완만히 올라갈경우 위 시간이 meet하지 않는다면 다른
방안(케이블을 좋은걸 사용하거나, 길이를 줄이거나) 을 강구해야 겠죠.
데이타쉬트 보시면
테이블 6에
bus timing (bus상에서 시간) 말고 명령어별로 delay시간이 우측에 있습니다.
즉 명령어에 따라 추가 시간이 필요합니다.
예를 들어 RS가 0인 것중에서도
clear display 명령어가 보낸후에는 최소 1.53 ms 까지 대기해야 하고
entry mode는 39 us 등
각 동작에 따른 delay 테이블을 두시거나,
해당 갑중 가능 큰값을 일괄 적용하시면 되겠죠.
bus 의 타이밍은 물리적은(전기적은) 규격이고, 그것을 통해 lcd에 명령이 전달되어서
해당 명령이 실행될때까지의 시간은 lcd 에서 내부적으로 더 필요한 시간입니다.
아 그래서 8-bit Initialization의 표와 같이 중간마다 명령어 수행후 최소 delay 값을 명시한거군요
그렇죠.
bus 타이밍은 전기적으로 상대편이 신호를 잘 받기 위한 규격이고
그렇게 전달된 명령/데이타가 내부에서 처리하는 시간이 있는거죠.
Subscribe to:
Posts (Atom)