Что такое децентрализованный денежный рынок и как он работает?

Беспрепятственный поток капитала между заемщиками является ключевым аспектом динамичной экономики. Любой, у кого есть дополнительные активы, может занять их, чтобы использовать свой свободный капитал, и люди, которым нужны средства для развития своего бизнеса или покрытия операционных расходов, могут легко получить к ним доступ. Денежные рынки — это платформы, на которых могут встретиться заемщики и кредиторы.

Как работает денежный рынок?

Традиционно денежные рынки представляли собой централизованные структуры, облегчающие операции между кредиторами и заемщиками.

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

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

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

Что такое децентрализованный денежный рынок?

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

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

Управляемый глобальным сообществом заинтересованных сторон через сильно децентрализованную сеть узлов, рынок устраняет любых посредников.

На популярном жаргоне денежный рынок относится к сфере децентрализованных финансов (DeFi).

Проанализируем функционирование децентрализованного денежного рынка на конкретном примере. Fringe Finance ($FRIN) — это децентрализованный денежный рынок, который высвобождает бездействующий капитал на всех уровнях криптовалютных активов путем выдачи обеспеченных кредитов.

Платформа облегчает децентрализованное кредитование и заимствование. Fringe Finance — это основная кредитная платформа, где каждый может одолжить дополнительные средства и заработать проценты или предоставить залог в альткойнах для получения кредита в стейблкоине.

Кредиторы и заемщики работают через код на блокчейне, контролируемом децентрализованными узлами, тем самым прекращая монополию одного контролирующего лица и уменьшая количество точек отказа.

Вот несколько преимуществ, которые приносят децентрализованные денежные рынки:

  • Отсутствие разрешения

    В децентрализованной среде пользователям не нужно спрашивать разрешения у центрального органа, прежде чем участвовать в какой-либо деятельности на денежном рынке. Любой пользователь онлайн может свободно получать проценты на свой капитал и/или занимать средства для своих нужд. Децентрализованные протоколы имеют внутреннюю устойчивую к цензуре структуру.

  • Отсутствие места для хранения

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

  • Излишнее обеспечение

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

  • Компонуемость

    Компонуемость — это принцип проектирования, который позволяет частям системы взаимодействовать друг с другом. Различные приложения и протоколы могут беспрепятственно взаимодействовать без разрешения. Приложения DeFi могут быть составлены для создания чистого холста с бесконечными возможностями для новых механизмов, таких как извлечение доходности и сложные производные инструменты.

Как меняются децентрализованные денежные рынки?

На заре DeFi протоколы денежного рынка отдавали предпочтение более устоявшимся криптовалютам с большой рыночной капитализацией и высокой ликвидностью. Однако новые денежные рынки хотят опробовать новые модели. Fringe Finance, например, фокусируется на альткойнах с меньшей рыночной капитализацией и более низкой ликвидностью. Большинство протоколов денежного рынка DeFi не поддерживают альткойны, в отличие от Fringe Finance.

Альткойны — это нишевый продукт, поэтому они, как правило, более спекулятивны, чем цифровые монеты с большой капитализацией. Однако, поскольку такие альткойны обслуживают несколько децентрализованных финансовых кредиторов и заемщиков, запертый в них капитал остался неиспользованным. Fringe Finance изменил этот сценарий.

Имейте в виду, что альткойны по своей природе более волатильны, что влечет за собой некоторые связанные риски стабильности, которые могут быть компенсированы потенциальной прибылью.

Как денежный рынок альткойнов поддерживает финансовую стабильность?

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

Параметры, применяемые Fringe Finance, включают максимальную кредитоспособность для всей платформы, для каждого залогового актива и автоматический расчет LVR (кредит к стоимости). Для адекватной реализации этих механизмов система учитывает доступную ликвидность актива, историческую волатильность и другие объективные показатели.

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

Чтобы расширить свою операционную базу, денежный рынок DeFi по мере роста платформы может включать межсетевое обеспечение, кредитование с поддержкой NFT, кредиты с фиксированной ставкой, встроенное страхование и децентрализованный пользовательский интерфейс.

Будущее децентрализованных денежных рынков

В то время, когда люди стали опасаться корыстного уклона на централизованных денежных рынках и просто потеряли доверие к банкам, протоколы DeFi предоставили им выгодный вариант с правами контроля для всех, кто владеет нативными монетами.

Децентрализованные денежные рынки перестают сосредотачиваться на популярных криптовалютных проектах со значительной рыночной капитализацией и сосредотачиваются на альткойнах, раскрывая хранящуюся там ценность.

Можно ожидать, что будущие протоколы денежного рынка DeFi будут исследовать ранее нетронутые территории.


ссылка на оригинал статьи https://habr.com/ru/post/681692/

Микроконтроллеры Megawin серии MG32F02: модули UART и отладка кода в ОЗУ

Введение

Мы продолжаем цикл статей по микроконтроллерам компании Megawin на ядре Cortex-M0. В предыдущей статье были рассмотрены: методика разработки и прошивки на основе gcc и OpenOCD, контроллер flash-памяти, работа с GPIO. В этой статье будут рассмотрены: периферийные модули UART, обработчики прерываний UART, метод отладки кода в ОЗУ МК с базовой частью инициализации во flash-памяти, механизм системных вызовов, тактирование МК от различных источников.

Модули UART МК MG32F02

Общие сведения

Микроконтроллеры серии MG32F02 включают два варианта модулей UART: расширенный (URT0-URT2) и базовый (URT4-URT7). В МК MG32F02A032 имеются только два расширенных модуля URT0 и URT1. Строго говоря, расширенный вариант корректнее называть USART, т.е. универсальный синхронный-асинхронный приёмопередатчик, поскольку он поддерживает множество режимов работы, в том числе с синхронизацией передачи данных.

Все модули UART имеют следующие особенности:

  • полный дуплексный режим работы,

  • скорость обмена до 6 Мбит/с,

  • длина символа 7 или 8 бит,

  • передискретизация (oversampling) при приёме с коэффициентом 4-32,

  • поддержка генерации и проверки бита четности/нечетности,

  • отдельное разрешение работы приемника и передатчика,

  • возможность перемены местами выводов RX и TX,

  • возможность отдельного изменения полярности сигналов RX и TX.

В режиме SPI (только для расширенного варианта UART) максимальная частота синхросигнала URTx_CLK составляет 16 МГц для MG32F02A032, 18 МГц для MG32F02A128/A064 и MG32F02U128/U064.

Расширенный вариант (модули URT0-URT2)

Функциональные возможности

Расширенный вариант UART (модули URT0-URT2) имеет следующие особенности:

  • асинхронный и синхронный режим работы,

  • режимы SPI master и slave, SmartCard, LIN, мультипроцессорный,

  • настраиваемый порядок бит в символе (MSB или LSB),

  • настраиваемая длительность стоп-бита 0.5, 1, 1.5 или 2,

  • детектирование сигнала RX по одной или трем выборкам,

  • таймер для определения таймаута событий Idle/RX/Break/Calibration,

  • «вход» и «выход» из режима «mute» в мультипроцессорном режиме работы,

  • размер буфера данных 4 байта с доступом ко всему буферу как 32-битному слову,

  • поддержка автоматического определения скорости обмена,

  • мультипроцессорный режим (с адресацией) в роди ведущего или ведомого,

  • поддержка формата IrDA,

  • аппаратный контроль потока на основе сигналов RTS и CTS,

  • формирование сигнала управления передачей для двунаправленного интерфейса (например, RS-485),

  • аппаратное определение ошибки при приеме и передаче в режиме SmartCard,

  • прием и передача данных на основе DMA,

  • частичная аппаратная поддержка программного контроля потока XON/XOFF.

Отметим, что расширенные модули UART в МК MG32F02A032 отличаются от остальных моделей схемой тактирования.

Функциональная схема расширенного варианта UART МК MG32F02A128/U128/A064/U064 приведена на рисунке.

Функциональная схема расширенного UART
Функциональная схема расширенного UART

Модуль использует следующие внешние сигналы:

  • URTx_CLK — тактовый сигнал для синхронного UART или режима SPI,

  • URTx_RX — принимаемые данные RX для режима UART или MISO для режима SPI master,

  • URTx_TX — передаваемые данные TX для режима UART или MOSI для режима SPI master,

  • URTx_NSS — входящий/исходящий сигнал выбора кристалла (chip select) для режима SPI slave/master соответственно,

  • URTx_CTS — входящий сигнал аппаратного управления потоком UART CTS,

  • URTx_RTS — исходящий сигнал аппаратного управления потоком UART RTS,

  • URTx_DE — сигнал «передача» для внешнего драйвера двунаправленного интерфейса,

  • URTx_BRO — выход тактового генератора,

  • URTx_TMO — выход интервального таймера таймаута TMO.

Модуль имеет основной узел управления тактированием Clock Control, принимающий исходный тактовый сигнал с делителя частоты Baud-Rate Generator. Блок Mode Control управляет режимом работы модуля. Блок Data Control управляет приемом и передачей данных и общей буферизацией. Блок Receiver Control обеспечивает физический уровень приема данных, детектирование ошибок, а также декодирование сигнала в режиме IrDA. Блок Transmitter Control обеспечивает физический уровень передачи данных, а также кодирование сигнала в режиме IrDA. Прием и передача данных будут рассмотрены далее.

Блок Event Detector определяет различные состояния модуля, включая возможные ошибки при приеме и передаче данных, а блок Interrupt Control формирует на их основе общий сигнал прерывания INT_URTx. Оба модуля будут рассмотрен далее. 16-разрядный интервальный таймер TMO предназначен для выдерживания временных интервалов и обнаружения таймаутов согласно выбранному режиму работы и настройкам. Таймер TMO может использоваться для других задач отдельно от модуля UART, даже, если модуль UART выключен.

Блок Hardware Flow Control обеспечивает аппаратный контроль потока на основе сигналов RTS/CTS. Контроль потока на основе символов XON/XOFF может быть реализован только программно, аппаратно имеется лишь возможность приостановить отправку данных (бит URTx_TX_HALT регистра URTx_CR2).

Блок Drive Enable Timing Control предназначены для управления внешним драйвером двунаправленного интерфейса (например, RS-485). Блок SPI NSS Timing Control обеспечивает управление сигналом NSS в режиме SPI. Блок Multi-Processor Control отвечает за мультипроцессорный режим, а блок Baud-Rate Calibration за калибровку частоты работы модуля UART.

Для включения модуля UART необходимо:

  • включить тактирование модуля URTx в регистре CSC_APB0 установкой соответствующего бита CSC_URTx_EN (предварительно нужно разблокировать возможность записи через регистр CSC_KEY),

  • установить бит URTx_EN в регистре URTx_CR0.

Схема управления тактированием

Схема управления тактированием Clock Control МК MG32F02A128/U128/A064/U064 приведена на следующем рисунке.

Схема управления тактированием расширенного UART
Схема управления тактированием расширенного UART

Первичный источник тактовых импульсов для расширенного модуля UART выбирается установкой поля URTx_CK_SEL регистра URTx_CLK из числа следующих:

  • сигнал CK_URTx_PR с выхода подсистемы тактирования CSC,

  • общесистемный сигнал CK_LS тактирования периферии,

  • выходной сигнал таймера TM00 TM00_TRGO,

  • выходной сигнал модуля NCO (Numerically Controlled Oscillator) NCO_P0 (кроме МК MG32F02A032).

Сигнал CK_URTx_PR формируется из сигнала CK_APB или CK_AHB в зависимости от значения бита CSC_URTx_CKS регистра CSC_CKS1. Сигнал CK_LS формируется из сигналов CK_ILRCO, CK_XOSC или CK_EXT в зависимости от значения поля CSC_LS_SEL регистра CSC_CR0 (см. первую статью цикла).

Выбранный тактовый сигнал (обозначен на схеме как CK_URTx) поступает на блок BR (Baud-Rate Generator), состоящий из 6-битного предделителя частоты (4-битного для МК MG32F02A032) и 8-битного счетчика. Предделитель формирует сигнал URTx_CKO, используемый для тактирования счетчика, а также как внешний тактовый сигнал синхронного обмена. В регистре URTx_RLR в поле URTx_PSR задается коэффициент деления предделителя Kp, а в поле URTx_RLR — коэффициент деления счетчика Kc. Реальные значения коэффициентов будут на единицу больше. 8-битный счетчик CNT формирует внутренний сигнал CK_URTx_INT, который далее используется для тактирования передатчика и приемника.

Тактирование передатчика и приемника может осуществляться также от выходных сигналов таймеров TM01_TRGO или TM10_TRGO, и от внешнего синхросигнала URTx_ECK. Выбор источника для сигнала тактирования передатчика CK_URTx_TX определяется полем URTx_TX_CKS, а источника для сигнала тактирования приемника CK_URTx_RX — полем URTx_RX_CKS регистра URTx_CLK. Для приемника сигнал CK_URTx_RX будет определять частоту передискретизации (oversampling), с которой берутся отсчеты сигнала RX для выявления шума и предотвращения ложных срабатываний. Конечный сигнал тактирования передатчика со скоростью обмена Btx формируется после дополнительного делителя, коэффициент которого Ktxos определяется 5-битным полем URTx_TXOS_NUM регистра URTx_CR1. Конечный сигнал тактирования приемника со скоростью обмена Brx формируется после дополнительного делителя, коэффициент которого Krxos определяется 5-битным полем URTx_RXOS_NUM регистра URTx_CR1.

Итоговая скорость обмена Btx для передатчика будет определяться как

Btx = Furt / ( (Kp+1)·(Kc+1)·(Ktxos+1) ),

а скорость обмена для приемника Brx как

Brx = Furt / ( (Kp+1)·(Kc+1)·(Krxos+1) ),

где Furt — частота сигнала CK_URTx.

Блок BR может использоваться отдельно от модуля UART как счетчик общего назначения, даже, если модуль UART выключен. При этом предделитель и счетчик могут работать в объединенном режиме как один счетчик (бит URTx_BR_MDS регистра URTx_CLK нужно установить в 1). В любом случае, если блок BR применяется, должен быть установлен бит URTx_BR_EN в регистре URTx_CLK.

События и прерывания модуля

Модуль детектирует события, приведенные в таблице, где также указаны соответствующие флаги событий и флаги, приводящие к генерации прерывания INT_URTx.

Название

Флагсобытия

Флагпрерывания

Описание

Общие состояния ошибки

ERRF

Error flag

Parity Error

PEF

ERRF

Ошибка бита четности/нечетности

Frame Error

FEF

ERRF

Ошибка стоп-бита

Receive Data Overrun

ROVRF

ERRF

Переполнение приемного буфера

Receive Noised Character

NCEF

ERRF

Детектирован шум при чтении бита символа

TX Error

TXEF

ERRF

Ошибка формата кадра (стоп-бита) для режимов SmartCard и LIN

Transmit data underrun

TUDRF

ERRF

Нет данных для отправки в режиме SPI

Состояния ошибки при работе таймера TMO

ERRF

Error flag

Receive Timeout

RXTMOF

ERRF

Таймаут приема символа при установленном бите URTx_RXTMO_EN

Idle Timeout

IDTMOF

ERRF

Таймаут простоя линии при установленном бите URTx_IDTMO_EN

Break Timeout

BKTMOF

ERRF

Превышено время состояния «Break» при установленном бите URTx_BKTMO_EN

Calibration Timeout

CALTMOF

ERRF

Таймаут калибровки при установленном бите URTx_CALTMO_EN

Общие события

UGF

UART general event

Slave Address Match

SADRF

UGF

Принят кадр с собственным адресом

Baud-Rate Timer Timeout

BRTF

UGF

Таймаут тактового таймера BR (Baud-Rate Timer)

Timeout Timer Timeout

TMOF

UGF

Таймаут интервального таймера TMO (Timeout Timer)

Calibration Complete

CALCF

UGF

Процесс калибровки завершен

Статус линии

LSF

Line status

Break Condition Detect

BKF

LSF

Обнаружено состояние «Break» (принята длинная последовательность нулевых битов)

Idle Line Detect

IDLF

LSF

Выдержан «Idle» интервал между символами

CTS Change

CTSF

LSF

Состояние сигнала CTS изменилось

NSS Change

NSSF

LSF

Состояние сигнала NSS изменилось на неактивное в режиме SPI slave

Receive Data

RXF

Приняты новые данные, доступные в регистре URTx_RDAT

Transmit Data

TXF

Данные из регистра URTx_TDAT переданы на отправку

Transfer Complete

TCF

Отправлены все данные, включая теневой буфер

На следующем рисунке показана схема формирования прерывания INT_URTx Interrupt Control при возникновении различных событий в модуле UART, а также показаны события, которые приводят только к установке флагов (в регистрах статуса URTx_STA и URTx_STA2).

Схема формирования прерывания модуля UART
Схема формирования прерывания модуля UART

Внутренние события UART General Event (UG), Line Status Event (LS) и состояние ошибки Error Event (ERR), в свою очередь, формируются по следующей схеме:

Схема формирования UART General
Схема формирования UART General

Статусные флаги, приводящие к прерыванию, доступны в регистре URTx_STA. Статусные флаги, не приводящие к прерываниям, доступны в регистре URTx_STA2, за исключением флага RXDF, который доступен в регистре URTx_STA. Кроме булевых флагов, в модуле имеются две числовые трехбитовые переменные: TX_LVL — число байт в буфере, ожидающих отправки, и RX_LVL — число несчитанных байт из буфера приема. Обе переменные относятся к регистру URTx_STA2.

Для включения прерывания модуля UART необходимо:

  1. Выбрать событие (или события) в регистре URTx_INT. Например, для разрешения прерывания по приему данных нужно установить бит URTx_RX_IE.

  2. Разрешить прерывание самого модуля установкой бита URTx_IEA в регистре URTx_INT.

  3. Разрешить прерывание IRQ от модуля URTx в контроллере прерываний NVIC в регистре CPU_ISER. Например, для разрешения прерывания от URT0 (IRQ#20) нужно установить бит 20.

Прием и передача данных

Рассмотрим основной механизм приема и передачи данных в режиме асинхронного UART. Остальные режимы работы модуля, а также контроль таймаутов при обмена данными остаются за рамками данной статьи. Буферизацию данных при приеме и передаче иллюстрирует следующая схема:

Схема буферизации данных расширенного модуля UART
Схема буферизации данных расширенного модуля UART

Для включения блока передачи данных необходимо установить бит URTx_TX_EN в регистре URTx_CR2. Передача данных начинается автоматически после того, как программа запишет передаваемые данные в регистр URTx_TDAT. В расширенной версии модуля этот регистр 32-битный, поэтому можно загружать в него 1, 2 или сразу 4 байта на отправку (должны использоваться машинные инструкции STRB, STRH или STR соответственно). Для передачи трех байт можно воспользоваться регистром URTx_TDAT3 (только в 32-битном режиме, т.е. через инструкцию STR).

Перед непосредственной отправкой в линию TX данные передаются в промежуточный «теневой» буфер TX Shadow Buffer, после чего устанавливается флаг TXF, что может быть использовано для генерации прерывания или опроса готовности передачи. Последующая запись в регистр URTx_TDAT автоматически сбрасывает этот флаг. Оставшееся число байт, не переданных из регистра URTx_TDAT в теневой буфер, можно получить из поля URTx_TNUM регистра URTx_CR4. Число байт, еще не переданных в линию TX из теневого буфера, отображается в поле URTx_TX_LVL регистра URTx_STA2. Когда отправлены все данные из регистра URTx_TDAT и теневого буфера, устанавливается флаг TCF, что может быть использовано в двунаправленном режиме работы модуля.

При реализации библиотечной функции отправки одного байта перед записью в регистр URTx_TDAT можно проверять значение поля URTx_TNUM или URTx_TX_LVL. Значение 0 будет говорить о готовности модуля к отправке очередных данных. Полагаться на активный флаг TXF в этом случае будет некорректно, поскольку до первой отправки (после инициализации модуля) он будет сброшен. Если же его проверять перед выходом из функции, то будет впустую потрачено время на ожидание.

Для включения блока приема данных необходимо установить бит URTx_RX_EN в регистре URTx_CR2. Принимаемые символы с линии RX из сдвигового регистра RX Shuft Buffer передаются в промежуточный приемный теневой буфер RX Shadow Buffer. Далее данные передаются в конечный буфер для считывания — регистр URTx_RDAT, после чего активируется флаг RXF. В случае получения новых данных при заполненном теневом буфере активируется флаг ROVRF (переполнение буфера). Число байт, ожидающих передачу из теневого буфера в буфер данных, отображается в поле URTx_RX_LVL регистра URTx_STA2. Число байт, переданных из теневого буфера в регистр URTx_RDAT и еще невосстребованных, отображается в поле URTx_RNUM регистра URTx_CR4.

Таким образом, модуль активирует флаг RXF как только полученные данные станут доступны программе, после чего их можно прочитать из регистра URTx_RDAT. В расширенной версии модуля этот регистр также 32-битный, поэтому сразу можно прочитать 1, 2 или 4 байта. После чтения данных из регистра флаг RXF автоматически сбрасывается.

Формат кадра задается отдельно для приемника и передатчика в регистре URTx_CR1. Основные параметры настройки с указанием полей регистра приведены в следующей таблице. Символом «*» отмечены значения по-умолчанию (формат 8N1).

Параметр настройки

Приемник

Передатчик

Размер, бит

Значения

Длина символа

URTx_RXDSIZE

URTx_TXDSIZE

2

0(*) — 8 бит,1 — 7 бит,2,3 — резерв

Наличие бита чет/нечет

URTx_RXPAR_EN

URTx_TXPAR_EN

1

0(*) — нет,1 — есть

Полярность бита чет/нечет

URTx_RXPAR_POL

URTx_TXPAR_POL

1

0(*) — чет,1 — нечет

Длина стоп-бита

URTx_RXSTP_LEN

URTx_TXSTP_LEN

2

0 — 0.5 бит,1(*) — 1 бит,2 — 1.5 бита,3 -2 бита

Базовый вариант (модули URT4-URT7)

Базовый вариант UART (URT4-URT7) имеет следующие особенности:

  • только асинхронный режим работы UART,

  • настраиваемая длительность стоп-бита 1 или 2,

  • размер буфера данных 1 байт.

Функциональная схема базового варианта UART приведена на рисунке.

Функциональная схема базового UART
Функциональная схема базового UART

В базовом варианте отсутствуют:

  • аппаратный контроль потока на основе сигналов RTS/CTS,

  • выход управления внешним драйвером для однопроводного двунаправленного варианта интерфейса,

  • интервальный таймер TMO и, соответственно, возможность контроля таймаутов,

  • автоматическая калибровка скорости обмена,

  • прием и передача данных на основе DMA.

Схема управления тактированием базового варианта значительно проще:

Схема управления тактированием базового UART
Схема управления тактированием базового UART

Имеется возможность тактирования приемника и передатчика только от делителя частоты Baud-Rate Generator. Скорость обмена для передатчика и приемника рассчитывается аналогично расширенному варианту UART.

В базовом варианте реализованы следующие флаги, приводящие к прерыванию: UGF, TCF, ERRF, RXF, TXF, BRTF, PEF, FEF, ROVRF, а также только статусные флаги PAR и BUSYF.

Схема буферизации данных базового модуля приведена на следующем рисунке.

Схема буферизации данных базового модуля UART
Схема буферизации данных базового модуля UART

Блоки приема и передачи данных не содержат теневые буферы, и соответственно, не имеют настройки и флаги, с ними связанные. Регистры URTx_TDAT и URTx_RDAT 8-битные и имеют лишь возможность байтового обращения. Формат кадра базового варианта UART задается аналогично расширенному варианту.

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

Аппаратная часть

В данном эксперименте на схеме подключения МК MG32F02A032 добавлен светодиод D2 для вспомогательной индикации, в том числе, для состояния «Hard Fault». Также показано подключение кварцевого резонатора Z1 на частоту 12 МГц (тип HC49S, С=30 пФ). Номиналы конденсаторов C5,C6 под конкретный резонатор выбираются согласно даташиту на МК. На схеме показаны выводы подключения порта UART. Со стороны ПК можно использовать любой UART-USB адаптер, например FTDI, CH340, или даже просто припаять микросхему моста MA112 от Megawin (есть в корпусе SOP16). При подключении нужно учитывать, что напряжение лог. «1» на выводе RXD не должно превышать напряжения питания МК 3,3 В. Вывод МК RXD подключается к выходу TX внешнего порта, а вывод МК TXD — к входу RX внешнего порта.

Схема подключения МК MG32F02A032
Схема подключения МК MG32F02A032

Библиотека работы с модулем UART

Перейдем к рассмотрению кода для работы с UART в обычном асинхронном режиме без контроля потока. Поскольку тестируемым является МК MG32F02A032, в распоряжении имеется только расширенный вариант UART. Приводимый код также должен быть работоспособен на базовом UART в более старших МК.

Инициализация порта UART с номером port_no выполняется функцией uart_init():

void uart_init(uint8_t port_no) {   register uint32_t da=(uint32_t)port_no*0x10000;    // Pins:   switch (port_no) {     case 0:       *(volatile uint16_t*)PC_CR0_h0 = (0xA << 12) | 2; // PC0 -> URT0_TX, push pull output       *(volatile uint16_t*)PC_CR1_h0 = (0xA << 12) | (1 << 5) | 3; // PC1 -> URT0_RX, pull-up resister enable, digital input       break;     case 1:       *(volatile uint16_t*)PB_CR10_h0 = (0x7 << 12) | 2; // PB10 -> URT1_TX, push pull output       *(volatile uint16_t*)PB_CR11_h0 = (0x7 << 12) | (1 << 5) | 3; // PB11 -> URT1_RX, pull-up resister enable, digital input       break;   }    // Clock source:   *((volatile uint16_t*)CSC_KEY_h0) = 0xA217; // unlock access to CSC regs   // (0x4C010022)   *(volatile uint16_t*)CSC_APB0_h1 = (1 << port_no); // CSC_URTx_EN = 1    // Leave default APB clock settings: CSC_URTx_CKS (bit 16) = CK_APB (0)   //*(volatile uint32_t*)CSC_CKS1_w = 0;   *((volatile uint16_t*)CSC_KEY_h0) = 0x1111; // lock access to CSC regs    // UART Global Enable (0x52000010)   *(volatile uint32_t*)(URT0_CR0_w+da) = 1; // URTx_EN = 1    // Frame format (0x52000014)   *(volatile uint32_t*)(URT0_CR1_w+da) =       (3 << 24) | // URT0_TXOS_NUM --- TX data oversampling samples select. The valid value is from 3 to 31 for oversampling samples from 4 to 32.       (3 << 8) | // URT0_RXOS_NUM --- RX data oversampling samples select. The valid value is from 3 to 31 for oversampling samples from 4 to 32.       (1 << 22) | (0 << 18) | (0 << 17) | (1 << 6); // tx_stopbit=1, parity=off, 8 bits, rx_stopbit=1    // Baud (assume CK_URT0 = 12 MHz ) (0x52000024)   *(volatile uint16_t*)(URT0_RLR_w+da) =        (1 << 8) | // URT0_PSR        12; // URT0_RLP    // Result: 115200 baud    // Включаем Baud-Rate Generator, поскольку используем тактирование от него (CK_URTx_INT)   *(volatile uint32_t*)(URT0_CLK_w+da) = (1 << 24); // URT0_BR_EN = 1    // Settings (0x52000018)   *(volatile uint32_t*)(URT0_CR2_w+da) = (1 << 3) | (1 << 2) ; // URT0_TX_EN=1 , URT0_RX_EN=1  } 

Поскольку в серии MG32F02 все модули URT имеют одинаковый набор регистров с базовым адресом 0x520n0000, где n — номер URTn, можно сразу написать код для работы со всеми модулями с номерами n=0-2,4-7 (URT3 в рассматриваемых актуальных МК серии не реализован). Поэтому далее в коде используется обращение к регистрам вида (URT0_CR0_w+da), где da=port_no*0x10000.

В начале происходит настройка выводов RXD (цифровой вход с подтяжкой) и TXD (push-pull выход). В данной части конфигурируются только первые два модуля 0 и 1. В реальном проекте эту часть можно вынести за пределы библиотеки, поскольку распределение выводов может быть самым разнообразным. На схеме ранее были показаны выводы RXD0 и TXD0. Выводы модуля 1 предполагаются следующие: RXD1 — PB11, TXD1 — PB10.

Далее происходит включение тактирования соответствующего модуля в регистре CSC_APB0. Здесь удобно использовать выражение типа (1 << port_no), поскольку биты, ответственные за включение тактирования URT0-URT7, расположены последовательно. В качестве источника тактирования всего модуля выбираем сигнал CK_URTx_PR от системного синхросигнала CK_APB шины APB, поэтому в поле URTx_CK_SEL регистра URTx_CLK оставляем значение по-умолчанию 0, в поле CSC_URTx_CKS регистра CSC_CKS1 также оставляем значение 0.

Следующим шагом разрешаем работу модуля в регистре URTx_CR0 установкой бита 0. После этого можно приступить к настройке скорости обмена. Здесь нужно учитывать, что в приведенных ранее формулах имеются ограничения на значения параметров:

  • URTx_PSR ( Kp ) — 0-15 для MG32F02A032, 0-63 для остальных МК;

  • URTx_RLR ( Kc ) — 0-255;

  • URTx_TXOS_NUM ( Ktxos ) и URTx_RXOS_NUM ( Krxos ) — в пределах 3-31.

В User Guide (с. 290) приводится таблица примеров выбора параметров для различных тактовых частот и скоростей обмена. В библиотеке DFP имеется функция MID_URT_SetConfig() для вычисления параметров в runtime, но в нашем простом примере мы укажем подобранные константные значения для частоты тактирования 12 МГц и скорости обмена 115200 бит/с: Kp= 1, Kc= 12, Ktxos= 3, Krxos= 3. Расчетная скорость обмена составляет 115385 бит/с, что дает погрешность всего 0,16 %. Далее включаем блок BR установкой бита URTx_BR_EN в регистре URTx_CLK.

В конце функции включаем узлы передачи и приема в регистре URTx_CR2. Специальную настройку формата кадра не выполняем, поскольку нас будет устраивать вариант по-умолчанию (8N1).

Функция передачи одного символа в простейшем случае может быть такой:

void uart_tx(uint8_t port_no, uint8_t d) {   register uint32_t da=(uint32_t)port_no*0x10000;   while ( (*(volatile uint8_t*)(URT0_STA2_b3+da) & 0x70)); // ждем, пока URT0_TX_LVL != 0   *(volatile uint8_t*)(URT0_TDAT_b0+da) = d;   // отправляем байт (0x52000034) <= d } 

Вначале ожидаем, когда теневой буфер передачи будет свободным (поле URTx_TX_LVL), затем передаем один байт через регистр URTx_TDAT. Это блокирующая функция, однако мы ожидаем только возможность отправки, а не факт передачи байта, поэтому она не должна вносить существенные задержки.

Функция приема одного символа может быть такой:

uint8_t uart_rx(uint8_t port_no) {   register uint32_t da=(uint32_t)port_no*0x10000;   while ( (*(volatile uint8_t*)(URT0_STA_b0+da) & 0x40) ==0); // waiting URT0_RXF==1   return *(volatile uint8_t*)(URT0_RDAT_b0+da); } 

Вначале ожидаем, когда активизируется флаг RXF, после чего считываем символ из регистра URTx_RDAT. Это также блокирующая функция, поэтому ее разумно использовать в прерывании по наступлению события приема данных.

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

void uart_send(uint8_t port_no, void* buf, uint32_t len) {   uint32_t i;   for (i=0; i<len; i++) uart_tx(port_no, *((uint8_t*)buf+i)); }   void uart_puts(uint8_t port_no, const char* s, uint32_t newline) {   uint32_t i;   uint8_t b;   for (i=0; s[i]!=0; i++) {     uart_tx(port_no, s[i]);   }   for (i=2; i; i--) {     b=(newline & 0xFF);     if (b) uart_tx(port_no, b); else break;     newline >>= 8;   } } 

Функция uart_send() отправляет в UART произвольную последовательность байт с указанием ее длины. Функция uart_puts() предназначена для отправки Си-строки с завершающим нулевым байтом, причем в конце можно одним целочисленным аргументом добавить любую последовательность из 1-2 байт (символ «новой строки») согласно следующим определениям (см. прилагаемый файл uart.h):

#define UART_NEWLINE_NONE 0x00000000 #define UART_NEWLINE_LF   0x0000000A #define UART_NEWLINE_CR   0x0000000D #define UART_NEWLINE_CRLF 0x00000A0D #define UART_NEWLINE_LFCR 0x00000D0A 

Метод отладки в ОЗУ

Традиционный процесс отладки микропрограммы предполагает каждый раз загрузку во flash-память МК всей «прошивки», включающей таблицу векторов, все необходимые сторонние библиотеки, собственный наработанный код, даже, если в программе изменилась только одна строка или один байт. Простота этого метода очевидна — программисту не надо особо задумываться над компоновкой, достаточно каждый раз при изменении кода нажимать только одну кнопку в IDE (Compile/Build/Flash) и в конечном итоге на кристалле окажется отлаженная «прошивка», которую можно включать в конечное изделие.

Однако, при каждой «прошивке» выполняется стирание всех занимаемых ею страниц, что повышает износ flash-памяти. Износ можно существенно снизить, если в ПО программатора будет функция постраничного сравнения существующей информации с новой и выдача команд на стирание и запись только в случае несовпадения. В любом случае каждый раз хотя бы одна страница, содержащая отлаживаемый код, должна быть стерта, даже если компоновщик не изменит положение большинства остальных функций и констант. При увеличении размера «прошивки» возрастает и время загрузки, хотя на современных ARM-ядрах это не так критично из-за высокой скорости работы интерфейсов JTAG/SWD.

Поскольку ЦПУ Cortex-M0 позволяет выполнять код не только из flash-памяти, но и из ОЗУ, напрашивается метод частичной отладки кода в области ОЗУ. Суть метода в следующем: во flash-память помещается базовая часть «прошивки», включающая таблицу векторов, обработчики прерываний, а также, при необходимости, некоторую уже отлаженную часть кода. После сброса МК базовая часть определяет, имеется ли в ОЗУ отлаживаемая часть программы, и в случае её наличия передает ей управление. Образ программы в ОЗУ загружается стандартными командами SWD-программатора.

Таким образом, формируются два совершенно отдельных загружаемых в МК образа:

  • базовая часть, которую далее будем называть supervisor (кратко svr),

  • отлаживаемая часть, которую далее будем называть application (кратко app).

Базовая часть может находиться в областях AP или ISP, может являться единственной во flash-памяти или активироваться после работы бутлоадера (кода области ISP). Основная инициализации МК может выполняться как в части svr, так и в app.

Метод отладки в ОЗУ оправдывает себя в следующих случаях:

  • необходимо максимально сократить износ flash-памяти МК на этапе разработки (например, при ограниченном количестве доступных экземпляров МК),

  • необходимо существенно сократить время загрузки прошивки,

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

  • отлаживаемая часть «с запасом» помещается в ОЗУ.

Поскольку каждая из частей svr и app собирается независимо (возможно применение даже разных компиляторов) и при линковке одной части будут неизвестны адреса объектов другой части, предстоит решить следующие задачи:

  • обеспечить вызов функций svr из отлаживаемой части,

  • обеспечить вызов функций app из базовой части кода (например, вызов обработчика прерывания, который сам находится в стадии разработки),

  • обеспечить доступ к переменным svr части со стороны app,

  • обеспечить доступ к переменным app части со стороны svr,

  • распределить адресное пространство ОЗУ между обеими частями, а также стеком и областью DMA.

Реализация

Базовая часть (Supervisor)

Одним из способов решения первых четырех задачи является применение механизма системных вызовов, подробно описанного в упомянутой ранее книге Джозефа Ю «The Definitive Guide to ARM ® Cortex ® -M0 and Cortex-M0+ Processors. Second Edition». Базовая часть берет на себя функцию обслуживания системного вызова, реализуя обработчик исключения SVCall. Отлаживаемая часть использует функционал базовой части путем обращения к ней через машинную инструкцию SVC, в которой кодируется номер вызова от 0 до 255. В системный вызов можно также передать аргументы через регистры или стек.

Рассмотрим реализацию предлагаемого метода на основе проекта megawin, описанного в предыдущей статье цикла. Базовая часть svr включает следующие файлы:

  • startup.c — код для генерации таблицы векторов прерываний и части функций их обработки;

  • init.c — код инициализации МК;

  • svr.c — код обработчиков исключений (прерываний);

  • main.c — главная часть, включающая только функцию main();

  • ulib.h и ulib.c — вспомогательные функции проекта, заменяющие функционал стандартной библиотеки;

  • api.h — файл с определениями программного интерфейса (API), предоставляемого для отлаживаемой части.

Файлы startup.c и init.c были рассмотрены ранее и остаются без изменения. Приведем основной файл базовой части (супервизора) svr.c:

#include "svr.h" #include "api.h" #include "ulib.h" #include "MG32x02z__RegAddress.h"   /// IRQ Handler type typedef void(*handler_t)();  /// IRQ Handlers volatile handler_t hdlr[32];   __attribute__ ((naked)) void HardFault_Handler() {   // Включаем мигание светодиодом на PB3   *(volatile uint16_t*)PB_CR3_h0 = 0x0002; // PB3 -> push-pull output   while (1) {     *(volatile uint16_t*)PB_SC_h0 = 0x0008; // set bit 3     delay_ms(100);     *(volatile uint16_t*)PB_SC_h1 = 0x0008; // clear bit 3     delay_ms(100);   } }   __attribute__ ((naked)) void SVC_Handler() { // From Yiu J.: // Stack frame contains: // r0, r1, r2, r3, r12, r14, the return address and xPSR // - Stacked R0 = svc_args[0] // - Stacked R1 = svc_args[1] // - Stacked R2 = svc_args[2] // - Stacked R3 = svc_args[3] // - Stacked R12 = svc_args[4] // - Stacked LR = svc_args[5] // - Stacked PC = svc_args[6] // - Stacked xPSR= svc_args[7]   // Используем только MSP, проверку бита 2 LR опускаем   asm(     "mrs    r0,msp\n"     "b      SVC_Handler_main\n"   ); }   /// Установка обработчика прерываний __attribute__ ((interrupt)) void SVC_Handler_main(uint32_t* sp) {   switch ( ((uint8_t*)sp[6])[-2] ) {     case SVC_HANDLER_UNSET:   hdlr[sp[0]]=0; break;     case SVC_HANDLER_SET:     hdlr[sp[0]]=sp[1]; break;   } }   __attribute__ ((interrupt)) void URT0_IRQHandler() {   if (hdlr[20]) hdlr[20](); }   __attribute__ ((interrupt)) void URT123_IRQHandler() {   if (hdlr[21]) hdlr[21](); } 

В файле определяется тип обработчика любого прерывания handler_t и создается массив hdlr из максимального числа ISR (32). Тип и массив пока больше нигде не используются и поэтому объявляются внутри svr.c.

При выполнении инструкции SVC im8 ( im8 — 8-битный номер вызова) ядро Cortex-M0 формирует специальный фрейм стека, содержащий сохраненные значения регистров R0, R1, R2, R3, R12, LR (R14), PC и xPSR (флаговый регистр состояния). После этого в регистр LR записывается специальное кодовое значение EXC_RETURN, содержащее флаги для работы механизма выхода из исключения, и управление передается в SVC_Handler(). Одним из флагов является бит 2, который указывает, из какого стека нужно восстанавливать регистры:

  • 0 — основной стек по указателю MSP (Main Stack Pointer),

  • 1 — стек процесса по указателю PSP (Process Stack Pointer).

Возвращение в прерванную программу происходит автоматически при загрузке в регистр PC значения LR: ЦПУ, получив значение EXC_RETURN, «понимает», что это не обычный адрес возврата (используется значение вида 0xFFFFFFF*, которое не может указывать на валидный адрес исполняемой области памяти), а специальный код выхода из исключения, восстанавливает значения регистров из фрейма стека. Поскольку при этом восстанавливается и значение регистра PC, работа прерванной программы возобновляется. Такой «трюк» позволяет оформлять обработчики прерываний как обычные функции, в том числе на Си.

Поскольку стек задач в нашем случае не используется, функция SVC_Handler() (объявлена как naked) просто копирует значение указателя основного стека MSP в доступный для Си-кода регистр R0 (без анализа бита 2 в EXC_RETURN) и передает управление фактическому обработчику исключения SVCall — функции SVC_Handler_main(uint32_t* sp). Эта функция через регистр R0 принимает единственный аргумент — указатель стека, относительно которого и надо обращаться к фрейму стека. Номер системного вызова в наборе инструкций Thumb кодируется младшим байтом кода инструкции SVC и легко доступен как sp[6])[-2]. В примере предусмотрены два системных вызова, определенные в файле api.h:

#include <stdint.h>  #define APP_ORIGIN      0x20000000 #define APP_SIGNATURE   0x46c046c0  #define SVC1(no,arg0)                 asm("mov r0,%0\n" "svc %1\n" :: "r"(arg0), "I"(no) : "r0") #define SVC2(no,arg0,arg1)            asm("mov r0,%0\n" "mov r1,%1\n" "svc %2\n" :: "r"(arg0), "r"(arg1), "I"(no) : "r0","r1") #define SVC3(no,arg0,arg1,arg2)       asm("mov r0,%0\n" "mov r1,%1\n" "mov r2,%2\n" "svc %3\n" :: "r"(arg0), "r"(arg1), "r"(arg2), "I"(no) : "r0","r1","r2") #define SVC4(no,arg0,arg1,arg2,arg3)  asm("mov r0,%0\n" "mov r1,%1\n" "mov r2,%2\n" "mov r3,%3\n" "svc %4\n" :: "r"(arg0), "r"(arg1), "r"(arg2), "r"(arg3), "I"(no) : "r0","r1","r2","r3")   /// syscalls enum IOSystemCalls {   SVC_HANDLER_UNSET =                  0,   SVC_HANDLER_SET   =                  1 }; 

Вызов SVC_HANDLER_UNSET (0) обнуляет адрес функции обработчика, чтобы заблокировать обращение к ней. Номер IRQ задается первым аргументом через регистр R0. Вызов SVC_HANDLER_SET (1) устанавливает обработчик, адрес которого задается вторым аргументом через регистр R1. Для удобства в файле также определены макросы SVC1()SVC4(), позволяющие в основной программе легко обращаться к системному вызову с указанием его номера и аргументов в количестве 1-4 соответственно.

Далее в файле svr.c определяются обработчики прерываний URT0_IRQHandler() и URT123_IRQHandler(). Если до этого был задан ненулевой указатель фактического обработчика (из части app), то выполняется его вызов. Замечание: поскольку в нашем проекте не используется стандартная библиотека, переменные секции .bss не инициализируются (нулем), так что устанавливать обработчик надо до разрешения прерываний соответствующего модуля (по крайней мере, до фактического срабатывания прерывания).

Дополнительно в файле svr.c реализован обработчик аппаратного исключения HardFault, который включает мигание светодиода D2 с частотой примерно 5 Гц, что может быть полезно при отладке кода.

Файл main.c содержит только функцию main():

#include "MG32x02z__RegAddress.h" #include "api.h" #include "ulib.h"   __attribute__ ((noreturn))  __attribute__ ((naked)) // omit prologue/epilogue sequences (garbage push/pop instructions) void main (void) {    if (*((volatile uint32_t*)(APP_ORIGIN)) == APP_SIGNATURE) {     asm("BX %0" : : "r"((APP_ORIGIN+4) | 1)); // Set bit 0 for Thumb !!!   }    *(volatile uint16_t*)PB_CR3_h0 = 0x0002; // PB3 -> push-pull output   while (1) {     *(volatile uint16_t*)PB_SC_h0 = 0x0008; // set bit 3     delay_ms(100);     *(volatile uint16_t*)PB_SC_h1 = 0x0008; // clear bit 3     delay_ms(900);   }  } 

В функции проверяется наличие отлаживаемой части в ОЗУ. Если она присутствует, ей передается управление через инструкцию BX, иначе включается мигание светодиода D2 с периодом 1 с и скважностью 10.

Отлаживаемая часть (Application)

Часть app имеет очень простой ld-скрипт mg32f02a032_app.ld:

SECTIONS { . = 0x20000000; .text : {   KEEP(*(.app_sign))   KEEP(*(.app))   *(.text)   }   . = 0x20000800;   .data : {     *(.data)   }   .bss : {     *(.bss)   } } 

Машинный код (секция .text) помещается в начало области ОЗУ с адреса 0x20000000 и имеет ограничение в размере 2048 байт. В самое начало области помещается константа с именем app_sign, определенная в основном файле отлаживаемой части app.c как переменная типа uint32_t. Константа представляет собой 4-байтовую сигнатуру, по которой базовая часть определяет наличие в ОЗУ части app. Значение сигнатуры 0x46c046c0 соответствует двум машинным инструкциям NOP, поэтому базовая часть может передавать управление на начало секции .text или отступив 4 байта, после которых начинается главная функция app().

Секции данных .data и .bss начинаются с адреса 0x20000800 и ограничиваются сверху началом области RAM базовой части svr с адреса 0x20000A00, т.е. максимальный размер для данных и переменных части app в рассматриваемом проекте составляет 512 байт (см. ld-скрипт в предыдущей статье цикла).

Отлаживаемая часть app включает следующие файлы:

  • app.c — основной файл со стартовой функцией app();

  • api.h — файл с определениями программного интерфейса, предоставляемого базовой частью через системные вызовы;

  • ulib.h и ulib.c — вспомогательные функции проекта, заменяющие функционал стандартной библиотеки;

  • uart.h и uart.c — библиотека для работы с модулем UART.

Рассмотрим основной файл app.c:

#include "MG32x02z__RegAddress.h" #include "ulib.h" #include "api.h" #include "uart.h"  #define PORT 0   // Mark first word with signature "Application is present" (nop; nop: 0x46c046c0) __attribute__ ((section (".app_sign"))) __attribute__ ((__used__)) static uint32_t  app_sign=APP_SIGNATURE;   // First function in application __attribute__ ((section(".app"))) // put function in the begin of .text after signature word "app_sign" __attribute__ ((noreturn)) void app() {   char s[4]="< >";    uart_init(PORT);   uart_puts(PORT,"Hello",UART_NEWLINE_CRLF);   while (1) {     s[1]=uart_rx(PORT);     uart_puts(PORT,s,UART_NEWLINE_CRLF);   }  }  

В самом начале объявляется статическая переменная app_sign, содержащая сигнатуру APP_SIGNATURE, определенную в файле api.h. Компоновщик помещает её в самое начало области .text. Далее в бинарный образ помещается главная функция app(). В данном случае мы не можем её объявить с атрибутом naked, поскольку при этом компилятор фактически перестает работать со стеком и выделять в нём память под локальные переменные. Поэтому пока приходится мириться с потерей по крайней мере 4 байт во flash, в которые записываются бесполезные инструкции PUSH и POP «пролога» и «эпилога», а также нескольких 32-битных слов в ОЗУ (в стеке).

Задача отлаживаемой части: в цикле ожидать данные из модуля UART, при получении одного символа обрамлять его угловыми скобками < и >, после чего сформированную строку отправлять обратно в UART, добавляя символы новой строки CR (0x0D) и LF (0x0A).

В начале функции app() выполняется инициализация порта uart_init(), затем в UART оправляется контрольная строка приветствия "Hello", после чего в цикле считывается один символ через функцию uart_rx() и выдается ответ через uart_puts().

Сборка и тестирование

Для сборки последующих примеров необходимо обновить файл premake5.lua. Основные изменения коснулись описания целей (ключевое слово project), которых теперь стало две:

project "svr"   kind "ConsoleApp"   language "C"   files {"src/init.c", "src/startup.c", "src/main.c", "src/svr.c", "src/ulib.c"}   linkoptions {"-nostdlib"}   linkoptions { "-Wl,--gc-sections"}   linkoptions {"-T mg32f02a032_svr.ld"}  project "app"   kind "ConsoleApp"   language "C"   files {"src/app.c", "src/uart.c", "src/ulib.c"}   linkoptions {"-nostdlib"}   linkoptions { "-Wl,--gc-sections"}   linkoptions {"-T mg32f02a032_app.ld"} 

Обе части собираются без использования стандартной библиотеки, для чего добавлена опция линкера -nostdlib. Однако при оптимизации -Os компилятор может генерировать вызов вспомогательных функций, которые мы не хотим линковать. Поэтому в секции workspace понижен уровень оптимизации до -O3 и добавлена опция -ffreestanding:

buildoptions {"-mthumb", "-mcpu="..MCPU, "-Wall", "-O3", "-g", "-fno-common", "-ffunction-sections", "-fdata-sections", "-ffreestanding"} 

Генерация make-файлов выполняется командой

premake5 gmake 

Сборка частей svr и app выполняется соответственно командами

make svr make app 

Команда make clean удаляет производные файлы для обеих целей.

Итоговый размер секций .text получился следующий: часть srv — 472 байта , часть app — 386 байт. «Прошивка» базовой части в область AP flash выполняется в telnet-соединении OpenOCD с помощью команды (должна быть подключена библиотека mg32f02_mem_ap.tcl)

mem_ap_flash $DIR/bin/svr.bin 0x18000000 

где $DIRабсолютный путь к каталогу проекта (чтобы не зависеть от каталога запуска самого OpenOCD).

Загрузка отлаживаемой части в ОЗУ выполняется с помощью штатной команды OpenOCD load_image с последующим сбросом МК:

halt load_image $DIR/bin/app.bin 0x20000000 bin reset 

Здесь последним аргументом в команде указывается формат загружаемого файла (bin).

Для удобства можно использовать shell-скрипты run_svr:

#!/bin/bash TELNET="telnet 127.0.0.1 4444" DIR=`pwd` (echo "mem_ap_flash $DIR/bin/svr.bin 0x18000000"; sleep 3;) | $TELNET 

и run_app:

#!/bin/bash TELNET="telnet 127.0.0.1 4444" DIR=`pwd` (echo "halt"; sleep 0.2; echo "load_image $DIR/bin/app.bin 0x20000000 bin"; sleep 0.2; echo "reset"; sleep 0.2;) | $TELNET 

Для проверки работы МК можно использовать любую терминальную программу на ПК, например minicom в ОС Linux. Необходимо установить скорость обмена 115200 бит/с, длину символа 8 бит, формат без контроля четности с одним стоп-битом.
В результате в терминале будет примерно следующее:

Обмен данными МК с терминалом
Обмен данными МК с терминалом

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

#define PORT 1 

и пересобрать часть app.

Применение прерывания модуля UART

Теперь усложним задачу, добавив обработчик прерываний по получению данных из модуля URT0. В файле app.c добавим функцию обработки прерывания uart_hdl() и изменим функцию app():

void uart_hdl() {   char s[4]="< >";   s[1]=uart_rx(PORT);   uart_puts(PORT,s,UART_NEWLINE_CRLF); }   __attribute__ ((section(".app"))) // put function in the begin of .text after signature word "app_sign" __attribute__ ((noreturn)) void app() {    *(volatile uint16_t*)PB_CR2_h0 = 0x0002; // PB2 -> push-pull output    uart_init(PORT);   SVC2(SVC_HANDLER_SET,20,uart_hdl);    // включаем прерывания в модуле URT0   *(volatile uint8_t*)URT0_INT_b0 = 0x40 | 0x01; // URT0_RX_IE | URT0_IEA   // включаем прерывание в модуле NVIC   *(volatile uint32_t*)CPU_ISER_w = (1 << 20); // SETENA 20    uart_puts(PORT,"Hello",UART_NEWLINE_CRLF);    while (1) {     *(volatile uint16_t*)PB_SC_h0 = 0x0004; // set bit 2     delay_ms(250);     *(volatile uint16_t*)PB_SC_h1 = 0x0004; // clear bit 2     delay_ms(250);   }  } 

Здесь те действия, которые в прошлом примере были в цикле, перенесены в обработчик uart_hdl(). В основном же цикле происходит только управление светодиодом D1. После инициализации модуля выполняется системный вызов SVC_HANDLER_SET, который устанавливает в качестве конечного обработчика прерывания модуля URT0 прикладную функцию uart_hdl(), код которой находится в ОЗУ.

Можно собрать и запустить часть app. В терминале убеждаемся, что UART МК работает так же, как и в прошлом примере. При этом параллельно мигает светодиод D1, показывая, что основная задача выполняется и ISR не блокирует ядро МК на длительное время.

Приведем фрагмент функции app() для модуля URT1 (макрос PORT нужно также установить в 1):

  uart_init(PORT);   SVC2(SVC_HANDLER_SET,21,uart_hdl);    // включаем прерывания в модуле URT1   *(volatile uint8_t*)URT1_INT_b0 = 0x40 | 0x01; // URT1_RX_IE | URT1_IEA   // включаем прерывание в модуле NVIC   *(volatile uint32_t*)CPU_ISER_w = (1 << 21); // SETENA 21 

Управление тактированием МК

В заключении рассмотрим некоторые практические примеры конфигурации схемы тактирования МК, которая была рассмотрена в первой статье цикла.

МК серии MG32F02 имеют возможность вывода одного из основных тактовых сигналов на вывод ICKO (всегда PC0). Конкретный сигнал выбирается мультиплексором по значению поля CSC_CKO_SEL регистра CSC_CKO. Частота конечного выводимого сигнала может быть ниже в 1, 2, 4 или 8 раз, в зависимости от настройки делителя в поле CSC_CKO_DIV регистра CSC_CKO. Следующая функция настраивает вывод сигнала CK_MAIN без деления частоты:

// CK_ICKO output through PC0 pin void setup_icko() {   *(volatile uint16_t*)PC_CR0_h0 = (0x1 << 12) | 2; // PC0 -> ICKO, push pull output   *(volatile uint16_t*)CSC_KEY_h0 = 0xA217; // unlock access to CSC regs   *(volatile uint32_t*)CSC_CKO_w = (0x0 << 4) | 1; // CK_MAIN, DIV=1, CSC_CKO_EN = 1   *(volatile uint16_t*)CSC_KEY_h0 = 0x1111; // lock access to CSC regs } 

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

До сих пор мы использовали настройки тактирования по-умолчанию, т.е. от внутреннего RC-генератора IHRCO с частотой 12,0000 МГц. Если при работе с модулем UART требуется скорость передачи настроить как можно ближе к стандартным значениям, нужно выбирать тактирование от IHRCO генератора с частотой 11,0592 МГц, которая будет кратна стандартным значениям. Например, отношение 11059200/115200 будет равно целому числу 96, которое нетрудно получить настройками делителей ( Kp= 1, Kc= 11, Ktxos= 3). Следующая функция переключает частоту генератора IHRCO на 11,0592 МГц:

void setup_ihrco() {   *(volatile uint16_t*)CSC_KEY_h0 = 0xA217; // unlock access to CSC regs   *(volatile uint32_t*)CSC_CR0_w |= (1 << 18); // CSC_IHRCO_SEL = 1 (11.0592 MHz)   *(volatile uint16_t*)CSC_KEY_h0 = 0x1111; // lock access to CSC regs } 

Встроенным RC-генераторам, как известно, свойственны невысокая точность и низкая стабильность частоты. Для большей точности и температурной стабильности рекомендуется применять кварцевый генератор. Следующая функция включает встроенный кварцевый генератор XOSC на внешнем резонаторе, подключаемом к выводам XIN и XOUT согласно приведенной ранее схеме:

void setup_xosc() {   uint32_t d;   // Setup pins XIN (PC13) & XOUT (PC14):   *(volatile uint16_t*)PC_CR13_h0 = (1 << 12); // PC13 -> XIN   *(volatile uint16_t*)PC_CR14_h0 = (1 << 12); // PC14 -> XOUT   while (! (*(volatile uint8_t*)CSC_STA_b3 & 2)); // waiting CSC_XOSCF == 1 (XOSC ready)   *(volatile uint16_t*)CSC_KEY_h0 = 0xA217; // unlock access to CSC regs   d=*(volatile uint32_t*)CSC_CR0_w;   d &= ~(3 << 10); // clear bits 10,11   d |= (1 << 10); // set CSC_HS_SEL = 0b01 (XOSC)   *(volatile uint32_t*)CSC_CR0_w = d;   *(volatile uint16_t*)CSC_KEY_h0 = 0x1111; // lock access to CSC regs } 

Вначале задаются функции XIN и XOUT для выводов подключения резонатора PC13 и PC14. После этого внутренний генератор XOSC автоматически запускается (отдельного бита разрешения генератора не предусмотрено). Затем ожидается готовность генератора (активизация флага CSC_XOSCF). После этого в регистре CSC_CR0 устанавливается XOSC в качестве источника системного сигнала тактирования CK_HS (поле CSC_HS_SEL устанавливается в 1).

Генератор XOSC может работать на частотах до 24 МГц. Если нужна тактовая частота выше, чем частота XOSC, необходимо использовать блок умножения частоты на основе PLL. Следующая функция включает PLL c умножением частоты в 2 раза:

// Включение умножения частоты на основе PLL (x2) void setup_pll() {   uint16_t d;   *(volatile uint16_t*)CSC_KEY_h0 = 0xA217; // unlock access to CSC regs    // CSC_PLLI_DIV = 2, CK_PLLI = 6 MHz (CK_HS/2)   // CSC_PLLO_DIV = 0 , CK_PLLO = 24 MHz (CK_PLL/4)   *(volatile uint8_t*)CSC_DIV_b0 = 0b00000001;    // CSC_PLL.CSC_PLL_MUL = 0, PLL_MULL = 16 (DEFAULT), CK_PLL = 96 MHz (CK_PLII*16)    *(volatile uint8_t*)CSC_CR0_b0 |= (1 << 5); // CSC_PLL_EN = 1    while (! (*(volatile uint8_t*)CSC_STA_b0 & (1 << 6))); // waiting CSC_PLLF == 1 (PLL ready)    d=*(volatile uint16_t*)CSC_CR0_h0;   d &= ~(3 << 14); // clear bits 14,15   d |= (2 << 14); // CSC_MAIN_SEL = 2 (CK_PLLO)   *(volatile uint16_t*)CSC_CR0_h0 = d;    *(volatile uint16_t*)CSC_KEY_h0 = 0x1111; // lock access to CSC regs } 

Исходным сигналом является CK_HS с частотой 12 МГц. Входной делитель блока PLL делит частоту на 2 (поле CSC_PLLI_DIV), чтобы попасть в допустимый для PLL МК MG32F02A032 диапазон 5-7 МГц. Полученная частота 6 МГц умножается на 16 в блоке PLL. Сигнал CK_PLL с частотой 96 МГц проходит выходной делитель на 4 (поле CSC_PLLO_DIV) и итоговый сигнал CK_PLLO с частотой 24 МГц выбирается как основной (CK_MAIN) в регистре CSC_CR0.

Все рассмотренные функции по управлению тактированием (находятся в файле app.c) можно запускать как из базовой части svr, так и из ОЗУ из части app, что позволяет экспериментировать с МК без стирания flash-памяти.

Листинг дизассемблера частей svr и app можно просматривать с помощью прилагаемых сценариев lst_svr и lst_app. Все файлы, рассматриваемые в статье, собраны в прилагаемом архиве.

На этом мы завершаем третью статью цикла. В следующий раз рассмотрим аналоговую часть МК серии MG32F02: АЦП и компаратор, а также встроенный температурный датчик.

Полезные ссылки


ссылка на оригинал статьи https://habr.com/ru/post/681702/

CherryPick DI — di библиотека для dart/flutter проектов

CherryPick DI

DI-контейнер – это библиотека, которая обеспечивает функциональность механизма внедрения зависимостей.

Содержание

1. Предисловие

2. Возможности библиотеки

3. Компоненты библиотеки

— 3.1. Scope

— 3.2. Module

— 3.3. Binding

4. Пример использования

5. Заключение

1. Предисловие

Первые попытки разработать свой DI для пет проектов написанных на Flutter SDK были начаты в начале 2020 года.

Сподвигло меня на этот шаг несколько причин:

1. На тот момент я не нашел DI в pub.dev с возможностью делить контейнер на scope (возможно плохо искал)

2. Упростить работу с зависимостями в проекте

3. Желание написать собственный DI

4. Иметь в арсенале простой DI (надеюсь с простым API)

2. Возможности библиотеки

Основные возможности DI контейнера:

— Инициализация экземпляра с именем

— Инициализация экземпляра как singleton

— Разделение контейнера на области видимости (scopes)

3. Основные компоненты DI

Библиотека состоит из трех основных компонентов:

— Scope

— Module

— Binding

3.1. Scope

Scope — это контейнер, который хранит все дерево зависимостей (scope,modules,instances).

Через scope можно получить доступ к instance, для этого нужно вызвать метод resolve<T>() и указать тип объекта, а так же можно передать дополнительные параметры.

Scope определяет область видимости и время жизни зависимостей.

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

Чтобы получить объект Scope, его нужно “открыть”. Для простоты сделаем один Scope на всё приложение:

final rootScope = CherryPick.openScope(named: 'appScope');

Если повторно открыть Scope с тем же самым именем, мы получим уже существующий экземпляр Scope.

Когда Scope перестанет быть нужным, его (и всё дерево “дочерних” Scope) можно будет закрыть с помощью метода CherryPick.closeScope(name)

3.2. Module

Module — это набор правил, по которым CherryPick будет разрешать зависимости в конкретном Scope. Пользователь в своем модуле должен реализовать метод void builder(Scope currentScope). Модули добавляются в Scope с помощью метода scope.installModules(…), после чего Scope может разрешать зависимости по правилам, определённым в его модулях.

Пример:

class AppModule extends Module {   @override   void builder(Scope currentScope) {     bind<ApiClient>().toInstance(ApiClientMock());   } }

3.3. Binding

Binding — по сути это конфигуратор для пользовательского instance, который содержит методы для конфигурирования зависимости.

Есть два основных метода для инициализации пользовательского instance toInstance() и toProvide() и вспомогательных withName() и singleton().

toInstance() — принимает готовый экземпляр

toProvide() —  принимает функцию provider (конструктор экземпляра)

withName() — принимает строку для именования экземпляра. По этому имени можно будет извлечь instance из DI контейнера

singleton() — устанавливает флаг в Binding, который говорит DI контейнеру, что зависимость одна.

Пример:

 // инициализация экземпляра текстовой строки через метод toInstance()  bind<String>().toInstance("hello world");   // или   // инициализация экземпляра текстовой строки  bind<String>().toProvide(() => "hello world");   // инициализация экземпляра строки с именем  bind<String>().withName("my_string").toInstance("hello world");  // или  bind<String>().withName("my_string").toProvide(() => "hello world");   // инициализация экземпляра, как singleton  bind<String>().toInstance("hello world");  // или  bind<String>().toProvide(() => "hello world").singleton();

4. Пример приложения

import 'dart:async'; import 'package:meta/meta.dart'; import 'package:cherrypick/cherrypick.dart';  class AppModule extends Module {   @override   void builder(Scope currentScope) {     bind<ApiClient>().withName("apiClientMock").toInstance(ApiClientMock());     bind<ApiClient>().withName("apiClientImpl").toInstance(ApiClientImpl());   } }  class FeatureModule extends Module {   bool isMock;    FeatureModule({required this.isMock});    @override   void builder(Scope currentScope) {     bind<DataRepository>()         .withName("networkRepo")         .toProvide(           () => NetworkDataRepository(             currentScope.resolve<ApiClient>(               named: isMock ? "apiClientMock" : "apiClientImpl",             ),           ),         )         .singleton();     bind<DataBloc>().toProvide(       () => DataBloc(         currentScope.resolve<DataRepository>(named: "networkRepo"),       ),     );   } }  void main() async {   final scope = openRootScope().installModules([     AppModule(),   ]);    final subScope = scope       .openSubScope("featureScope")       .installModules([FeatureModule(isMock: true)]);    final dataBloc = subScope.resolve<DataBloc>();   dataBloc.data.listen((d) => print('Received data: $d'),       onError: (e) => print('Error: $e'), onDone: () => print('DONE'));    await dataBloc.fetchData(); }  class DataBloc {   final DataRepository _dataRepository;    Stream<String> get data => _dataController.stream;   StreamController<String> _dataController = new StreamController.broadcast();    DataBloc(this._dataRepository);    Future<void> fetchData() async {     try {       _dataController.sink.add(await _dataRepository.getData());     } catch (e) {       _dataController.sink.addError(e);     }   }    void dispose() {     _dataController.close();   } }  abstract class DataRepository {   Future<String> getData(); }  class NetworkDataRepository implements DataRepository {   final ApiClient _apiClient;   final _token = 'token';    NetworkDataRepository(this._apiClient);    @override   Future<String> getData() async => await _apiClient.sendRequest(       url: 'www.google.com', token: _token, requestBody: {'type': 'data'}); }  abstract class ApiClient {   Future sendRequest({@required String url, String token, Map requestBody}); }  class ApiClientMock implements ApiClient {   @override   Future sendRequest(       {@required String? url, String? token, Map? requestBody}) async {     return 'Local Data';   } }  class ApiClientImpl implements ApiClient {   @override   Future sendRequest(       {@required String? url, String? token, Map? requestBody}) async {     return 'Network data';   } }

5. Заключение

На текущий момент библиотека используется в трех коммерческих проектах и собственных пет проектах.

За дополнительной информацией можно обратиться к документации.

Исходный код проекта.

Пакет для установки.


ссылка на оригинал статьи https://habr.com/ru/post/681714/

Переезд с Evernote на Joplin

В начале года я составлял список альтернатив Evernote для того, чтобы выбрать, куда бы с него валить. Основные требованием был хостинг на своей территории. Тогда перебрал много чего, фаворитом был Joplin, но решил остаться с Evernote — насущной необходимости валить не было, оставалось ещё полгода подписки и вообще неплохо кормили.

Сейчас же подписка кончилась, оплатить так просто нельзя, а бесплатной версией я пользоваться не могу. Возможностей мне хватило бы, в принципе, но вот то, что всего два устройства можно синхронизировать — это для меня за гранью неудобства. Есть вариант с заведением ещё нескольких аккаунтов и расшариванием на них блокнотов, но это, на мой взгляд, костыльный костыль.

Так что нашелся повод свалить. Поехали.

Установка

С установкой на Windows вопросов никаких, скачал да поставил. Есть portable-версия.

Android — есть в маркете, можно отдельно скачать apk.

Сервер синхронизации — можно обойтись без него и работать через какое-нибудь облако, как чужое, так и личное. Но сервер, по отзывам, работает быстрее. Плюс — в дальней перспективе — хотят к нему прикрутить возможность делиться заметками. Может пригодиться. Так что решил сразу с сервером, ставил в Unraid из Community Applications (хочет postgres), можно просто в докере запустить. Но, как уже сказал, это не обязательно.

Ещё мне хотелось иногда иметь доступ через веб. Официально пока решения нет, костыльное — в докере запустить десктопного клиента. Ну или в виртуалке. Пока перебьюсь, потом решу, что мне удобнее.

Перенос информации

Кнопки «импортировать все заметки с сохранением структуры» в joplin нет, можно только импортировать отдельные enex-файлы, которые по форме «плоские» — просто список заметок. Но зато переносятся теги, так можно их использовать для восстановления дерева блокнотов после импорта.

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

Запароленные заметки расшифровал перед экспортом.

Где заметок было мало, просто через Ctrl+C/V скопировал, быстрее было, чем импорт/экспорт организовывать.

Работал несколько дней (с перерывами), но кому сейчас легко? Попутно немного навёл порядок, что-то рассортировал по другому, выкинул совсем уж ненужное и т.п.

Содержимое сохранилось, форматирование в заметках сохранилось почти полностью, а вот в сохранённых страницах оно ощутимо поехало. Но пережить можно, текст читаем остался.

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

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

Синхронизация

Сравнил скорость синхронизации на своей базе (заметок пара тысяч, размер порядка 200 мегабайт — в эверноуте было около гигабайта, но при переносе я много аттачей отбросил). Разница сильно зависит от того, какое подключение, что с вандрайвом у меня меньше получаса на выкачку всей базы не выходило, а со своим сервером за пять минут укладывался — это когда дома по кабелю. С ноутбука в поле через слабый вайфай — 20 минут.

По отзывам, с webdav’ом примерно такая же разница. Скорее всего, из-за того, что качается куча мелких файлов — и со своим сервером/протоколом это проще оптимизировать. Впрочем, там можно поиграть с количеством одновременных подключений, вроде это несколько увеличивает скорость, но не пропорционально.

Плагины

Их есть.

Взял три:

Simple Backup — для создания копий по расписанию. Бэкапов много не бывает.

Joplin Note Tabs — табы для того, чтобы можно было быстро переключаться между несколькими открытыми заметками, а не бегать за ними по дереву.

Text Colorize — раскраска текста. Кнопка получилась довольно далеко (хоткей либо через меню), но это всё равно проще, чем лезть в код. А разноцветные буквы я с детства люблю.

А теперь попробуем со всем этим взлететь:

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

Мобильная версия

Она есть. Выглядит не слишком интересно, плюс обладает неприятным косяком — не умеет в фоновую синхронизацию. Говорят, что это из-за используемого фреймворка. Evernote10 тоже подобным болел — одна из причин, по которым я пользовался восьмёркой (ну кроме того, что интерфейс десятки стал кривой, пропала часть функций и всё стало тормозить :)).

Это неприятно, но я могу под это подстроиться. Всерьёз это раздражает только при первом скачивании базы на устройство — надо держать включенным экран несколько минут. Дальше уже при запуске только изменения скачиваются.

Интерфейс, как уже сказал, не фонтан — просто копия десктопной версии, разве что разбито на три экрана — дерево блокнотов, список заметок и сама заметка. Впрочем, это тоже терпимо — всё равно на телефоне мне чаще нужно чтение заметок и поиск по ним, а не создание/редактирование. Я и раньше обычно создавал заметки в Samsung Notes — только там полноценно работает стилус — а потом уже на десктопе переносил их в основную базу. Так что теперь просто буду в Joplin их переносить вместо Evernote.

Итого

Evernote, конечно, был привычнее и более вылизанным, тут чувствуется недоделанность развивающегося проекта. Веб-клиппер очень так себе, к примеру, мобильное приложение на тройку, недоделки в интерфейсе… Но с требуемыми задачами справляется, денег не просит, живёт на моём железе, а не у дяди — за это можно на недоработки закрыть глаза.

Я знал, куда ехал. Другие варианты мне нравились ещё меньше. Идеал встречается очень редко, гораздо чаще приходится выбирать меньшее из зол.


ссылка на оригинал статьи https://habr.com/ru/post/681712/

Недельный геймдев: #81 — 7 августа, 2022

Из новостей: игровой движок The Machinery больше не поддерживается, а разработчики просят клиентов удалить исходники и бинарники, 9 месяцев разработки и вот вышел Godot 3.5, DreamWorks к концу года планирует выложить в опенсорс под лицензией Apache 2.0 рендерер MoonRay.

Из интересностей: из разработчиков игр в разработчики сервиса Balancy для разработчиков игр, 5 часов наслаждаемся концентрированным Джоном Кармаком, пулы памяти GPU в D3D12, шейдер водички в UnrealEngine.

Обновления/релизы/новости

​Игровой движок The Machinery больше не поддерживается, а разработчики просят клиентов удалить исходники и бинарники

Движок больше не поддерживается. Но самое интересное тут то, что:

  1. Разработчики оного пишут, что клиенты должны удалить все исходники и бинарники движка.

  2. Пункт о том, что они могут такое запрашивать, они добавили в EULA совсем недавно. Ещё в майской версии пользовательского соглашения этого пункта не было. Т.е. тупо задним число поменяли без согласия текущих клиентов.

Движок малоизвестный, но пилили его те, кто работал над движками Stingray/BitSquid, которые использовались в Magicka и Warhammer Vermintide. Он лёгкий, модульный и написан на C с упором на кастомизацию.

Ещё одно напоминание в пользу того, что технологии нужно обдумано выбирать. Ну и ещё один звоночек в сторону того, чтобы брать опенсорсные решения.

И не забывайте читать лицензионное соглашение.

9 месяцев разработки и вот вышел Godot 3.5

Основные моменты:

  • Новая система навигации

  • Интерполяция физики

  • Улучшенная анимация

  • Синглтон Time

  • Label3D и TextMesh

  • Асинхронная компиляция шейдеров

  • Нативный редактор под Android

И многое другое.

DreamWorks к концу года планирует выложить в опенсорс под лицензией Apache 2.0 рендерер MoonRay

Вместе с распределённым фреймворком рендеринга Arras.

Рендерер использовался при производстве, например, The Bad Guys и Puss in Boots: The Last Wish.

Khronos glTF 2.0 выпущен в виде международного стандарта ISO/IEC

Это укрепит глобальное признание и принятие glTF в качестве формата 3D-ассетов.

Вышел Bevy 0.8

Популярный игровой движок с открытым исходным кодом на Rust получил обновление, добавляющее несколько новых функций, включая новую систему материалов, улучшения ECS системы и новую гораздо более гибкую и мощную систему камер.

Microsoft и Unity заключили партнёрство — разработчики движка будут использовать «облачные» технологии Azure

В Unity утверждают, что сотрудничество с Microsoft позволит им улучшить всю свою инфраструктуру, а также развить экосистему инструментов и сервисов, которые компания предоставляет разработчикам./p>

В раннем доступе вышел Sculptron 2022.1

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

The Grove Release 11

Обновление добавляет новый инструмент Roots для создания наружних корней, панель Surround для имитации форм деревьев, растущих в густых насаждениях и обновляет софт для использования системы геометрических нод из Blender.

Вышел BagaPie V7

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

Игровые рынки (01.08.2022 — 05.08.22)

Продажи игр в Европе на подьёме, а вот рынки США и Китая падают; Newzoo поделился отчётом об использовании IP в мобильных играх; 93% PC-геймеров в Германии покупают цифровые копии игр.

AWS Thinkbox теперь доступны бесплатно

Любой, у кого есть бесплатная учётная запись AWS, может загрузить софт, для каждого доступно 50 000 годовых лицензий. Пользователи Deadline и Krakatoa также могут бесплатно получить время рендеринга по лицензии на базе использования (UBL).

Разработчик Tiny Tactics пожаловался на то, что забыл про маркетинг игры и поднял таким образом её продажи

В последнюю неделю автор начал рассылать ключи и письма с просьбой посмотреть его игру Tiny Tactics, но почти никто не играл в игру. После рассказа о своих проблемах, что игра плохо стартанула, она появилась в топе «Новые и популярные» в Steam.

Халява/раздачи/бандлы/курсы

Августовская раздача ассетов в магазине Unreal Engine

Очередной пак полезный ресурсов.

Бесплатный пак 3D-моделей Modern Industrial Pack

Состоит из набора 3D-лестниц, платформ и строительных лесов, а также декоративных элементов, таких как трубы, воздуховоды, кабели, трубки, кнопки и фонари, представленных в FBX формате для использования в DCC-приложениях и игровых движках.

Интересные статьи/видео

Из разработчиков игр в разработчики сервиса Balancy для разработчиков игр

Несколько лет стартапства и разработки своей провальной MOBA, чтобы в итоге создать новый стартап для помощи другим разработчикам игр. Сорванные оферы из-за войны, переезд на Кипр и другие приключения.

Портирование AnKi на Android…снова, спустя ~8 лет

Разработчик движка AnKi 3D решил переписать порт оного под Android и рассказал про приключения, с которыми столкнулся по пути.

5 часов наслаждаемся концентрированным Джоном Кармаком

Легендарный программист, соучредитель id Software, ведущий разработчик многих революционных видеоигр, включая Wolfenstein 3D, Doom, Quake и серии Commander Keen обсудили множество вопросов в подкасте.

Создание снежного гнома в ZBrush, Maya и Arnold

Энрике Матео-Сагаста рассказал о проекте, объяснил, как сделать правдоподобную кожу в ZBrush, и поделился некоторыми советами по созданию волос.

Интервью с 3D-художником по персонажам Артемом Добрусиным

Артем занимается персонажами и их дизайном, горит созданием образов — ведь именно через них можно погрузить зрителя в историю персонажа: кто он и кем является, какой у него характер и настроение.

Игре Urban Chaos под PS1 в своё время модераторы отказали, т.к. сейвы работали слишком быстро

Игрок не успевал прочитать сообщение «Saving… please do not remove the memory card». Пришлось искусственно увеличивать время работы.

Что в итоге сделали:

  1. Сохраняли прогресс

  2. Показывали сообщение

  3. Паузили

По факту сообщение врало игрокам.

Battle Pass в мобилках. Исследование тенденций

Никита Красов поисследовал, а потом написал статью в двух частях о том, как нынче делают battle pass.

Геймдев без прикрас: мифы и реальность начинающего инди-разработчика

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

Gaia и набор инструментов Intel Game Dev AI Toolkit

Используя ИИ, разработчики игр могут создавать гиперреалистичные миры, наполненные бесчисленным множеством замысловатых адаптивных NPC. Теперь большинство разработчиков могут эффективно интегрировать возможности ИИ с помощью функций Unity.

Создание BoxRob

В посте в блоге d954mas поделился своим опытом работы над игрой, от первоначальной идеи до готового продукта.

Использование Midjourney для создания концепции и ассетов

Тимур Оздоев рассказал о превращении изображений, созданных в Midjourney, в ассеты для игры и поделился своими мыслями о взаимосвязи ИИ и традиционного искусства.

Скамейки на пустой площади: как создать условия для геймдев-обучения и решить кадровый вопрос на годы вперед

История образовательной программы студии BIT_GAMES.

Варианты материалов: решение для управления сложными библиотеками материалов

Когда-нибудь хотели автоматически применять изменения одного материала к нескольким другим? Или повторно использовать базовый материал для локальных настроек? В Unity 2022.1 была представлена концепция, аналогичная префабам, совместимую со всеми пайплайнами рендеринга, для управления вариантами материалов в редакторе.

Компенсации за вашу игру: как делать не надо

Для того, чтобы ваша игра вышла и стала успешной, необходимо правильно составить бюджет игры. Вам также может понадобиться оценить, сколько единиц, по вашему мнению, будет продано.

Как разработчикам следует оценивать возможную рентабельность инвестиций в игру — независимо от того, самофинансируется она или нет?

Новая серия туториалов по архитектуре для художников по 3D-окружению

3D-художник Джош Х. запустил новую серию уроков, посвященных темам, связанным с архитектурой, актуальным для художников по окружению.

Как выпустить мобильную инди-игру в РФ сегодня

Где выпустить и как заработать на своей игре, если вы сделали свою первую игру именно сейчас или вот-вот доделаете?

Настройка волн Герстнера в Unreal Engine

Ghislain Girardot выпустил подробный разбор воды, похожей на Sea of Thieves, и объяснил, как она была сделана.

Настройка стилизованного меха с помощью Ornatrix, gFur и UE4

Ведущий художник по персонажам Глен Янси подробно рассказал о работе с Ornatrix и gFur, объяснил, как настроить стилизованный мех с помощью этих программ, и показал, как экспортировать файлы в Unreal Engine.

Создание ассета здания из одной фотографии

С помощью специального генератора на базе нод в Блендере.

Синхронизация вызовов между приложениями в распределённых системах с помощью DirectX 12

В статье представлено расширение Nvidia API, позволяющее синхронизировать несколько буферных свопов (между окнами и приложениями).

Показано API D3D12 и обсуждается использование, а также ограничения.

Пулы памяти GPU в D3D12

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

Автор представил показатели производительности для операций чтения/записи ЦП и ГП и загрузки в различные типы памяти.

Внутри студии, разрабатывающей продолжение Hyper Light Drifter

Новая документалочка от Noclip.

Язык шейдеров Rust EDSL

В статье обсуждается инструмент, который позволяет писать на предметно-ориентированном Rust’е, чтобы потом использовать для генерации GLSL.

Создание научно-фантастического оружия в ZBrush, 3ds Max и Substance 3D Painter

Сандро Бонфанти рассказал про проект Alien Gun, объяснил, как поддерживать хорошее разрешение и качество текстур, а также поведал о том, как добиться ощущения действия при создании визуальных эффектов.

Простой симулятор лидара автомобильного базирования на Unity

Автор статьи показывает, как просто и быстро получить данные трёхмерного сканирования улицы.

Как рисовать несколько схожих предметов и не тратить время: Smart Object и его применение в геймдеве

Smirnov School рассказывают, что такое Smart Object, как с ним работать и о чём помнить при использовании.

Trek to Yomi, вдохновлённая фильмами о самураях Куросавы, — одна из самых ярких игр года

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

Test Automation of Unity3D game

Автор статьи на примере Unity игры разбирает как писать автоматизацию для мобильных игр.

Как создаётся фанатский синематик по God of War на Unreal Engine с видюхой Nvidia 1060

Андрей уже пару месяцев активно ведёт разработку видеоролика по God of War на движке Ureal Engine. В статье он немного рассказал про проект.

Разное

Милая пародия на Welcome to the Internet

3D-художник Саванна Шайр, известная созданием высококачественных стилизованных персонажей, представила песню «Welcome to 3D Software», пародию на «Welcome to the Internet» Бо Бернхэма.

Шейдер водички в UnrealEngine

Сделано в UE5. Найдено в Твиттере.

Вкусняшки из Блендера

Как всегда, на геометрических нодах.

Использование нейросети dalle для текстурирования

В перспективе подобные инструменты могут упростить рабочий процесс, что сэкономит кучу времени.

Niagara от Unreal предназначена не только для частиц/эффектов, её можно использовать для вычислений общего назначения

Автор показал пример использования для Relaxed Cone Step Map.

Первый эпизод документального фильма о Arcane

Узнайте, как воплотилась в жизнь история Джинкс.

Персонажи Dota 2, сгенерированные в Midjourney

Найдено на Реддите.

Реалистичная PlayStation 2, созданная с помощью 3ds Max и Substance 3D Painter

3D-художник Илья Долгов продемонстрировал ещё один проект, который легко спутать с обычной фотографией.

Чертежи космического корабля, созданные ИИ Midjourney

Арт-директор Ubisoft Montréal поделился сгенерированными работами.

Реалистичный Геральт из Ривии

С ArtStation.


Если хотите поддержать выход дайджеста и других материалов, сделать это можно одним из способов.


ссылка на оригинал статьи https://habr.com/ru/post/681720/