Пролог

В математике есть такая тема как Диофантовы уравнения. В самом простом виде выглядят они так.

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

Тут одно уравнение и две неизвестные: x,y. При этом a, b, d – это известные константы.

На первый взгляд может показаться как бесполезная вещь для программирования Micro Controller Unit (MCU), но не тут-то было.

Когда программируешь микроконтроллер (MCU), то первое, что приходится делать – это конфигурировать тактирование процессорного ядра. Тактированием заправляет устройство с названием phase-locked loop (PLL/ФАПЧ). Это подсистема SoC(а).

И там надо подобрать три константы (натуральных числа): M, N и F. В микроконтроллере Artery, абстрактно изображая, эта электрическая цепь выглядит вот так. Умножители и делители частот.

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

По формуле (2)

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

Вычисляется системная частота F_sys (sclk). Это уравнение (2) преобразуется в уравнение (3)

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

А уравнение (3), в свою очередь, это самое настоящее Диофантово уравнение! Да.. Тут F_quartz – это частота кварцевого резонатора, который задается схемотехникой электронной платы.
F_sys задается программистом для достижения желаемой производительности прошивки. Остаются целочисленные неизвестные N, M и F.

Далее накладываются ещё ограничения уже производителем микроконтроллера. Для Artery это

Переменная

Минимальное

Максимальное

M

1

15

N

31

500

FR (степени двойки)

1

32

Это ограничение даже прописано комментариями в исходных кодах на Cи, которые бесплатно предоставляет производитель Artery Tech.

 /**   *    config crm pll   *                        pll_rcs_freq * pll_ns   *         pll clock = --------------------------------   *                           pll_ms * pll_fr_n   *         attemtion:   *                  31 <= pll_ns <= 500   *                  1  <= pll_ms <= 15   *   *                       pll_rcs_freq   *         2mhz <=  ---------------------- <= 16mhz   *                          pll_ms   *   *                       pll_rcs_freq * pll_ns   *         500mhz <=  -------------------------------- <= 1200mhz   *                               pll_ms   * @param  clock_source   *         this parameter can be one of the following values:   *         - CRM_PLL_SOURCE_HICK   *         - CRM_PLL_SOURCE_HEXT   * @param  pll_ns (31~500)   * @param  pll_ms (1~15)   * @param  pll_fr   *         this parameter can be one of the following values:   *         - CRM_PLL_FR_1   *         - CRM_PLL_FR_2   *         - CRM_PLL_FR_4   *         - CRM_PLL_FR_8   *         - CRM_PLL_FR_16   *         - CRM_PLL_FR_32   * @retval none   */ void crm_pll_config(crm_pll_clock_source_type clock_source,                      uint16_t pll_ns,                      uint16_t pll_ms,                     crm_pll_fr_type pll_fr)   

Итак, постановка задачи:

Есть электронная плата с Artery MCU . На PCB припаян кварцевый резонатор c частотой 8 MHz и подключен к MCU. Необходимо программно сконфигурировать системную частоту ядра ровно на 100 MHz.

Какими при этом должны быть коэффициенты PLL: N, M и RF?

Решение

По сути, задача свелась к тому чтобы решить Диофантово уравнение (4).

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

Можно попробовать прибегнуть к помощи Artificial intelligence (AI) на сайте Wolfram Alfa

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

Однако это не решение в частном виде. На практике же нужно численное решение, чтобы проинициализировать им функцию crm_pll_config().

Однако нам повезло. В частности, тут область значений функции (2) достаточно маленькая, поэтому можно найти решение уравнения (3) обыкновенным перебором.

Для этого я написал свой простой численный решатель Диофантова уравнения для PLL прямо на Си.

uint64_t ipow(uint32_t base, uint32_t exponenta) { 	uint64_t ret = 1, i = 0;     if(0 != exponenta) {         for(i = 1; i <= exponenta; i++) {             ret *= base;         }     }     return ret; }  typedef struct{     uint32_t ms;     uint32_t ns;     uint32_t fr; }PllArtety_t;  bool pll_calc_artery(uint32_t freq_xtal_hz,                       uint32_t freq_sys_hz,                      PllArtety_t* const PllArtety) {     bool res = false;      LOG_INFO(PLL_CALC, "FreqXtal:%u Hz,FreqSys:%u  Hz", freq_xtal_hz,               freq_sys_hz);     log_printf("{[(Xtal:%uHz/M)*N]/FR }= Sys:%u Hz" CRLF,                 freq_xtal_hz, freq_sys_hz);     if(PllArtety) {         uint32_t m = 0;         uint32_t temp_hz = 0;         uint32_t cur_freq_sys_hz = 0;         for(m = 1; m <= 15; m++) {             uint32_t n = 0;             for(n = 31; n <= 500; n++) {                 uint32_t f = 0;                 for(f = 0; f <= 5; f++) {                     uint32_t fr = ipow(2, f);                     cur_freq_sys_hz = ((n * freq_xtal_hz) / (m * fr));                     if(freq_sys_hz == cur_freq_sys_hz) {                         temp_hz = freq_xtal_hz * n / m;                          /*condition from Artery New Clock Config*/                         if(500000000 <= temp_hz) {                             if(temp_hz <= 1200000000) {                                 log_printf("MS:%u,NS:%u,FR:%u" CRLF, m, n, fr);                                 PllArtety->ms = m;                                 PllArtety->ns = n;                                 PllArtety->fr = fr;                                 res = true;                             }                         }                     }                 }             }         }     }     if(res) {         LOG_INFO(PLL_CALC, "SpotPllVals!");     } else {         LOG_ERROR(PLL_CALC, "NoPllVals!");     }     return res; }

Отладка

Вот так, в симуляторе прошивки на PC я исполнил команду обсчета PLL и получил аж 5 решений на выбор.

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

Далее подставив четвёртое решение в утилиту проверки PLL я увидел, что конфиг валидный!

Зачем Программисту Микроконтроллеров Диофантовы Уравнения

Успех!

Итоги

Как видите, программирование микроконтроллеров требует математической подготовки. А как Вы хотели?

Благодаря способности решать Диофантовы уравнения, Вы можете переконфигурировать частоту процессора далеко в run-time.

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

Вот так..

Links/URLs

https://www.wolframalpha.com/input?i=8000000x-100000000y%3D0

http://latex.codecogs.com/eqneditor/editor.php

https://ru.wikipedia.org/wiki/Диофантово_уравнение