Мультиплексор. Зображення взято тут. |
STM32 надають певну гнучкість у тому, які піни прив'язані до яких функцій -- так-званий remapping (перепризначення). STM32CubeMX автоматично користується цією можливістю під час візуального редагування конфігурації. Для кращого розуміння, спробуємо зробити це ж вручну, на рівні CMSIS.
Що це за можливість і де шукати інформацію про неї, вже описувалася в попередньому пості: "Таймери STM32 -- огляд", то я просто зацитую:
Контролер підтримує перепризначення, remapping-гу, пінів -- в залежності від потреб, існує кілька фіксованих комбінацій відповідності пінів "функціям" таймерів. Тобто, можна зробити, щоб TIM2_CH1 був під'єднаний до PB3, але при цьому, TIM2_CH1_ETR перейде з PA0 до PA15. Комбінацій небагато і вони фіксовані, але навіть такий обмежений ремапінг сильно спрощує розробку схем.
Щодо документації, то знайти відповідну інформацію -- задача нетривіальна. Зокрема, описана вона не там, де мова про таймери, а:
- Для STM32F100 -- в розділі "General-purpose and alternate-function I/Os (GPIOs and AFIOs)" документації на всю лінійку: "RM0041 Reference manual: STM32F100xx advanced ARM-based 32-bit MCUs": Табличка достатньо зручна. Зразу видно, наприклад, що TIМ1_CH2 -- це PA9, а за потреби його можна перекинути (remap) на пін PE11.
- Для STM32F303 ситуація веселіша -- загальна документація, еквівалентна згаданій вище: "RM0316 Reference manual: STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE advanced ARM®-based MCUs" відсилає до таблиці "alternate function mapping", десь побіжно згадуючи, що її слід шукати "у документі на пристрій", тобто просто цієї інформації не містить. Документація конкретніша, "STM32F303xB STM32F303xC: ARM®-based Cortex®-M4 32b MCU+FPU, up to 256KB Flash+ 48KB SRAM, 4 ADCs, 2 DAC ch., 7 comp, 4 PGA, timers, 2.0-3.6 V" справді містить таблички виду "Table 13.STM32F303xB/STM32F303xC pin definitions" для для кожного піна є, ким він може бути: та "Alternate functions for port X" для кожного із портів: Тобто, знайти інформацію можна, але зробити це важче.
Почнемо із прикладу "Таймери STM32 -- ШІМ/CMSIS", де за допомогою каналу CH2 таймера TIM3, генерувався ШІМ, змінюючи яскравість світлодіодна. TIM3_CH2 під'єднано до піна PA7. Припустимо, нас це не влаштовує і спробуємо знайти альтернативи. Візьмемо табличку для TIM3 (нагадаю, що приклади цієї серії -- для STM32F100):
Як видно, є два варіанти ремапінгу -- на пін PB5 чи на PC7. Зауважте, при тому буде перепризначено й інші канали -- немає можливості перепризначити лише один канал.
За ремаппінг (перепризначення) в STM32F100 відповідають два регістри, AFIO_MAPR і AFIO_MAPR2:
Регістр AFIO_MAPR STM32F100 |
Регістр AFIO_MAPR2 STM32F100. |
За TIM3 відповідають біти TIM3_REMAP регістра AFIO_MAPR:
Код налаштування таймера не змінився -- див. відповідний пост, змінилося лише налаштування пінів порту.
Отож, режим по замовчуванню:
1 2 3 4 5 6 7 8 9 10 11 12 13 | RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Дозволяємо тактування порту A GPIOA->CRL &= ~GPIO_CRL_CNF7_0; // 10 -- AF PP (Alternative function -- push-pull) GPIOA->CRL |= GPIO_CRL_CNF7_1; GPIOA->CRL |= GPIO_CRL_MODE7; //Встановити обидва біти MODE для піна 1 -- швидкість 50MHz // Значення по замовчуванню -- 0, NOREMAP нас влаштують. // Встановити його можна так: AFIO->MAPR &=~AFIO_MAPR_TIM3_REMAP; // Формально треба так, але так як AFIO_MAPR_TIM3_REMAP_NOREMAP == 0, // воно нічого не змінить: // AFIO->MAPR &=~AFIO_MAPR_TIM3_REMAP; // AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_NORE |
Рядок 9 показує, як до нього (режиму по замовчуванню) можна повернутися.
Зараз плавно загоратиметься світлодіод, під'єднаний до піна PA7.
Частковий ремапінг:
1 2 3 4 5 6 7 8 9 10 | RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Дозволяємо тактування порту B RCC->APB2ENR |= RCC_APB2Periph_AFIO; // Дозволяємо альтернативні ф-ції, // без цього remapping не працює AFIO->MAPR &=~AFIO_MAPR_TIM3_REMAP;// Зануляємо. По замовчуванню і так буде нуль, // але для порядку і з педагогічних міркувань... AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP; GPIOB->CRL &= ~GPIO_CRL_CNF5_0; // 10 -- AF PP (Alternative function -- push-pull) GPIOB->CRL |= GPIO_CRL_CNF5_1; GPIOB->CRL |= GPIO_CRL_MODE5; //Встановити обидва біти MODE для піна 1 -- швидкість 50MHz |
Зауважте, без тактування блоку альтернативних функцій ремапінг не працює! Також доводиться налаштовувати інший порт.
Тепер працюватиме світлодіод на піні PB5, а той, що на PA7 -- не світитиметься.
Нарешті, повний ремапінг:
1 2 3 4 5 6 7 8 9 10 11 | RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Дозволяємо тактування порту C RCC->APB2ENR |= RCC_APB2Periph_AFIO; // Дозволяємо альтернативні ф-ції, // без цього remapping не працює AFIO->MAPR &=~AFIO_MAPR_TIM3_REMAP;// Зануляємо. По замовчуванню і так буде нуль, // але для порядку і з педагогічних міркувань... AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_FULLREMAP; GPIOC->CRL &= ~GPIO_CRL_CNF7_0; // 10 -- AF PP (Alternative function -- push-pull) GPIOC->CRL |= GPIO_CRL_CNF7_1; GPIOC->CRL |= GPIO_CRL_MODE7; //Встановити обидва біти MODE для піна 1 -- швидкість 50MHz |
В такій конфігурації працюватиме світлодіод, під'єднаний до PC7.
Нотатка щодо STM32F303
Для сімейства STM32F3 підсистема GPIO була реорганізована -- зокрема, змінилися імена регістрів. Детальніше про це, можливо, іншим разом, а зараз глянемо, як у них організований ремапінг. (Де шукати відповідну інформацію в документації -- див. цитату вище.)За перепризначення відповідають регістри GPIOx_AFRL ("нижні" піни 0-7) та GPIOx_AFRH ("верхні" піни 8-15):
Регістра GPIOx_AFRL сімейства STM32F303 |
Регістра GPIOx_AFRH сімейства STM32F303 |
Для кожного піна поле AFRy містить номер альтернативної функції:
Номери альтернативних функцій для GPIOx_AFRL, такі ж вони для GPIOx_AFRH. |
Тобто, бути піном, керованим каналом CH2 таймера TIM3, можуть піни PA4, PA7, PB5, PC7 i PE3. Для всіх них це є альтернативна функція номер два -- AF2.
Зауваження: для більшої читабельності, зображення обрізані, але подивившись на оригінал, можна побачити, що порти A i B використовують до 16 альтернативних функцій, а решту -- до восьми. (Насправді, навіть на обрізаному це видно із масштабу стовпців :-).Чому так зробили із керування перепризначення -- можна запідозрити. Але отак сходу -- працювати стало важче. Правда, якщо користуватися STM32Cube -- проблем немає.
Проект можна скачати тут. Вибір ремапінгу здійснюється макросом REMAP_LEVEL:
1 2 3 4 5 6 7 8 9 10 11 12 | //! REMAP_LEVEL = 0 --- no remap, TIM3_CH2 -> PA7 //! REMAP_LEVEL = 1 --- partial remap, TIM3_CH2 - > PB5 //! REMAP_LEVEL = 2 --- full remap, TIM3_CH2 - > PC7 #define REMAP_LEVEL 0 #if REMAP_LEVEL == 0 // ................. #elif REMAP_LEVEL == 1 // ................. #elif REMAP_LEVEL == 2 // ................. #endif |
Як вже згадувалося, для Cube + HAL повторювати сенсу немає -- все буде зроблено автоматично.
Немає коментарів:
Дописати коментар