К1921ВГ015 общее

32-разрядные микроконтроллеры разработки АО "НИИЭТ"

Модераторы: ea, dav, bkolbov, Alis, pip, _sva_

mkf
Сообщения: 20
Зарегистрирован: 14 апр 2025, 11:31
Предприятие: AO TEMZ

Re: К1921ВГ015 общее

Сообщение mkf »

RabidRabbit писал(а): 23 июл 2026, 16:56 Ого, РП для К1921ВГ015 на английском переписали?
Наоборот. На русском переписали. Это документация к riscv, которой должны следовать разработчики ядер.
Ядро BM-310S6 (возможно вместе с контроллером прерываний) разработал CloudBear. НИИЭТ приобрел лицензию на него и сделал свою периферию. Видимо поэтому ядро и контроллер прерываний очень скромно описаны в документации НИИЭТ.
По крайней мере русский текст по контроллеру прерываний что у НИИЭТ, что у МИЛАНДР местами дословно совпадает (кроме названий регистров), что наталкивает на мысль, что этот скромный кусок текста тоже достался от CloudBear.

Что из всей спецификации riscv реализовано в ядре к1921вг015, надо по крупинкам надо собирать отовсюду. Было бы очень хорошо, если бы была сводная информация по ядру. Может она где-то есть, но не нашел.
RabidRabbit писал(а): 23 июл 2026, 16:56 И чем собственно ОСы не угодили? Что значит "время реакции совсем не то"?

Всем угодили там, где нет необходимости быстро реагировать. То есть разрулить несколько неспешных потоков - очень хорошо, но разруливать машинные события операционной системой как-то не очень. Тем более там, где присутствие user-а не предполагается.
Можно сделать UART средствами ОС, если модуль UARTa не работает как надо. Но быстрее, чем у аппаратного UARTа не получится.

Уже начал было прерывание на уровень привилегий user спихивать, но вовремя опомнился - это будет куда более мутная схема, чем разрешить вложенные прерывания. Хотя вложенные как раз и не нужны. Нужны вытесняющие. На миландре с ядром BM-310S0 вытесняющие получается сделать. Там конечно контроллер прерываний более гораздый (CLIC), но даже в том же самом безвекторном режиме (как в PLIC) можно сделать вытесняющие прерывания без вложений. Там сигнал о наличии следующего ожидающего прерывания доставляется ядру сразу, не дожидаясь окончания действующего обработчика. Насколько я понимаю, так документацией riscv и предусмотрено.
Вытеснение организуется легко - в начале сохраняем пару регистров и глобально разрешаем прерывания, в конце запрещаем прерывания и восстанавливаем эту пару регистров.
Задержка на вызов вытесняющего прерывания только на время выполнения критической секции от автоматического глобального запрещения прерывания до ручного его разрешения (и наоборот). По сути это только сохранение всех регистров в стек (так в startup_k1921vg015.S сделано - занимает доли микросекунды). Какая ОС так может? То есть можно и ОС - она будет делать тоже самое, что и должен был делать PLIC, но только программно.
Тут (в к1921вг015) получается, что тоже можно сделать вытесняющие прерывания, но потеряется полезная аппаратная фича - блокировка вложений от одного и того же источника. Блокировку вложений обратно приделывать программно придется. Только это уже костыли, когда ноги без них не ходят.
RabidRabbit
Сообщения: 254
Зарегистрирован: 10 июн 2025, 12:11
Предприятие: HomeWork

Re: К1921ВГ015 общее

Сообщение RabidRabbit »

mkf писал(а): 24 июл 2026, 07:56 Всем угодили там, где нет необходимости быстро реагировать. То есть разрулить несколько неспешных потоков - очень хорошо, но разруливать машинные события операционной системой как-то не очень. Тем более там, где присутствие user-а не предполагается.
Что такое "присутствие user-а"? Что означает "неспешных"? Слышали что-нибудь про scmRTOS или FreeRTOS? "Быстро реагировать" - это насколько быстро? Вы в который раз отделываетесь общими фразами и ни разу не привели никакой конкретики. Неужели Ваш проект настолько секретный, что даже требуемое время реакции системы - это тайна?
mkf
Сообщения: 20
Зарегистрирован: 14 апр 2025, 11:31
Предприятие: AO TEMZ

Re: К1921ВГ015 общее

Сообщение mkf »

RabidRabbit писал(а): 24 июл 2026, 11:58 Что означает "неспешных"? Слышали что-нибудь про scmRTOS или FreeRTOS? "Быстро реагировать" - это насколько быстро? Вы в который раз отделываетесь общими фразами и ни разу не привели никакой конкретики. Неужели Ваш проект настолько секретный, что даже требуемое время реакции системы - это тайна?
Уважаемый, где ж я ранее пропустил вопрос про быстродействие ? :)
Для контроллеров работающих с железом ожидается, что реагировать они будут на события со скоростью соизмеримой с величиной такта.
Тут нет аппаратного сохранения регистров в стек и прерывания не векторные и частота 50 МГц, поэтому доли микросекунды вполне устроит в данном конкретном случае.
Одно прерывание длительностью 10 мкс, перебивается другим более срочным, длительностью 1 мкс. Что тут необычного?
Разбирался с работой PLIC вобще на двух свободных таймерах, потому как было удобно на осциллографе наблюдать.
Очень хорошо, что есть разные ОСы для тех кому они нужны.
Есть задачи, где они не нужны, так как процесс один, хотя у него есть несколько подзадач живущих от внешних событий параллельно. Для внешних событий есть прерывания. Есть контроллер прерываний, который прекрасно справится с одновременной (почти) реакцией на внешние события. Да, тут костыль получился, но три дополнительные строчки куда проще, чем операционную систему прикручивать.
RabidRabbit писал(а): 24 июл 2026, 11:58 "присутствие user-а"
к1921вг015 имеет два уровня привилегий. Как раз чтобы операционная система могла жить на машинном уровне, а пользовательские программы жили на юзерском. И даже если пользователь загрузит с помощью ОС кривую программу, то с ОСью ничего не случится, ибо она отгородилась от пользователя (запретила ему лезть в свою память на уровне процессора) и позволит ему залить еще раз правильную программу. Вот для таких условий в самый раз с ОСями заморачиваться.


Итог с вытесняющими прерываниями (блокировку от вложенных вызовов городить не стал) на примере таймера:

Код: Выделить всё

void TMR32_IRQHandler()
{
        //Разрешение вытесняющих прерываний (с бОльшим приоритетом):
        //сохраняем регистры, которые могут быть попорчены вытесняющим прерыванием
        uint32_t __MCAUSE, __MEPC;
        __MCAUSE=read_csr(mcause); //сохраняем причину предыдущего вызова
        __MEPC=read_csr(mepc);     //и программный счетчик 
        //разрешаем глобальные прерывания
        set_csr(mstatus,MSTATUS_MIE);
        //FIX к1921вг015:
        TMR32->IC = 0x1F; //очисить флаг до посылки сигнала PLIC-у о выполнении обработки, иначе сразу вложенное прерывание получим
        PLIC->MICC = 6; //посылаем сигнал PLIC-у с номером источника, который активировал обработчик
        //END_FIX:
        {
               /*тело прерывания, которое может быть прервано другими*/
        }
        
        clear_csr(mstatus,MSTATUS_MIE); //запрещаем прерывание обратно
        write_csr(mepc,__MEPC);            //восстанавливаем регистры, которые могли быть попорчены вытесняющим прерыванием
        write_csr(mcause,__MCAUSE);     
}
Может кому пригодится
mkf
Сообщения: 20
Зарегистрирован: 14 апр 2025, 11:31
Предприятие: AO TEMZ

Re: К1921ВГ015 общее

Сообщение mkf »

может быть модераторы вынесут "о прерывания и PLIC" в отдельную тему, чтобы не мешалась и не потерялась?
RabidRabbit
Сообщения: 254
Зарегистрирован: 10 июн 2025, 12:11
Предприятие: HomeWork

Re: К1921ВГ015 общее

Сообщение RabidRabbit »

mkf писал(а): 24 июл 2026, 14:59 Тут нет аппаратного сохранения регистров в стек и прерывания не векторные и частота 50 МГц, поэтому доли микросекунды вполне устроит в данном конкретном случае.
Быстрее микросекунды захода в прерывание не сделаете :) Особенно используя plib015.
mkf
Сообщения: 20
Зарегистрирован: 14 апр 2025, 11:31
Предприятие: AO TEMZ

Re: К1921ВГ015 общее

Сообщение mkf »

RabidRabbit писал(а): 24 июл 2026, 21:08 Быстрее микросекунды захода в прерывание не сделаете Особенно используя plib015.
plib015 тут прчием?
Вход в прерывание тут - startup_k1921vg015.S
Вот он и съедает основное время - сохраняет все регистры при вызове и восстанавливает при возврате.
Здесь да, будет больше 1 мкс.

Код: Выделить всё

### #########################
### trap handler
    .section ".text.crt.trap_entry","ax",@progbits
    .align 6
    .type trap_entry, @function
trap_entry:
    ## save context
    context_save
    ## save mstatus priv stack
    csrr s0, mstatus
    ## load trap handler args
    csrr a0, mcause
    csrr a1, mepc
    mv   a2, sp

    ## setup gp
    load_addrword_abs gp, __global_pointer$
    ## call trap handler
    load_addrword t0, trap_handler
    jalr t0

    ## restore mstatus priv stack
    csrw mstatus, s0
    ## restore context
    context_restore
    mret
максросы context_save и context_restore - это сохранение и восстановление всех регистров, которое и создает задержку вызова.
Они самые объемные - context_save (context_restor - такой же, только порядок наоборот):

Код: Выделить всё

    ## save context
    context_save
80000200:	fe512e23          	sw	t0,-4(sp)
80000204:	00010293          	mv	t0,sp
80000208:	f8010113        	  	add	sp,sp,-128
8000020c:	ff017113          		and	sp,sp,-16
80000210:	00112223          	sw	ra,4(sp)
80000214:	00512423          	sw	t0,8(sp)
80000218:	ffc2a283        	  	lw	t0,-4(t0)
8000021c:	00312623          	sw	gp,12(sp)
80000220:	00412823          	sw	tp,16(sp)
80000224:	00512a23          	sw	t0,20(sp)
80000228:	00612c23          	sw	t1,24(sp)
8000022c:	00712e23          	sw	t2,28(sp)
80000230:	02812023          	sw	s0,32(sp)
80000234:	02912223          	sw	s1,36(sp)
80000238:	02a12423          	sw	a0,40(sp)
8000023c:	02b12623          	sw	a1,44(sp)
80000240:	02c12823          	sw	a2,48(sp)
80000244:	02d12a23          	sw	a3,52(sp)
80000248:	02e12c23          	sw	a4,56(sp)
8000024c:	02f12e23      	    	sw	a5,60(sp)
80000250:	05012023          	sw	a6,64(sp)
80000254:	05112223          	sw	a7,68(sp)
80000258:	05212423          	sw	s2,72(sp)
8000025c:	05312623          	sw	s3,76(sp)
80000260:	05412823          	sw	s4,80(sp)
80000264:	05512a23          	sw	s5,84(sp)
80000268:	05612c23          	sw	s6,88(sp)
8000026c:	05712e23          	sw	s7,92(sp)
80000270:	07812023          	sw	s8,96(sp)
80000274:	07912223          	sw	s9,100(sp)
80000278:	07a12423          	sw	s10,104(sp)
8000027c:	07b12623          	sw	s11,108(sp)
80000280:	07c12823          	sw	t3,112(sp)
80000284:	07d12a23          	sw	t4,116(sp)
80000288:	07e12c23          	sw	t5,120(sp)
8000028c:	07f12e23     	    	sw	t6,124(sp)
80000290:	34002273          	csrr	tp,mscratch
80000294:	34102373          	csrr	t1,mepc
80000298:	00612023          	sw	t1,0(sp)
Вызов вложенного прерывания может быть задержан на двойной такой кусок кода. В худшем случае, сначала при вызове менее приоритетного прерывания, будут автоматически запрещены все прерывания, и при возникновении более приоритетного критическая секция, где запрещены прерывания и сохраняются регистры, должна будет выполниться дважды.
Но это так написано в startup_k1921vg015.S
При необходимости и желании это можно переписать и, регистры сохранять только нужные в уже теле обработчика своего сигнала прерывания (там будет точно известно, какие регистры используются).
Ответить

Вернуться в «32-разрядные микроконтроллеры»