Перейти к содержанию

CH32V

  • записей
    8
  • комментариев
    12
  • просмотров
    3 085

Как затактировать систему


zhevak

2 840 просмотров

То решение, какое предлагает фирменный фреймфорк (или как это  китайцы называют у себя на фирме) мне, честно говоря, вообще не нравится. Я уже писал об этом. Там, в их коде полно ошибок, а, кроме того, компилятор генерирует много ненужного кода.

Я вообще не понимаю, зачем нужно использовать структуру GPIO_InitStructure разработчику, который, знает состав портов ввода-вывода и как они работают.

Вот, пример, кода который, я взял из фреймворка:

void GPIO_Toggle_INIT(void)
{
  GPIO_InitTypeDef GPIO_InitStructure = {0};
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
}

Возможно кому-то это и нравится, но я считаю, что это какой-то ужас.

Вместо того, чтобы одной командой включить тактирование порта, а другой сконфигурировать все известные на данный момент биты, — создаётся структура. Затем инициализируются её поля. Потом вызывается функция GPIO_Init().

Вы заглядывали во внутрь, что делает функция GPIO_Init()? — Нет?!!

Не поленитесь, загляните! Получите массу удовольствия. Или инфаркт.

И как изощрённое издевательство — не поленитесь просмотреть код настройки тактирования, который находится в файлах system_ch32v00x.c и system_ch32v00x.h. Я думаю, после этого вы поймёте моё негодование.

Понятно, что весь этот «сервис» создаёт огромную кучу бессмысленного и беспощадного кода.

Вы спросите — а для чего это всё так сделано? Точного ответа я не знаю, но предполагаю, что в основе лежит вполне благородная цель — типа чтобы программист не изучал регистры, а пользовался нашим замечательным фреймворком. Скорее всего предполагается, что такое решение сэкономит время разработки программы, а значит -- не сильно увеличит цену изделия. Ну, не знаю... сэкономит ли.

А с другой стороны. Ну, хорошо. Теперь программисту не надо изучать регистры и назначение битов. А как насчёт того, что вместо этого программисту придётся изучать сам фреймворк? Нет ли в этом подходе того, что вместо изучения одной (базовой) сущности, нужно изучать другую (производную) сущность? Ладно, если производная сущность окажется проще. А если нет? А если, тем паче, — что-то пойдёт не так? Тогда программисту придётся изучать "обе две" сущности — и фреймворк, и регистры. Вот, счастье-то!

Короче, хотите быть ардуинщиком — будьте им! Никто вам не мешает! А кто уважительно относится к технике, того прошу за мной!

Итак, ниже я провожу код инициализации тактирования от встроенного генератора. В этом коде я не использую PLL, поэтому ядро микроконтроллера будет работать на частоте 24 МГц. Поскольку частота не высокая, то флеш-памяти не потребуется дополнительный такт для работы.

void system_init(void)
{
  RCC->CTLR |= RCC_HSION;    // Включаю HSI (24 МГц)
  RCC->CFGR0 &= 0x00000000;  // Отключаю MCO, пределители в исходное сотояние, HSI
  RCC->CTLR &= ~(RCC_PLLON | RCC_CSSON | RCC_HSEON); // Выключаю PLL и HSE
  RCC->CTLR &= ~RCC_HSEBYP;  // Выключаю байпас
  RCC->INTR = (RCC_CSSC | RCC_PLLRDYC | RCC_HSERDYC | RCC_HSIRDYC | RCC_LSIRDYC); // Сбрасываю флаги

  FLASH->ACTLR &= ~FLASH_ACTLR_LATENCY;
  FLASH->ACTLR |=  FLASH_ACTLR_LATENCY_0; // Цикл обращения к флеш-памяти

  RCC->CFGR0 |= RCC_HPRE_DIV1; // HCLK = SYSCLK = 24 MHz
}

Вот такой рабочий код размером в полтора десятка строк.

Если мне понадобится, к примеру, затактировать систему от внешнего кварцевого резонатора или увеличить частоту в два раза, я тупо сделаю копию этого кода и изменю нужные мне параметры, а исходный код (чтобы не потерялся) просто закомментирую. И не надо говнокодить никаких заумныйх решений на все случаи жизни. Ни к чему это.

Потом, спустя какое-то время, я могу снова вернуться к этим исходным кодам и выбрать то, что мне будет нужно в следующем проекте. Разумеется, рядом с кодом нужно разместить комментарии.

Во первых, это красиво. (с)

А во вторых, код таким образом получается наглядный, понятный, осязаемый. В отличие от говнокода из фреймворка. Ведь при таком подходе будет сразу понятно, что этот код делает.

Мне остаётся только добавить, что функция system_init() вызывается из ассемблерного файла startup_ch32v00x.S.

Вот, несколько последних строк этого файла:

...
la      t0, _start
ori     t0, t0, 3
csrw    mtvec, t0

jal     system_init
la      t0, main
csrw    mepc, t0
mret

Да, это ассемблер RISC-V. Это не важно, что вы сейчас ничего не понимаете, что тут происходит. Я как-нибудь потом вернусь к этому файлу.

Сейчас важно чтобы вы увидели команду вызова функции system_init() и команду вызова функции main(). Заметьте, что сначала вызывается функция system_init(). А функция main() начинает работать, когда оборудование уже настроено.

1 Комментарий


Рекомендуемые комментарии

la t0, main
csrw mepc, t0
mret

Интересно зачем это сделано, почему было не обойтись обычным call (который jal) или вовсе безусловным переходом. Неужели для выхода из kernel-mode в user?

Цитата

Вы спросите — а для чего это всё так сделано?

Видать, их ST-шники покусали. Хорошо еще не до изобретения ST-HAL-а. Видать, даже трудолюбивым китайцам не захотелось такую кучу говнокода лопатить.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Добавить комментарий...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...

×
×
  • Создать...