Портуємо U8x8 на STM32 CMSIS
Для Arduino є доволі популярна бібліотека для монохромних екранів - U8g2. Ця бібліотека має дві незалежні підсистеми: U8g2 — для малювання різних графічних елементів та u8x8 — суто для тексту.
І сьогодні мені потрібно запустити u8x8 на STM32 без Arduino, у чистому CMSIS-проєкті.
У мене є PlatformIO-проєкт, тому першим кроком я додаю в нього залежність від U8g2:
[env:genericSTM32F103C8]
platform = ststm32
board = genericSTM32F103C8
framework = cmsis
upload_protocol = cmsis-dap
debug_tool = cmsis-dap
lib_deps =
olikraus/U8g2
lib_compat_mode = off
Параметр lib_compat_mode = off вимикає перевірку сумісності, інакше PlatformIO не додасть бібліотеку до збірки, оскільки вона призначена для фреймворку Arduino.
Наш початковий код — поки що майже порожній, ініціалізуємо лише таймер. Будемо працювати від внутрішнього RC-генератора на частоті 8 МГц.
#include "stm32f1xx.h"
volatile uint32_t ms_ticks = 0;
extern "C" void SysTick_Handler(void) {
ms_ticks++;
}
void Delay_Ms(uint32_t ms) {
uint32_t start = ms_ticks;
while ((ms_ticks - start) < ms);
}
int main() {
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000);
__enable_irq();
while(1) {
}
}Цей порожній проєкт у мене займає 424 байти, далі подивимося, скільки займе бібліотека:
RAM: [ ] 0.2% (used 36 bytes from 20480 bytes)
Flash: [ ] 0.6% (used 424 bytes from 65536 bytes)
Пояснення, як використати U8g2 на інших фреймворках та архітектурах, є на цій сторінці: https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform/. Найпростіший варіант адаптації — це використати «ногодриг» (bit-banging), тобто програмну реалізацію інтерфейсу.
Спробуймо! Потрібно лише перевизначити функцію:
uint8_t u8x8_gpio_and_delay_template(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
та додати код ініціалізації:
#include "stm32f1xx.h"
#include "clib/u8x8.h"
volatile uint32_t ms_ticks = 0;
extern "C" void SysTick_Handler(void) {
ms_ticks++;
}
void Delay_Ms(uint32_t ms) {
uint32_t start = ms_ticks;
while ((ms_ticks - start) < ms);
}
uint8_t u8x8_gpio_and_delay_stm32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
switch(msg) {
case U8X8_MSG_GPIO_AND_DELAY_INIT:
// використаємо піни PB6, PB7 в open drain режимі
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
GPIOB->CRL &= ~((0xF << 24) | (0xF << 28));
GPIOB->CRL |= (0x7 << 24) | (0x7 << 28);
GPIOB->BSRR = (1 << 6) | (1 << 7);
break;
case U8X8_MSG_DELAY_MILLI:
Delay_Ms(arg_int);
break;
case U8X8_MSG_DELAY_10MICRO:
for (volatile uint32_t i = 0; i < (arg_int * 8); i++) { __NOP(); }
break;
case U8X8_MSG_DELAY_100NANO:
__NOP();
break;
case U8X8_MSG_GPIO_I2C_CLOCK:
if (arg_int) {
GPIOB->BSRR = (1 << 6);
} else {
GPIOB->BSRR = (1 << (6 + 16));
}
break;
case U8X8_MSG_GPIO_I2C_DATA:
if (arg_int) {
GPIOB->BSRR = (1 << 7);
} else {
GPIOB->BSRR = (1 << (7 + 16));
}
break;
}
return 1;
}
int main() {
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000);
__enable_irq();
// ініціалізація u8x8
u8x8_t u8x8;
u8x8_Setup(&u8x8, u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_i2c, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_stm32);
u8x8_InitDisplay(&u8x8);
u8x8_SetPowerSave(&u8x8, 0);
u8x8_ClearDisplay(&u8x8);
u8x8_SetFont(&u8x8, u8x8_font_chroma48medium8_r);
u8x8_DrawString(&u8x8, 0, 0, "Hello from CMSIS");
while(1) {
}
return 0;
}Далі підключаємо дисплей до виводів:
GND, VCC - живлення
SCL - до PB6
SDL - до PB7
Компілюємо й зараз побачимо, скільки місця займе бібліотека:
RAM: [ ] 0.2% (used 36 bytes from 20480 bytes)
Flash: [= ] 5.1% (used 3324 bytes from 65536 bytes)
Затягнуло 2900 байтів. Тепер можемо запускати та перевіряти що все працює.

Коментарі
Дописати коментар