Вход

Просмотр полной версии : Выставить биты данных на ШД Микроши в диапазоне 8000H-BFFFH



xintrea
10.05.2022, 21:01
Привет, народ.

Пробую я сделать "эмулятор ПЗУ" для Микроши на базе платы STM32 (STM32F103C8T6, она же BluePill). Но есть одна проблема: я в схемотехнике полный ноль.

Пока что у меня задача - научиться выставлять один повторяющийся байт во всех ячейках адресного диапазона 8000H-BFFFH.

Для этого я сделал схемку, которая втыкается в разъем "Внутренний интерфейс" (https://webhamster.ru/mytetrashare/index/mtb0/163621373041975uf2oz). От этого разъема к 5V-tolerance ножкам STM-ки напрямую подключены сигналы /32К, /RD и ШД. Подключал тупо напрямую, потому что так для экспериментов советовали вот в этой теме: https://zx-pk.ru/threads/34004-preobrazovatel-urovnej-5v-3v-na-shinu-dannykh.html?p=1140494#post1140494

STM-ка слушает два сигнала - /32К и /RD (они инверсные). Пока эти сигналы оба не равны физическому 0, STM-ка держит ноги, которые подключены к ШД Микроши, в режиме Input, чтобы не мешать работе компьютера. STM-ка работает на частоте 72MHz, и в ней сделан быстрый бесконечный цикл без всяких таймеров и прерываний. Как только в нем обнаруживается, что оба сигнала /32 и /RD стали равны физическому 0, STM-ка переключает ноги ШД в режим Output Push-Pull, и выставляет на них байт данных. Как только /32 и /RD оба не равны нулю, ноги возвращаются в Input-состояние.

И это дело даже работает. Как минимум, STM-ка не влияет на работу компьютера (а пока я не отладил цикл и режимы - очень даже влияла), а в диапазоне 8000H-BFFFH появляется байт данных. Но появляется он очень своеобразно:

Если выставить байт 00h - на шине будет 82h
Если выставить байт 01h - на шине будет 83h
Если выставить байт 02h - на шине будет 82h
Если выставить байт 03h - на шине будет 83h
Если выставить байт 04h - на шине будет 86h

Я даже могу объяснить, почему так происходит. Если к разъему "Внутренний интерфейс" ничего не подключать, и просмотреть диапазон 8000H-BFFFH, то в нем будет всегда считываться число 82h. На просторах интернета я нашел такую информацию "Если ничего не подключено, в Микроше по этим адресам считывается значение 82h. Это слово состояние (status word) процессора, выдаваемое им на шину данных в начале каждого машинного цикла". Откуда оно берется (сам процессор изнутри себя ставит на ШД в начале машинного цикла это значение?) - не совсем понятно. Но это значение действительно присутствует на ШД в диапазоне 8000H-BFFFH.

Когда STM-ка выставляет байт на ШД, он "подмешивается" к значению 82h. Там, где были единицы от числа 82h, они остаются. И к ним выставляются единицы, которые присутствуют в байте, генерируемым STM-кой. То есть, получается как бы логическое ИЛИ между числом 82h и байтом STM-ки.

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

Вот, и я не могу сообразить, как решить эту проблему. Я пробовал использовать на ножках ШД не режим Output Push-Pull, а Output OpenDrain, подавая инверсные биты на эти ножки (да и неинверсное значение тоже пробовал), но это не дало результата. Сейчас думаю попробовать соединить все ножки ШД с землей через резисторы в 10КОм, однако тоже не знаю, стоит ли действительно это делать.

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

HardWareMan
10.05.2022, 22:09
Откуда оно берется (сам процессор изнутри себя ставит на ШД в начале машинного цикла это значение?) - не совсем понятно.
Так точно, он выставляет слово для внешнего арбитра для выделения типа памяти. А остаётся оно из-за ёмкостей шины.
https://i.ibb.co/7WHVhvY/image.png
82H означает Memory Read, т.е. обычное чтение из обычной памяти.

xintrea
10.05.2022, 22:35
Так точно, он выставляет слово для внешнего арбитра для выделения типа памяти. А остаётся оно из-за ёмкостей шины. 82H означает Memory Read, т.е. обычное чтение из обычной памяти.

Благодарю, с 82h стало понятнее.

А что делать с выставлением байта на ШД STM-кой?

HardWareMan
11.05.2022, 07:51
Ну тут просто: юзай шифтер, Люк! Активный, двунаправленный. Что-то из SN74LVC8T245 / SN74LVC16T245.

xintrea
11.05.2022, 15:15
Ну тут просто: юзай шифтер, Люк! Активный, двунаправленный. Что-то из SN74LVC8T245 / SN74LVC16T245.

А отечественного аналога нет? Желательно в DIP-корпусе. Можно наверно даже без преобразований уровней, тупо ТТЛ.

UPD: Похоже, можно использовать 5572ИН1АУ, но это с ромбиком. Надыть понять, какой ОТК-шный аналог есть.

xintrea
12.05.2022, 10:28
И кстати, не понятно, чем нули, выставленные на ножках STM32 хуже тех нулей, которые будут выставлены на ножках микросхемы SN74LVC8T245 / SN74LVC16T245 ?

То есть, другими словами: почему микросхемы SN74LVC8T245 / SN74LVC16T245 будут нормально выставлять все биты на ШД, а STM32 может выставить только единички на ШД?

Я еще подумываю на STM32 выставлять для нулевых битов режим Open Drain вместо Push-Pull, может быть это поможет снять высокий потенциал на ШД, устанавливаемый Микрошей.

Serg6845
12.05.2022, 11:28
А отечественного аналога нет? Желательно в DIP-корпусе. Можно наверно даже без преобразований уровней, тупо ТТЛ.



555АП6 вполне прокатит. только надо не забыть добавить управление направлением и/или Z-состоянием, иначе он всю шину повесит. но что-то мне подсказывает что не в этом дело...

- - - Добавлено - - -


И кстати, не понятно, чем нули, выставленные на ножках STM32 хуже тех нулей, которые будут выставлены на ножках микросхемы SN74LVC8T245 / SN74LVC16T245 ?

надо осциллографом смотреть. либо конфликт на шине (тайминги), либо ножки STM по факту неправильно конфигурируются.


То есть, другими словами: почему микросхемы SN74LVC8T245 / SN74LVC16T245 будут нормально выставлять все биты на ШД, а STM32 может выставить только единички на ШД?

а 100% уверенности что с ними все будет нормально - нет.


Я еще подумываю на STM32 выставлять для нулевых битов режим Open Drain вместо Push-Pull, может быть это поможет снять высокий потенциал на ШД, устанавливаемый Микрошей.

разницы не вижу, физически в STM ножку тянуть вниз будет тот же самый транзистор.

xintrea
12.05.2022, 14:42
надо осциллографом смотреть. либо конфликт на шине (тайминги), либо ножки STM по факту неправильно конфигурируются.

Сейчас доступа к оборудованию нет, но в процессе ковыряния еще обнаружилась такая вещь: если отключить ШД Микроши от STM, и повесить щуп осциллографа на ножки STM, которые отвечают за ШД, то выставленная STM-кой единица выглядит как прямой фронт с последующим экспоненциальным спадом. Примерно так, как на приложенном рисунке. Вот только длительность спада до 0.5В не помню.

А когда ШД Микроши подключена, то эта единица тоже плавно убывает, но только до следующего изменения к 0 или 1, вызванного Микрошей.

https://zx-pk.ru/attachment.php?attachmentid=77311&d=1652353694

Serg6845
12.05.2022, 16:24
Сейчас доступа к оборудованию нет, но в процессе ковыряния еще обнаружилась такая вещь: если отключить ШД Микроши от STM, и повесить щуп осциллографа на ножки STM, которые отвечают за ШД, то выставленная STM-кой единица выглядит как прямой фронт с последующим экспоненциальным спадом. Примерно так, как на приложенном рисунке. Вот только длительность спада до 0.5В не помню.


значит надо разбираться с прошивкой STM. спад сигнала должен начинаться по окончании /RD (или /32к), а по картинке получается что ножка STM переводится в нужное состояние и затем сразу переводится на ввод. а длительность спада определяется емкостью проводов (щуп осциллографа и прочее).

HardWareMan
12.05.2022, 18:27
значит надо разбираться с прошивкой STM. спад сигнала должен начинаться по окончании /RD (или /32к), а по картинке получается что ножка STM переводится в нужное состояние и затем сразу переводится на ввод. а длительность спада определяется емкостью проводов (щуп осциллографа и прочее).
Нет, ему просто надо открыть вход осциллографа для начала. А уже потом думать.

xintrea
13.05.2022, 00:04
значит надо разбираться с прошивкой STM. спад сигнала должен начинаться по окончании /RD (или /32к), а по картинке получается что ножка STM переводится в нужное состояние и затем сразу переводится на ввод. а длительность спада определяется емкостью проводов (щуп осциллографа и прочее).

Вот, добрался до оборудования, сделал замер (извиняюсь за JPG, движок форума на лету из PNG конвертит). Напоминаю, что надо смотреть на место, где /RD и /32К в нуле.

1. Замер произведен на ножке STM, на которой выставляется 1. ШД Микроши отключена, то есть замер именно ножки микроконтроллера STM.

Желтый - /RD
Голубой - /32К
Синий - ножка STM

https://zx-pk.ru/attachment.php?attachmentid=77315&d=1652381620

Видно, что есть некоторое запаздывание появления сигнала на ножке, ибо код не оптимизировал. Но оно укладывается в диапазон когда на /RD еще 0. Видна "полочка" когда STM единичку удерживает. И Микроша этот сигнал считывает правильно. Но вот почему он так спадает - непонятно. И как с этим бороться (и нужно ли) тоже не могу понять.

2.А если добавить щуп на ШД Микроши (с STM ШД еще не соединена), и посмотреть что в этот момент происходит на стороне Микроши, то на фиолетовой линии видно, как Микроша в этот момент генерит единичку на D7 (потому что при 82H на D7 единица будет) и 0 на D6:

Единичка на D7:

https://zx-pk.ru/attachment.php?attachmentid=77318&d=1652384176

Ноль на D6:

https://zx-pk.ru/attachment.php?attachmentid=77319&d=1652384186


3.Далее я соединяю ШД Микроши и STM-ку. И вот какие "общие" сигналы получаю:

1 на STM - и 1 на Микроше:

https://zx-pk.ru/attachment.php?attachmentid=77320&d=1652388578

0 на STM - и 0 на Микроше:

https://zx-pk.ru/attachment.php?attachmentid=77321&d=1652388587

1 на STM - и 0 на Микроше - это устраивает, установка 1 на STM дает 1 на "общей" ШД:

https://zx-pk.ru/attachment.php?attachmentid=77322&d=1652388595

0 на STM - и 1 на Микроше - а вот это не устраивает, установка 0 на STM все равно оставляет 1 на "общей" ШД:

https://zx-pk.ru/attachment.php?attachmentid=77323&d=1652388604

Вот и нужно придумать, как сделать так чтобы 0 на STM давал 0 на "общей" ШД.

А так же я все равно не понимаю, чем 0 от STM хуже чем 0 от шинного преобразователя, который мне советуют.

- - - Добавлено - - -


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

Что значит "открыть вход осциллографа"?

HardWareMan
13.05.2022, 06:47
Что значит "открыть вход осциллографа"?
Инструкция пользования осциллографом (http://electrik.info/main/praktika/995-kak-polzovatsya-oscillografom.html), смотреть раздел "Открытый и закрытый вход". Переключатель режима у Rigol на картинке ниже.
https://i.ibb.co/zFjcj9B/image.png

- - - Добавлено - - -


А так же я все равно не понимаю, чем 0 от STM хуже чем 0 от шинного преобразователя, который мне советуют.

Выход шинного формирователя рассчитан на работу с шиной. Это значит, что его выход (когда активен) достаточно сильный и может эффективно перезаряжать ёмкость шины. В то же время у микроконтроллера никто не обещает такого функционала, т.к. выводы не рассчитаны на работу с большой шиной (а в случае с микрошей - ещё и длинной). Именно поэтому я и рекомендую развязать через буфер. И если направление только в одну сторону (от МК в ЛК) то можно использовать просто буфер/регистр с третим состоянием, типа 555АП6/555ИР22 и иже с ними.

Serg6845
13.05.2022, 10:09
Вот, добрался до оборудования, сделал замер

0 на STM - и 1 на Микроше - а вот это не устраивает, установка 0 на STM все равно оставляет 1 на "общей" ШД:
Вот и нужно придумать, как сделать так чтобы 0 на STM давал 0 на "общей" ШД.

вот здесь (обведено кружком) четко видно что STM вместо 0 выставляет на шину 1. почему так - вопрос к прошивке.

77324



А так же я все равно не понимаю, чем 0 от STM хуже чем 0 от шинного преобразователя, который мне советуют.


так как бы правильнее. и даже в данном случае возможно поможет скрыть явный баг в прошивке (который возможно сидит где-нибудь в стандартных библиотеках). но добавит гемор по управлению 3 состоянием этого самого буфера (или потребует дополнительной логики для управления).
с другой стороны - выходы у STM32 как бы не мощнее чем у АП6 будут...

- - - Добавлено - - -


Инструкция пользования осциллографом (http://electrik.info/main/praktika/995-kak-polzovatsya-oscillografom.html), смотреть раздел "Открытый и закрытый вход".

кстати ни разу не похоже на закрытый вход. во-первых постоянная времени не того порядка.
77325
(это я на закрытом входе подключил батарейку)

во-вторых - на спадах импульсов нет выбросов в минус.

HardWareMan
13.05.2022, 11:02
кстати ни разу не похоже на закрытый вход. во-первых постоянная времени не того порядка.
во-вторых - на спадах импульсов нет выбросов в минус.
Ну, вы можете продолжать есть кактус, это ваше право.

От себя добавлю, что вероятно вы на ножке включили PULL_DOWN а выход ваш не в PUSH_PULL.

TomaTLAB
13.05.2022, 15:40
Ну кактус ест не Serg6845, а xintrea. А во вторых, на скопшотах :) ТСа входы явно открытые.

- - - Добавлено - - -


- выходы у STM32 как бы не мощнее чем у АП6 будут...
Не сильно, но мощнее, зато симметричные ±25ма, против -15ма +24ма у АП6.

HardWareMan
13.05.2022, 18:14
Ну кактус ест не Serg6845, а xintrea.
Приношу свои извинения.

А во вторых, на скопшотах :) ТСа входы явно открытые.
С чего вы так решили? Явного указания я не вижу, а такие картинки я без проблем получал и при закрытом входе, когда выходы на сигналах с хорошим пуш-пуллом. Ему просто надо было захватить принтскрин с меню входа, как это сделал я и тогда бы вопроса не было от слова совсем. Запись перехода полностью соответствует закрытому входу, что было подтверждено через батарейку. Что касается якобы "не те масштабы" так я вам незамедлительно отвечу: кривая заряда/разряда конденсатора строго зависит от сопровождающих его сопротивлений.

TomaTLAB
13.05.2022, 21:18
принтскрин с меню входа, Зачем?
Основные настройки входов видно в нижней строчке.
У Вас закрыты входы №1, №2, №3, открыт №4. Чувствительность 0,5В; 2В; 0,2В; 1В соотв.
У ТСа все открыты с чувст. 2В/дел :)
Ну и маркер канала, он же ноль указывает? Будь вход закрыт он бы где то между нулем и единицей болтался. Вернее логический ноль съехал бы под маркер.

Что-то не то в прошивке СТМки, дури у нее должно хватать чтобы, как минимум, сигнал уполовинить, даже если его кто-то активно вверх тащит.

xintrea
14.05.2022, 01:04
вот здесь (обведено кружком) четко видно что STM вместо 0 выставляет на шину 1. почему так - вопрос к прошивке.

Я перепроверил именно то место что ты обвел кружком. Именно оно, кстати, и не дает мне двинуться дальше.

При разорванной ШД между STM и Микрошей:
- замеряю на стороне STM - ножка для D7 выдает 0, вообще ровная линия на 0В постоянно.
- замеряю на стороне Микроши на D7 - выдает 1 (старший бит от 82h).

При соединенной ШД картина именно такая, что ты обвел кружком. Но это не потому что STM ставит 1 из-за какой-то баги. STM, как было проверено, все время ставит 0.

А фишка в том, что тонкий провал на левой границе нарисованного тобой кружка - это как раз и есть момент, где STM ставит 0. Но он сразу же вытягивается до 1 потенциалом ШД Микроши.

Вот более широкая картинка этого места:

https://zx-pk.ru/attachment.php?attachmentid=77343&d=1652478638

Получается, что STM-ка в режиме Push-Pull не может толком притянуть к земле линию с общей ШД. Вроде как в теории, если на ШД было выставлено слово стостояния 82h, то оно хранится там к интересуещему нас моменту просто за счет емкости шины. И когда STM-ка поставила на шине 0, емкость должна была разрядиться (наверное). И до следующего машинного цикла на шине должен был остаться 0. Но происходит другое - сигнал почему-то снова вытягивается до 1.

Вот я и не могу понять причину такого явления.

tnt23
14.05.2022, 03:09
Проверьте настройки тока GPIO (оно же "быстродействие" пинов)

Serg6845
14.05.2022, 09:21
[QUOTE]Я перепроверил именно то место что ты обвел кружком. Именно оно, кстати, и не дает мне двинуться дальше.

При разорванной ШД между STM и Микрошей:
- замеряю на стороне STM - ножка для D7 выдает 0, вообще ровная линия на 0В постоянно.
- замеряю на стороне Микроши на D7 - выдает 1 (старший бит от 82h).

При соединенной ШД картина именно такая, что ты обвел кружком. Но это не потому что STM ставит 1 из-за какой-то баги. STM, как было проверено, все время ставит 0.

А фишка в том, что тонкий провал на левой границе нарисованного тобой кружка - это как раз и есть момент, где STM ставит 0. Но он сразу же вытягивается до 1 потенциалом ШД Микроши.



а выглядит оно так что именно STM ставит 1 - там дальше ровная полка с уровнем 3.3В.



Получается, что STM-ка в режиме Push-Pull не может толком притянуть к земле линию с общей ШД.


может и спокойно притягивает, и даже держит какое-то время. там где стрелка. а вот потом что-то идет не так...



Вот я и не могу понять причину такого явления.

предлагаю провести пару экспериментов.
1 - повторить замер с оторванной ШД, но притянуть D7 STM через 1кОм к 3.3В
2 - со стороны Микроши притянуть D7 к земле через 2кОм и к +5В через 3кОм, все соединить и повторить замер. там будет хорошо видно кто, когда и куда тянет шину.

а причин там может быть куча - начиная от "звона" на проводах, из-за чего STM думает что /RD уже закончился хотя это не так, или например выставление уровня на ножке через логическую операцию непосредственно над портом, или в прерывании что-то лишнее срабатывает... я не спец по STM, просто общие моменты...

HardWareMan
14.05.2022, 09:37
Зачем?
Основные настройки входов видно в нижней строчке.
У Вас закрыты входы №1, №2, №3, открыт №4. Чувствительность 0,5В; 2В; 0,2В; 1В соотв.
У ТСа все открыты с чувст. 2В/дел :)
Ну и маркер канала, он же ноль указывает? Будь вход закрыт он бы где то между нулем и единицей болтался. Вернее логический ноль съехал бы под маркер.
А, блин, точно. Эх, нужно в отпуск.


Что-то не то в прошивке СТМки, дури у нее должно хватать чтобы, как минимум, сигнал уполовинить, даже если его кто-то активно вверх тащит.
Так я и говорю, у него либо подтяжки либо скорость пина. Либо всё вместе.

xintrea
16.05.2022, 22:59
[QUOTE=xintrea;1153161]
предлагаю провести пару экспериментов.
1 - повторить замер с оторванной ШД, но притянуть D7 STM через 1кОм к 3.3В
2 - со стороны Микроши притянуть D7 к земле через 2кОм и к +5В через 3кОм, все соединить и повторить замер. там будет хорошо видно кто, когда и куда тянет шину.

Видимо, достаточно эксперимента 1. Отключил полностью ШД Микроши, подтянул D7 STM через 1кОм к 3.3В. И мерию на нем. Вот что получается:

https://zx-pk.ru/attachment.php?attachmentid=77347&d=1652729956

То есть, дело не в Микроше, а просто по какой-то причине не сохраняется 0 на ноге D7 дольше 100нс. Хотя по-хорошему, контроллер должен дождаться когда желтый и голубой сигнал перестанут быть одновременно 0, и с некоторой задержкой перестать удерживать 0 на ноге D7.

А тут складывается впечатление, что контроллер увидел желтый и голубой в нуле, выставил 0 на ноге D7, и думает что там 0 так и держится. А этот 0 за 100нс притянулся к 3.3V.

tnt23
16.05.2022, 23:13
xintrea, покажите конфигурацию GPIO. Можно в виде исходников, можно скриншотом из CubeMX.

Ведущий_специалист
25.05.2022, 14:39
Подключал как то stm к рк86, проблемы такой не было, была другая проблема, стм банально не успевал войти в прерывание по сигналам RD или WR. Пропуская обращение и получалась каша. А так - да, коллеги выше правильно подсказали - неправильно настроены порты микроконтроллера.

xintrea
28.05.2022, 01:35
xintrea, покажите конфигурацию GPIO. Можно в виде исходников, можно скриншотом из CubeMX.

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


Исходники можно взять здесь: https://github.com/xintrea/mikroshamem
(На всякий случай, здесь идет речь о коммите aed203fd684d2adade93fdf8efbb0ae2e138d670, который актуален на момент написания данного сообщения)


По сути, проект написан с использование CMSIS, в нем всего два файла на Си и один заголовочный (в каталоге /src, естественно).

Сейчас код в таком состоянии, что в нем есть только инициализация перифирии и бесконечный цикл. В бесконечном цикле сделано ожидание чтобы сигналы /32К и /RD (ножки A10 и A11 на STM) одновременно были в физическом 0. Если не так, то ШД на B8-B15 находится в состоянии Input, чтобы не мешать работе Микроши. Если оба сигнала в 0, то ШД на B8-B15 переключается на выход в классическом режиме Push-Pull, и на ШД выставляется байт 0x00.

Для эксперимента, нога старшего разряда (B15) притянута к 3.3V через резистор 1кОм, а ШД Микроши отключена полностью. Это притягивание как-бы эмулирует единицу, которая "остается" от слова состояния 82H когда Микроша подключена к STM.

Так вот, в этом эксперименте картина абсолюто та же самая, что и на последнем скриншоте (https://zx-pk.ru/attachment.php?attachmentid=77347&d=1652729956). STM-ка почему-то притягивает к нулю B15 всего на ~120нс и сразу отпускает, даже не дождавшись, когда хотя бы один сигнал /32К или /RD перестанет быть равен 0. Хотя по алгоритму в коде этого не должно быть.

И самое главное: если в коде раскомментировать строчку 146, в которой написана единственная команда:



// GPIOA->BSRR = (1<<GPIO_BSRR_BS0_Pos); // Светодиод включается


... то длительность притягивания B15 к 0 сильно удлинняется, и можно сказать что становится правильной! А эта строчка всего-навсего устанавливает 1 на ноге A0, которая никакого отношения к делу не имеет! Причем на ноге A0 никаких переключений нет, она как в первый раз установилась в 1 так и переставляется все время на 1 этой строчкой.


На скриншоте:
Желтый - /RD
Голубой - /32К
Синий - ножка B15 STM (с подтяжкой к 3.3V через 1кОм)

https://zx-pk.ru/attachment.php?attachmentid=77391&d=1653690426


Если быть точным, то при раскомментировании строчки установки 1 на A0, длительность притягивания B15 к 0 все же длинновата, по-хорошему возврат в 1 должен начаться спустя не более ~150-280нс после восходящего фронта желтой линии. Установка 1 для A0 должна занимать не более 30нс, я это проверял на ногодрыге. Детектирование состяния /32К или /RD занимает, как мы видим, 120-250нс. Поэтому возврат к 1 должен начинаться спустя ~150-280нс от восходящего желтого фронта. А он начинает восходить к 1 спустя 500нс. Это странно.

Возможно, у меня ошибка в коде, но я ее не вижу. Буду рад, если кто-нибудь ткнет носом где в коде проблема.

- - - Добавлено - - -


была другая проблема, стм банально не успевал войти в прерывание по сигналам RD или WR. Пропуская обращение и получалась каша. А так - да, коллеги выше правильно подсказали - неправильно настроены порты микроконтроллера.

Поэтому я сразу отказался от прерываний. В моем коде просто бесконечный цикл.

HardWareMan
28.05.2022, 07:47
Детектирование состяния /32К или /RD занимает, как мы видим, 120-250нс. Поэтому возврат к 1 должен начинаться спустя ~150-280нс от восходящего желтого фронта. А он начинает восходить к 1 спустя 500нс. Это странно.
Ууу.... А теперь посмотрите, что там вам накуралесил Ц в ассемблере и посчитайте, сколько команд у вас уходит на то-сё просто так. У вас ODR может быть уже в нуле, тогда данные пойдут вниз уже при установке режима. А то, что находится за пределами условия выбора режима - вы не увидите. Попробуйте инициализировать ODR как 0xFFFF при дезактивации и увидете интересное, а именно - настоящую задержку от детекта до реакции на шину. Это раз. Приведу пример из моего проекта SuperDumper (https://github.com/HardWrMan/SuperDumperFW). Проблема была в том, что 6502 в NES RISC и он долбит шину каждый такт. А этим фактом пользуются мапперы: так как на слоту нет сигнала сброса, то там простой RCD цепочкой детектируют наличие этих импульсов на стробе шины. Поэтому, сдампить такие картриджи без постоянной частоты на ноге F2 нельзя, от чего у людей с дамперами на AVR есть проблемы. Я же включаю таймер на генерацию частоты, тут требуется около 1,7МГц (~588нс период, ~290нс каждый уровень). А так как этот сигнал однозначно используется для упправления шиной данных картриджем, то требуется синхронизация. Я сделал вот так (src/dumper/dendy.c):

// Чтение данных PRG в буфер
__attribute__ ((naked)) void Read_PRG( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{ // Начинаем
__asm volatile
( "PUSH {R0-R8}\n"
// R0 = PBuf
// R1 = Start
// R2 = Size
// R3 = GPIOA_IDR (Для чтения F2)
"MOVW R3, #0x0010\n"
"MOVT R3, #0x4002\n"
// R4 = GPIOE_ODR (Для вывода адреса)
"MOVW R4, #0x1014\n"
"MOVT R4, #0x4002\n"
// R5 = GPIOD_IDR (Для ввода данных)
"MOVW R5, #0x0C10\n"
"MOVT R5, #0x4002\n"
// R6 = Маска $0000FFFF
"MOVW R6, #0xFFFF\n"
"MOVT R6, #0x0000\n"
// Выделим
"AND R1, R1, R6, LSL #0\n"
"AND R2, R2, R6, LSL #0\n"
// Синхронизируемся
"CPSID f\n"
"Read_PRG_Syn0:\n"
"LDR R7, [R3, #0]\n"
"ANDS R7, R7, #1\n"
"IT EQ\n"
"BEQ Read_PRG_Syn0\n"
"Read_PRG_Syn1:\n"
"LDR R7, [R3, #0]\n"
"ANDS R7, R7, #1\n"
"IT NE\n"
"BNE Read_PRG_Syn1\n"
// Цикл чтения
"Read_PRG_Loop:\n"
// Выставляем адрес
"STR R1, [R4, #0]\n"
// Ждем F2 = 1
"Read_PRG_LWt0:\n"
"LDR R7, [R3, #0]\n"
"ANDS R7, R7, #1\n"
"IT EQ\n"
"BEQ Read_PRG_LWt0\n"
// Увеличиваем адрес чтения
"ADD R1, R1, #1\n"
// Ждем F2 = 0
"Read_PRG_LWt1:\n"
"LDR R8, [R5, #0]\n"
"LDR R7, [R3, #0]\n"
"ANDS R7, R7, #1\n"
"IT NE\n"
"BNE Read_PRG_LWt1\n"
// Сохраняем данные
"AND R8, R8, #0x00FF\n"
"STRB R8, [R0, #0]\n"
// Следующий байт
"ADDS R0, R0, #1\n"
// Счетчик байт
"SUB R2, R2, #1\n"
"ANDS R2, R2, R6, LSL #0\n"
"IT NE\n"
"BNE Read_PRG_Loop\n"
"CPSIE f\n"
// Обнулим адрес
"MOVW R6, #0x0000\n"
"STR R6, [R4, #0]\n"
"POP {R0-R8}\n"
"BX LR\n"
);
}
Сама синхронизация происходит у меток Read_PRG_LWt0 и Read_PRG_LWt1. И CortexM4 с его 168МГц работает прям таки туго, настолько, что даже приходится выключать глобальные прерывания: CPSID f. Но даже тут мне всё же удалось "спрятать" часть команд внутри ожидания полупериода. А у тебя Ц, прерывания (всё тот же SysTick) и 72МГц.

xintrea
29.05.2022, 13:12
посмотрите, что там вам накуралесил Ц в ассемблере и посчитайте, сколько команд у вас уходит на то-сё просто так. У вас ODR может быть уже в нуле, тогда данные пойдут вниз уже при установке режима. А то, что находится за пределами условия выбора режима - вы не увидите. Попробуйте инициализировать ODR как 0xFFFF при дезактивации и увидете интересное, а именно - настоящую задержку от детекта до реакции на шину.

Все нормально накуралесил Си, ничего лишнего нет.

Сейчас ситуация такая. В эксперименте-1 (как было уже показано), нога STM-ки притянута к 3.3V через 1кОм, и STM-ка устанавливает на ней 0 когда /32К и /RD в нуле. И длительность такого притягивания слишком короткая, и мы так и не выяснили почему (синяя линия):

https://zx-pk.ru/attachment.php?attachmentid=77347&d=1652729956

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

Поэтому я придумал "зеркальный" эксперимент-2. Я ничего не меняю в коде, то есть не добавляю команды включения светодиода, ничего. Я всего-навсего меняю устанавливаемый байт с 0x00 на 0xFF. И чтобы увидеть единицу на старшем разряде, теперь наоборот, притягиваю к нулю через 1кОм ножку STM-ки. По-сути ничего не поменялось. Но длительность все равно увеличилась очень сильно:

https://zx-pk.ru/attachment.php?attachmentid=77394&d=1653817310

Вот так.

Я подозревал, что присвоение byte=0x00 может быть оптимизировано во что-то типа XOR r1,r1 вместо MOV r1,0, а выставление byte=0xFF так не заоптимизируется. И это видно в дизассемблере: переменная byte хранится в r2, и для заполнения нулем этот регистр вообще не трогается, так как, видимо, он уже содержит 0. А для заполнения 0xFF используется четырехбайтовая команда orn r2, r2, 255. Вот и все различие - одна команда без обращения к памяти, все данные в опкоде.

Вот diff ассемблера: https://i.ibb.co/KmbCnPj/2022-05-29-13-07-43.png

Пускай эта инструкция выполняется 2 такта. Это значит ее длительность 2*(1/72 000 000) = 27нс. А удержание единицы, судя по графикам, удлинняется на 500 нс. Разница в 20 раз. Откуда такая разница?

HardWareMan
29.05.2022, 13:40
Т.е., прерывания продолжают стрелять, ок. А RCC гарантированно настроен правильно?

tnt23
29.05.2022, 13:44
Еще важно, какие оптимизации включены при компиляции (ключи -o в GCC, например).

xintrea
29.05.2022, 15:43
Т.е., прерывания продолжают стрелять, ок. А RCC гарантированно настроен правильно?

Ты код смотрел? Нет там никаких прерываний. В новой версии (еще не заливал) я даже добавил при инициализации, как у тебя:


int main(void)
{
clockInit();
portClockInit();
disableGlobalInterrupt();
...
}

// Остановка глобальных прерываний
void disableGlobalInterrupt(void)
{
__asm volatile (
"CPSID f\n"
);
}

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

И еще я провел два чистых эксперимента. Решил, что коль установка 0x00 оптимизируется, то надо сделать две вещи:


Собрать весь проект с -O0,
Устанавливать в первом случае 0x0F вместо 0x00 (все равно мы мониторим старший бит, и при 0x0F в нем так же будет 0), чтобы не срабатывала оптимизация установки 0x00.

Так я и сделал. Сборка с 0x0F и 0xFF стали отличаться только в единственном месте, вот так:


< 80004b2: b292 uxth r2, r2
< 80004b4: f442 6270 orr.w r2, r2, #3840 ; 0xf00
---
> 80004b2: f062 02ff orn r2, r2, #255 ; 0xff
> 80004b6: b292 uxth r2, r2

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


Странная конструкция orr.w r2, r2, #3840; 0xf00 действительно дает 0x0F, можно сравнить с таким примером:


LCD_DATA_PORT->BSRR=0x00FF0000 | (sColor&0x00FF);
0x08000bbe: orr.w r7, r7, #16711680 ; 0xff0000

Так что показали эти два чистых эксперимента? Да то же самое. Установка с 1 на 0 дает "провал" в ~120нс. Установка с 0 на 1 дает "полочку" в ~700нс. Объяснить почему так я своим скудным умишком не могу.

Ну и самый первый вопрос остался: почему установка с 1 на 0 такая короткая? По алгоритму отпускание удерживания нуля не может начаться раньше, чем желтая линия вернется к единице. Вначале STM должен увидеть, что /32К или /RD не 0, и только после этого отпустить удерживать 0. А на деле этого не происходит. И почему так - тоже не ясно.

- - - Добавлено - - -


Еще важно, какие оптимизации включены при компиляции (ключи -o в GCC, например).
Выше написал, сделал проверку с -O0.

tnt23
29.05.2022, 19:46
if(workAddrDiapason!=0) // Если сигналы /32К и /RD физически не установлены в 0

Мне думается, что тут не "и", а "или" (хотя бы один из /32K или /RD не установлен)

HardWareMan
29.05.2022, 21:58
if(workAddrDiapason!=0) // Если сигналы /32К и /RD физически не установлены в 0

Мне думается, что тут не "и", а "или" (хотя бы один из /32K или /RD не установлен)

У него перед этим стоит это:

uint32_t workAddrDiapason = GPIOA->IDR & (GPIO_IDR_IDR10_Msk | GPIO_IDR_IDR11_Msk)
И 0 там будет только если оба в нуле будут. А условие выше срабатывает на 1 для отключения шины, иначе включает и эта ветка после else.

xintrea
30.05.2022, 09:23
И 0 там будет только если оба в нуле будут. А условие выше срабатывает на 1 для отключения шины, иначе включает и эта ветка после else.

Да, именно так. В if-ветке обрабатывается ситуация когда не оба в нуле, там режим ножки выставляется как input чтобы не влиять этой ножкой на подключаемую схему. В else-ветке включается режим выхода и выставляется нужное значение на ножке (в эксперименте-1 выставляю 0, в эксперименте-2 выставляю 1).

Для варианта выставления нуля (эксперимент-1), этот ноль выставляется на слишком короткое время. Ноль должен удерживаться как минимум до момента восходящего фронта на желтой линии. После этого еще нужно время чтобы STM-ка поняла, что не оба сигнала в нуле, и только после этого перестать удерживать ноль. А по графику мы видим, что ноль перестает удерживаться гораздо раньше. И почему так происходит, я не могу понять.

tnt23
30.05.2022, 14:09
Еще из мыслей навскидку - не доверяю локальным переменным с областью видимости в пределах ветки цикла. Попробуйте вынести объявление переменной повыше, или вообще сделайте ее статической/volatile.

uint32_t workAddrDiapason

xintrea
30.05.2022, 16:15
Еще из мыслей навскидку - не доверяю локальным переменным с областью видимости в пределах ветки цикла.

Новое слово в программировании? :) Нельзя же так к алгоритмизации относиться.

Но! Я проверю, я готов поверить в любую дичь.

Serg6845
30.05.2022, 21:52
Новое слово в программировании? :) Нельзя же так к алгоритмизации относиться.

Но! Я проверю, я готов поверить в любую дичь.

надо брать листинг того что нагенерил компилятор и вникать. возможно просто бага компилятора.
и еще - я бы для проверки перенес кусок кода со 165 по 181 строки в район 145 строки. чем-то мне этот кусок подсознательно не нравится...

tnt23
31.05.2022, 17:40
Новое слово в программировании? Нельзя же так к алгоритмизации относиться.

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