[QUOTE=Serg6845;1153169]Видимо, достаточно эксперимента 1. Отключил полностью ШД Микроши, подтянул D7 STM через 1кОм к 3.3В. И мерию на нем. Вот что получается:
То есть, дело не в Микроше, а просто по какой-то причине не сохраняется 0 на ноге D7 дольше 100нс. Хотя по-хорошему, контроллер должен дождаться когда желтый и голубой сигнал перестанут быть одновременно 0, и с некоторой задержкой перестать удерживать 0 на ноге D7.
А тут складывается впечатление, что контроллер увидел желтый и голубой в нуле, выставил 0 на ноге D7, и думает что там 0 так и держится. А этот 0 за 100нс притянулся к 3.3V.
Любопытный хомячок webhamster.ru - маленький и пушистый IT-проект
xintrea, покажите конфигурацию GPIO. Можно в виде исходников, можно скриншотом из CubeMX.
Подключал как то stm к рк86, проблемы такой не было, была другая проблема, стм банально не успевал войти в прерывание по сигналам RD или WR. Пропуская обращение и получалась каша. А так - да, коллеги выше правильно подсказали - неправильно настроены порты микроконтроллера.
Здравствуйте. Выкроилось свободное время, продолжаю.
Исходники можно взять здесь: 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.
Так вот, в этом эксперименте картина абсолюто та же самая, что и на последнем скриншоте. 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кОм)
Если быть точным, то при раскомментировании строчки установки 1 на A0, длительность притягивания B15 к 0 все же длинновата, по-хорошему возврат в 1 должен начаться спустя не более ~150-280нс после восходящего фронта желтой линии. Установка 1 для A0 должна занимать не более 30нс, я это проверял на ногодрыге. Детектирование состяния /32К или /RD занимает, как мы видим, 120-250нс. Поэтому возврат к 1 должен начинаться спустя ~150-280нс от восходящего желтого фронта. А он начинает восходить к 1 спустя 500нс. Это странно.
Возможно, у меня ошибка в коде, но я ее не вижу. Буду рад, если кто-нибудь ткнет носом где в коде проблема.
- - - Добавлено - - -
Поэтому я сразу отказался от прерываний. В моем коде просто бесконечный цикл.
Последний раз редактировалось xintrea; 28.05.2022 в 01:38.
Любопытный хомячок webhamster.ru - маленький и пушистый IT-проект
Ууу.... А теперь посмотрите, что там вам накуралесил Ц в ассемблере и посчитайте, сколько команд у вас уходит на то-сё просто так. У вас ODR может быть уже в нуле, тогда данные пойдут вниз уже при установке режима. А то, что находится за пределами условия выбора режима - вы не увидите. Попробуйте инициализировать ODR как 0xFFFF при дезактивации и увидете интересное, а именно - настоящую задержку от детекта до реакции на шину. Это раз. Приведу пример из моего проекта SuperDumper. Проблема была в том, что 6502 в NES RISC и он долбит шину каждый такт. А этим фактом пользуются мапперы: так как на слоту нет сигнала сброса, то там простой RCD цепочкой детектируют наличие этих импульсов на стробе шины. Поэтому, сдампить такие картриджи без постоянной частоты на ноге F2 нельзя, от чего у людей с дамперами на AVR есть проблемы. Я же включаю таймер на генерацию частоты, тут требуется около 1,7МГц (~588нс период, ~290нс каждый уровень). А так как этот сигнал однозначно используется для упправления шиной данных картриджем, то требуется синхронизация. Я сделал вот так (src/dumper/dendy.c):
Сама синхронизация происходит у меток Read_PRG_LWt0 и Read_PRG_LWt1. И CortexM4 с его 168МГц работает прям таки туго, настолько, что даже приходится выключать глобальные прерывания: CPSID f. Но даже тут мне всё же удалось "спрятать" часть команд внутри ожидания полупериода. А у тебя Ц, прерывания (всё тот же SysTick) и 72МГц.Код:// Чтение данных 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" ); }
Все нормально накуралесил Си, ничего лишнего нет.
Сейчас ситуация такая. В эксперименте-1 (как было уже показано), нога STM-ки притянута к 3.3V через 1кОм, и STM-ка устанавливает на ней 0 когда /32К и /RD в нуле. И длительность такого притягивания слишком короткая, и мы так и не выяснили почему (синяя линия):
Единственное, что заметили, что этот сигнал становится длиннее, если включать уже включенный светодиод на совершенно другой ножке. Но такой подход вносит некоторые лишние команды, и не подходит для понимания того, почему сигнал короткий.
Поэтому я придумал "зеркальный" эксперимент-2. Я ничего не меняю в коде, то есть не добавляю команды включения светодиода, ничего. Я всего-навсего меняю устанавливаемый байт с 0x00 на 0xFF. И чтобы увидеть единицу на старшем разряде, теперь наоборот, притягиваю к нулю через 1кОм ножку STM-ки. По-сути ничего не поменялось. Но длительность все равно увеличилась очень сильно:
Вот так.
Я подозревал, что присвоение 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 раз. Откуда такая разница?
Любопытный хомячок webhamster.ru - маленький и пушистый IT-проект
Т.е., прерывания продолжают стрелять, ок. А RCC гарантированно настроен правильно?
Еще важно, какие оптимизации включены при компиляции (ключи -o в GCC, например).
Ты код смотрел? Нет там никаких прерываний. В новой версии (еще не заливал) я даже добавил при инициализации, как у тебя:
Не знаю, достаточно ли этого. И еще не знаю, останавливаются ли таким способом все глобальные прерывания во всем последующем коде, или только в коде функции disableGlobalInterrupt(), а при выходе из нее опять восстанавливаются (слишком сложный STM для меня), просвяти.Код:int main(void) { clockInit(); portClockInit(); disableGlobalInterrupt(); ... } // Остановка глобальных прерываний void disableGlobalInterrupt(void) { __asm volatile ( "CPSID f\n" ); }
И еще я провел два чистых эксперимента. Решил, что коль установка 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, можно сравнить с таким примером:Так что показали эти два чистых эксперимента? Да то же самое. Установка с 1 на 0 дает "провал" в ~120нс. Установка с 0 на 1 дает "полочку" в ~700нс. Объяснить почему так я своим скудным умишком не могу.
Код:LCD_DATA_PORT->BSRR=0x00FF0000 | (sColor&0x00FF); 0x08000bbe: orr.w r7, r7, #16711680 ; 0xff0000
Ну и самый первый вопрос остался: почему установка с 1 на 0 такая короткая? По алгоритму отпускание удерживания нуля не может начаться раньше, чем желтая линия вернется к единице. Вначале STM должен увидеть, что /32К или /RD не 0, и только после этого отпустить удерживать 0. А на деле этого не происходит. И почему так - тоже не ясно.
- - - Добавлено - - -
Выше написал, сделал проверку с -O0.
Любопытный хомячок webhamster.ru - маленький и пушистый IT-проект
Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)