2015-01-11 1 views
2

В настоящее время я портирую свой DCF77 library (вы можете найти source code at GitHub) от Arduino (на базе AVR) до Arduino Due (ARM Cortex M3).SysTick-> LOAD vs SysTick-> CALIB

Для библиотеки требуется точное время в 1 мс. Очевидным кандидатом является использование систолов. Приблизительно Arduino Due уже настроен для систем с частотой 1 кГц.

Однако моя библиотека (DCR) библиотеки AVR способна настраивать синхронизацию после ее блокировки до 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 Reload Value регистр с интервалом требуемого между событиями SysTick , Таймер бит прерывания или бит COUNTFLAG (в регистре управления SysTick и статусом ) активируется при переходе от 1 до 0, поэтому он активирует каждые n + 1 тактов. Если требуется период в 100, 99 должен быть записан в регистр значения SysTick Reload Value. Регистр обновления SysTick поддерживает значения от 1 до 0x00FFFFFF.

Если вы хотите использовать SysTick для генерации события в таймерном интервале, например, 1мс, вы можете использовать SysTick Calibration Value Register для масштабирования значения для регистра Reload. Регистр калибровочного значения SysTick является регистром только для чтения, который содержит число импульсов в течение периода 10 мс в поле TENMS (бит 0 до 23). Этот регистр также имеет бит SKEW (30), который используется для указания , что калибровка в течение 10 мс в секции TENMS не является точно 10 мс из-за небольших изменений в тактовой частоте. Бит 31 используется для указания , если имеется опорный тактовый сигнал.

...

К сожалению, я не нашел ничего о том, как SysTick-> НАГРУЗКИ и SysTick-> CALIB связаны. То есть: если я хочу дросселировать или ускорять систолы, мне нужно управлять значением LOAD или CALIB? И какие значения мне нужно внести в эти регистры?

Поиск в Интернете не вызвал никаких улучшенных намеков. Возможно, я искал неправильные места. Есть ли где-нибудь более подробная ссылка на эти вопросы? Или, может быть, даже хорошие примеры?

ответ

2

Сравнивая AtMega328 datasheet с Cortex-M3 TRM, точка безусловного победителя является то, что таймеры работают противоположные пути круглые: на AVR, вы загружаете значение в OCR2A и ожидание таймера в TCNT2, чтобы сосчитать до него, в то время как на M3 вы загружаете значение задержки в SYST_RVR, тогда система будет считать вниз от этого значения до 0 в SYST_CVR.

Большая разница для калибровки будет заключаться в том, что значение сравнения зафиксировано на 0, и вы можете отрегулировать значение перезагрузки, у вас может быть больше латентности по сравнению с непосредственным регулированием значения сравнения (при условии, что перезагрузка счетчика происходит на одновременно генерируется прерывание).

Значение, доступное только для чтения, в SYST_CALIB (если оно действительно существует, будучи определенным реализацией и необязательным), это просто для привязки тиков SYSTICK к фактическому времени разгона - при первом инициализации таймера вам необходимо знать частоту тика чтобы выбрать соответствующее значение перезагрузки в течение требуемого периода времени, поэтому наличие поля регистров, в котором говорится, что «это количество эталонных эталонных часов происходит в 10 мс (возможно)», дает некоторую возможность вычислить, что во время выполнения переносимым образом, а не иметь hard-code значение, которое может потребоваться изменить для разных устройств.

В этом случае, однако, не только имеет более точные внешние часы для синхронизации, но и, самое главное, , прошивка уже настроила таймер для вас. Таким образом, вы можете предположить, что любое значение в SYST_RVR представляет собой достаточно близко к 1KHz и работает оттуда - на самом деле для точной настройки периода 1 кГц вам даже не нужно знать, что такое фактическое значение, просто выполните SysTick->LOAD++ или SysTick->LOAD--, если ошибка становится слишком большой в любом направлении.


Копаясь немного глубже, то SAM3X datasheet показывает, что для конкретной реализации M3 в этой SoC, SysTick имеет базовую частоту 10,5 МГц, поэтому SYST_CALIB регистр должен дает значение 105000 клещей для 10ms. Кроме того, это не так, потому что, по-видимому, Атмел подумал, что было бы действительно разумно сделать одноименное поле TENMS, чтобы подсчитать количество для 1ms, 10500. Замечательно.

+0

Arduino устанавливает систолы таким образом, чтобы они работали на частоте 1 кГц. Однако моя библиотека нуждается в лучшей точности. Поэтому мне нужно настроить его лучше. Следовательно, мне нужно соответствующим образом изменить значения. Задержка не является проблемой. То, что меня затачивает, - это значение «Значение, доступное только для чтения в SYST_CALIB (если оно действительно существует, будучи реалистичным и необязательным), это просто для привязки тиков SYSTICK к фактическому времени настенного закрытия -« Как именно работает этот механизм ? Или я должен просто игнорировать значение калибровки и напрямую корректировать значение перезагрузки? Но какова же ценность калибровки? –

+0

Таким образом, в принципе SYST_CALIB не относится к RELOAD. Это относится только к другим частям программного обеспечения -> я могу игнорировать его. Отлично. Ваш комментарий также объясняет, почему я этого не понял. Я заметил ту же проблему (10 мс против 1 мс) в таблицах данных, но я подумал, что это мое отсутствие понимания. –

+0

Согласно тому, что я узнал сейчас (см. Мой ответ ниже), SysTicks, похоже, имеет тактовую частоту 84 МГц. Соответственно, я ожидал бы, что SYST_CALIB (который я игнорирую в любом случае) должен быть заполнен 84000 или 8400 в зависимости от того, как вы интерпретируете документацию - правильно? –

1

Только по той причине, что другим не нужно копаться, как должно было быть - вот что я узнал дополнительно.

В arduino-1.5.8/hardware/arduino/sam/system/CMSIS/CMSIS/Include/core_cm * .h есть код для управления SysTick. В частности, в core_cm3.h есть функция

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 */ 
} 

Затем в arduino-1.5.8/hardware/arduino/sam/variants/arduino_due_x/variant.cpp в функции init есть

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

Поскольку SystemCoreClock вычисляется в 84000000 следует, что это компилируется как SysTick_Config(84000). Я проверил против модуля DCF77, что SysTick_Config(84001) замедлит SysTicks, в то время как SysTick_Config(83999) ускорит его.

+0

Хорошая находка - я немного посмотрел, но ужасный поиск GitHub заставил меня сдаться. Предположительно 'SysTick_CTRL_CLKSOURCE_Msk' является 0x04, который устанавливает бит CLKSOURCE для привода SysTick от тактовой частоты процессора, а не опорной частоты (хотя в данном случае это просто тактовая/8 в любом случае). Обратите внимание, что эта функция сбрасывает текущий счетчик, что может привести к ненужному дрожанию, и делает кучу работы, которая действительно только для первоначальной инициализации - лично я бы просто изменил «SysTick-> LOAD» там, где это необходимо. – Notlikethat

+0

Спасибо за подсказку. Хотя у меня это было прямо перед глазами, я пропустил этот момент. Поэтому я потом модифицирую SysTick-> Load. –