ATmega328에서 64의 클럭 프리스케일러를 실행할 때, 타이머 중 하나가 특정 시간에 알 수없는 이유로 실행 속도가 빨라집니다.
ATmega328에서 두 개의 타이머를 사용하여 TLC5940에 필요한 클럭킹을 생성하고 있습니다 (아래 이유를 참조하십시오. 이는 중요하지 않습니다). TIMER0
Fast PWM을 사용하여 클록 신호를 생성하며 OC0B
다음과 같이 설정됩니다.
TCCR0A = 0
|(0<<COM0A1) // Bits 7:6 – COM0A1:0: Compare Match Output A Mode
|(0<<COM0A0) //
|(1<<COM0B1) // Bits 5:4 – COM0B1:0: Compare Match Output B Mode
|(0<<COM0B0)
|(1<<WGM01) // Bits 1:0 – WGM01:0: Waveform Generation Mode
|(1<<WGM00)
;
TCCR0B = 0
|(0<<FOC0A) // Force Output Compare A
|(0<<FOC0B) // Force Output Compare B
|(1<<WGM02) // Bit 3 – WGM02: Waveform Generation Mode
|(0<<CS02) // Bits 2:0 – CS02:0: Clock Select
|(1<<CS01)
|(0<<CS00) // 010 = clock/8
;
OCR0A = 8;
OCR0B = 4;
TIMSK0 = 0;
TIMER2
256 TIMER0
사이클 마다 블랭킹 펄스를 생성하기 위해 데이터 라인을 돌리고 다음과 같이 설정됩니다.
ASSR = 0;
TCCR2A = 0
|(0<<COM2A1) // Bits 7:6 – COM0A1:0: Compare Match Output A Mode
|(0<<COM2A0) //
|(0<<COM2B1) // Bits 5:4 – COM0B1:0: Compare Match Output B Mode
|(0<<COM2B0)
|(0<<WGM21) // Bits 1:0 – WGM01:0: Waveform Generation Mode
|(0<<WGM20)
;
TCCR2B = 0
|(0<<FOC2A) // Force Output Compare A
|(0<<FOC2B) // Force Output Compare B
|(0<<WGM22) // Bit 3 – WGM02: Waveform Generation Mode
|(1<<CS22) // Bits 2:0 – CS02:0: Clock Select
|(0<<CS21)
|(0<<CS20) // 100 = 64
;
OCR2A = 255;
OCR2B = 255;
TIMSK2 = 0
|(1<<TOIE2); // Timer/Counter0 Overflow Interrupt Enable
TIMER2
오버 플로우시 (256주기마다) ISR을 호출합니다. ISR은 수동으로 블랭킹 펄스와 필요한 경우 래칭 펄스를 생성합니다.
volatile uint8_t fLatch;
ISR(TIMER2_OVF_vect) {
if (fLatch) {
fLatch = 0;
TLC5940_XLAT_PORT |= (1<<TLC5940_XLAT_BIT); // XLAT -> high
for (int i=0;i<10;i++)
nop();
TLC5940_XLAT_PORT &= ~(1<<TLC5940_XLAT_BIT); // XLAT -> high
}
// Blank
TLC5940_BLANK_PORT |= (1<<TLC5940_BLANK_BIT);
for (int i=0;i<10;i++)
nop();
TLC5940_BLANK_PORT &= ~(1<<TLC5940_BLANK_BIT);
}
nop()
위 코드 의 지연은 로직 분석기 트레이스에서 펄스를보다 명확하게하기위한 것입니다. main()
함수 의 루프는 다음과 같습니다. 직렬 데이터를 보내고 ISR이 래칭을 처리 할 때까지 기다린 후 다시 수행합니다.
for (;;) {
if (!fLatch) {
sendSerial();
fLatch = 1;
_delay_ms(1);
}
nop();
}
sendSerial()
일부 SPI 전송을 수행합니다 ( 간단히하기 위해 pastebin의 코드 ). 내 문제는 sendSerial()
완료 후 fLatch
처리 시간을 낮게 설정하기 를 기다리는 동안 클럭 타이머가 빨라진다는 것입니다. 다음은 로직 분석기 트레이스입니다 (동일한 신호가 그래픽을 계속 작게 만드는 영역을 잘라 냈습니다).
왼쪽에서 채널 0과 1은 전송중인 SPI 데이터의 꼬리 끝을 보여줍니다. 또한 왼쪽의 채널 4에서 블랭킹 펄스를 볼 수 있습니다. 채널 2에서 클럭킹 펄스가 예상대로 맞춰집니다. 이미지의 틈이있는 곳 바로 주위가 루틴 내부 fLatch
로 설정됩니다 . 그 후 곧 4 배 정도 속도가 빨라집니다. 결국, 블랭킹 펄스와 래칭 펄스가 수행되고 (채널 3과 4, 이미지의 오른쪽 1/3), 이제 클럭킹 펄스가 규칙적인 주파수를 재개하며 직렬 데이터는 다음과 같습니다. 다시 보냈습니다. 에서 줄을 가져 오려고 했지만 동일한 결과가 나타납니다. 무슨 일이야? ATmega는 20Mhz 크리스탈에서 클럭킹 된 후 다음 코드를 사용하여 64 배 느리게 진행됩니다.1
main()
TIMER0
delay_ms(1);
main()
CLKPR = 1<<CLKPCE;
CLKPR = (0<<CLKPS3)|(1<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);
TLC5940 LED 드라이버 제어를 실험 중입니다 .이 칩에는 클럭주기가 끝나면 외부 클럭과 리셋이 필요합니다.
sendSerial()
SPI를 통해 데이터를 보내는 코드입니다. TCCR
(타이머 컨트롤) 레지스터를 건드리지 않습니다 .