Обновить
64K+

C *

Типизированный язык программирования

149,42
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Обработка звука в реальном времени (или Full Duplex I2S на STM32)

Уровень сложностиПростой
Время на прочтение14 мин
Охват и читатели9.2K

В этом тексте я написал про то как настроить I2S трансивер работать в полнодуплексном режиме (Full Duplex). Показал как настроить на микроконтроллере STM32F407VG одновременное воспроизведение и запись встречного аудио потока по интерфейсу I2S.

Читать далее

Или я вообще ничего не понял про устройство NeoGeo, или я не понимаю, почему Wolf3D не был портирован на него в 90-х

Уровень сложностиПростой
Время на прочтение37 мин
Охват и читатели14K

Недавняя статья открыла для меня устройство столь упоро необычное и несущее столь любимый нами трудноуловимый флёр «балдёжности», существование которого раньше проходило мимо меня — NeoGeo. Как говорится, «это не первое моё родео» — на использовании 2D‑ускорителей в качестве 3D‑ускорителей я съел изрядного бобика.

Читать далее

Операционная Система на C без знаний C

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели14K

Всем привет! Давно не писал статей и вот наконец решил вернуться.

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

Читать далее

Иллюстрированный разбор одной пользовательской реализации malloc()

Время на прочтение21 мин
Охват и читатели12K

Программисты, работающие с языком C, несомненно, узнают стандартную функцию malloc(). Это главный аллокатор памяти в языке, который тесно связан со всем известными ошибками сегментирования. Функция malloc() – именно то средство, при помощи которого программы приобретают память во время выполнения. Зачастую она также превращается в основной инструмент создания объектов и управления ими. Учитывая такой центральный статус malloc(), удивлён, что большинство программистов обращаются с ней как с чёрным ящиком. Этот пост призван немного исправить ситуацию, и в нём рассказано, что именно происходит под капотом. Также рассмотрим одну из возможных реализаций этой функции.

Читать далее

Doom работает везде, даже на Neo Geo

Время на прочтение5 мин
Охват и читатели13K

Примерно месяц назад мы сняли видео [а на Хабре опубликовали его перевод] о сложности реализации игры наподобие Doom на консоли Neo Geo. Причина заключается в том, что у Neo Geo нет концепции буфера кадров, то есть всё, что мы видим на экране Neo Geo, рендерится, как спрайт. Также в этом видео я рассуждал о концепции движка рейкастинга, который вполне неплохо работал на Neo Geo. Придуманная мной концепция, по сути, заключалась в создании плоской сетки блоков и испускании одного луча на каждый вертикальный столбец. Разработчик Sabino даже предпринял любопытную попытку создать на этом движке игру в стиле Doom.

Но, разумеется, рейкастер и движок уровня Doom — это далеко не одно и то же. Рейкастер может работать только с сеткой, то есть с квадратными блоками, а значит, все объекты на карте должны иметь одинаковую высоту, а стены находиться под прямыми углами. Doom же устроен сложнее: в нём есть стены, располагающиеся под любыми углами, помещения с разной высотой полов, лестницы, лифты и двери. Ничто подобное невозможно реализовать в простой игре с рейкастингом. Даже в проекте Sabino поворот за угол выглядит не особо естественно. В конечном итоге, мы имеем дело с сеткой из квадратных блоков, поэтому в таком движке с рейкастингом невозможно реализовать что-то наподобие уровня E1M1, The Hangar.

Однако у этой саги «Doom на Neo Geo» недавно появилось несколько продолжений, и я в восторге от того, куда всё это может привести. Как я упоминал в последующем видео, люди действительно серьёзно принялись за решение этой задачи. У нас появились новые подходы к реализации Doom на Neo Geo.

Читать далее

Qwen 3.6 27b на 8-12gb vram в llama.cpp до 256к контекста

Уровень сложностиСредний
Время на прочтение2 мин
Охват и читатели22K

Вышло 2 модели prism-ml/Ternary-Bonsai-27B-gguf и prism-ml/Bonsai-27B-gguf

Модели представлены в 2-битном и 1-битном вариантах и занимают всего 7,2 и 3,8 ГБ соответственно. Но самое интересное здесь не размер, а качество после столь агрессивного сжатия. По заявленным результатам, 2-битная версия сохраняет около 95% качества FP16, а 1-битная - примерно 90%.

Благодаря столь компактному размеру 1-битную модель можно запускать даже на смартфонах. Например, на iPhone 17 Pro Max скорость генерации достигает примерно 11 токенов в секунду.

Для запуска потребовался форк PrismML-Eng/llama.cpp. На RTX 3090 мне удалось получить около 60 токенов в секунду. Скорость вполне достойная, однако потребление видеопамяти меня не устроило: при контексте в 256 тысяч токенов 2-битная версия заняла около 18 ГБ VRAM. В это значение входят примерно 3 ГБ, используемые Windows 11.

Я привык работать с TurboQuant версиями llama.cpp, которые заметно эффективнее расходуют память, при использовании параметров: -ctk tbqp3 -ctv tbq3 объём памяти занимаемый контекстом, сокращается в 4.71 раза. При этом качество такого сжатия контекста, согласно результатам тестов, оказывается примерно на 8% выше, чем у F16.

Читать далее

Парсер C++ на своем DSL: попытка обогнать компилятор

Уровень сложностиСложный
Время на прочтение22 мин
Охват и читатели7.7K

Проекты растут. Кодовая база растёт. Время компиляции растёт вместе с ними и переходит все границы разумного.

В какой-то момент я решил: а что если попробовать написать свой компилятор? Пока только для разработки, не для прода. На замену Clang++/G++/CL.EXE.

Эта статья — о первом шаге на этом пути. О парсере C++, который я написал на своём DSL специально сделанном для этого изначально.

Матчинг запущен? Кооперация предложена?

О Raspberry Pi Pico, RP2040 и Baremetal

Уровень сложностиСредний
Время на прочтение41 мин
Охват и читатели14K

В этой статье пойдет речь о первом поколении микроконтроллеров от Raspberry Pi Foundation — RP2040 на основе двух ядер ARM Cortex‑M0+, и о плате, которая базируется на этом чипе — Raspberry Pi Pico. Статья призвана облегчить понимание некоторых принципов работы RP2040 и микроконтроллеров в целом.

Читать далее

Писать свои инструменты лучший способ изучить CAN-шину

Уровень сложностиСредний
Время на прочтение2 мин
Охват и читатели11K

Все знают авто-электриков и диагностов. Я IT-автоэлектрик объединяю знание физики автомобильных цепей и низкоуровневого программирования на С для создания инструментов анализа и изучения j1939.

CAN шина это мост между двумя мирами авто-электриков и IT специалиста. Но для многих этот мост, увы кажется непреодолимой пропастью. Ребята попробуйте программировать на Си и вы пойдёте по этому мосту. Я начинал программировать в телефоне termux. То есть для этого нужно только желание.

Я себя не считаю самым умным. Я просто нашел для себя мощную точку пересечения этих профессий и стал называть этот подход IT-автоэлектрик. Писать свои собственные утилиты на С чтоб заглянуть под капот CAN шины. Под капотом ДВС менее интересно.

Размер моих логов на сегодняшний день 1 - 3 мегабайта. Если вес лога гигабайты то по идее данные нужно положить в голову страницы и процессор полетит как пуля. Размер скомпилированного файла map_id_j1939.c и viz_j1939.c по 16.5 КБ.

Читать далее

ВВОД В СИСТЕМУ «УМНЫЙ ДОМ» МОДУЛЯ GSM

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели10K

Данная статья является продолжением публикаций про созданную мною систему "Умный дом" на основе проводного интерфейса CAN. Также предлагаемый проект может быть использован для разработки каких то других пользовательских программ, так как оформлен в виде задачи (Task) в FreeRTOS. Программа написана на языке программирования C/C++ в среде программирования ESP-IDFv5.

Читать далее

Подключение вакуумного люминесцентного индикатора (ВЛИ) типа ИВЛ1-8/13 от старого кассового аппарата АМС-100Ф

Уровень сложностиПростой
Время на прочтение7 мин
Охват и читатели9.4K

Как оживить старый ВЛИ (VFD) без родной электроники? В этой статье разберем подключение неизвестного дисплея, управление сетками и сегментами, работу с высоким напряжением и создание собственного драйвера на Arduino Nano, который позволит управлять индикатором через Serial‑порт.

Читать далее

OSDEV: Itanium часть 2: One-time Construction API и сигнлтоны Майерса

Уровень сложностиПростой
Время на прочтение9 мин
Охват и читатели8.9K

Приветствую!

В этой части мы рассмотрим что такое guard variables и как под капотом работают синглтоны Майерса.

И так, стандарт начиная с С++11 гарантирует нам что локальные статические переменные инициализируются потокобезопасно. Но кто и как это обеспечивает? Это делает ABI.

И все таки о чем же идет речь? Представьте себе что есть вот такая структура:

Читать далее

Самый недооцененный механизм безопасности SSH или почему known_hosts — это не кэш

Уровень сложностиПростой
Время на прочтение4 мин
Охват и читатели7.6K

Каждый, кто работает с SSH, наизусть знает ритуал первого подключения (TOFU) и страшный ворнинг о смене ключей хоста. Но почему в 99% случаев мы просто слепо сносим записи через ssh-keygen -R, превращая важный механизм ИБ в формальность, а known_hosts в бездонный кэш?

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

Полюбопытствовать

Ближайшие события

Диктофон на микроконтроллере (WM8731 + I2S + STM32 + SDIO + FAT16)

Уровень сложностиПростой
Время на прочтение19 мин
Охват и читатели13K

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

Перечислены особенности разработки звукозаписывающей аппаратуры и типичные трудности разработки диктофонов.

Читать далее

USB-ключ для ввода TOTP-кодов и сохранённого пароля

Уровень сложностиСредний
Время на прочтение4 мин
Охват и читатели14K

Мне всегда было лень доставать телефон ради TOTP-кода, а вручную вводить длинные сложные пароли — удовольствие тоже сомнительное. С паролями эту проблему часто решают плохо: делают пароль попроще и покороче, чтобы его было удобно набирать. Но с TOTP так не получится — код живёт отдельно, его всё равно нужно открыть, посмотреть и перепечатать.

Поэтому я решил сделать маленький «вписыватель паролей»: USB-устройство, которое притворяется клавиатурой и само вводит TOTP-код или сохранённый пароль.

Читать далее

OSDEV: Itanium ABI часть 1: Array Operator new Cookies

Уровень сложностиПростой
Время на прочтение7 мин
Охват и читатели9.6K

Приветствую!

Код тут

Реализация new cookies в соответствии с C++ Itanium ABI зависит только от osdev-libstdc

Погнали!

Проигрыватель WAV файлов на STM32

Уровень сложностиПростой
Время на прочтение15 мин
Охват и читатели14K

В этом тексте я показал как можно разработать прототип музыкального проигрывателя на основе микроконтроллера STM32F407VG и аудио кодека WM8731. Показал как спроектировать прошивку проигрывателя wav файлов на основе I2C, I2S, DMA, SDIO и FatFs.

Читать далее

УМНЫЙ К1 — контроллер на базе ESP32 с REST, syslog и много опенсорса

Уровень сложностиПростой
Время на прочтение4 мин
Охват и читатели7.3K

Предисловие

Возможно то, про что я хочу рассказать в своей первой статье тут, покажется не новым, уже знакомым велосипедом. Речь пойдет о контроллерах на базе ESP32 и программном обеспечении. Да, современных решений, открытых и бесплатных – много. А сейчас зарождается еще одно (а опенсорса мало не бывает, я считаю).

В статье я упущу и не буду рассказывать ни про свое знакомство с ардуиной, esp, php, python, js ни про то, что пришел сюда давным-давно гуманитарием. И да простят мой, вероятно не корректный, «жаргон» истинные профессионалы в микроэлектронике и программировании - итак, приступим.  

Совсем недавно я отключил RPI4 с HA и наконец «воткнул» в котельную очередную, но «готовую к деплою» версию контроллера (разрешите его далее называть «УМНЫЙ К1», спасибо).

Читать далее

Структуры данных на практике. Глава 18: Очереди драйверов устройств

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели7.7K

Наш сетевой драйвер терял пакеты. Не время от времени, а постоянно. На пропускной способности линии с 64-байтными пакетами мы теряли 31% всего трафика.

В качестве оборудования использовался Ethernet-контроллер на 1 Гбит/с на SoC RISC-V. В спецификациях говорилось, что он может справляться со скоростью проводного трафика. Движок DMA работал корректно. Обработчик прерываний срабатывал вовремя. Тем не менее, пакеты исчезали.

Я начал с очевидного подозреваемого: очереди получения. Реализация выглядела вполне логично — простой связанный список с указателями на голову и хвост. Под нагрузкой (64-байтные пакеты на пропускной способности линии) драйвер терял 31% пакетов! При профилировании обнаружилась причина проблемы: производительность убивали связанный список и спин-блокировки.

Я переписал драйвер, использовав кольцевой буфер без блокировок. Результаты: потеря 31% пакетов превратилась в 0,12% — улучшение в 258 раз!

В этой главе мы поговорим о структуре очередей для драйверов устройств.

Читать далее

Структуры данных на практике. Глава 17: Структуры данных загрузчиков

Время на прочтение11 мин
Охват и читатели11K

Наш загрузчик оказался слишком медленным. Требование было чётким: загружаться менее чем за 500 миллисекунд. Показатели оставались не менее чёткими: 720 миллисекунд. Мы отставали от нужного значения на 44%.

Это требование не было «мягким». Загрузчик должен был работать в промышленном контроллере, обязанном реагировать вскоре после включения питания. Каждая секунда времени загрузки — это потерянная продуктивность. В спецификации к изделию был указан максимум в 500 мс. Мы обязаны были их обеспечить.

Задача загрузчика была простой:

1. Инициализировать оборудование (UART, SPI, DDR-контроллер)

2. Загрузить ядро из флэш-памяти

3. Спарсить дерево устройств

4. Перейти ко точке входа ядра

Реализация казалась логичной: стандартные структуры данных из библиотеки C. Проблема выявилась при профилировании: 45% времени загрузки тратилось на malloc/free! В загрузчике всего с 64 КБ ОЗУ динамическое распределение роняло производительность.

Читать далее