Ви не увійшли.
Купив собі колись кілька плат з CH32V003F4P6 на розпродажі, і програматор, і нарешті дійшли ручки іх помацати ![]()
І вияснилось, що програматор не той
Я купив wch-link, а треба wch-linkE ![]()
Але не все так фатально. В інтернетах є проект емулятора minichlink на arduino ![]()
Береться хттпс://github.com/Community-PIO-CH32V/Ardulink-pio, зашивається звичайним способом в Arduino (я взяв Uno). Для інших варіантів треба вказати правильну плату, з правильною частотою резонатора.
Тепер arduino стає Ardulink Programmer. І platformio може з ним працювати (mounriver-studio, на жаль, ні).
Якщо в platformio.ini вписати
[env:ch32v003f4p6_evt_r0]
platform = ch32v
board = ch32v003f4p6_evt_r0
framework = arduino
upload_protocol = minichlink
upload_port = /dev/ttyACM0
upload_flags = "-c ${UPLOAD_PORT}"то все прошивається, правда повільно.
З"єднання таке:
Arduino - CH32
GND - GND
8 - 1K резистор - SWD
9 - V
Класичний blink
#include <Arduino.h>
#define LED_PIN PD0
void setup() {
pinMode(LED_PIN, OUTPUT); }
void loop() {
digitalWrite(LED_PIN, HIGH);
delay(250);
digitalWrite(LED_PIN, LOW);
delay(250);
}працює, але не без особливостей. Internal LED тут припаяний до PD1, він же SWD, і, схоже, не можна його просто взяти і використати як GPIO.
Неактивний
CH32V003F4P6
Бавився з ними трохи, а також з восьминогими CH32V003J4M6. Правда, не через ардуіно фреймворк, а з ch32v003fun.
Якби їм ще зовнішній Vref зробили, взагалі ціни би їм не було. І засмутила відсутність SPI у J4M6.
він же SWD, і, схоже, не можна його просто взяти і використати як GPIO.
Так, не можна. Мало того, якщо спробувати використати, можна залочити чіп у непрацездатний стан. І якщо F4P6 розлочити доволі просто, то щоб розлочити J4M6 без NRST піна довелось потанцювати з бубном.
Я купив wch-link, а треба wch-linkE
wch-linkE сам по собі на CH32V305 зроблений)
Остання редакція dimich (2026-07-24 16:17:49)
Неактивний
Тепер би ще придумати до чого приспособити той wch-link ![]()
Тепер би ще придумати до чого приспособити той wch-link
Ну як мінімум як USB-UART адаптер має працювати
А можна заморочитись і спробувати перешити його додатково під інший протокол, зробити 1-Wire / debugWIRE адаптер, чи I²C, чи повільний напівдуплексний SPI. Дивлячить на якому МК і як він там зроблений. А AVR ISP, мабуть, без хірургічного втручання не вийде, бо 4 лінії потрібно.
Неактивний
ch32v003 весч.....вже більше 10 проектів зробив ...на 8ногій ...теж купив wch-link, а потім докупляв з буквою Е
прогер можна зробити на CH32V003F4P6 та ch340 - проект на гітхабі NHC_WCH_SDI
Софт на ардуіно,прогер WCH-LINKUTILITY 2.90
Остання редакція nickjust (2026-07-25 19:33:16)
Неактивний
Хттпс://github.com/NgoHungCuong/1-Wire-CH32V003 ?
Щось сложне. Няп це ліба під ch32f103
Ну.. такоє.. якщо в мене є програматор, який по 3 проводах може залити bootloader.. і працювати як debugger.. навіщо заливати програму через uart і 4 проводи?
Ну.. такоє.. якщо в мене є програматор, який по 3 проводах може залити bootloader.. і працювати як debugger.. навіщо заливати програму через uart і 4 проводи?
Мені здається, сенс приведених лінків у тому, що Ardulink-pio - не єдине можливе рішення працювати з CH32V003 при відсутності WCH-LinkE.
А з Ardulink-pio прошивщик хіба не пише у віртуальний UART, який по USB пише в USB-UART адаптер, який в свою чергу пише в атмегу, яка уже по 3х проводах взаємодіє з цільовим МК? Тут від ардуіно просто зручність, що USB-UART та контролер на одній платі.
Це якщо взяти МК, який реалізує USB девайс, то можна позбутись UART'а із ланцюжка. Але тоді прошивщик має вміти взаємодіяти з vendor-specific USB девайсом.
Неактивний
Follow this document to flash the USART IAP boot-loader using WCH-LinkE hardware
Няп тут про bootloader, який переводиться в режим dfu підтяжкою одної ноги. Для 8-ногого контроллера 3 ноги віддати для програмування це по багатому
можна, звичайно, вивернутись, вкрутити резисторів.. але wch-linke все одно потрібен.
Няп тут про bootloader, який переводиться в режим dfu підтяжкою одної ноги. Для 8-ногого контроллера 3 ноги віддати для програмування це по багатому
Ну 2 з них - UART, як і в ардуіні. Атмегу ж теж можна хоч по ISP, хоч одним проводом по debugWIRE прошивати, але не всі хотять додаткові провода, хотять бутлоадер і аплоад з IDE. В деяких випадках так зручніше.
Колись хотів детально розібратись, які там є доступні варіанти прошивки окрім SWIO, але руки не дійшли. З WCH-LinkE запрацювало, цього було достатньо. Але надибав такий опис: WCH CH32V003 Factory Bootloader - The Missing Manual.
Неактивний
Ну коли замість програматора за 300 грн UART за 50 - в принципі непогано..
хттпс://github.com/aappleby/picorvd
Надибав таке. Виглядає непогано, і rp2040 в хазяйстві є ![]()
Але не працює ![]()
blink наче заливає, але рівень на пінах не міняється.
При спробі debug - відтворюється хттпс://github.com/aappleby/picorvd/issues/8
Що хотів сказати автор issue.. Не та версія компілятора? gdb? А яка потрібна? ..
Жаль що до кінця ту штуку не доробили ![]()
Неактивний
blink наче заливає, але рівень на пінах не міняється.
На пінах цільового CH32? А якщо той же бінарик зашити заздалегідь робочим програматором?
Впевніться, що дивитесь на тому ж піні, яким цей blink дригає. На різних платах LED на різних пінах може бути, це ж не ардуіно.
Що хотів сказати автор issue.. Не та версія компілятора? gdb? А яка потрібна?
А х.з., у нього треба питати. Мабуть тулчейн мається на увазі, бо в xpack і компілятор, і gdb.
Теоретично, на момент написання того комента уже був gdb 13-ї версії, а може й 14-ї. А platformio досі ставить 12.1.
Жаль що до кінця ту штуку не доробили
Я б не покладав сподівань на проект, в якому приклад blink лінкується з libgcc.a, що лежить в цьому ж репозиторії.
Неактивний
gdb-multiarch -x gdbinit -ex 'load' -ex 'detach' -ex 'quit' bin/blink.elfТрохи дивує що заливається не .bin, а .elf. Десь під капотом повинна бути магія objcopy?
А якщо той же бінарик зашити заздалегідь робочим програматором?
Зашивається, працює
Через ardulink, зроблений з arduino, і пише і читає. Ок ![]()
Ага, трохи роз"ясняється. picorvd - заливає прошивку правильно, але в кінці не робить reset. ardulink, походу, робить reset через живлення
Якщо ребутнути через power - blink запускається. Але з debug - облом ![]()
GNU gdb (xPack GNU RISC-V Embedded GCC x86_64) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv-wch-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from bin/blink.elf...
0x000001e4 in busywait (x=600000) at blink.cpp:4
4 for (volatile int i = 0; i < x; i++) {
(gdb) break 10
Breakpoint 1 at 0x212: file blink.cpp, line 10.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) break 11
Breakpoint 2 at 0x214: file blink.cpp, line 13.
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x000001e4 in busywait (x=<error reading variable: Cannot access memory at address 0xfffffff4>) at blink.cpp:4
4 for (volatile int i = 0; i < x; i++) {
(gdb) Щось там недороблено ![]()
Остання редакція jokeR (Вчора 13:46:52)
Неактивний
Трохи дивує що заливається не .bin, а .elf.
Gdb бере elf на вхід. З нього ж таблицю символів читає для дебага, і дебажні символи, якщо є, і цільову архітектуру для multiarch.
Сирий бінарик прошити можна командою restore.
Десь під капотом повинна бути магія objcopy?
Та яка там магія. Заголовок, секції з атрибутами, таблиця символів. Avrdude ж теж elf шʼє.
Ага, трохи роз"ясняється. picorvd - заливає прошивку правильно, але в кінці не робить reset.
А "monitor reset" працює?
ardulink, походу, робить reset через живлення
WCH-LinkE теж вміє живленням смикати. Корисно коли нема NRST.
Note: automatically using hardware breakpoints for read-only addresses.
Дивно, в README picorvd пишуть же:
The CH32V003 chip does not support any hardware breakpoints.
0x000001e4 in busywait (x=<error reading variable: Cannot access memory at address 0xfffffff4>) at blink.cpp:4
Скоріш за все той аргумент x зник ще на етапі компіляції. Але чому gdb в неіснуючу памʼять лізе, замість того щоб сказати value optimized out - то вже х.з.
Взагалі, щоб більш-менш адекватний рантайм дебаг отримати, потрібно збирати з -Og, або хоча б -fno-omit-frame-pointer.
UPD: А, бачу, воно вже з -O0 компілиться. Але ж агрумент все одно через регістр передається: https://godbolt.org/z/o5YYEjYEK
Остання редакція dimich (Вчора 17:45:10)
Неактивний
А "monitor reset" працює?
ніт, "monitor" command not supported by this target.
потрібно збирати з -Og,
$CC -g -O0 -ffunction-sections -static-libgcc -lgcc -march=rv32ec_zicsr -mabi=ilp32e -I/usr/include/newlib -nostdlib -I. -Wall -c ch32v003fun.c -o obj/ch32v003fun.oщось недороблене ![]()
Неактивний
ніт, "monitor" command not supported by this target.
А ви gdb з монітором зʼєднали?
After that run "gdb-multiarch {your_binary.elf}" and type "target extended-remote /dev/ttyACM0" to connect to the debugger (replace ttyACM0 with whatever port your Pico shows up as).
$CC -g -O0
Так, уже побачив, відредагував.
Неактивний
У нас є gdb-multiarch, є ttyACM0
Ну gdb-multiarch має ж якось взнати, що є ttyACM0, на якому його будуть слухати.
є магічний пристій, що слухає ttyACM0 і смикає CH32V003 за SDIO.
Магічний пристрій і є монітор, який реалізує протокол gdb-сервера. В "класичній" конфігурації цю роль виконує openocd, який в свою чергу вже спілкується з залізом по іншом протоколу, наприклад, по JTAG.
Неактивний
Ну gdb-multiarch має ж якось взнати, що є ttyACM0, на якому його будуть слухати.
Через файл gdbinit ![]()
Магічний пристрій і є монітор, який реалізує протокол gdb-сервера.
Походу його не навчили цьому ![]()
Ну reset то таке.. можна і руками.. а що debug не працює - незручно ![]()
Неактивний
Через файл gdbinit
А, ну якщо там є target remote / extended-remote, і gdb запускаєте з '-x gdbinit', то має зʼєднуватись.
Не знаю, чи лежить він там у вас як ~/.config/gdb/gdbinit і ваш gdb-multiarch автоматично виконує його при старті, чи потрібно в командному рядку кожний раз передавати.
Походу його не навчили цьому
Код для ресету там є: src/RVDebug.cpp:95. А
"monitor" command not supported by this target.
- це про команду "monitor", яка не supported, поки target не визначений. Тому логічно припустити, що gdb просто нікуди не підключений в цей момент.
а що debug не працює - незручно
По факту він-то працює. На брекпоінті зупинився ж якось. Регістри та машинний код показує? Ну а змусити значення змінних показувати, коли вони у регістрах - це навіть на рідній хостовій системі не завжди вдається.
Неактивний
Вирішив теж спробувати цей picorvd. Довелось обробити напильником, щоб зібрати під сучасним Arch.
По-перше, в pico_sdk_import.cmake замінив PicoSDK на 2.3.0, бо з 1.5.1 виникала помилка через версію cmake. Ще і з нею розбиратись не хотілось, тому просто бампнув тег на останній, там версію cmake уже пофіксили.
По-друге, в example/build замінив префікс тулчейна на riscv64-elf-, та шлях до хедерів newlib на /usr/risc64-elf/include, де воно в мене і лежить.
Також поправив blink.cpp, щоби блимало PC4, а не PD0 та PD4. Бо LED у мене на PC4, а на PD4 SWIO.
Прошилось і навіть щось запрацювало.
А, бачу, воно вже з -O0 компілиться. Але ж агрумент все одно через регістр передається: https://godbolt.org/z/o5YYEjYEK
Тут трохи не додивився: аргумент-то передається в регістрі, але в самій функції потім кладеться в стек.
При blink зібраному з "-ggdb -Og" навіть значення аргумента показує правильно.
$ riscv32-elf-gdb ./bin/blink.elf
Reading symbols from ./bin/blink.elf...
(gdb) target extended-remote /dev/ttyACM0
Remote debugging using /dev/ttyACM0
0x0000019e in busywait (x=x@entry=300000) at blink.cpp:8
8 for (volatile int i = 0; i < x; i++) {
(gdb) p x
$1 = 300000
(gdb) info frame
Stack level 0, frame at 0x200007f0:
pc = 0xd28 in busywait (blink.cpp:8); saved pc = 0xdb4
called by frame at 0x200007fc
source language c++.
Arglist at 0x200007f0, args: x=x@entry=300000
Locals at 0x200007f0, Previous frame's sp is 0x200007f0
(gdb) bt
#0 0x00000d28 in busywait (x=x@entry=300000) at blink.cpp:8
#1 0x00000db4 in main () at blink.cpp:35При зупинці по брекпоінту перестає, "Breakpoint 1, busywait (x=<error reading variable: Cannot access memory at address 0xfffffff0>) at blink.cpp:8"
А от якщо при збірці blink прибрати garbage collection секцій (при цьому розмір blink зростає майже до 4 кб), то початкове вхідне значення показує правильно, а поточне відповідає значенню регістра, в якому передавався аргумент:
(gdb) break 8
Breakpoint 1 at 0xd24: file blink.cpp, line 8.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) continue
Continuing.
Breakpoint 1, busywait (x=32800, x@entry=300000) at blink.cpp:8
8 for (volatile int i = 0; i < x; i++) {
(gdb) info registers
ra 0xda4 0xda4 <main()+108>
sp 0x200007f0 0x200007f0
gp 0x20000800 0x20000800
tp 0x804e06a4 0x804e06a4
t0 0x1a0 416
t1 0x40014281 1073824385
t2 0x5b763111 1534472465
fp 0x0 0x0 <InterruptVectorDefault>
s1 0x40011000 1073811456
a0 0x8020 32800
a1 0x4002200c 1073881100
a2 0x8000d40 134221120
a3 0x50000 327680
a4 0x10040 65600
a5 0x90000 589824
pc 0xd2e 0xd2e <busywait(int)+12>"monitor reset" працює, покрокове виконання працює.
Неактивний