2015-01-11 1 views
2

현재(source code at GitHub)을 Arduino (AVR 기반)에서 Arduino Due (ARM Cortex M3)로 이식하고 있습니다.SysTick-> LOAD 대 SysTick-> CALIB

라이브러리에는 정확한 1ms 타이밍이 필요합니다. 명백한 후보자는 게임의 사용이다. Condueniently Arduino Due는 이미 1kHz의 시스템을위한 시스템입니다.

그러나 내 (AVR) DCF77 라이브러리는 일단 DCF77에 고정되면 타이밍을 조정할 수 있습니다. 이는 같은 타이머 다시로드 값을 조작하여 수행됩니다 그래서

void isr_handler() { 
    cumulated_phase_deviation += adjust_pp16m; 
    // 1/250/64000 = 1/16 000 000 
    if (cumulated_phase_deviation >= 64000) { 
     cumulated_phase_deviation -= 64000; 
     // cumulated drift exceeds 1 timer step (4 microseconds) 
     // drop one timer step to realign 
     OCR2A = 248; 
    } else if (cumulated_phase_deviation <= -64000) { 
     // cumulated drift exceeds 1 timer step (4 microseconds) 
     // insert one timer step to realign 
     cumulated_phase_deviation += 64000; 
     OCR2A = 250; 
    } else { 
     // 249 + 1 == 250 == 250 000/1000 = (16 000 000/64)/1000 
     OCR2A = 249; 
    } 

    DCF77_Clock_Controller::process_1_kHz_tick_data(the_input_provider()); 
} 

나는 ARM 프로세서에 포트에이 작업을 할 수 있습니다. 는 ARM 정보 센터에서 나는 다음과 같은 documentation.

이 SysTick

을 ... 구성 발견

당신이 SysTick 이벤트 사이에 필요한 간격을두고 SysTick 다시로드 값 레지스터를로드하는 데 필요한 SysTick을 구성하려면 . 타이머 인터럽트 또는 COUNTFLAG 비트 (SysTick 컨트롤 및 상태 레지스터)가 1에서 0으로 전환 될 때 활성화되므로 은 n + 1 클럭 틱을 활성화합니다. 100의 기간이 필요한 경우 99 을 SysTick Reload Value 레지스터에 기록해야합니다. SysTick Reload Value 레지스터는 1과 0x00FFFFFF 사이의 값을 지원합니다. 당신은 예를 들어,이 1ms를 들어, 시간 초과 간격으로 이벤트를 생성하는 SysTick을 사용하려면

, 당신은 다시로드 레지스터에 대한 가치를 확장 할 수있는 SysTick 교정 값 등록을 사용할 수 있습니다. SysTick 교정 값 레지스터는 TENMS 필드 (비트 0 ~ 23)에 10ms의주기 동안 펄스 수를 포함하는 읽기 전용 레지스터입니다. 또한이 레지스터에는을 나타내는 데 사용되는 SKEW 비트 (30)가 있으며 TENMS 섹션의 10ms에 대한 보정은 클록 주파수의 작은 변동으로 인해 정확히 10ms 이 아닙니다. 기준 클럭이 제공되면 비트 31은 을 나타내는 데 사용됩니다.

...

불행하게도 내가 어떻게 SysTick-> LOAD에 아무것도를 찾아 SysTick-> CALIB하지 않았다가 연결되어 있습니다. 즉, 내가 스로틀을하거나 가속을하고 싶다면 LOAD 또는 CALIB 값을 조작해야합니까? 그리고이 레지스터에 어떤 값을 넣어야합니까?

인터넷을 검색해도 더 좋은 힌트가 표시되지 않았습니다. 어쩌면 나는 잘못된 곳을 찾고 있을지도 모른다. 이 질문에 대한 더 자세한 참조는 어디에서 있습니까? 아니면 좋은 예가 있을까요? AVR의에, 당신은 OCR2A에 값을로드하는 그것까지 계산 TCNT2에 타이머를 기다리고, 반면에 :

답변

2

Cortex-M3 TRM으로 AtMega328 datasheet 비교의 뛰어난 점은 타이머 라운드 반대 방식으로 작동한다는 것입니다 M3에서 지연 값을 SYST_RVR에로드하면 시스템은 에서이 값에서 SYST_CVR으로 계산합니다.

비교 값이 0으로 고정되어 재로드 값만 조정할 수 있기 때문에 보정의 큰 차이점이 발생합니다. 비교 값을 직접 조정할 때보 다 지연 시간이 길어질 수 있습니다 (카운터 재로드가 인터럽트가 생성되는 것과 같은 시간).

SYST_CALIB의 읽기 전용 값 (구현 정의 및 선택 사항 인 경우 실제로 존재하는 경우)은 단순히 SYSTICK 틱을 실제 벽시계 시간과 관련시키기위한 것입니다. - 타이머를 처음 초기화 할 때 틱 주파수를 알아야합니다 원하는 기간에 적절한 리로드 값을 선택하려면 "이 많은 참조 클럭 틱이 10ms (또는 가능하게) 발생합니다"라는 레지스터 필드가 있으므로 실행 시간에 휴대용 방식으로 계산할 가능성이 있습니다. 다른 장치에 대해 변경해야하는 값을 하드 코드하십시오.

그러나이 경우 동기화 할 외부 클럭을 더 정확하게 지정하는 것이 덜 중요하지만 중요하게는 펌웨어가 이미 용 타이머를 구성했습니다. 따라서 어떤 값이든지 SYST_RVR은 1KHz에 근접 할 정도로 충분히 가깝다는 것을 가정 할 수 있습니다. 실제로는 실제 값이 무엇인지 알 필요가없는 1KHz 기간을 미세 조정하기 만하면됩니다. SysTick->LOAD++ 또는 SysTick->LOAD-- 오류가 어느 방향 으로든 너무 커지면 비트 깊이 탐구


상기 SAM3X datasheet 해당의 SOC 특정 M3 구현에서, SYSTICK은 10.5 MHz의 기준 클럭을 갖는 것을 나타내고, 따라서 SYST_CALIB 레지스터 은 10ms 위해 105,000 틱 값을 제공한다. 분명히 Atmel은 명백하게 TENMS 필드에 1ms, 10500의 틱 수를 부여하는 것이 정말 영리하다고 생각했기 때문에 예외는 아닙니다. 훌륭한.

+0

Arduino는 1kHz에서 실행되도록 시스템을 설정합니다. 그러나 제 라이브러리는 더 나은 정밀성을 필요로합니다. 따라서 나는 그것을 더 잘 조정할 필요가있다. 따라서 그에 따라 값을 수정해야합니다. 대기 시간은 문제가되지 않습니다. 계속 나를 괴롭히는 것은 "SYST_CALIB의 읽기 전용 값 (실제로 존재하더라도 구현 정의 및 선택 사항 임)은 SYSTICK 틱을 실제 벽시계 시간과 관련시키는 것입니다."이 메커니즘이 얼마나 정확하게 작동합니까? ? 아니면 보정 값을 무시하고 재로드 값을 직접 조정해야합니까? 그러나 보정 값은 무엇에 좋은가? –

+0

기본적으로 SYST_CALIB는 RELOAD와 관련이 없습니다. 그것은 소프트웨어의 다른 부분에만 관련이 있습니다 -> 나는 그것을 무시할 수 있습니다. 우수한. 귀하의 의견은 또한 내가 왜 그것을 얻지 못했는지 설명합니다. 나는 데이터 시트에서 같은 문제 (10ms 대 1ms)를 보았지만 이해가 부족하다고 생각했다. –

+0

SysTicks는 84 MHz 클록을 가진 것 같습니다. 따라서 나는 SYST_CALIB (어쨌든 무시한다)가 84000이나 8400으로 채워 져야한다고 생각한다. –

1

다른 사람들이해야 할 것처럼 주위를 파지 않아도되는 이유만으로도 - 여기에 내가 알아 낸 것이 있습니다.

arduino-1.5.8/hardware/arduino/sam/system/CMSIS/CMSIS/Include/core_cm * .h에는 SysTick을 조작하는 코드가 있습니다. core_cm3.h에 특히 기능이

// Set Systick to 1ms interval, common to all SAM3 variants 
    if (SysTick_Config(SystemCoreClock/1000)) 
    { 
    // Capture error 
    while (true); 
    } 

이다 SystemCoreClock는 84,000,000 평가 이래로이 SysTick_Config(84000)처럼 컴파일하는 것이 다음의 기능 initarduino-1.5.8/hardware/arduino/sam/variants/arduino_due_x/variant.cpp에이어서

static __INLINE uint32_t SysTick_Config(uint32_t ticks) 
{ 
    if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);   /* Reload value impossible */ 

    SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;  /* set reload register */ 
    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */ 
    SysTick->VAL = 0;           /* Load the SysTick Counter Value */ 
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 
        SysTick_CTRL_TICKINT_Msk | 
        SysTick_CTRL_ENABLE_Msk;     /* Enable SysTick IRQ and SysTick Timer */ 
    return (0);             /* Function successful */ 
} 

에게있다. DCF77 모듈에 대해 SysTick_Config(84001)이 SysTicks를 느리게하는 반면 SysTick_Config(83999)은 속도를 올릴 것임을 확인했습니다.

+0

좋은 찾기 - 약간의 모습이 있었지만 GitHub의 끔찍한 검색으로 인해 나를 포기했습니다. 아마도 'SysTick_CTRL_CLKSOURCE_Msk'는 0x04이며, CLKSOURCE 비트를 설정하여 SysTick을 기준 클럭 대신 CPU 클럭에서 끕니다 (이 경우 CPU 클럭/8). 이 함수는 불필요한 지터를 유발할 수있는 현재 카운트를 리셋합니다. 실제로 처음으로 초기화 할 때만 작동합니다. 개인적으로 필자는 필요할 때'SysTick-> LOAD'를 직접 수정합니다. – Notlikethat

+0

힌트를 보내 주셔서 감사합니다. 나는 내 눈앞에서 그것을 직접 가지고 있었지만 나는이 점을 놓쳤다. 그래서 나는 SysTick-> Load를 직접 수정할 것이다. –