Pull to refresh
119
18
Send message

Если вдруг собственных шумов контроллера не хватит для oversampling-а.
В принципе, было бы забавно продемонстрировать описанный 1-битный АЦП и какую точность из него можно выжать. Вот там искусственные шумы были бы необходимы, все-таки их амплитуда должна быть равна питанию.

Никогда не понимал любителей сделать отладочную плату как можно более монструозной. Вот зачем там антенна или разъем для SD-карточки? Они что, будут хотя бы в 20% проектов? Да даже если и так, их один раз отладил и забыл. Финальную отладку так и так вести на финальной плате. А место они занимают постоянно.

Потому что это отладочная плата. Навесные компоненты будут напаиваться, отпаиваться, снова напаиваться. А фольга за текстолит не так уж хорошо держится.
Лучше ух взять отдельную макетку, распаять на ней гребенку, и подключать отладочную плату через нее.

Обычно это переменная из линкер скрипта. Вершина ОЗУ. Но никто не мешает поправить ld-файл и руками.

Просто константа, которую "ручками" загружают в sp.

	.section	.text.handle_reset,"ax",@progbits
	.weak	handle_reset
	.align	1
handle_reset:
.option push
.option	norelax
	la gp, __global_pointer$
.option	pop
1:
	la sp, _eusrstack
2:
	/* Load data section from flash to RAM */
...

Если вы пометите volatile только регистр конца списка

Ну, в реальности контроллеры при работе с массивами обычно не чудят. То есть как будто там volatile. Может, на более мощных системах по-другому, не знаю. В любом случае, разницы между разными типами синхронизации там не будет. Ну и, по-хорошему, если вы один и тот же массив хотите использовать в разных потоках, его бы тоже стоило объявить как volatile.

Вместо этого надо ставить явные барьеры перед записью отдельных элементов.

В теории (и, возможно, для больших систем) да. На практике для контроллеров - ставить fence на каждой второй строчке все-таки перебор. Тем более что все нужные области и без того обычно помечены производителем как volatile.

Вот почитайте про READ_ONCE, WRITE_ONCE

Спасибо, почитаю.

Прерывания - да. А сисколлы сейчас именно что функции.

Сисколы это вызовы функций ядра. Для "стандартных" ядер поведение и побочные эффекты стандартизированы. Если написано "записать кошку в ascii art", а состояние sp после вызова не определено, значит запишет кошку и испортит sp. Строгой договоренности на уровне RISC-V нет. Но, все-таки, сискол - вызов кода с машинными привилегиями. Со всеми вытекающими опасностями.

Не знаю. Но расширения Zfinx, Zdinx выглядят удобно.

Там речь о формате, демонстрируемом пользователю. Сохранение измеренного массива в файл, отображение через UART и т.д. Внутри контроллера, естественно, удобнее оперировать абстрактными "попугаями".
Вот что еще надо будет исправить (не помню, упоминал ли где-то). Всяческие настройки и дефайны для величин из реального мира. Их тоже стоит записывать в "человеческом" формате. Написать макрос, переводящий их во внутреннее представление, несложно. Зато потом проще разобраться что за что отвечает и в каких единицах записано.

И это ровно ни на что не повлияет. Такое допущение приняли только для простоты расчета. Ну не надо считать разработчиков идиотами.

Попробуем еще раз. Сигма-дельта АЦП отличается тем, что подстраивает сигнал порционно, то плюс опорой, то минус. И считает их соотношение.

В тактовые периоды 2 и 7 состояния системы идентичны, так как при неизменном входном сигнале Uвх=0,6 В цикл работы занимает пять тактовых периодов. Усреднение выходного сигнала ЦАП за цикл действительно дает величину напряжения 0,6 В: (1-1+1+1+1)/5=0,6.

Видите: складываются дискретные отсчеты и делятся на количество. Абсолютное значение времени там никакой роли не играет.

Вы же сами кидали ссылку на описание сигма-дельты. Там именно это и написано. А относительно вг015 вам открыть документацию ничуть не сложнее, чем мне. Но лично я там подробностей не нашел. Разве что то, что в источник опорного напряжения "выполнен с использованием напряжения запрещенной зоны полупроводника".

Оно N тактов линейно увеличивается, потом M тактов линейно уменьшается. И значение имеет только отношение N к M, а не их абсолютные величины. Только в примитивных АЦП однократного интегрирования измерялось абсолютное время. Но они практически нигде не применяются. Именно поэтому.

Вот только окно счета задается тем же генератором, что и окно интегрирования. Вы же не думаете, что разработчики самых точных АЦП настолько глупые чтобы завязываться на счетчик времени сомнительной стабильности?

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

Сдается мне, вы путаете точность и стабильность. То есть систематическую погрешность и случайную. То, что HSI отличается на 5% от номинала, не значит, что он на 5% плавает во время работы - это всего лишь значит, что НИИЭТ не стали его калибровать. Для АЦП важна именно стабильность частоты, а не точность. И интуитивно мне кажется, что стабильность у любых встроенных RC-генераторов будет примерно одинаковая, что у stm32, что у ch32, что у вг015.

int C = 5;

int foo(int a, int b) {
    return a + b + C;
 202:	952e                	add	a0,a0,a1
 204:	20000797          	auipc	a5,0x20000
 208:	dfc7a783          	lw	a5,-516(a5) # 20000000 <C>
}
 20c:	953e                	add	a0,a0,a5
 20e:	8082                	ret

Похоже, дело во флаге -mcmodel. У меня стоял medany, а у вас, вероятно, medlow. По крайней мере, я сейчас его поменял и ваше lui получилось. Так вот зачем этот флаг нужен. Спасибо что пнули в нужном направлении.
Что забавно, в документации позиционно-независимым назван как раз medany:

The code generated by the medium-any code model is position-independent, but is not guaranteed to function correctly when linked into position-independent executables or libraries.

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

Если в ld-скрипте адрес начала прошивки указан 0x8000'0000, в реальности ее располагают в 0x8001'0000, а для доступа к оперативке используется auipc, стартап никак не может на это повлиять.

Другое дело, что если mcmodel действительно позволяет отвязать адреса оперативки от адресов флеша и генерировать позиционно-независимый код (надо будет еще проверить ссылки на функции, таблицы переходов и т.п.), то со стартапом заморачиваться уже стоит.

Еще раз. Любое обращение к памяти из юзерского кода на Си. Оно разворачивается в auipc, а не в lui. Если не предпринимать дополнительных мер. И с этой проблемой стартап-код никак не поможет, будь он хоть трижды позиционно-независимым.

Во всех этих случаях заботиться о позиционно-независимом коде приходится самому программисту. А речь-то шла о том, что компилятор gcc по умолчанию будет генерировать обычный, позиционно-зависимый код.
И, на самом деле, это проблема: я-то надеялся написать бутлоадер, который бы располагался в начале флеша, а юзерский код записывал где-нибудь дальше. И если бы прошивка получалась позиционно-независимой, проблемы бы не было: ну стартует он не с 0x8000'0000, а с 0x8001`0000 - не страшно, переходы-то относительные. Но вот обращение к ОЗУ из-за la поломается. Поэтому придется либо вкручивать флаги компилятору (пока не знаю с какими побочными эффектами), либо править ld-скрипт. А раз так, то и возня с позиционно-независимым загрузчиком не особо полезна.
А самое обидное, что я так и не нашел способа передать в li адрес метки, компилятор ругается и требует la.

Мне разбираться с openocd не под силу. Вот написать бутлоадер - другое дело. Впрочем, там видно будет.

1
23 ...

Information

Rating
661-st
Registered
Activity