OpenOCD — виправлено помилку в команді stm32f1x unlock

Щось останнім часом я практично лише про помилки і пишу. Але тут поруч з поганою новиною є і хороша.

Ще десь перед новим роком виявив біду — у найсвіжішому на той час OpenOCD команда stm32f1x unlock захист зчитування наче знімає, але по тому записати у мікроконтролер нічого не вдається.

На щастя, у мене десь лежала перевірена версія, зібрав її, встановив і все пішло. Вже десь у січні підключився до OpenOCD через telnet, потикався різними командами і з’ясував, що в усі option bytes (окрім readout protection) записані випадкові значення, тобто на довільні сектори flash-пам’яті було встановлено захист від запису, а також попсовано опції SW/HW WDT і інші.

І оце лише на минулому тижні розібрався. Драйвер stm32f1x використовується для роботи з stm32f10x, stm32f0xx, stm32f3xx, але біда лише з stm32f10x. З’ясувалося, що в них захист від зчитування поширюється і на область флеш-пам’яті для блоку опцій. Для двох інших згаданих лінійок цього нема, у документації в табличках окремо відзначено можливість такого зчитування (при захисті з рівнем L1). Можливо, саме тому в коді зчитування опцій з регістрів FLASH_OBR і FLASH_WRPR замінили зчитуванням безпосередньо з адрес 0x1ffff800..0x1ffff80f.

Процедура unlock перед стиранням опцій зчитує їхні значення, щоб під час запису коду дозволу зчитування відновити те, що було. Але ж доступу нема, OpenOCD доповідав, що прочитати не може і йшов далі. Тобто записував випадкові значення, які на той час були у неініціалізованій структурі.

Відповідно, ремонт простий — повернутися до зчитування з регістрів. Зараз патч лежить на узгодженні в їхньому gerrit-і, а я вже користуюся виправленим 🙂

ECC і HW parity

Знову згадую Лиса з Маленького принца, пора вже тег «Світ недосконалий» на його честь заводити.

STM32F0 (і не лише, але я зараз Cortex-M0 дивлюся) — є апаратний контроль парності в оперативній пам’яті.

STM32L0 — є контроль і виправлення помилок (ECC) у флеші та EEPROM.

А от щоб разом, так ні.
І, до речі, STM32F0 має переривання по збою оперативної пам’яті, а STM32L0 не має переривань від свого блоку ECC. Хоча переривання «все виправлено, але збій був» було б дуже корисним для раннього попередження про можливі відмови.

p.s. Ще цікава штука на цю тему є в ATtiny41x/81x, апаратна перевірка флеша по CRC16.

LPUART? USART1? обидва і в одну прошивку!

Є в мікроконтролерах 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() в іншому файлі, але воно чудово проінлайнило функцію в обидва обробники.

Перехідна плата qfp32

Зовсім випадково надибав на AliExpress чудову перехідну плату з qfp32 на два ряди штирів 2,54 мм для безпаєчної макетки. На відміну від інших, зі зворотного боку вона має не tssop32, виправданий з точки зору здешевлення макетки, а місця під корпуси 0805 з кожного виводу мікроконтролера, які виходять на полігон.

Адаптер з QFP32 на штирі з місцями 0805

Чудове рішення для того, щоб відразу з’єднати потрібні виводи з землею і якомога ближче до мікросхеми розмістити конденсатори. Також зручно для підтяжок до землі на потрібних виводах, наприклад, BOOT0 в мікроконтролерах STM32 (тут запаяно STM32L051K8). І не забудеш поставити при зміні схеми, і не займає дірочок у макетній платі.

Вона є у декількох продавців, я брав у цього.

p.s. Паяв знову не сам. Пора заводити тег скористався службовим становищем. 😉

Недорога плата розробки для STM32L05x

Останнім часом я трохи працюю з мікроконтролерами STM32, зокрема STM32L011 і STM32L051, але то все конкретні плати, на яких виводи задіяно під конкретні функції. І коли раптом хочеться поколупатися із якоюсь ідеєю, то на тих тісних платах то страшенно незручно. А використати їх як носій мікросхеми, прибравши все зайве, так прибирати доведеться майже все і то буде навіть гірше, ніж просто перехідник «TQFP на штирі».

Існують плати STM32L1xxDISCOVERY, але там на найдешевших одна радість — вбудований «фірмовий» ST_LINK. Платити за те під 500 гривень неохота. Та й на них L100 або L152, а мені сподобалися STM32L0xx.

От для STM32F103C8 є декілька варіантів плати, яку називають «синя таблетка» (що викликає деякі застарілі асоціації[1]). Недорого, є необхідний мінімум.
Але то F103…
Тю, так виводи ж у STM32 стандартизовані!
STM32F103C8 і STM32L051C8… Співпадають!
Чудово, вчора син по дорозі зі свого університету заїхав у мікроАмпер і забрав потрібну плату, я ж заїхав у Імрад і взяв STM32L052C8, щоб вже й USB було.

Сьогодні на роботі скористався службовим становищем — попросив похімічити, здути F103 і запаяти на її місце L052:
Створення плати розробки STM32L052 із плати STM32F103

Під дією тепла проведено реакцію, у результаті якої я отримав бажану плату, а STM32F103C8 випала в осад. Залежно від того, чи буде цей мікроконтролер десь використаним, плата розробки для L05x обійшлася у суму від десь 110 до 180 гривень.

p.s. Там ще STM32F303C у такому ж корпусі TQFP48 бувають 😉


1 Колись давно мем про червону і синю таблетки використовували на форумах як вибір між червоним кольором PIC/Microchip і синім AVR/Atmel. Тепер і те і те мірочіпівське, хоч кольори і не помінялися.

OpenOCD, STM32L011 і всі-всі-всі

Тему так і не закінчено. Доводиться тримати на столі обидва адаптери — і саморобний на FT2232H, і китайський ST-Link.

Мікроконтролери STM32L011, на відміну від інших STM32L0, мають одну особливість. Якщо флеш стерта (точніше, якщо стерте перше слово флеша, у якому початкова адреса стеку сидить), то незалежно від ніжки BOOT0 мікроконтролер стартує у boot-loader. Зроблено це з метою «полегшити початкове прошивання», але мені лише поважчало.

Біди не було б, якби OpenOCD у комбінації з адаптером на FT2232 з цією ситуацією міг упоратися. Але він чомусь не може прошити флеш. Під’єднується по SWD до ядра, показує вміст вказівника команд десь у діапазоні системної пам’яті, каже, який мікроконтролер побачив і обсяг флеш-пам’яті, а от шити відмовляється. Цей же OpenOCD з адаптерами ST-Link, що з «чесним» з плати STM32F3DISCOVERY, що з китайським, — перешиває.

Іноді потрібно стерти геть усе, через що влетіти у бут-лоадер, а плату DISCOVERY, у якої є reset, використовувати як програматор мені трохи незручно.
От тому лежать на столі два адаптери.

p.s. Про всяк випадок повторю: якщо не зупиняти основний генератор (не піднімати біт SLEEPDEEP у регістрі SCB->SCR) і не перепрограмовувати ніжки, потрібні для SWDIO/SWDCLK, то цілком можна обійтися китайським ST-Link-ом. Інакше — доведеться шукати/робити інший програматор або додавати кнопку reset і вчитися її відпускати у потрібний момент 🙂

Китайський ST-Link v2 проти STM32F3-Discovery

Щоб вже закінчити вчорашню тему.

Витягнув із шухлядки плату STM32F3-Diіcovery — на ній є вбудований ST-Link, який можна відключити від процесора на платі і використовувати для програмування інших плат. На штирі виведено всі сигнали, включно з RESET і SWO. До речі, перемички розривають лише лінії SWCLK і SWDIO, тому свою плату можна скидати, натиснувши кнопку на платі Discovery.

Ну що — все працює, RESET піднімає мікроконтролер зі Stop-у і перепрошиває. Тобто проблема в тому, що клон ST-Link з Ali-Express-у не вміє виконувати відповідні команди.

Коли вже знову сів за макетку з STM32L051, то перевірив і роботу команд stm32lx lock / stm32lx unlock і швидкість програмування. У клонованого ST-Link тут теж щось в генотипі порушене, бо набагато повільніший. Хоча в ньому стоїть STM32F101, тобто USB зроблене програмно, тому швидким він і не може бути, але ж одиниці кілобайт на секунду не така вже й велика швидкість.

Результати тестування на швидкість (файли для прошивки 2-12kB).
Команда “reset init” перемикає STM32L0x з внутрішнього MSI 2 MHz на HSI 16 MHz і піднімає частоту обміну.

Програматор Fswclk = 300 kHz
(-c “reset halt”)
Fswclk = 2.5 MHz
(-c “reset init”)
Клон ST-Link 1.5-1.7 KiB/s 1.5-1.7 KiB/s
F3-Discovery 4.9-5.0 KiB/s 5.2-5.3 KiB/s
FT2232H 3.8-4.2 KiB/s 8.0-8.3 KiB/s

Платку з FT2232D діставати було ліньки, на цих швидкостях має бути не набагато повільніша за FT2232H, хіба ото не зможе виставити 2.5 MHz частоти SWCLK, буде 2.

Китайський ST-Link v2, STM32L011 і Stop

Точніше, «Stop і не-Reset».
І не STM32L011F4, бо у Імраді їх нема. Граюся на а STM32L051C8T, поки дрібніші кристали їдуть.

Cortex-M, зокрема STM32F10x і трохи раніше LPC176x, я вже трохи помацав у невеликих «одноразових» проектах. У виробах досі йшли ATmega48PA, хоча не все влаштовувало і поглядав на нові можливості нових ATtiny (можна погортати назад, я писав, що мене цікавить). Запитуючи про ціни-доступність цих кристалів, мимоволі роззирався навкруги, як на старіші MSP430 та 8-бітні PIC-и, так і на STM8L, які теж мають цікаві можливості. Та останнім заважає біда — вибір між 16-мегагерцовим RC (забагато, навіть якщо для ядра поділити частоту — багато їсть сам генератор) і низькочастотним low consumption, якого малувато і який має доволі великі початковий розкид і нестабільність частоти.

Так потихеньку доповз і до STM32L0. Аналоговий компаратор, хоч і повільніший, ніж в AVR, але ж пару мікроампер, а не 70, LPTIM1, який може слухати компаратор при зупиненому ядрі і маршевому RC, і, головне, MSI-генератор, який зменшує споживання при зменшенні частоти (привіт, MSP430, я вас ціную, та так до вас і не дійшов). Все, «беру».

Ті «товстіші» Cortex-M я програмував через OpenOCD/JTAG і платки на FT2232D/FT2232H, яких у мене вистачає. Тут же потрібен SWD. Ну що, «досить самому ліпити адаптери», Ali-express, копійчаний клон ST-Link v2, побігли.

І тут вилізла проблема. Якщо програма використовує ніжки SWCLK/SWDIO для себе, або якщо ядро йде у Stop, зупиняючи генератор, то для перепрошивки необхідно смикнути кристал за Reset і потримати на ньому під час з’єднання, параметр connect_assert_srst для OpenOCD. І от чи то всі ці китайські клони, з якими взагалі йдуть 4 дротики (SWDIO, GND, SWCLK, VCC для STM32 і RESET, GND, SWIM, VCC для STM8), не вміють смикати за Reset, чи ще що, але з моїм ST-Link v2 для перепрошивки в потрібний момент необхідно тицяти у кнопку скидання вручну.
Не діло.

Згадав, що опис OpenOCD згадував resistor hack, який дозволяє для FTDI-них адаптерів працювати з SWD. Дописав потрібні рядки у конфіг для своєї плати на FT2232H, спробував — все чудово працює. Ото недаремно мені такі адаптери завжди подобалися 😉

Десь у мене лежить кілька незапаяних FT2232D і ще 2-4 штуки можна зняти із зоопарку платок, який зібрався за минулі роки. Накидаю я luminary-icdi-подібну плату і притулю її до чергового замовлення експериментальних зразків.


Доповнення: оскільки через «справжній» ST-LINK v2 на платі STM32F3DISCOVERY все працює, це точно генетичний дефект клона. Кажуть, його можна перепрошити на інший, кращий програматор, але зараз не до того.

Порти STM32F30x

От не чекав такого.

Є у Cortex-ів M0/M3/M4 така зручна штука, як bit-band, призначена для атомарної роботи з однісіньким бітом IO або пам’яті.
Коротко, для тих, хто не знає — два одномегабайтних регіони адресного простору, в яких цей механізм працює, мають поставлені їм у відповідність 32-мегабайтні регіони bit-band. Кожна адреса 32-бітного слова у цих регіонах відображається на один біт відповідного 1-мегабайтного, тобто старші 20 біт адреси всередині bit-band регіону вибирають слово у відповідному 1-мегабайтному, а молодші 5 —вибирають біт у цьому слові. Звертання на запис десь на апаратному рівні контролера пам’яті призводить до циклу читання-модифікація-запис зі зміною одного біту.

Ну так от, чому я саме про F30x. Попросили тут організувати одному студентові робоче місце з STM32F3DISCOVERY — компілятор-те-се, допомогти стартувати. Вирішив відразу показати scmRTOS як просту-швидку і практично дармову по ресурсах та нескладну в освоєнні міні-RTOS. Порт для Cortex-M4F є, прикладів для STM32F4xx вистачає. Вирішив почати з найпростішого 1-EventFlag (він зовсім простий майже у всіх портах scmRTOS, ускладений я зробив колись для AVR та STM8). Поліз модифікувати startup.c з таблицею векторів, у sysinit.cpp переписав ініціалізацію PLL.
Ну і ще pin.h, C++-ний аналог «Волковських» макросів на препроцесорі мови C для роботи з портами.
Все так наче нормально, GPIO у STM32F30x по організації такі ж, як у STM32F2xx та STM32F4xx — той же принцип, такі ж регістри (практично такі — у F3 повернули назад регістр BRR, який був у STM32F1xx, а у F2 та F4 пропав, скинути біт порту можна лише через верхню половину BSRR).
Підправив базові адреси портів, компілюю, зашиваю… Висить.
Ну, думаю, десь щось або в ініціалізації PLL, або десь у векторах чи в самій rtos щось таки треба міняти. Вирішив мигнути кілька разів світлодіодами до OS::run(), тобто до дозволу переривань під час запуску ОС.
Не мигають.
Перевірив код ініціалізації PLL. Все нормально.
І тут… І тут… І тут до мене доходить, що базові адреси портів дещо незвичні після STM32F1xx та тих, що були у старому pin_stm32F4xx.h у прикладах.

Лізу знову у документацію. Отже:

У кортексів два 1-мегабайтних регіони з відображенням на bit-band
SRAM: 0x20000000-0x20100000 → 0x22000000-0x24000000
PERIPH: 0x40000000-0x40100000 → 0x42000000-0x44000000

У STM32F1xx GPIO на APB2, діапазон 0x40010800-0x400123FF, потрапляє у bit-band
STM32F2xx, STM32F4xx — на AHB1, діапазон 0x40020000-0x400223FF, потрапляє у bit-band
STM32F30x — на AHB2, діапазон 0x48000000-0x480017FF, НЕ потрапляє у bit-band

Таймери-АЦП потрапляють, а це – ні! У таймерів з різних місць атомарно клацати бітиками дозволу/заборони переривань на CC-каналах теж приємно, але ж місця там валом, все б влізло, навіщо було GPIO закидати так далеко?
Довелося переписати весь цей pin.h у стилі «прочитали, наклали маску, врізали біти, записали». Для роботи з виходом атомарність залишається завдяки старим-добрим BRR/BSRR, з усім іншим (перемикання вхід/вихід/альтернативна функція, pull-up/pull-down) тепер треба буде уважно.

p.s. Пора розбиратися з GDB через OpenOCD, ними б я за хвилину проблему знайшов би…

[flagcounter image]