ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Понедельник
8 июня
1590611 Топик полностью
Связанные сообщения
Risc-VCh32
RISC-V, QingKeV2 (CH32V006). По мере роста размера кода (4кБ сейчас), начал сваливаться в хардфолт. Компилятор GCC15 для WCH от ...2026-05-05
ch32c407/467, наличие в нем RVV, авто-векторизация кода в текущей версии GCC: спешите хотеть... спешите иметь2026-04-22
KGP свежак riscv32 . небеса упали на землю, собрал для масдая... не идет гора к Магомету. акцент на оптимизацию под популярные м...2026-04-22
китайцы медленно но верно захватывают жилплощадь, как борщевик. дока на ch32v407/467 говорит что в нем новое ядро qkv3V с...2026-04-14
Проверил код на другой плате, где нормальная разводка земли полигоном и шумов питания должно быть меньше, нашел обещанный гистер...2025-11-24
Китайцы пояснили насчёт остановки таймера в отладке. Есть отладочный регистр dcsr и в нём бит 9 отвечает за остановку СисТика.2025-08-20
для CH32V317 ключи: -mcpu=ch32v317 -mcmodel=medlow -mabi=ilp32f -Os. в данном случае ключ -march=rv32imafc не является не...2025-06-18
свежак KGP для riscv:32 gcc16.0.0 bu2.44.50.20250610 хост x86_64 zenv4 avx512 linux. похоже мне наконец то удалась таки сделать ...2025-06-11
Про FLASH в CH32V203. Вкратце: похоже, что при частичной записи страницы, автоматически стирается и перезаписывается вся страниц...2025-04-02
На озоне за сутки выкупили все отечественные RISC-V микроконтроллеры2025-03-15
Вот моё творчество:2025-03-09
В приличном обществе принят BOM (Byte Order Mark). 0xEF 0xBB 0xBF в начале файла.2025-03-04
всунул и протянул. gcc теперь умеет так: riscv32-kgp-elf-g++ ..... -mcpu=к1948вк018 ...., мой вклад в импортозамещение - буквы р...2024-10-10
Немного рассуждений про ch32v307+freerto+libwchnet.a2024-07-10
Китайский CH582. Я тут опять немного прихренел от китайского МК.2024-06-19
китайцы что то изобретают - ch32v006/ch32v007/ch32m007 : Streamlined Timer. непонятое... но интересное2024-05-18
[09.01.2024] по ходу подпрыгивании на тему "подъема-взлета" ch32v003 всунул в него CoreMark. промерил...2024-01-09
нашел на китайской версии сайта WCH ннфографику про семество riscv ch32 - сделал картинку. теперь легче понять отличия. удобно ч...2023-12-11
VisionFive. SBC на RISC-V со встроенным GPU.2023-11-16
Я извиняюсь народ.) Но пролейте пожалуйста свет кто чем сейчас programmирует чипы на RISC-V?2023-11-07
Пришел десяток CH32V003 в soic8 с Ali по 13 руб. Показались удобными для всяческой мелкой хренотени. Ну и как у китайцев положен...2023-07-26
СH32V203F8P6 - 96МГц. SPI - 12MГц, ENC28J60. Ping + UDP ping-pong 50 байт + UDP "спам" 1500 пак/сек. Вот такую вот картинку вижу...2023-07-03
Цука... CH32V00x с WCHlink нихт арбайтен. Требуют WCHlinkE. "Вот нахуя так делать? И, главное, зачем?"(С)... Да знаю, знаю зачем...2023-05-12
проект выходного дня....вроде заработало! свежак KGP для riscv32-kgp-elf с поддержкой CH32Vxxx (QingKeV4, QingKeV4B, QingKeV4C, ...2023-04-10
У ядра QingKeV4 есть расширенный набор коротких команд. Их пока только WCH-ный GCC порддерживает.2023-04-06
Траблы с WCH для CH32V203RBT6.2023-03-24
Risc-V, CH32V203RBT6, MounRiver Studio IDE, Си. Отладчик WCH-Link.2023-03-22
почитал доки на свежий китайский микроконтроллер ch32v307, есть много фич которые я воображал но не было в cortex-m. похоже risc...2023-03-03
Кто-нибудь уже пробовал использовать IAR EWARM для разработки под CH32F* от WCH? У производителя можно найти примеры и библиотек...2023-01-04
[RISC-V от WCH] - перспективно для замены всего недружественного. Klen, просьба покурить. ch32v103, ch32v307. - брать. Ес...2022-03-24
Платочки в формфакторе Raspberry Pi на RISC-V грядут. Заметим, сразу идет bare metal ПО, FreeRTOS, и на картинке видим ChipLink....2021-12-01
Allwinner обещается в этом году выкатить жЫрный RISC-V2021-02-09
ну давай Муська! еще капельку!: поразгонял gd32vf103cb + oled 0.962020-05-31
gd32vf103: выполнил обезжиривание кода rv-link/longan-nano, пришлось переделывать китайский код. меня попросили дать бинарь для ...2020-04-26
кто нибудь знает? GigaDevice планирует в gd32vf всунуть FPU или еще что нибудь, нигде не нашел их планов по захвату поляны - я б...2020-02-12
Computer Organization and Design RISC-V edition. просто бесподобны мануаЛЬ!2019-11-30
gd32vf103: Думаю можно подумать открывать новый раздел - RISCV2019-10-28
Китайцкая GigaDevice залепила мелкокристаллку на RISC-V. 108Mhz, 128K Flash, 32K RAM. На замену STM32F103, вроде как совместима ...2019-08-31
[RISC-V: ядра, SoC для микропроцессоров и микроконтроллеров] Сводный системный топик.2018-12-04
[RISC-V как предел софткорного процессоростроения]. Текущие результаты капиталистического соревнования.2018-04-28
[Сводный топик про RISC-V] Гнездо архитектуры -> -->2017-08-11
klen (Сегодня, 02:35, просмотров: 310)
для меня таки настала новая эра - мульти ядерных микроконтроллеров. с алика приехала muse lab nanoCH32H417. посчупал за вымя.. две сиськи, а не одна как обычно, на осчупь приятно....карашооо 

0. сабж на алике

https://aliexpress.ru/item/1005012151617553.html

1. доки на платку

https://github.com/wuxx/nanoCH32H417

2. никогда мультипроцессорной железной мелочи не трогал, давно хотел понять как оно отлаживается там где нет ОС. не мог отдуплить. оказалось что я не правильно представлял этот космос - как одно устройство с двумя вычислительными модулями. это порочное представлен. правильно понимать в контексте прошивки и отладки - два независимых устройства имеющих как побочный эффект - общее адресное пространство и который могут взаимодействовать..... а могут и нет!

с точки зрения отладчика каждый процессор это отдельный девайс.

для начала работы нужно прицепится через отладочны интерфейс к процам. мы используем openocd:


в файле конфига openocd прописывается не не один таргет, а два:


#interface wlink
adapter driver wlinke
adapter speed 6000
transport select sdi

wlink_set_address 0x00000000
set _CHIPNAME wch_riscv
sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001

set _TARGETNAME $_CHIPNAME.cpu

#---------------- target 0 ----------------------------------------------------------------------------------

target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME -coreid 0
$_TARGETNAME.0 configure -event reset-init {

    echo "core 0 reset initialized."
}
$_TARGETNAME.0 configure -gdb-port 3333 

$_TARGETNAME.0 configure -rtos FreeRTOS -work-area-phys 0x20100000 -work-area-size 0x4000 -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash0

flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0

#---------------- target 1 ----------------------------------------------------------------------------------

target create $_TARGETNAME.1 wch_riscv -chain-position $_TARGETNAME -coreid 1
$_TARGETNAME.1 configure -event reset-init {
    echo "Core 1 reset initialized."
}
$_TARGETNAME.1 configure -gdb-port 3334  

$_TARGETNAME.1 configure -rtos FreeRTOS -work-area-phys 0x20104000 -work-area-size 0x4000 -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash1

flash bank $_FLASHNAME wch_riscv 0x00005000 0 0 0 $_TARGETNAME.1

#----------------config event ------------------------------------------------------------------------------

echo "ready for remote connections"

$_TARGETNAME.0 configure -event gdb-attach {
     echo "GDB_EVENT $_TARGETNAME.0  attach"
     # TODO command
   }
$_TARGETNAME.0 configure -event gdb-detach { 
     echo "GDB_EVENT $_TARGETNAME.0  detach"
     # TODO command
   }
$_TARGETNAME.1 configure -event gdb-attach {
     echo "GDB_EVENT $_TARGETNAME.1  attach"
     # TODO command
   }
$_TARGETNAME.1 configure -event gdb-detach { 
     echo "GDB_EVENT $_TARGETNAME.1  detach"
     # TODO command
   }

что приводит к созданию процессом openocd двух копий gdb monitor-серверов, которые вниз независимо по одному отладочному интерфейсу через wlink педалируют каждый свой таргет hart, то есть процеесор:




таким образом в данном месте можно совершенно независимым копиям GDB присосатся к пртам 3333 и 3334 ( в скрипте конфига это указано явно и можно изменить на свои красивые значения )


слева будут картинки с hart0 ( мелкий процессор v3f ) справа hart1 ( жирненький v5f)

итак - пускаем GDB две шткуи на соответствующие открытые tcp-порты openocd:





тут происходит следующее

1. запуск GDB

riscv32-kgp-elf-gdb -ex "tar ext :3333"
riscv32-kgp-elf-gdb -ex "tar ext :3334"

запись двух прошивок

(gdb) load '/home/klen/mounriver-studio-projects/ch32h417qeu/V3F/obj/ch32h417qeu_v3f.elf'


(gdb) load '/home/klen/mounriver-studio-projects/ch32h417qeu/V5F/obj/ch32h417qeu_v5f.elf'


также подгружены элф файлы как символы чтоб поотлаживать с исходниками.


причем как я понимаю если нужно - можно генерить монолитный бинарь и шить в одном сеансе сразу все - флешь вроде бы одна банка...

но это не точно.


ФИСЕЁЁ - двухглавй дивайс готов к работе - можно пускать :)


при ресете hart1 спит. запускается hart0 который v3f. он должен себя запустит, настроить RCC и прочие вещи и разбудиь hart1.


в коде для hart0 это овыглядит так

int main(....)
{
SystemInit(); SystemAndCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); Delay_Ms(1000); printf("Привет \"multiсorem\" космос!!!\r\n"); printf("SystemClk:%d\r\n", SystemClock); printf("V3F SystemCoreClk:%d\r\n", SystemCoreClock); Delay_Ms(500); NVIC_WakeUp_V5F(Core_V5F_StartAddr);//wake up V5 HSEM_ITConfig(HSEM_ID0, ENABLE); NVIC->SCTLR |= 1<<4; RCC_HB1PeriphClockCmd(RCC_HB1Periph_PWR, ENABLE); PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFE); HSEM_ClearFlag(HSEM_ID0);

.......

Жирным выделены пасы ручками - обеспечивающие оживление второго жирного ядра hart1 - то есть процессор v5f


если вы дожили до этого места - поздравляю. мы научились запускать многоядерные процессоры.


с этого места в принципе эти две сучности - hart0 и hart1 живут абсолютно независимо, если только не столкнутся в общем адресном пространстве при транзакциях чтения записи...


как я понимаю шинная матрица - все таже, за исключением того что теперь она имеет не два мастер-порта - cpu и dma, а три порта - cpu0, cpu1 и dma, то есть с точки зрения системы в общем то ничего не произошло принципиально нового - вместо двух акоров, стало три - шинная матритрца ка диспетчерезировала запросы чтения записи на адресное пространство, так и продолжает это делать, только желающих стало больше на одного.


ФСЁЁЁ, этого в целом достаточно понимать про ТАКОЕ ЖЕЛЕЗО чтоб тупо писать прикладной С-говнокод и зарабатывать баблосики.



3. теперь можно подумать а как правильно! писать код. обозначу некотрые специфичные моменты

два проца трутся жёпами на одной поляне, могут друг другу и лапы оттдавить - поэтому нужно как то организовать их в послушное стадо, на это есть три аппаратных механизма:

1. для синхронизации имеется 32 канальныей аппаратный семафор: работает по принципу - кто первый того и тапки. наверно это аппаратный SpinLock

2. имеется стандартное riscv расширение "A"-значит atomic команд. это уже дергалки через интерфейс памяти... ну типа эксклюзивного чтения-записи. накидал по быстрому обертки чтоб поюзать эту фичу

/*
 * riscv32а++.h
 *
 *      Author: klen
 */

#pragma once

// The RISC-V Instruction Set Manual Volume I, Unprivileged Architecture Version 20240411
// Chapter 14. "A" Extension for Atomic Instructions, Version 2.1

// RISC-V: Managing concurrency using spinlocks
// https://strajabot.com/posts/kernel-concurrency-riscv/

// определения общие для расширения riscv32a
namespace riscv32a
{
  __ais__ auto amo_lrw(volatile  int32_t& obj, const  int32_t val) noexcept {  /*TODO  lr.w */ }
  __ais__ auto amo_scw(volatile  int32_t& obj, const  int32_t val) noexcept {  /*TODO  sc.w */ }

  __ais__ auto amo_swapw(volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amoswap.w %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory"); return result; }

  __ais__ void amo_addw (volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amoadd.w  %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}
  __ais__ void amo_andw (volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amoand.w  %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}
  __ais__ void amo_maxw (volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amomax.w  %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}
  __ais__ void amo_minw (volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amomin.w  %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}
  __ais__ void amo_orw  (volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amoor.w   %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}
  __ais__ void amo_xorw (volatile  int32_t& obj, const  int32_t val) noexcept {  int32_t result; asm volatile ("amoxor.w  %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}

  __ais__ void amo_maxuw(volatile uint32_t& obj, const uint32_t val) noexcept { uint32_t result; asm volatile ("amomaxu.w %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}
  __ais__ void amo_minuw(volatile uint32_t& obj, const uint32_t val) noexcept { uint32_t result; asm volatile ("amominu.w %0, %2, %1" : "=r"(result), "+A"(obj) : "r"(val) : "memory");}


  // реализация аппаратного spinlock


  template < auto (*gloabl_interrupt_enable)(), auto (*gloabl_interrupt_disable)() >
  class amo_spinlock_tt
    {
      public:
	     __ai__  amo_spinlock_tt () noexcept
	         {
/*	    	    if( !nested )*/ gloabl_interrupt_disable();  // запрещение прерываний
//	    	    nested++ ;
	    	    asm volatile (
	    	      " loop%=:                          \n"
	              "   li t0, 1 			             \n" //#load 1 into t0
	    	      "   amoswap.w.aq t0, t0, %[obj]    \n" //#   t0(1) => amo_obj(?) => t0(?)  ( захват объекта блокировки и чтенте его предидущего сотояния )
	    	      "   bnez t0, loop%=			     \n" //# циклическа проверка по t0 == 1 ( объекта блокировкт уже был занят )
	    	                  : [obj]"+A"(obj) :  : "memory" , "t0" ) ;

	         }
	     __ai__ ~amo_spinlock_tt () noexcept
	         {
	    	    asm volatile (
	              "   amoswap.w.rl zero, zero, %[obj] \n"  //  0 -> amo_obj (сброс объекта блокировкт)
	                         : [obj]"+A"(obj) :  : "memory" ) ;
//	    	    --nested ;
/*	    	    if( !nested )*/ gloabl_interrupt_enable(); // разрешение прерываний
	         }
	  //private:
	     static volatile uint32_t obj ;
	     //static volatile uint32_t nested ;
    };


  template < auto (*gloabl_interrupt_enable)(), auto (*gloabl_interrupt_disable)(), bool interrupt_handling = false >
  class amo_barrier_tt
    {
      public:
	     __ai__  amo_barrier_tt () noexcept : obj(0) {}
	     __ai__ ~amo_barrier_tt () noexcept {}

	     // return true if barrier reject
	     template <typename T>
	     __ai__ bool try_call ( T func ) noexcept
	         {
	    	    if (interrupt_handling)
	    	       {
	    	          if( !nested ) gloabl_interrupt_disable();  // запрещение прерываний
	    	          nested++ ;
	    	       }

                uint32_t res ;
                asm volatile (
	              "   li t0, 1 			              \n" //#load 1 into t0
	    	      "   amoswap.w.aq %[res], t0, %[obj] \n" //#   t0(1) => amo_obj(?) => t0(?)  ( захват объекта блокировки и чтенте его предидущего сотояния )
            	              :   [obj]"+A"(obj), [res]"=r"(res)   :  : "memory" , "t0" ) ;

                if ( !res ) { func(); asm volatile ("   amoswap.w.rl zero, zero, %[obj] \n" :   [obj]"+A"(obj) : : "memory") ; }  //  0 -> amo_obj (сброс объекта блокировкт)

                if (interrupt_handling)
	    	       {
	    	    	 --nested ;
	    	    	 if( !nested ) gloabl_interrupt_enable(); // разрешение прерываний
	    	       }
                return res ;
	         }

	  //private:
	     volatile uint32_t obj ;
	     volatile uint32_t nested ;
    };


#endif
}

using namespace riscv32a ;

это пока черновик но вроде бы заработало как обещают. обязательно почитайте вот это. иначе трудно понять че это за херь
https://strajabot.com/posts/kernel-concurrency-riscv/


3. ворос непосредственного передергивания веревок привязанных к йайцам друг к другу решает аппаратный периферийный модулем IPC который настраивается и потом разруливает какой как и когда проц дернет другой - ну типа генерация прерываний друг другу.








4. в одноядерных микроконтроллерах сигнал прерывания PFIC непосредственно пихается на процессор. а тут че??? какой из процессоров интерраптить? один, оба?? вопрос решается так - здесь PFIC имеет апгрейд на один финтик поросячим хвостиком:

раздел мануала 4.7.5.45 PFIC Interrupt Allocation Register (PFIC_IALLOCRx) (x=0-63) PFIC->IALLOCRx = CoreID ... ну вы все поняли :)... точно поняли? PFIC позволит добавить в микросхему еще процов.. 256 штук... есси кристал не треснет


в коде выглядит так

/*********************************************************************
 * @fn      NVIC_SetAllocateIRQ
 *
 * @brief   Set Interrupt Allocate
 *
 * @param   IRQn - Interrupt Numbers ( >31 )
 *          Core_ID - Core ID
 *            Core_ID_V5F - V5F
 *            Core_ID_V3F - V3F
 *
 * @return  none
 */
__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_SetAllocateIRQ(IRQn_Type IRQn, uint8_t Core_ID)
{
  if(IRQn > 31)  return ;
  NVIC->IALLOCR[(uint32_t)(IRQn)] = Core_ID;
}


эксепшены ессессено в этот механизм не влазят - ибо это субстанция нативно-внутренне конкретного процессора, в отличие от прерываний - суть внешних событий. поэтому как бы намек

IRQn - Interrupt Numbers ( >31 ) что все что ниже 32 - не шарятся по ядрам






ну теперь осталось все это удобно втащить в эклипсу вместе со всеми тулсами


в первых тестах с ходу v3f завелся на 150мгц а v5f на 500МГц ... из флеша.... думаю загоним код в ITCM , данные в DTCM нажмем на педаль газа... и

охуеем от открывшись перспектив использования субгигарцовых мк:




немного говнеца на любителей масдая. MRS2 сама по себе гамно... так она под виндой еще и встроенный в платку отладчик засрала - пришлось wlinke препрошивать. не заработало под виндой оригинальный пак MRS2. все падает в непонятном месте. В линухе ниче не падат, ибо залитвать в флеш заливает но не стартует отладака. Ну его нах эти проприетарные софтины. за деньги видимо в принципе ничего сделать хорошего не возможно - идея баблосиков ставит крест на изящном... не даром еще древние заметили - сытый писатель не пишет стихов, а сытый музыкан делает музло.


утром я еще понятия не имел как это все бывает на самом деле. итог дня - все понятно. надеюсь Вам было также интересно как и мне. рот закрыл - рабочее место убрал! спасибо за внимание :).