gd32e2-hal
English
Hardware abstraction layer (HAL) for the gd32e230x and gd32e231x microcontrollers (Cortex-M23), written on top of the PAC crate: github, crates.io.
Work in progress. Written piece by piece, the API is unstable. Implemented modules:
adc,cmp,crc,dma,exti,fmc,gpio,i2c,rcu,spi,syscfg,time,timer,usart,watchdog. Usage examples live inexamples/, all of them run on the board. Not verified: option byte fields other than the data bytes.
Principles
- Errors at compile time. The identity of an entity (a pin, a peripheral, a peripheral channel and so on) determines the list of available methods — an input pin has no
.set_high()to call; - Thanks to Rust ownership and borrowing, the same peripheral cannot be initialized twice or taken before its clock is enabled, and hardware cannot be modified from two places at once;
- Zero-cost. The same register writes as less abstract PAC code; most of the abstractions are ZSTs.
Chip variants
A feature name is the part number with x in the fields the code does not see: the letter is the number of bonded pads, the digit is the flash code, the trailing x is the temperature grade.
| feature | pads | flash | SRAM |
|---|---|---|---|
gd32e230f4xx / f6xx / f8xx |
20 | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230e8xx |
24 | 64K | 8K |
gd32e230g4xx / g6xx / g8xx |
28 | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230k4tx / k6tx / k8tx |
32, LQFP | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230k4ux / k6ux / k8ux |
32, QFN | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230c4xx / c6xx / c8xx |
48 | 16K / 32K / 64K | 4K / 6K / 8K |
32 pads is the only place where the package matters: on QFN32 ground moves to the belly pad, and the two freed pins go to PB2 and PB8; LQFP32 has neither.
Development targets
GD32E230K8U6, that isgd32e230k8ux; the examples take the feature from the crate depending on itself in[dev-dependencies]. The published documentation is built forgd32e230c8xx, the largest part, so the page shows pins and peripherals the smaller parts do not have.build.rsturns the choice into thememory.xthe linker needs and into cfg flags that gate the source. The AF map depends on the flash code — the same pin on the same AF number may lead to a different peripheral.
The orthogonal defmt feature derives defmt::Format on public enums and error types. Off by default; it also enables embedded-hal/defmt-03.
Documentation
Method details are in the documentation. A shorter view of most of the public API is in examples/.
Example
use *;
use pac;
use ;
use ;
let dp = take.unwrap;
let mut fmc = dp.fmc.constrain;
let config = default
.sysclk; // PLL from IRC8M -> 48 MHz
let mut rcu = dp.rcu.constrain.freeze;
let clocks = rcu.clocks;
let parts = dp.gpioa.split; // enables the GPIOA clock
let mut led = parts.pa5.into_output;
led.set_high;
let tx = parts.pa9.; // USART0_TX; ::<3>() does not compile
let rx = parts.pa10.;
let mut usart0 = new;
if let Ok = usart0.read_byte
Building
Flashing and debugging over SWD (ST-Link V2 +
probe-rs,PA13/PA14). Firmware output goes over RTT through the same probe (defmt+defmt-rtt).
- Target
thumbv8m.base-none-eabi; build.rswrites thememory.xthe linker needs from the selected library feature, nothing has to be copied. (Amemory.xin the project root still overrides the generated one — the linker looks there before the search paths — and that is the supported way out for a board that is not in the table);
cargo aliases
cargo lib # the library only, an alias for build --features gd32e230c8xx
cargo libclippy # clippy over the library, with the same feature
cargo pubdry # publish --dry-run with the same feature
cargo be usart-echo # check that one example builds, no probe needed
cargo bre usart-echo # the same in release
cargo examples # every example in release, skipping the ones for another part
cargo re usart-echo # build + flash over SWD, stays attached afterwards
Roadmap
Peripherals not covered at all
-
PMU— sleep / deep-sleep / standby, wakeup pin, LDO. - The rest of
SYSCFG— remappingPA11/PA12onto thePA9/PA10pads below 32 pins, and the second DMA channel map. -
RTC— calendar. With no crystal it runs off IRC40K, with the accuracy of IRC40K.
Finishing what is there
- DMA interrupts — the
Event/listenshape has settled, the work is mechanical. - DMA: circular mode,
M2M,embedded-dmafor buffers. - ADC: scan over several channels, which needs DMA.
- Timers: complementary outputs, break and dead time;
TRGOonTIMER5so it can drive DMA. - I²C: 10-bit addressing, SMBus, slave, DMA.
- SPI: half-duplex and single-wire modes (
BDEN/BDOEN/RO); hardware NSS, CRC, TI mode and slave — low priority. - USART: hardware flow control (
CTS/RTS); a non-blocking API for 9-bit words. - FWDGT: window mode (
WND);FWDGT_HOLDandWWDGT_HOLDin a DBG module, so that the watchdogs do not count under a halted debugger. - RCU:
HXTALandLXTAL(no crystal is fitted on the board). - FMC:
embedded-storage(ReadNorFlash/NorFlash) on top of the existing program and erase.
Infrastructure
- gd32e231x support: part number features, pin map, gates. The PAC module exists, the chip is not at hand.
- Async:
embedded-hal-async/embedded-io-async, starting with a time driver on one of the timers — that is what Embassy expects from a HAL. - Host tests and CI — there are none at all; the crate does not build for the host, so mocks are needed.
- Moving the HAL into its own crate/repository.
License
Dual licensed, at your option:
- Apache License 2.0 (LICENSE-APACHE)
- MIT (LICENSE-MIT)
Any contribution submitted for inclusion in this work shall be licensed the same way, without additional terms, unless stated otherwise (Apache-2.0, section 5).
Русский
Hardware abstraction layer (HAL) для микроконтроллеров семейства gd32e230x и gd32e231x (Cortex-M23), написанный поверх PAC-крейта: github, crates.io.
В работе. Пишется частями, API нестабилен. Реализованные модули:
adc,cmp,crc,dma,exti,fmc,gpio,i2c,rcu,spi,syscfg,time,timer,usart,watchdog. Имеются примеры использования вexamples/, все прогнаны на плате. Из непроверенного: поля option bytes кроме байтов данных.
Принципы
- Ошибки на этапе компиляции. Идентичность сущности (пин, элемент периферии, канал периферии и пр.) определяет список доступных методов (например, input-пин не позволит вызвать у него метод
.set_high()); - Благодаря концепциям владения и заимствования языка Rust одну и ту же периферию не удастся инициализировать дважды или взять до включения тактования, а также не получится менять железо из двух разных участков кода одновременно;
- Zero-cost. Те же записи в регистры, что и у менее абстрактного PAC-кода; большая часть абстракций — ZST.
Варианты чипа
Имя фичи — партномер с x в тех полях, которых код не видит: буква — число разваренных выводов, цифра — код флеша, хвостовой x — температурный класс.
| фича | выводы | флеш | SRAM |
|---|---|---|---|
gd32e230f4xx / f6xx / f8xx |
20 | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230e8xx |
24 | 64K | 8K |
gd32e230g4xx / g6xx / g8xx |
28 | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230k4tx / k6tx / k8tx |
32, LQFP | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230k4ux / k6ux / k8ux |
32, QFN | 16K / 32K / 64K | 4K / 6K / 8K |
gd32e230c4xx / c6xx / c8xx |
48 | 16K / 32K / 64K | 4K / 6K / 8K |
32 вывода — единственное место, где корпус имеет значение: у QFN32 земля уходит на брюшко, и два освободившихся вывода достаются PB2 и PB8, у LQFP32 нет.
Разработка идёт под
GD32E230K8U6, то естьgd32e230k8ux; примеры берут фичу из записи крейта на себя в[dev-dependencies]. Опубликованная документация собрана дляgd32e230c8xx, самой жирной детали, поэтому страница показывает ноги и периферию, которых у мелкой нет.build.rsпревращает выбор в нужный линкеруmemory.xи в cfg-флаги, по которым гейтится исходник. Карта AF зависит от кода флеша — одна и та же нога на одном номере AF может вести к разной периферии.
Ортогональная фича defmt вешает defmt::Format на публичные enum и типы ошибок. По умолчанию выключена; заодно включает embedded-hal/defmt-03.
Документация
Подробности по методам можно найти в документации. Более краткое отражение большей части публичного API библиотеки в examples/.
Пример
use *;
use pac;
use ;
use ;
let dp = take.unwrap;
let mut fmc = dp.fmc.constrain;
let config = default
.sysclk; // PLL от IRC8M -> 48 МГц
let mut rcu = dp.rcu.constrain.freeze;
let clocks = rcu.clocks;
let parts = dp.gpioa.split; // включает такт GPIOA
let mut led = parts.pa5.into_output;
led.set_high;
let tx = parts.pa9.; // USART0_TX; ::<3>() не соберётся
let rx = parts.pa10.;
let mut usart0 = new;
if let Ok = usart0.read_byte
Сборка
Прошивка и отладка по SWD (ST-Link V2 +
probe-rs,PA13/PA14). Вывод из прошивки идёт по RTT через тот же зонд (defmt+defmt-rtt).
- Таргет
thumbv8m.base-none-eabi; build.rsпишет нужный линкеруmemory.xиз выбранной фичи библиотеки, копировать ничего не надо. (memory.xв корне проекта всё равно перебивает сгенерированный — линкер смотрит туда раньше путей поиска, — и это штатный выход для платы, которой нет в таблице);
Алиасы cargo
cargo lib # только библиотека, алиас для build --features gd32e230c8xx
cargo libclippy # clippy по библиотеке, с той же фичей
cargo pubdry # publish --dry-run с той же фичей
cargo be usart-echo # проверить сборку одного примера, зонд не нужен
cargo bre usart-echo # то же в release
cargo examples # все примеры в release, кроме примеров под другой партномер
cargo re usart-echo # сборка + прошивка по SWD, дальше остаётся подключённым
Roadmap
Периферия, не покрытая вовсе
-
PMU— sleep / deep-sleep / standby, wakeup-нога, LDO. - Остаток
SYSCFG— ремапPA11/PA12на площадкиPA9/PA10ниже 32 выводов и вторая карта каналов DMA. -
RTC— календарь. Без кварца пойдёт от IRC40K, с его же точностью.
Доделать имеющееся
- Прерывания DMA — форма
Event/listenустоялась, работа механическая. - DMA: циклический режим,
M2M,embedded-dmaдля буферов. - ADC: scan по нескольким каналам, для чего нужен DMA.
- Таймеры: комплементарные выходы, break и dead time;
TRGOуTIMER5, чтобы он мог запускать DMA. - I²C: 10-битная адресация, SMBus, slave, DMA.
- SPI: half-duplex и однопроводные режимы (
BDEN/BDOEN/RO); аппаратный NSS, CRC, TI mode и slave — низкий приоритет. - USART: аппаратное управление потоком (
CTS/RTS); неблокирующий API для 9-битных слов. - FWDGT: оконный режим (
WND);FWDGT_HOLDиWWDGT_HOLDв модуле DBG, чтобы сторожа не считали под остановленным отладчиком. - RCU:
HXTALиLXTAL(ни один кварц на плате не запаян). - FMC:
embedded-storage(ReadNorFlash/NorFlash) поверх готовых записи и стирания.
Инфраструктура
- Поддержка gd32e231x: фичи партномеров, карта пинов, гейты. PAC-модуль есть, чипа на руках нет.
- Async:
embedded-hal-async/embedded-io-async, начиная с драйвера времени поверх одного из таймеров — именно его Embassy ждёт от HAL. - Тесты на хосте и CI — их нет вовсе; крейт не собирается под хост, поэтому нужны моки.
- Вынос HAL в отдельный крейт/репозиторий.
Лицензия
Двойное лицензирование, на выбор:
- Apache License 2.0 (LICENSE-APACHE)
- MIT (LICENSE-MIT)
Любой вклад, отправленный для включения в эту работу, лицензируется так же, без дополнительных условий, если не оговорено иное (Apache-2.0, раздел 5).