Кажется мне, на фотке в посте дорожки от чипа влево-вниз (с резисторами R57, R58, ...) и на "изнанку" платы - это джитаг и есть. По крайней мере, пины джитага в этом углу чипа находятся. Так что остался только вопрос нужного адаптера и софтины для этих МИПСов (ну и провода в нужном порядке припаять...).
Из прочтения кода стало даже чуть понятнее, что происходит. Заодно прочитал, что такое posix cksum, без этого знания понять исходник невозможно (вы где-то укра.. позаимствовали реализацию? Не знаю, насколько большим оригиналом надо быть, чтобы использовать восьмеричную!!! константу 0o377).
Сравнил вашу картинку с гидрой и карту памяти похожего чипа (стр.13). Там что получается, загрузчик тоже использует MMU ? Вы и таблицу трансляции расковырять успели? UPD. Нашёл правильный документ, в нём таблица адресов совпадает с вашей.
Экскурс в психологию занятный. В смежной теме наблюдал что-то похожее. Подход "моя прелесссть", и нежелание делиться со всякими там халявщиками хоть какой-то полезной информацией.
Собственно, ближе к теме. Мне что-то не нравится, как гидра разобрала вызовы функций. Выложите бинарник, пожалуйста, охота посмотреть, как там что в MIPS устроено.
PS в качестве второго введения могли бы написать, чем эти роутеры так замечательны. Неочевидно, чем оно лучше какого-нибудь тп-линка. Чем хуже (официально продаётся в комплекте с подключением билайна) - понятно.
у меня понимание такого низкого уровня уже сломалось.
Удивительно. Человек, который пишет приличный (имхо) шаблонный код и умеет пользоваться IDA - и такая странная дырка в знаниях. Наверное, это от их избытка - было б поменьше, просто б не задумывались, оно б "само" работало :-)
доступ к flash-памяти из программы прозрачен и не отличается от доступа к участку RAM?
В случае кортексов - да, абсолютно прозрачен и никак не отличается от доступа к ОЗУ (ну, если не писать туда ничего и не заниматься тщательными измерениями "сколько тактов занимает чтение"). На уровне ассемблера это одни и те же инструкции, только разные адреса. На уровне Си/Си++ - во всех заготовках стартового кода (стартап, скрипт линкера) сделано так, чтобы RW переменные ложились в ОЗУ, RO - только во флеш.
Если чуть подробнее, то для переменных Си/С++ есть возможны три варианта - неинициализированные не-const переменные кладутся в секцию BSS, инициализированные не-const переменные кладутся в секцию DATA, const перменные (они, очевидно, все инициализированы) кладутся в секцию RODATA.
В промежутке между стартом контроллера и началом main() выполняется маленький кусочек кода (в случае gcc он обычно весь в одном исходном файле), который обнуляет BSS (ассемблерной вставкой или вызовом memset) и копирует DATA из флеша в ОЗУ (также ассемблерной вставкой или обычным memcpy). В случае RODATA никаких копирований нет, код сразу работает с данными во флеш.
Это не совсем так. Если мы говорим о STM32F1xx (не F7 и более быстрых процессорах) и о внутренней SRAM (а не о внешней SDRAM, про которую статья по вашей ссылке), там нет никаких задержек, память работает на частоте ядра.
Но, с другой стороны, скорость работы внутренней флеш - максимум 24 МГц, при больших скоростях ядра надо конфигурировать контроллер, чтобы он вставлял циклы ожидания при обращении к ней. Чтобы эта конструкция не ОЧЕНЬ тормозила, есть микро-кэш: два 64-битных буфера. Каждое чтение флеш заполняет один из них (все 64 бита за раз). Для линейного кода, который не читает никаких констант, оно работает нормально. Но это сферический код в вакууме, и на хаотичные прыжки по коду эта конструкция отреагирует плохо.
можно ли статический массив разместить во Flash, а доступ к нему получать в runtime?
Или я не понял вопрос, или у вас компилятор (скрипт линкера) сломался. Потому что на мелких армах банальный `const int arr[42] = {1,2,3}` с настройками компилятора по умолчанию ляжет во флешку.
Вот, например, в ATMega это не так - там гарвардская архитектура, и "память по умолчанию" - это ОЗУ. Чтобы переменная легла в ПЗУ, нужны магические заклинания.
Также по-другому могут работать "большие" армы - всякие cortex-a. Там, слава фон-Нейману, адресное пространство единое, но программа зачастую копируется целиком из ПЗУ в ОЗУ при старте и уже оттуда исполняется.
Ну, написать threadsafe код, который будет работать на любой, заранее неизвестной, ОС (у нас же baremetal, RTOS у каждого своя любимая), задача нетривиальная. Т.е. штуки, которые не трогают глобальные объекты (тот же memcpy и strlen), по умолчанию работают хорошо. printf тоже по идее должен быть без глобального буфера (ну да, будет putchar по каждому поводу дёргать). Вот malloc и free придётся самому делать, чтоб они знали, как именно в данной ОС принято делать критические секции и прочие мютексы.
PS полез почитать, чем всё-таки отличается newlib-nano из gcc none-aebi с arm.com. И не нашёл. В исходниках есть общее описание, но что конкретно выложено на arm.com, надо отдельно разбираться...
Какие альтернативы? Вы предлагаете делать свой велосипед? Так он будет наверняка кривее и наверняка больше.
К слову, в embedded компиляторах (точнее, линкерах) есть способы "обезжиривания" stdlib. Для gcc, который во флиппере, есть ключик -specs=nano.specs, который подключает меньшую библиотеку (особым образом собранная gcc'шная newlib, список отличий сейчас сходу не найду). Для IAR и Keil также есть отдельные переключатели в настройках проекта, которые указывают, какие библиотеки использовать.
Кстати, @Andrey2008, вы в курсе, что не всякий embedded printf/scanf умеет все возможные опции форматирования? Если вы умеете вытягивать из среды настройки линкера, можно проверять ещё и это. Я один раз на это наступил (правда, там был самодельный sprintf, вы про такой точно не знаете :-) ).
Хорошая статья, спасибо. Разве что в примерах должн быть не робот, который катается по лесу, а тележка, которая ездит по одномерным рельсам.
Потому что в первом случае задача становится куда интереснее - из координат X/Y и скорости/курса с GPS и датчиков скорости с колёс (фактически, линейная скорость движения + угловая скорость поворота) надо получить координаты/скорость/курс. А оно внезапно многомерное и нелинейное. Такую задачку я решить не могу. Надо всё-таки плотно сесть, попробовать...
Возможно, тот, кто просмотрел первый ролик, и за 5 минут узнал только то, что фильтр Калмана - очень крутая штука, которая по неточным измерениям может давать хороший результат. Остальное смотрите в продолжении (ещё 54 серии в сезоне "фильтр Калмана").
Но минус не мой,@DirectXто в чём виноват? Господина van Biezen, собственно, тоже обвинять как-то странно.
Вспоминается давно забытое слово "мультипортовка". Судя по картинке и нагугленному даташиту, вместо "Any MCU" в левой части картинки надо читать "какой-то странный толстый процессор, у которого есть лишний PCIe, но нет нужного количества GPIO / UART / SPI / ...".
Он стоит пару баксов только потому, что оооочень массовый. Внутри он довольно продвинутый. И общаться с хостом он желает не по примитивным SPI/I2C/UART, а по PCI-Express, поддержку которого на STM32 никак не сделать...
Можно, правда, поискать Ethernet PHY c интерфейсом RMII. Его, правда, во флиппере тоже нет, но конфигурация такого чипа читается-пишется по отдельному интерфейсу MDIO, который, кажется, можно имитировать ногодрыгом. Насколько хорошо там реализована диагностика проблем с кабелем, я никогда не думал, но в каких-то чипах она заявлена.
Решение, честно скажу, через задни выглядит очень по-хакерски. Насколько в принципе оно работает, я не знаю (и работает ли вообще MDIO при мёртвом RMII). Я когда-то давно разбирался с MII, но мне надо было байтики в сеть передавать, а не вот этой диагностикой заниматься.
На всякий случай сообщу, что ток измеряется в миллиамперах, а не в милливольтах (и вольт до появления power delivery там всегда было 5, плюс-минус отклонения китайских реализаций).
Термопринтер же жрёт при печати полсотни ватт, и питание от USB там никак не помогает - оно просто используется для определения факта подключения кабеля, потребление от USB - доли мА.
На самом деле, можно просто сделать тупой протокол, который будет работать по success path (там парой страниц выше расписано), а потом, для обработки ошибок, просто начинать всё заново, если не удалось отправить (получить ack на команду). Главное, не отправлять команду, если пришёл на неё ack (вы же не хотели получить две одинаковые продажи? :-) ), остальное протокол со стороны железки нормально съест.
Про миллисекунды там тоже ничего не написано, совершенно лошадиные таймауты (минимум 0.5 сек). Я, правда, совершенно не в курсе работы с ком-портами под андроидом. Там совсем всё плохо, и к стандартным /dev/ttyXXX не пускают?
Если там, чтото типа Атолловских, то это полная жопа. Все должно передаваться с выдержкой до миллисекунд.
Что-то страшное вы рассказываете. Там довольно наркоманский протокол с кучей переподтверждений, но он как работал 20 лет назад на гробиках с двумя лентами на убогих 51 контроллерах, так и с минимальными изменениями работает на супер передовых онлайн кассах. Задержки там, соответственно, прокатывают +- километр.
Или могут «оптимизировать» строки, где много однотонной заливки — сделать их светлее
Это не оптимизация, и с битмапами никак не связано. Это физика и кривые руки разработчика принтера. Штука в том, что тёмная точка на бумаге получается, если эту бумагу нагреть. Самый простой и быстрый способ печати - греть сразу все нужные точки в текущей печатаемой линии. Но если нужны сразу ВСЕ точки, происходит беда - на это банально не хватает электричества, печать становится бледной.
Решения: 1) считать чёрные точки, если их много, по некоей эмпирической формуле увеличивать время нагрева 2) делить область печати на несколько частей, печатать по-очереди 3) мерять напряжение и опять-таки увеличивать время при необходимости.
Правда, надо заметить, идеального результата у меня достигнуть не удалось...
но всем известно что фискальные регистраторы делаются на основе той машинки что я держу в руках сейчас...
Всем известно, что фискальные регистраторы делаются методом выкидывания из этой машинки всех мозгов, и заменой их на свои, с возможностью подключения внешней штуковины для сохранения чеков (Не знаю, как у вас в стране это устроено. Наверняка, как и у нас в РФ - память для чеков делается отдельной конторой, которая имеет особо близкое знакомство с законодателями и имеет кучку бумажек от заведения, занимающегося криптографией) и полностью своим протоколом.
Не совсем так. ЭКЛЗ могли сохранять весь чек. Но была "дырка" в законодательстве, что требовалось только совпадение итоговой суммы. Кроме того, памяти ЭКЛЗ довольно ограничена (при активной работе они заканчивались меньше чем за год, а замена стоила заметных денег), а интерфейса обмена касса-эклз весьма тормозной.
В итоге, все использовали только одну команду "покупка" на всю сумму сразу (касса при этом печатает "лишнюю" строчку с суммой перед строкой "итого"), а все остальные строки печатались обычным текстом, и ни в какие ЭКЛЗ не попадали.
Кажется мне, на фотке в посте дорожки от чипа влево-вниз (с резисторами R57, R58, ...) и на "изнанку" платы - это джитаг и есть. По крайней мере, пины джитага в этом углу чипа находятся. Так что остался только вопрос нужного адаптера и софтины для этих МИПСов (ну и провода в нужном порядке припаять...).
О, спасибо. Вместо тысячи слов, так сказать :-)
Из прочтения кода стало даже чуть понятнее, что происходит. Заодно прочитал, что такое posix cksum, без этого знания понять исходник невозможно (вы где-то укра.. позаимствовали реализацию? Не знаю, насколько большим оригиналом надо быть, чтобы использовать восьмеричную!!! константу 0o377).
Сравнил вашу картинку с гидрой и карту памяти похожего чипа (стр.13). Там что получается, загрузчик тоже использует MMU ? Вы и таблицу трансляции расковырять успели? UPD. Нашёл правильный документ, в нём таблица адресов совпадает с вашей.
Экскурс в психологию занятный. В смежной теме наблюдал что-то похожее. Подход "моя прелесссть", и нежелание делиться со всякими там халявщиками хоть какой-то полезной информацией.
Собственно, ближе к теме. Мне что-то не нравится, как гидра разобрала вызовы функций. Выложите бинарник, пожалуйста, охота посмотреть, как там что в MIPS устроено.
PS в качестве второго введения могли бы написать, чем эти роутеры так замечательны. Неочевидно, чем оно лучше какого-нибудь тп-линка. Чем хуже (официально продаётся в комплекте с подключением билайна) - понятно.
Я правильно нагуглил https://sk.skolkovo.ru/storage/file_storage/4b954252-7c3d-4975-94e3-910612e77464/SKOLKOVO_SEDeC_Atlas_2.0.pdf ?
Или ещё более трешовое издание существует?
Удивительно. Человек, который пишет приличный (имхо) шаблонный код и умеет пользоваться IDA - и такая странная дырка в знаниях. Наверное, это от их избытка - было б поменьше, просто б не задумывались, оно б "само" работало :-)
В случае кортексов - да, абсолютно прозрачен и никак не отличается от доступа к ОЗУ (ну, если не писать туда ничего и не заниматься тщательными измерениями "сколько тактов занимает чтение"). На уровне ассемблера это одни и те же инструкции, только разные адреса. На уровне Си/Си++ - во всех заготовках стартового кода (стартап, скрипт линкера) сделано так, чтобы RW переменные ложились в ОЗУ, RO - только во флеш.
Если чуть подробнее, то для переменных Си/С++ есть возможны три варианта - неинициализированные не-const переменные кладутся в секцию BSS, инициализированные не-const переменные кладутся в секцию DATA, const перменные (они, очевидно, все инициализированы) кладутся в секцию RODATA.
В промежутке между стартом контроллера и началом main() выполняется маленький кусочек кода (в случае gcc он обычно весь в одном исходном файле), который обнуляет BSS (ассемблерной вставкой или вызовом memset) и копирует DATA из флеша в ОЗУ (также ассемблерной вставкой или обычным memcpy). В случае RODATA никаких копирований нет, код сразу работает с данными во флеш.
Это не совсем так. Если мы говорим о STM32F1xx (не F7 и более быстрых процессорах) и о внутренней SRAM (а не о внешней SDRAM, про которую статья по вашей ссылке), там нет никаких задержек, память работает на частоте ядра.
Но, с другой стороны, скорость работы внутренней флеш - максимум 24 МГц, при больших скоростях ядра надо конфигурировать контроллер, чтобы он вставлял циклы ожидания при обращении к ней. Чтобы эта конструкция не ОЧЕНЬ тормозила, есть микро-кэш: два 64-битных буфера. Каждое чтение флеш заполняет один из них (все 64 бита за раз). Для линейного кода, который не читает никаких констант, оно работает нормально. Но это сферический код в вакууме, и на хаотичные прыжки по коду эта конструкция отреагирует плохо.
Или я не понял вопрос, или у вас компилятор (скрипт линкера) сломался. Потому что на мелких армах банальный `const int arr[42] = {1,2,3}` с настройками компилятора по умолчанию ляжет во флешку.
Вот, например, в ATMega это не так - там гарвардская архитектура, и "память по умолчанию" - это ОЗУ. Чтобы переменная легла в ПЗУ, нужны магические заклинания.
Также по-другому могут работать "большие" армы - всякие cortex-a. Там, слава фон-Нейману, адресное пространство единое, но программа зачастую копируется целиком из ПЗУ в ОЗУ при старте и уже оттуда исполняется.
Ну, написать threadsafe код, который будет работать на любой, заранее неизвестной, ОС (у нас же baremetal, RTOS у каждого своя любимая), задача нетривиальная.
Т.е. штуки, которые не трогают глобальные объекты (тот же memcpy и strlen), по умолчанию работают хорошо. printf тоже по идее должен быть без глобального буфера (ну да, будет putchar по каждому поводу дёргать). Вот malloc и free придётся самому делать, чтоб они знали, как именно в данной ОС принято делать критические секции и прочие мютексы.
PS полез почитать, чем всё-таки отличается newlib-nano из gcc none-aebi с arm.com. И не нашёл. В исходниках есть общее описание, но что конкретно выложено на arm.com, надо отдельно разбираться...
Какие альтернативы? Вы предлагаете делать свой велосипед? Так он будет наверняка кривее и наверняка больше.
К слову, в embedded компиляторах (точнее, линкерах) есть способы "обезжиривания" stdlib. Для gcc, который во флиппере, есть ключик
-specs=nano.specs
, который подключает меньшую библиотеку (особым образом собранная gcc'шная newlib, список отличий сейчас сходу не найду). Для IAR и Keil также есть отдельные переключатели в настройках проекта, которые указывают, какие библиотеки использовать.Кстати, @Andrey2008, вы в курсе, что не всякий embedded printf/scanf умеет все возможные опции форматирования? Если вы умеете вытягивать из среды настройки линкера, можно проверять ещё и это. Я один раз на это наступил (правда, там был самодельный sprintf, вы про такой точно не знаете :-) ).
Хорошая статья, спасибо. Разве что в примерах должн быть не робот, который катается по лесу, а тележка, которая ездит по одномерным рельсам.
Потому что в первом случае задача становится куда интереснее - из координат X/Y и скорости/курса с GPS и датчиков скорости с колёс (фактически, линейная скорость движения + угловая скорость поворота) надо получить координаты/скорость/курс. А оно внезапно многомерное и нелинейное. Такую задачку я решить не могу. Надо всё-таки плотно сесть, попробовать...
Возможно, тот, кто просмотрел первый ролик, и за 5 минут узнал только то, что фильтр Калмана - очень крутая штука, которая по неточным измерениям может давать хороший результат. Остальное смотрите в продолжении (ещё 54 серии в сезоне "фильтр Калмана").
Но минус не мой,@DirectXто в чём виноват? Господина van Biezen, собственно, тоже обвинять как-то странно.
Вспоминается давно забытое слово "мультипортовка". Судя по картинке и нагугленному даташиту, вместо "Any MCU" в левой части картинки надо читать "какой-то странный толстый процессор, у которого есть лишний PCIe, но нет нужного количества GPIO / UART / SPI / ...".
Он стоит пару баксов только потому, что оооочень массовый. Внутри он довольно продвинутый. И общаться с хостом он желает не по примитивным SPI/I2C/UART, а по PCI-Express, поддержку которого на STM32 никак не сделать...
Можно, правда, поискать Ethernet PHY c интерфейсом RMII. Его, правда, во флиппере тоже нет, но конфигурация такого чипа читается-пишется по отдельному интерфейсу MDIO, который, кажется, можно имитировать ногодрыгом. Насколько хорошо там реализована диагностика проблем с кабелем, я никогда не думал, но в каких-то чипах она заявлена.
Решение, честно скажу,
через заднивыглядит очень по-хакерски. Насколько в принципе оно работает, я не знаю (и работает ли вообще MDIO при мёртвом RMII). Я когда-то давно разбирался с MII, но мне надо было байтики в сеть передавать, а не вот этой диагностикой заниматься.Простите, а как в тёплую компанию РИА и Рамблера попал без пяти минут иноагент The Bell ?
На всякий случай сообщу, что ток измеряется в миллиамперах, а не в милливольтах (и вольт до появления power delivery там всегда было 5, плюс-минус отклонения китайских реализаций).
Термопринтер же жрёт при печати полсотни ватт, и питание от USB там никак не помогает - оно просто используется для определения факта подключения кабеля, потребление от USB - доли мА.
Ох, преданья старины глубокой...
На самом деле, можно просто сделать тупой протокол, который будет работать по success path (там парой страниц выше расписано), а потом, для обработки ошибок, просто начинать всё заново, если не удалось отправить (получить ack на команду). Главное, не отправлять команду, если пришёл на неё ack (вы же не хотели получить две одинаковые продажи? :-) ), остальное протокол со стороны железки нормально съест.
Про миллисекунды там тоже ничего не написано, совершенно лошадиные таймауты (минимум 0.5 сек). Я, правда, совершенно не в курсе работы с ком-портами под андроидом. Там совсем всё плохо, и к стандартным /dev/ttyXXX не пускают?
Что-то страшное вы рассказываете. Там довольно наркоманский протокол с кучей переподтверждений, но он как работал 20 лет назад на гробиках с двумя лентами на убогих 51 контроллерах, так и с минимальными изменениями работает на супер передовых онлайн кассах. Задержки там, соответственно, прокатывают +- километр.
Это не оптимизация, и с битмапами никак не связано. Это физика и кривые руки разработчика принтера. Штука в том, что тёмная точка на бумаге получается, если эту бумагу нагреть. Самый простой и быстрый способ печати - греть сразу все нужные точки в текущей печатаемой линии. Но если нужны сразу ВСЕ точки, происходит беда - на это банально не хватает электричества, печать становится бледной.
Решения: 1) считать чёрные точки, если их много, по некоей эмпирической формуле увеличивать время нагрева 2) делить область печати на несколько частей, печатать по-очереди 3) мерять напряжение и опять-таки увеличивать время при необходимости.
Правда, надо заметить, идеального результата у меня достигнуть не удалось...
Всем известно, что фискальные регистраторы делаются методом выкидывания из этой машинки всех мозгов, и заменой их на свои, с возможностью подключения внешней штуковины для сохранения чеков (Не знаю, как у вас в стране это устроено. Наверняка, как и у нас в РФ - память для чеков делается отдельной конторой, которая имеет особо близкое знакомство с законодателями и имеет кучку бумажек от заведения, занимающегося криптографией) и полностью своим протоколом.
Не совсем так. ЭКЛЗ могли сохранять весь чек. Но была "дырка" в законодательстве, что требовалось только совпадение итоговой суммы. Кроме того, памяти ЭКЛЗ довольно ограничена (при активной работе они заканчивались меньше чем за год, а замена стоила заметных денег), а интерфейса обмена касса-эклз весьма тормозной.
В итоге, все использовали только одну команду "покупка" на всю сумму сразу (касса при этом печатает "лишнюю" строчку с суммой перед строкой "итого"), а все остальные строки печатались обычным текстом, и ни в какие ЭКЛЗ не попадали.