Прошу помощи знатоков внутренней кухни работы ардуино. Нужно понять как работает некоторый код, написанный под ардуино. Сам я не знаком с её внутренней кухней.
Как я понимаю: Пользовательский код в ардуино должен быть описан внутри loop(), которая платформой вызывается итеративно, в супер-цикле. А пользовательский обработчик прерывания handleInterrupt(), регистрируемый вызовом attachInterrupt(..., handleInterrupt, ...) - он в каком контексте будет вызван? В отдельном контексте аппаратного ISR (как обычное прерывание на микроконтроллере)? Или он будет вызван в контексте супер-цикла, в котором итеративно выполняется loop()?
Погуглив, нашёл следующую инфу, что среда исполнения Ардуино реализована в виде си-шного:
Код:
int main(void) { init(); initVariant(); #if defined(USBCON) USBDevice.attach(); #endif setup(); for (;;) { loop(); if (serialEventRun) serialEventRun(); } return 0; }
Получается - serialEventRun() вызывается из контекста главного цикла. handleInterrupt() зарегистрированная attachInterrupt() будет также вызвана (последовательно рядом с serialEventRun())? Или она будет вызвана непосредственно из контекста аппаратного ISR?
Или она будет вызвана непосредственно из контекста аппаратного ISR?
attachInterrupt - это чисто железячное прерывание. Поэтому в некоторых туториалах рекомендуют минимум кода в присоединенном обработчике прерывания. Например взведение каких либо флагов и немедленный выход. А флаги уже обрабатываются в супер цикле loop()
attachInterrupt - это чисто железячное прерывание. Поэтому в некоторых туториалах рекомендуют минимум кода в присоединенном обработчике прерывания. Например взведение каких либо флагов и немедленный выход. А флаги уже обрабатываются в супер цикле loop()
Это точно???
Почему сомнения: Тот код, в котором разбираюсь, внутри handleInterrupt() содержит кучу кода. В handleInterrupt() есть не только функции типа delayMicroseconds(...), но и даже записи/чтения массивов байт в SPI. Т.е. - блокирующий доступ к разделяемым ресурсам. В главном цикле (loop()) есть такой доступ к этим ресурсам и в handleInterrupt() - тоже. Получается одно из двух: 1) или этот handleInterrupt() не может вызываться из ISR, а вызывается из контекста главного цикла; 2) или это говнокод.
Компиляторы и IDE не помешают вам писать плохой код. Но некоторые из них выдадут предупреждения. Даже если просто попытались тестировать. Ответственность за происходящее несет автор кода, даже если код бесполезен.
jcxz, если тебе так хочется на аврке древней писать, то зачем абдурина? Ну и пиши себе на сях. И не будет никаких вопросов к "внутренней кухне", т.к. вся она будет самодельной. Но таки лучше 32-битные приличные ARM'ы или RISC-V взять, у которых шикарная периферия (хотя, все равно всегда не хватает каналов DMA, количества таймеров или еще чего). Главное - пиши сам код, а не генерируй калокубами всякими!
_________________ Windows must die! And the users of this crap should either become smarter or become janitors.
jcxz, если тебе так хочется на аврке древней писать, то зачем абдурина? Ну и пиши себе на сях.
Для вас персональный совет: Учитесь читать тему, на которую отвечаете! Ни на какой "аврке" я не пишу. Так же как не пишу на абдурине. Вопрос был про попытку понять: Как работает некий готовый чужой код написанный на ардуино.
PS: Если вам нечего сказать по теме - прошу не засорять её бесполезным мусором! Чукчи-нечитатели - проходите пожалуйста мимо!
Обработчик serial уже встроен "внутри" по умолчанию. А вот функция attachInterrupt() добавляется по желанию/необходимости. Можно и чего то своего добавить, но с оглядкой на возможные проблемы при "наложении" ресурсов IDE, добавляемых по умолчанию и собственноручно написанных самоделок. В принципе... Или пользуйтесь "чистым СИ" или принимайте правила/ограничения референса ардуино. можно еще и тут посмотреть: https://alexgyver.ru/lessons/ Особое внимание к "чужим кодам" - чтоб что то "свое" встраивать за рамками предоставленных в IDE правил надо очень детально разбираться как в структуре самой IDE, так и в Си да в придачу и в С++. Довольно неблагодарная задача с учетом отношения к ардуиноIDE у местных обитателей...
Ни на какой "аврке" я не пишу. Так же как не пишу на абдурине. Вопрос был про попытку понять: Как работает некий готовый чужой код написанный на ардуино.
Абдурина === быдлокод. Если он еще и чужой, то единственный правильный вариант - выбросить его в мусорку! Да и самому в этой говно-среде писать ни в коем случае не стоит. Как и во всяких калокубах и им подобных говногенераторах.
_________________ Windows must die! And the users of this crap should either become smarter or become janitors.
BOB51, не отрицаю, среди абдуринщиков может затесаться 0.01% грамотных. Но это - скорей исключение, чем правило. Обычно этой "средой" пользуются лишь совсем уж безграмотные. И почерпнуть из их кода что-либо полезное не получится. Кстати, было как-то дело: перенесли эту гадость под STM32 и некоторые другие 32-битные МК. Доходило до абсурда: на МК есть аппаратный USB, а пользуются софтовым. Или, как они любят: МК не умеет делений даже, а в него флоаты пихают. Ну и самый цимус: I2C ногодрыгом. Или ШИМ. Или неиспользование DMA там, где он очень даже не помешал бы.
_________________ Windows must die! And the users of this crap should either become smarter or become janitors.
За АРМы ничего сказать не могу поскольку таковыми не пользуюсь. Относительно АВР под ардуино - то более известная тематика, имеющая прикладное применение и относительно хорошо проработаны по различным источникам информации.
jcxz, предоставьте весь код. Потому что то, что вы показали, не является Arduino - там нет ни USBDevice, ни for (;;), ни пустой loop(); и setup(); Ето просто код на C/C++, скомпилированный компилятором Arduino (GCC).
jcxz, предоставьте весь код. Потому что то, что вы показали, не является Arduino
Опять нечитатель... Я ничего не "предоставлял". Я спрашивал об общей структуре процесса выполнения кода. И привёл нагугленный вариант описания такой структуры. Схематичный вариант. Просто иллюстрирующий схему выполнения кода в ардуино.
jcxz, предоставьте весь код. Потому что то, что вы показали, не является Arduino
Опять нечитатель... Я ничего не "предоставлял". Я спрашивал об общей структуре процесса выполнения кода. И привёл нагугленный вариант описания такой структуры. Схематичный вариант. Просто иллюстрирующий схему выполнения кода в ардуино.
УПС... А что это за платформа такая: "Библиотека, предоставляющая базовые функции для использования чипов/модулей DW1000 от Decawave с Arduino"?? СпойлерDecawave теперь является частью Qorvo Узнайте больше о технологии сверхширокополосной связи, продуктах и многом другом на сайте Qorvo: Сверхширокополосный концентратор: Технологии Рынки и сферы применения Продукты: Решения UWB, совместимые с чипом Apple U1 Оценочные комплекты UWB Модули UWB Микросхемы UWB Ресурсы: Часто задаваемые вопросы Инструкции по применению Официальные документы Видео Партнеры UWB Форум сообщества Брошюра о сверхширокополосной связи Пресс-релиз: Qorvo завершает сделку по приобретению Decawave Это ведь специализированный модуль со своими специфическими библиотеками. Его рассматривать то надо имея знания по соответствующим микросхемам/МК, там применяемым... В среде ардуино достаточно много разнообразных МК с собственными особыми правилами (а бывает и с дополнительными компиляторами). То уж точно не для начинающих разбор кодов устраивать. Если простенькое UNO(нано или про-мини) то структура программы к примеру по симулятору (и в рамках GCC): Спойлер
А что это за платформа такая: "Библиотека, предоставляющая базовые функции для использования чипов/модулей DW1000 от Decawave с Arduino"??
Это код для работы с DW1000. Для измерения расстояния между двумя приёмо-передатчиками с точностью не хуже 10 см (заявлена производителем) и дальностью до 200-300 м.
Это ведь специализированный модуль со своими специфическими библиотеками. Его рассматривать то надо имея знания по соответствующим микросхемам/МК, там применяемым...
Это готовый проект кода для DW1000. На youtube есть ролики пользователей, которые использовали его и получали примерно заявленную точность. "Знание применяемых микросхем" - это юзер-мануал на более чем сотню регистров. Со сложным и запутанным программированием. Хочется взять этот проект и портировать его на свой МК. А не устраивать "закат солнца вручную" длительностью в несколько месяцев самостоятельных кувырканий с нуля. С негарантированным результатом.
Но после даже поверхностного анализа кода этого проекта, заметил, что функция обработчика прерываний handleInterrupt() в этом проекте обращается ко множеству разделяемых ресурсов (глобальные переменные, SPI-канал и т.п.) параллельно фоновому процессу в loop(). Без каких-либо видимых средств синхронизации/cериализации доступа. Что недопустимо в принципе. Или я не вижу этих средств синхронизации/cериализации. Тогда просьба - указать мне на них. Т.е. - допустимо такое только если handleInterrupt() будет вызываться платформой ардуино из контекста фонового процесса loop(), а не из контекста аппаратного ISR. Отсюда и возник исходный вопрос. Судя по роликам на youtube, код должен прекрасно работать.
PS: Ещё раз повторяю для нечитающих исходный вопрос: Я не спрашиваю как правильно делать! Не спрашиваю как работать с прерываниями и в многопоточной среде. И не просил меня поучать на эту тему. Я это сам прекрасно знаю и умею писать код для МК. Может даже получше вас, поучатели. Мой вопрос только о том: Как в среде ардуино реализовано исполнение пользовательского обработчика handleInterrupt()? Всё! Не более. Не знаете - проходите мимо.
Такие библиотеки анализируют по другому. Прикладные для спецкрсталлов могут быть написаны в рамках и по правилам стандартного GCC да плюс подключение файлов на ассемблере внутри. Не надо путать с теми функциями, что "референсом" предоставляются. И раскапывать там ничего смысла нет - или используем "как есть" или своё по даташитам пишем (ежли достаточно знаний и навыков).
Для всезнайки - ISR всегда выполняется средствами ISR (обработка прерывания) вне зависимости где и как лежит код. Для любого процессора. Иное невозможно. Выполнение кода может прерываться другими прерываниями, если контроллер прерываний это позволяет. Но выполнение кода ISR не может быть перенесено в фоновый процесс (USER). В некоторых процессорах это вообще два типа пространства - системное и user. Ваша тема не имеет смысла. Хватит флудить.
Ну уж так и не может обслуживание прерывания идти фоновым. К примеру основная программа и псевдо параллельный обработчик на прерываниях по таймеру (клавиатура, динамическая индикация)... Переключение на другую часть программы с последующим возвратом в основную (обработчик аппаратного прерывания выполняет только подстановку в стек адреса возврата и reti). Это только адрес вектора точки запуска обработчика прерывания жестко аппаратно определен. А что там дальше будет выполняться и где сам обработчик прерывания будет размещён - на усмотрение автора программы...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения