Comments 94
Я попытался проделать трюк с прописываем CPUTAPID 0 в IDE с версиями 1.8, 1.7 и 1.5 и long story short — ни разу не получилось.
Кажется где то писали, что 1.3 последняя версия, где можно изменить CPUTAPID в конфиге. В более старших версиях он захардкожен в самом IDE.
переходили с STM32 на GD32 (F4), все взлетело из почти из коробки, даже на ST либах (HAL не используем). IDE SW4STM32. Отладка на st-linkV2 прекрасно работает, на V3 уже нет (почему так не разбирались).
Начиная с 22-го разработали пару устройств на gd32. Полет нормальный.
Да, сделать новый проект на GD32 - проблем ноль. Хороший чип.
А вот впилить в старый STM32 проект, новый чип - вот задача.
Успешно и довольно легко впиливал. Пришлось только кое-где времянки поправить, т.к. мало того, что GD32 умеет работать на более высокой частоте, у него еще и нулевое время ожидания чтения флэша для первых 512 (если не ошибаюсь) кб, так что работает он заметно быстрее даже на той же частоте, что и STM32.
Правда, я работал в IAR (который, кстати, из коробки поддерживает GD32 без всяких дополнительных аддонов), а у вас тут больше про борьбу с проприетарным софтом, а не с различиями между МК :)
Точно? Насколько я помню, в IAR чтобы выбрать чип GD в настройках проекта - надо именно поставить IAR_GD32Fxx0_ADDON.
Или вы про то, что ST проект из коробки запускается и дебажится на GD в IAR?
А так задача была, не бороться с чипами, а запустить один проект на двух железках с минимальными телодвижениями.
Вот без всяких аддонов :)
Скрытый текст

Или вы про то, что ST проект из коробки запускается и дебажится на GD в IAR?
Ну, может быть с каким-то отладчиком так и получится, но JLink начинает ругаться на несоответствие идентификатора контроллера при попытке отладить проект под STM32 на GD32. Побороть можно правкой конфигов IAR.
А вообще, тот проект был единственным, который я переводил на поддержку и STM32 и GD32, это как раз был тот чипогеддон, когда STM32 исчезли или их стоимость взлетела до небес. После него я уже делал проекты изначально под GD32.
Поймал в 400й серии проблему, не описанную в errata - задержка от включения UART до физической передачи плавала случайно от 0 до 11 бит. Пришлось костылить хардкорный сброс UART (вместе с приёмником) перед каждым пакетом.
Но вообще основное отличие GD от остальных флеш-мк в том, что он не флеш-мк. Внутри корпуса 2 кристалла - мк и SPI-флеш. По-моему @BarsMonster его вскрывал, или ещё кто-то, не помню точно. Прошивка из SPI-флеши при старте кэшируется в теневое ОЗУ, и оттуда уже выполняется.
Из-за этого появляется несколько нюансов:
Время старта прошивки увеличивается, т.к. прошивку ещё надо скопировать.
Это в даташите для F103xC Кэшируется не вся флеш, а только часть, которая влазит в теневое ОЗУ. Его объём одинаковый у каждой серии, независимо от объёма флеши. Хотя и довольно большой.
Вот это, например, в мануале для всей серии F10x Зато отсутствие флеши на том-же кристалле позволяет повысить тактовую частоту, и главное - уменьшить время случайного доступа к программной памяти. JMPы, циклы, загрузка длинных констант становятся заметно быстрее.
Так далеко про GD32 я еще не копал, спасибо за информацию.
Да, с флешем все так: https://zeptobars.com/en/read/GD32F103CBT6-mcm-serial-flash-Giga-Devices
насколько я помню, вроде даже можно настраивать теневой ОЗУ: сколько использовать под "флеш", а сколько в качестве честной оперативки.
Встречал в сети такое утверждение от анонимусов, но ни разу не видел его подтверждения :)
Давайте засаммоним @COKPOWEHEU он с китайцами всяко больше нашего работал :)
/me потапал бутылку на пиво
Это было в CH32V/Fxxx
На счет именно gd32 сказать не могу, но в некоторых других настраивается.
Скажем, в ch32v303 можно настроить 288+32 | 256+64 | 224+96 | 192+128. А вся флешка целиком 480к, так что всегда остается некешируемый хвост, который можно использовать для хранения данных. На счет хранения кода не уверен, поскольку настроек wait-state-ов там вроде бы нет. Настраивается это через option-byte-ы, что-то вроде фьюзов.
А в других контроллерах от тех же wch, такой настройки нет. В ch32v203 (кроме RB) размеры флеш и ОЗУ заданы жестко.
Думаю, самым простым критерием кешируется ли флеш, будет скорость доступа. Если предусмотрены wait-state (пара битов в конце FLASH->ACTLR), то кеша нет.
Если предусмотрены wait-state (пара битов в конце FLASH->ACTLR), то кеша нет.
Не факт. У GD они предусмотрены, видимо, чтобы программные задержки были совместимы с кодом для ST. А при выходе за пределы кэша проц увеличивает задержку молча, безо всяких настроек.
Вот это интересно. Получается, вы проверяли скорость доступа к началу флеша и концу? А подскажите, какой у gd32 объем кеша.
Не проверял. В даташите посмотрел.
https://habr.com/ru/companies/selectel/articles/851478/comments/#comment_27443304
Не очень понял. 30к кешируется или 256к? Впрочем, тему вы подняли интересную, надо будет проверить
В этом семействе максимум до 3М флеши. 256к кэшируется независимо от конкретного объёма флеши.
256к? Тогда не проверю. У vf103 всей памяти максимум 128к
GD32F103RKT6 - 3 МБ
Минимум 16кБ в этой серии. Цифры я не выдумываю, всë в даташите есть.
Если у вас есть gd32f103rk - отлично, можете проверить скорость доступа и рассказать что там с кешированием. У меня же под рукой только gd32vf103c8. Из всех riscv контроллеров gd у него больше всего памяти - целых 128 кБ. Но из того, что я от вас услышал, этого недостаточно.
А даташит почитать слабо?
VF103 - это другое семейство. Не про них обсуждение началось. У них по поводу скорости доступа английским по белому написано - без задержек:

Однако время запуска у VF103 тоже адски большое:

Ровно столько же времени требуется, чтобы прочитать 128 кБ на скорости 8 Мбит/с. Делайте выводы.
В смысле risc-v, а не arm? Ну и что, на организацию кристалла это не влияет: и у тех, и у других флешка внешняя.
По остальному - ничего нового: как не было у меня возможности проверить границу кеша самостоятельно, так и нет. Разве что в ch32 (да, это тоже risc-v, как и gd32vf, о которых мы в этой ветке говорили). Но там про него пишут прямым текстом.
Поймал в 400й серии проблему, не описанную в errata - задержка от включения UART до физической передачи плавала случайно от 0 до 11 бит. Пришлось костылить хардкорный сброс UART (вместе с приёмником) перед каждым пакетом.
Можно этот момент описать поподробней? Спасибо!
Было у меня 2 задачи:
простая - сформировать таймером сигнал направления передачи для RS485, +-1 бит,
и сложная - сымитировать дифф.сигнал для обмена с MAX17843. +- 1/4 бита.
Мк из разных семейств, но я думаю, всё похоже должно быть и у остальных. Везде UART работал через DMA - один раз запустил вместе со стробом, и забыл до следующей передачи. Синхростарт, естественно, делается с запретом прерываний.
У ST (F105) передатчик UART стартует с задержкой +-1/2 бита, если не отключать UE. Если отключать, то не хуже +-1/16 бита. Отключение TE приводит к фиксированной доп.задержке в 11 бит.
У GD (F405) 11-битная задержка появляется полностью рандомно, независимо от TE и UE. Точная повторяемость получилась, только если UART перед каждой передачей сбрасывать через RCC. И, соответственно, инициализировать заново.
Спасибо. Я это делаю через TC (Transmit Complete) флаг и прерыание
В обработчике прерывания UART ловим полученный байт и если нужно обрабатываем полное завершение трансмита
handleUART uart onReceive onDrain = do
handleReceive uart onReceive
traverse_ (handleDrain uart) onDrain
handleReceive uart onReceive = do
rbne <- getInterruptFlag uart usart_int_flag_rbne
when rbne $ do
clearInterruptFlag uart usart_int_flag_rbne
onReceive =<< S.receiveData uart
handleDrain uart onDrain = do
tc <- getInterruptFlag uart usart_int_flag_tc
when tc $ do
clearInterruptFlag uart usart_int_flag_tc
disableInterrupt uart usart_int_tc
onDrain
В обработчике прерывания DMA, если нужно, разрешаем прерыание UART при полном завершении передачи
handleDMA dmaPer dmaCh uart onTransmit onDrain = do
f <- getInterruptFlagDMA dmaPer dmaCh dma_int_flag_ftf
when f $ do
clearInterruptFlagDMA dmaPer dmaCh dma_int_flag_ftf
M.when (isJust onDrain) $ do
enableInterrupt uart usart_int_tc
onTransmit
Есть подобное решение для передачи без DMA, только на прерываниях
Я так понимаю TE происходит когда трансмит буффер освободился и можно туда писать новые данные на передачу, а вот TC когда уже полностью данные переданы. Я их импользую оба для RS-485
А в dfu режим gd32 также входит? Прошить можно также без проблем через usb? Хочу попробовать использовать gd32 вместо stm32f405rtg6 в полетном контроллере для квадрокоптера(не военная тема), но не совсем понял ваши замечания про задержки на уартах, как они влияют на работу с девайсами, такими как gps модуль или приемник elrs.
В даташите про Boot modes написано, что входит. Не знаю, на сколько dfu совместим с stm - не проверял ещё.
Если пользоваться голым уартом, проблем не видел. Проблемы начинаются, когда с уартом нужно что-то синхронизировать в пределах 1 битового интервала.
Поменял на плате полетника stm32 на gd32, в дфу режим заходит, но нужны уже свои драйвера. Скачал, поставил, прошил их фирменной утилитой прошивку, которой шил стм-ку и.. ничего, не запускается плата, com-порт не появляется.
Может быть можно подменить драйвера для dfu usb, чтобы шить из под родного приложения, не знаю дальше куда копать..)
О, мы тоже собирались переходить с PIC32 на STM32 а перешли в итоге на GD32. В процессе заодно перешли на GCC, а с С на Haskell. После перехода на Haskell привычный процесс отладки стал не нужен в принципе! По пути отказались и от RTOS! Код пишем в VSCode, но это не принципиально.

У меня нервная система в порядок не пришла, после попыток писать под nrf52833 в VSCode. Очень своеобразный этот VSCode, к нему надо привыкнуть после эклипсоподобных IDE. Но скорее конечно, дело во мне и надо привыкнуть.
Мы как раз уходили от всех этих визардов в IDE для конфигурирования проектов
На Haskel все через библиотеку STM32-Zombie же делается? Правильно я понимаю, что идея такая же как на Rust?
Нет, мы используем EDSL Ivory – безопасное подмножество AST С99 на Haskell. На выходе получаем C99 и его уже компилируем с помощью GCC
Почитал, немного понял - как, но так и не понял - зачем) поясните, чем это лучше написания конфигурации руками или внешним конфигуратором?
Безопасность за счет системы типов Haskell. Нельзя разыменовать
null
указатели, нельзя выйти за границы массива, опечататься и спутать=
с==
, забыть вставитьbreak
вswitch/case
, аллоцировать память там где запрещено и многое другое. Подробнее можно посмотреть в этой презентацииПереносимость кода.
Весь платформенно-зависимый код, "подтягивается", настраивается и инициализируется сам, нам достаточно описать бизнес-логику работы устройства и предоставить ей ресурсы платформы.
Использовать внешние конфигураторы для одного проекта, вероятно, удобно. Для нескольких десятков с пересекающимся функционалом становится очень сложно, особенно если разные платформы и компиляторы.
Исключение муторного процесса отладки с программатором и брейкпоинтами. Забыли что такое дебаг совсем!
Скрипты сборки вместо CMake и Make так же на Haskell с использованием библиотеки Shake. Компилятор, его параметры и переменные окружения описаны и статически типизированы и встроены в единый пайплайн от генерации кода получения бинарников.
Вот это мы используем https://github.com/GaloisInc/ivory
Если интересна тема безопасного C99, то есть еще вот такое (тоже от Галуа изначально)
https://github.com/leepike/Copilot
Haskell? Можете поделиться, каким образом?
О_о, Haskell в embedded. А можете показать кусок кода? Например, как мигать светодиодом в прерывании таймера?
Писать-то можно на чем угодно, но там же библиотеки всякие иногда удобно взять (ethercat/modbus/freertos/Lvgl) Или у вас самописное всё?
https://www.youtube.com/watch?v=dhBYPcK23Dg&list=PLM_iD1tGoZA4MOGg5Eb3CwDnf7pQgRZuH&ab_channel=Би-2
Из библиотек используем, например, LwIP
О_о, Haskell в embedded. А можете показать кусок кода? Например, как мигать светодиодом в прерывании таймера?
В нашем фреймворке поверх Ivory EDSL будет вот такое описание самой прошивки:
blink330 :: Formula GD32F3x0
blink330 = Formula { name = "blink330"
, model = 0xff
, version = (1, 0)
, shouldInit = false
, implementation = blink out_pa_15 out_pa_14 timer_15
}
И сам "блинк", например, такой (тут пара ножек мигать будет, одна в прерывании таймера, другая в основном цикле):
blink :: (MonadState Context m, MonadReader (Domain p ()) m, Output o, Pull p u, Timer t)
=> (p -> u -> m o) -> (p -> u -> m o) -> (p -> Uint32 -> Uint32 -> m t) -> m ()
blink out1 out2 timer = do
let name = "blink"
mcu <- asks mcu
let peripherals' = peripherals mcu
out1' <- out1 peripherals' $ pullNone peripherals'
out2' <- out2 peripherals' $ pullNone peripherals'
timer' <- timer peripherals' 1_000 1
state1 <- value (name <> "_state1") false
state2 <- value (name <> "_state2") true
addHandler $ HandleTimer timer' $ toggle state1 out1'
addTask $ delay 100 "blink" $ toggle state2 out2'
Из этого будет сгенерирован такой C код:
Hidden text
/* This file has been autogenerated by Ivory
* Compiler version 0.1.0.9
*/
#include "blink330.h"
uint32_t system_time = (uint32_t) 0U;
uint8_t mac[6U];
uint8_t model = (uint8_t) 255U;
struct version_struct version = {.major =(uint8_t) 1U, .minor =(uint8_t) 0U};
bool should_init = false;
bool blink_state1 = false;
bool blink_state2 = true;
void systick_init_init(void)
{
SysTick_Config((uint32_t) 83999U);
}
void SysTick_Handler(void)
{
uint32_t n_deref0 = system_time;
system_time = (uint32_t) (n_deref0 + (uint32_t) 1U);
}
void mac_init(void)
{
uint32_t n_r0 = read_addr_32u((uint32_t) 536868832U);
uint32_t n_r1 = read_addr_32u((uint32_t) 536868780U);
uint32_t n_r2 = read_addr_32u((uint32_t) 536868784U);
uint32_t n_r3 = read_addr_32u((uint32_t) 536868788U);
uint64_t n_cse4 = (uint64_t) ((uint64_t) ((uint64_t) ((uint64_t) n_r0 << (uint64_t) 32U) | (uint64_t) n_r1) % (uint64_t) 281474976710597U);
uint64_t n_cse15 = (uint64_t) ((uint64_t) ((uint64_t) ((uint64_t) n_r2 << (uint64_t) 32U) | (uint64_t) n_r3) % (uint64_t) 281474976710597U);
uint64_t n_local4 = (uint64_t) (n_cse4 ^ n_cse15);
uint64_t *n_ref5 = &n_local4;
for (int32_t n_ix6 = (int32_t) 0; n_ix6 <= (int32_t) 5; n_ix6++) {
uint64_t n_deref7 = *n_ref5;
uint64_t n_cse29 = (uint64_t) (n_deref7 & (uint64_t) 255U);
mac[n_ix6] = (uint8_t) ((bool) (n_cse29 <= (uint64_t) UINT8_MAX) ? (uint8_t) n_cse29 : 0);
*n_ref5 = (uint64_t) (n_deref7 >> (uint64_t) 8U);
}
}
void GPIOA_GPIO_PIN_15_init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
}
void GPIOA_GPIO_PIN_14_init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_14);
}
void TIMER15_init(void)
{
rcu_periph_clock_enable(RCU_TIMER15);
timer_deinit(TIMER15);
uint32_t n_cse3 = (uint32_t) (SystemCoreClock / (uint32_t) 1000U);
uint32_t n_cse8 = (uint32_t) (n_cse3 - (uint32_t) 1U);
struct timer_parameter_struct n_local0 = {.prescaler =(uint16_t) ((bool) (n_cse8 <= (uint32_t) UINT16_MAX) ? (uint16_t) n_cse8 : 0), .period =0, .alignedmode =TIMER_COUNTER_EDGE, .counterdirection =TIMER_COUNTER_UP, .clockdivision =TIMER_CKDIV_DIV1, .repetitioncounter =(uint8_t) 0U};
struct timer_parameter_struct *n_ref1 = &n_local0;
timer_init(TIMER15, n_ref1);
timer_enable(TIMER15);
}
void TIMER15_irq_init(void)
{
nvic_irq_enable(TIMER15_IRQn, (uint8_t) 0U, (uint8_t) 0U);
timer_interrupt_enable(TIMER15, TIMER_INT_UP);
}
void TIMER15_IRQHandler(void)
{
bool n_r0 = timer_interrupt_flag_get(TIMER15, TIMER_INT_FLAG_UP);
if (n_r0) {
timer_interrupt_flag_clear(TIMER15, TIMER_INT_FLAG_UP);
bool n_deref1 = blink_state1;
blink_state1 = (bool) !n_deref1;
if (n_deref1) {
gpio_bit_set(GPIOA, GPIO_PIN_15);
} else {
gpio_bit_reset(GPIOA, GPIO_PIN_15);
}
}
}
void blink_task(void)
{
bool n_deref0 = blink_state2;
blink_state2 = (bool) !n_deref0;
if (n_deref0) {
gpio_bit_set(GPIOA, GPIO_PIN_14);
} else {
gpio_bit_reset(GPIOA, GPIO_PIN_14);
}
}
void init(void)
{
systick_init_init();
mac_init();
GPIOA_GPIO_PIN_15_init();
GPIOA_GPIO_PIN_14_init();
TIMER15_init();
TIMER15_irq_init();
}
void loop(void)
{
uint32_t n_local0 = (uint32_t) 0U;
uint32_t *n_ref1 = &n_local0;
{
int forever_loop __attribute__((unused));
for (forever_loop = 0; IFOREVER; IFOREVER_INC) {
uint32_t n_deref2 = system_time;
uint32_t n_deref3 = *n_ref1;
if ((bool) ((uint32_t) (n_deref2 - n_deref3) >= (uint32_t) 100U)) {
blink_task();
*n_ref1 = n_deref2;
}
}
}
}
int32_t main(void)
{
init();
loop();
return (int32_t) 0;
}
Основное отличие между ними — это цена, так как GD32 обычно дешевле, что делает его привлекательным для проектов с ограниченным бюджетом.
Имхо, если оценивать устройство на этапе запуска первой серии и эта серия менее 1000-10000 изделий, то цена МК не является решающей, если, конечно, это не что-то толстое уровня Н7 или специализированное. Да, если серии большие и мы уже на этапе оптимизации - можно попробовать отыграть 1-2 бакса на мк, иначе смысла мало. Для меня более важным является доступность; сейчас у STM и GD (у них "голова" в США, кстати) она примерно одинаковая, но для перестраховки я б переходил на континентальных китайцев - WCH и Artery, причем на RISC-V для новых проектов.
Да, вы скорее правы. В статье шла речь, про чиппагедон 22 года, когда STM32 пропали, а GD32 резко стали "предлагаться" дистрибьюторами в качестве pin2pin замены.
На Artery уже смотрели для новых проектов, но как то страшновато пока, нет пока большого опыта разбираться в китайском коде и китайских схемах. Но скорее всего это неизбежно.
GD тоже пропадали примерно в то же время, в 22 было окно поставок примерно на полгода. Они были доступнее в то время в основном в силу меньшей популярности: хвосты стмок в магазинах подъели быстро, а гдшки залежались. В 20м была примерно такая же история - пропало всё сразу, со сроком поставки в 40-60 недель.
Что WCH, что AT в обоих версиях (RISC/ARM) стараются сохранять имена и раскладку регистров и pin2pin совместимость с STM, по поводу документации и инструментов... ну, сильно скромнее STM, но из-за исполнения где не понял - можно читать STшную документацию, обычно работает :)
Из критичных отличий - более слабые порты, то есть 10 мА оптрон MOC3052 он может открыть только при температуре выше нуля. И гнилой АЦП - ниже 0,3 В его приходится линеаризировать по таблице, а входное сопротивление во всём диапазоне раз в 10 меньше, из-за чего сигналы приходилось буферизировать. У нас использовалась почти вся периферия Ф103 и общие впечатления негативные.
И, несмотря на более высокую тактовую частоту, по сравнению с ART-акселератором СТМ32 в реальных приложениях заметного прироста производительности нет. Это особенности работы конвейера и теневого ОЗУ.
Позвольте Вас дополнить ссылкой на мой комментарий по результатам сравнения STM32F103C8T6 и GD32F103C8T6 https://habr.com/ru/news/676068/comments/#comment_24512920
Не вижу статей про замену stm32 младших серий на risc v, поморгали светодиодом и успокоились, никто особо переезжать не хочет. Путь с заменой на gd32 прошли два года назад.
Дайте на арме освоиться, что за зверь risc v - вообще не знаю.
В принципе, как я пробовал, так как большой нужды не было -
если пишешь на С без извратов, и выносишь аппаратную (этакий HAL) отдельно - пофиг.
Я не загонялся с таймерами и прочим - простая State-Machine.
То есть на многих задачах разницы не будет, если грамотно подходить к ним.
Ну вообще да, C без извратов - наше все.
Мы так и сделали, бизнес-логика на С++, можно использовать на любом контроллере, а HAL на C уже для каждого свой собственный. У нас тут получилась более забавная ситуация: всё писали на GD32, а потом один проект нужно было на STM32. В общем, никаких проблем не возникло.
никто особо переезжать не хочет
Скорее никто особо статей писать не хочет.
Тоже работаю с gd32 действительно удивительный чип. Типа клон, но со своими идеями. Хотя непонятно, типа скопировать аппаратный api это вообще законно, если да почему никто раньше не додумался так делать для популярных чипов.
Хотя может просто не было смысла
А так на плате для стм32 работает стабильно
Кстати заметил много комментов про ide и прочее, сам давно перелез с iar, ses, кейлов и кубов на gcc и vscode. Работает местами неидеально, зато универсально.
Если, кому интересно могу написать как настроить связку gcc + gdb + jlink + vscode + cmake. Хотя таких статей много и на Хабре в том числе, но ещё одна не помешает для популяризации)) Как говорится я использую Арч кстати😂😂
Из плюсов связки удобно делать эмулятор прошивки, писать тесты и ci/cd. Все делается в одной среде и тем же компилятором по сути.
API копировать законно. И аппаратный интерфейс - тоже законно, кроме его названия. Незаконно - копировать его реализацию.
Как говорится я использую Арч кстати😂😂

А может уже и пора уйти от всего вот этого и прийти к "gcc + gdb + jlink + vscode + cmake". Надо решиться.
c iar и keil - понятно, cubeMX имхо вобще только для назначения ног использовать можно, а вот чем ses не угодил? Сам на него перешел достаточно давно использую и под Windows и под linux
я использую Арч кстати😂😂
До этого пытался попробовать gcc + gdb + ... но честно говоря не понял приемущества данного решения, скорее больше сложностей со сборкой данного комбайна.
Из плюсов связки удобно делать эмулятор прошивки, писать тесты и ci/cd
ci/cd вроде как в ses имеется, тесты - честно не понял что с ними в ses не так и на сколько удобнее их писать в предлагаемой сборке?
До этого пытался попробовать gcc + gdb + ... но честно говоря не понял преимущества данного решения, скорее больше сложностей со сборкой данного комбайна.
Это и есть глубокое понимание предметной области и собственно опыт. А вот опыт замены одной IDE на другую можно выкинуть в помойку при переходе от одного чипа к другому, что скорее всего произойдет скоро с окончательным уходом STM.
В случае глубокого понимания меняете в одном месте архитектуру и все и не нужны вот такие вот статьи про жонглирование версией IDE. Лучше день потерять, а потом за 5 минут долететь (с)
Если используете HAL, то в определенный момент и вовсе можно (в теории) заменить архитектуру и заменить STM на что-то ну совсем другое.
Я бы сказал, что вас преднамеренно подсадили на это Windows решение и теперь вы занимаетесь решением проблем, которые с какой-то вресии и вовсе не решаемые. А еще это VendorLock... Как говорит молодеж ну комон это же база...
P.S. В прошлом Gentoo-шник, но в целом лоялен к Arch, правда сейчас из Debian ;)
Все эти сложности понимание того что происходит под капотом IDE
Все же без понимания что происходит внутри IDE работать можно, пожалуй, только в кубе. IAR, Keil, Ses требуют минимального понимания, как все устроено при настройке проекта (настройки по "мануалу" из интернетов рассматривать не будем). Опять же я опираюсь на свой опыть, начинал С как раз на gcc + gdb и notepad++ с gcc использовал. В итоге пришел к ses, для меня это оказался более простой и удобный вариант. Хотя, честно говоря, с удовольствием почитал бы, не столько о настройке сколько об опыте вашего использования данной связки.
с удовольствием почитал бы, не столько о настройке сколько об опыте вашего использования данной связки.
Я начал изучать контроллеры в какой-то переходный момент ухода с Windows на Linux где-то 10-15 лет назад и отладку производил через повторяемую сборку (поменял код + собрал + смотрю результат) и здесь мне показалось удобнее иметь одну команду (цель в make) для комбинированной связки сборка, заливки прошивки и т.д.
Вы вероятно возразите, что это неоправданная сложность не дает гарантий, что вся эта связка скриптов (целей make-а) спустя 10 лет заработает сегодня на современном дистрибутиве, но все флаги компилятора описаны в документации, а вот удастся ли в следующей версии IDE найти нужное название Java класса для своего собственного конфига это очень большой вопрос.
Конечно собрать экосистему руками может показаться достаточно сложным занятием (особенно первый раз), но есть проект platformio позволяющий получить готовое окружение одним конфигурационным файлом, но это тоже определенного рода компромисс.
Я считаю, что неплохо было бы каким-то образом стандартизировать всех поставщиков инструментария для контроллеров, так как каждый разводит свой зоопарк, что сред IDE, что компиляторов и вишенкой на торте обилие Bash скриптов с какими-то переменными окружения.
Когда переходили на GD, то первое, что "порадовало" - пин-ту-пин совпадают только самые популярные модели. Шаг в сторону - название совпадает, а i2c уже на других ногах, и всё сломалась. 😅
Ещё первое время сбивало с толку нумерация периферии с нуля.
St-Link, часто работает с gd32 совершенно отвратительно. У них есть свои отладчики gd-link.
CubeIDE совершенно не обязательна.
Нужен тулчейн. Я беру Linaro arm-none-eabi, Openocd и QtCreatоr.
Все это прекрасно работает.
Хорошо что домашних проектов это бред не касается. только что купил 401ю за 60 рублеи нордик 52й за стоку.
А где покупаете их? Почему-то на том же lcsc их нет
Не знаю как там в 107, в 103 я столкнулся с тем, что на векторах прерываний висел разный набор таймеров, и вот так вот просто бинарник от stm не зашить
У меня еще был опыт работы с 100 и 103 и там такого не заметил. И в документе от GD тоже такого не видел.
Единственное, что подходит под это описание - прерывания вроде 43-го "TIM8_BRK_TIM12", где один и тот же обработчик вызывается для событий от двух таймеров. Но при чем здесь "бинарник не зашить", как прошивка контроллера связана с таблицей векторов?
А вы таблицу векторов прерываний шьёте отдельно от прошивки? Поделитесь способом
Если на пальцах у stm конкретное irq вызывает определенный набор таймеров, у gd этот набор другой
Я могу, конечно, придумать пару способов зашить таблицу векторов отдельно от прошивки. Но вы сначала скажите зачем вам это надо.
Или вы пытались сказать, что таблица векторов прерываний в gd32f103 отличается от таблицы в stm32f103, и без переклмпиляции один и тот же бинарник может не заработать? Так тоже экзотическая ситуация.
Переходим с STM32 на GD32