а еще можно начало пакета пометить как-то совсем уникально. например, перейти на 9бит. или протянуть еще один проводок между мастером и слейвом(ами). и заодно в этом уникальном байте кодировать тип пакета - код может определять направление передачи и длину блока данных.
особенно тщательно не анализировал влияние отключения контроля ошибок. на первый взгляд отключение оного дает выигрыш незначительный, до 10% примерно в данном тесте в обеих ос контроль ошибок не отключался. вот прогон embos в варианте release (os7t_al_r.a)
поскольку пробиться через входной фильтр хабра и опубликовать маленькую статейку у меня не получилось, положу информацию сюда. По-моему, вполне по теме статьи
итак, «Народная отладка» многоядерных приложений ARM Cortex
преамбула: ..попала мне в руки плата с 2х ядерным Cortex-A7
амбула: Как оказалось, нельзя просто так подключиться ко всем (2м в моем случае) ядрам Cortex-A7 при помощи JLink.
И нельзя останавливать по software breakpoint ядро0 (к которому легко и просто цепляется отладчик IARa), ибо в этом случае ядро1 может налететь на измененный код (breakpoint) и, если не повезет, что случается, как оказалось чаще, в итоге debug-сессия зависает наглухо вместе с процессором (почему не разобрался пока).
Однако нас это не остановит! Как известно, технология Segger RTT умеет несколько каналов как upStream, так downStream.
Нас в данном случае интересуют up (от нашего процессора к компутеру). По умолчанию их даже и сконфигурировано 2!. В памяти они расположены независимо, каждый имеет свой буфер и свои указатели голова-хвост.
Эврика! Пишем простейший враппер на SEGGER_RTT_WriteString:
unsigned int RTT_WriteStringEx(unsigned char str)
{
unsigned int rc=0,bufN=getCPUID();
if(bufN<SEGGER_RTT_MAX_NUM_UP_BUFFERS) { rc=SEGGER_RTT_WriteString(bufN,(const char )str); }
return(rc);
}
Все, что он делает, запрашивает номер ядра на котором работает ( вызовом getCPUID() ) , и отправляетстроку в соответствующий буфер. Таким образом, нам не нужно заботиться о взаимоблокировках при вызовах WriteString из разных ядер.
Со стороны компьютера поток rtt0 смотрим, как обычно, RTTViewer'ом, поток rtt1 он не умеет к сожалению, поэтому используем JlinkRTTLogger.exe (его путем нехитрых танцев с бубном можно направить в консоль)
И вот такую красоту получаем на экране:
Все, что он делает, запрашивает номер ядра на котором работает ( вызовом getCPUID() ) , и отправляет строку в соответствующий буфер. Таким образом, нам не нужно заботиться о взаимоблокировках при вызовах WriteString из разных ядер.
Со стороны компьютера поток rtt0 смотрим, как обычно, RTTViewer'ом, поток rtt1 он не умеет к сожалению, поэтому используем JlinkRTTLogger.exe (его путем нехитрых танцев с бубном можно направить в консоль)
И вот такую красоту получаем на экране:
PS. Останавливать ядро0 (к которому, как мы помним, подключен наш отладчик IARa) можно! там где код гарантированновыполняется на ядре0, что можно обеспечить в случае режима SMP заданиемaffinity_mask при создании задачи rtos.
PPS Данный прием может пригодиться и для отладочной печати, например, из прерывания.
PPPS Вопрос, сколько потоков upStream умеет RTT, мне пока хватило 2, но видимо скоро понадобится 4 или 5.
PPPPS "Антинародная" отладка выглядит сильно круче, может потом сделаю еще подход к пробитию входного фильтра хабра
возможно стоит для начала найти где ошибка? в низкоуровневых процедурах чтения записи карты (стм куб ведь поди, да? с дма?) или в фатфс (в которой, например, некоторые действия в фат32 вызывают рекурсию, посему от фат32 я напрочь отказался при использовании фатфс)
проверить корректность записи чтения можно, не используя никакую файл систему, работать с секторами, что кстати, несколько быстрее )
понятно, то есть реально рекурсия вызова обработчика прерывания? хмм, никогда такого не встречал. если не сложно, расскажите вкратце, для решения каких задач это вы применяете?
безусловно, у каждой конкретной задачи ест ь свое оптимальное решение, но, полагаю, для пущей корректности "сотни машинных циклов" следует заменить на "ххх мкс" и тогда все становится не столь однозначно. коль мы про уарт, то сейчас в проекте оный работает на 3мбит, передавая туда-сюда данные от 2х CAN. внутри ртос. но да, там самопридуманный протокол
речь о рекурсии не обработки прерывания а пользовательских функций, добавлю, что если используется ртос, то вложенные (то, что вы, видимо, называете рекурсивными, что не совсем корректно, мне кажется) прерывания совершенно не являются необходимостью, ибо _хорошая практика - НЕ ДЕЛАТЬ ничего в обработчике прерывания, в нем только отправляется сигнал задаче, которая, собственно, уже и производит обработку события
а мне НЕ нужно прописывать уникальные пути и добавлять/убирать .c файлы (ибо условная трансляция как я выше написал). видимо мы о разном говорим, подразумевая разные варианты конфигурации проекта
в этом случае я делаю так - переменные, задающие конфигурацию сборки/прошивки выносятся в отдельный .h, в исходниках проекта эти переменные анализируются директивами #if define... На каждый вариант прошивки создается такой файл. При необходимости собрать нужн вариант - в определенное место копируется соотв конфиг файл. Дальше либо из ИДЕ, либо из ком строки это все собирается. В особо извратном случае пишется разлапистый командный файл, который на RAM-диске запускает параллельно несколько потоков сборки. Реальный случай - число конфигураций сборки 101. Собирается в 8 потоков ибо компилятор GHS древней версии однопоточный
PS В другом проекте эти "опции" можно задать в процессе работы прошивки. Изменения применяются после рестарта. Методы решения зависят от задачи
Ну это давно известный прием, практически все ртос его имеют, как и контроль стека задач "на лету" с выпадением в ловушку. Но это все борьба с УЖЕ случившейся проблемой. А мы выше обсуждали способ недопущения этой проблемы
а еще можно начало пакета пометить как-то совсем уникально. например, перейти на 9бит. или протянуть еще один проводок между мастером и слейвом(ами). и заодно в этом уникальном байте кодировать тип пакета - код может определять направление передачи и длину блока данных.
заменю результаты в теле статьи
действительно не то, спасибо!
вот результат когда test1 более приоритетна
embos **_r.a
и threadx
tx_user.h пустой
tx_user.h содержит
хммм...
то есть я не то меряю? а вероятно может быть
сейчас перемеряю
особенно тщательно не анализировал влияние отключения контроля ошибок. на первый взгляд отключение оного дает выигрыш незначительный, до 10% примерно
в данном тесте в обеих ос контроль ошибок не отключался.
вот прогон embos в варианте release (os7t_al_r.a)
чуть быстрее, но непринципиально
не знаю как "убрать под кат" слишком длинные блоки исх текста
спасибо за замечания по оформлению. буду учиться писать статьи
Форматтер хабра плохо умеет обрабатывать .png, снова загрузил картинки в .jpg
клоны J-Link сейчас не сказать что дороги
поскольку пробиться через входной фильтр хабра и опубликовать маленькую статейку у меня не получилось, положу информацию сюда.
По-моему, вполне по теме статьи
итак, «Народная отладка» многоядерных приложений ARM Cortex
преамбула:
..попала мне в руки плата с 2х ядерным Cortex-A7
амбула:
Как оказалось, нельзя просто так подключиться ко всем (2м в моем случае) ядрам Cortex-A7 при помощи JLink.
И нельзя останавливать по software breakpoint ядро0 (к которому легко и просто цепляется отладчик IARa), ибо в этом случае ядро1 может налететь на измененный код (breakpoint) и, если не повезет, что случается, как оказалось чаще, в итоге debug-сессия зависает наглухо вместе с процессором (почему не разобрался пока).
Однако нас это не остановит! Как известно, технология Segger RTT умеет несколько каналов как upStream, так downStream.
Нас в данном случае интересуют up (от нашего процессора к компутеру). По умолчанию их даже и сконфигурировано 2!. В памяти они расположены независимо, каждый имеет свой буфер и свои указатели голова-хвост.
Эврика! Пишем простейший враппер на SEGGER_RTT_WriteString:
unsigned int RTT_WriteStringEx(unsigned charstr) { unsigned int rc=0,bufN=getCPUID(); if(bufN<SEGGER_RTT_MAX_NUM_UP_BUFFERS) { rc=SEGGER_RTT_WriteString(bufN,(const char)str); } return(rc); }Все, что он делает, запрашивает номер ядра на котором работает ( вызовом getCPUID() ) , и отправляетстроку в соответствующий буфер. Таким образом, нам не нужно заботиться о взаимоблокировках при вызовах WriteString из разных ядер.
Со стороны компьютера поток rtt0 смотрим, как обычно, RTTViewer'ом, поток rtt1 он не умеет к сожалению, поэтому используем JlinkRTTLogger.exe (его путем нехитрых танцев с бубном можно направить в консоль)
И вот такую красоту получаем на экране:
Все, что он делает, запрашивает номер ядра на котором работает ( вызовом getCPUID() ) , и отправляет строку в соответствующий буфер. Таким образом, нам не нужно заботиться о взаимоблокировках при вызовах WriteString из разных ядер.
Со стороны компьютера поток rtt0 смотрим, как обычно, RTTViewer'ом, поток rtt1 он не умеет к сожалению, поэтому используем JlinkRTTLogger.exe (его путем нехитрых танцев с бубном можно направить в консоль)
И вот такую красоту получаем на экране:
PS. Останавливать ядро0 (к которому, как мы помним, подключен наш отладчик IARa) можно!
там где код гарантированно выполняется на ядре0, что можно обеспечить в случае режима SMP заданием affinity_mask при создании задачи rtos.
PPS Данный прием может пригодиться и для отладочной печати, например, из прерывания.
PPPS Вопрос, сколько потоков upStream умеет RTT, мне пока хватило 2, но видимо скоро понадобится 4 или 5.
PPPPS "Антинародная" отладка выглядит сильно круче, может потом сделаю еще подход к пробитию входного фильтра хабра
присоединяюсь к мнению предыдущего оратора. жду статью про блоки pio, которые являются главной изюминкой этого чипа
да полно ) ЖД, Росатом, связь, медицина - это знакомые и коллеги, бывшие и настоящие
карта вроде говорит какую частоту она умеет. через csd если правильно помню
автор сильно заблуждается. есть проекты и посложнее задвижек на водопроводных трубах
возможно стоит для начала найти где ошибка? в низкоуровневых процедурах чтения записи карты (стм куб ведь поди, да? с дма?) или в фатфс (в которой, например, некоторые действия в фат32 вызывают рекурсию, посему от фат32 я напрочь отказался при использовании фатфс)
проверить корректность записи чтения можно, не используя никакую файл систему, работать с секторами, что кстати, несколько быстрее )
понятно, то есть реально рекурсия вызова обработчика прерывания? хмм, никогда такого не встречал. если не сложно, расскажите вкратце, для решения каких задач это вы применяете?
безусловно, у каждой конкретной задачи ест ь свое оптимальное решение, но, полагаю, для пущей корректности "сотни машинных циклов" следует заменить на "ххх мкс" и тогда все становится не столь однозначно. коль мы про уарт, то сейчас в проекте оный работает на 3мбит, передавая туда-сюда данные от 2х CAN. внутри ртос. но да, там самопридуманный протокол
речь о рекурсии не обработки прерывания а пользовательских функций,
добавлю, что если используется ртос, то вложенные (то, что вы, видимо, называете рекурсивными, что не совсем корректно, мне кажется) прерывания совершенно не являются необходимостью, ибо _хорошая практика - НЕ ДЕЛАТЬ ничего в обработчике прерывания, в нем только отправляется сигнал задаче, которая, собственно, уже и производит обработку события
а мне НЕ нужно прописывать уникальные пути и добавлять/убирать .c файлы (ибо условная трансляция как я выше написал). видимо мы о разном говорим, подразумевая разные варианты конфигурации проекта
в этом случае я делаю так - переменные, задающие конфигурацию сборки/прошивки выносятся в отдельный .h, в исходниках проекта эти переменные анализируются директивами #if define...
На каждый вариант прошивки создается такой файл. При необходимости собрать нужн вариант - в определенное место копируется соотв конфиг файл. Дальше либо из ИДЕ, либо из ком строки это все собирается. В особо извратном случае пишется разлапистый командный файл, который на RAM-диске запускает параллельно несколько потоков сборки. Реальный случай - число конфигураций сборки 101. Собирается в 8 потоков ибо компилятор GHS древней версии однопоточный
PS В другом проекте эти "опции" можно задать в процессе работы прошивки. Изменения применяются после рестарта. Методы решения зависят от задачи
Ну это давно известный прием, практически все ртос его имеют, как и контроль стека задач "на лету" с выпадением в ловушку. Но это все борьба с УЖЕ случившейся проблемой. А мы выше обсуждали способ недопущения этой проблемы