Є в мікроконтролерах STM32L0x така приємна штука, як LPUART. Може працювати від LSE — 32768Hz кварца коли мікроконтролер спить і піднімати його по приходу байта. Ну там ще дрібно-дробовий дільник, який дозволяє витягувати доволі високі частоти обміну від такого кварца, але то для мене вже не так важливо було. Просто є за оптроном ще один мікроконтролер, який періодично посилає інформацію про стан того, що він контролює. А на цій стороні бажано побільше спати.
У пристрої і STM32L011K вистачить, програма ледь перевалює за 8 кілобайт флеша. На нього і розраховував. Але на малих кількостях ціноутворення штука малопередбачувана, STM32L051K8 може бути суттєво дешевшим за STM32L011K4. Тому хочеться, щоб можна було поставити чи те, чи те.
Все було б добре, але «світ дуже недосконалий»© Лис з «Маленького принца». LPUART не потрапив на ніжки в 32-виводному корпусі STM32L051K. Мікроконтролери L051 мають можливість незалежної роботи від LSE є і для USART1, USART2. Але ж (ой правий Лис, ой правий!) L011 спрощений, USART2 у нього є, але він так не вміє.
Зрештою, знайшлася ніжка (PB7), де сидить LPUART_RX для L011K і USART1_RX для L051K. Все добре.
Тільки от прошивка має бути єдина, щоб той, хто прошиватиме плати, не вдивлявся у маркування мікроконтролера. Ну та до цього не звикати, все одно під одну прошивку маю реально п’ять різних варіантів виконання пристрою (на 4 різних платах). Плати візуально відрізняються відчутно, але однак простіше віддати одну прошивку. Код плати задано підключенням двох ніжок мікроконтролера на VCC/GND і ще один резистор каже «тут запаяно лише ту малу частину, яка спільна для всіх плат, це спрощений п’ятий варіант».
Вид мікроконтролера L011 («категорія 1») чи L051 («категорія 3») можна прочитати з ідентифікаційного регістра
// cat1 (L011) or cat3 (L051)
bool is_mcu_cat1()
{
return (DBGMCU->IDCODE & 0xFFF) == 0x457;
}
і далі все просто. Відмінності ініціалізації LPUART і USART1 невеликі. Ініціалізувати і дозвіл переривань лише для одного, та ще ніжку треба увімкнути на потрібний номер альтернативної функції.
Два обробники переривань викликають одну й ту ж процедуру обробки
extern "C" void USART1_IRQHandler(void)
{
device.octrl.byte_received(USART1->RDR);
}
extern "C" void LPUART1_IRQHandler(void)
{
device.octrl.byte_received(LPUART1->RDR);
}
До речі, гарна штука LTO (link-time optimization). Ця byte_received()
в іншому файлі, але воно чудово проінлайнило функцію в обидва обробники.