Комментарии 30
Читается как детектив! Спасибо!
DMA надо использовать. Благо на чипах STM этого добра навалом.
А IRQ я откуда возьму?
Я не припомню, чтобы там был такой реквест.
Я не припомню, чтобы там был такой реквест.
Я полистал ref man, действительно в лоб не очень получается, но можно с использованием ETR одного из таймеров.
Ага, я думал о том, чтобы использовать таймерные кэпчур фичи, но т.к. при реальной работе придется все декодить адрес и режим доступа, и в соответствии с ними брать/класть значение в память, ДМА уже не поможет, поэтому я решил его не трогать.
Вот с SDшки в буфер читать им — это да, одно удовольствие.
Вот с SDшки в буфер читать им — это да, одно удовольствие.
Современный 72МГц ARM не может совладать с архаичной 8МГц шиной. Чем же он занимается все это время? )
Можно подробнее описать куда такты тратятся? Т.е. 12 на вход в обработчик прерывания, а сколько на чтение порта?
Можно подробнее описать куда такты тратятся? Т.е. 12 на вход в обработчик прерывания, а сколько на чтение порта?
Судя по осциллограмме — далеко не 12.
На осциллограмме я так понимаю там еще некоторое количество тактов затратилось на выставление уровня на ножке, т.е. войти в прерывание он вошел раньше чем мы увидели? Или ноги быстро дрыгаются?
Уж очень какой-то он неторопливый этот STM ))
Уж очень какой-то он неторопливый этот STM ))
Да, на выставление безусловно затратилось, но куда меньше, чем на вход в интеррапт.
Вот это дает 20 МГц на ноге, 50 нс задержку. То есть на то, чтобы выставить уровень выходит 25 нс, около двух тактов.
Основное время занимает именно заход в этот интеррапт, и я не очень понимаю, почему — согласно документации он должен занимать 12 тактов + два такта на выставление уровня — 350 нс примерно. А занимает это все больше 500 нс.
GPIOB->BSRR=GPIO_Pin_2;
GPIOB->BRR=GPIO_Pin_2;
GPIOB->BSRR=GPIO_Pin_2;
GPIOB->BRR=GPIO_Pin_2;
GPIOB->BSRR=GPIO_Pin_2;
Вот это дает 20 МГц на ноге, 50 нс задержку. То есть на то, чтобы выставить уровень выходит 25 нс, около двух тактов.
Основное время занимает именно заход в этот интеррапт, и я не очень понимаю, почему — согласно документации он должен занимать 12 тактов + два такта на выставление уровня — 350 нс примерно. А занимает это все больше 500 нс.
Потрясающе. Только что вот решил для эксперимента поменять уровень оптимизации. Результат превзошел все ожидания — при оптимизации О1 вместо О3 система работает ровно так, как я и рассчитывал — 350 нс на вход и выставление пина. На О2 хуже, на О3 вообще ужасно.
Программа написана на С, а не на асме, да еще и с использованием Standard Peripheral Library. В результате там в ассемблерном коде адЪ и iзралилЪ. Не следует удивляться.
Нет, в интеррапте никакой SPL, вы же видите код.
Вот весь код интеррапта. Сейчас сниму осциллограммы со всеми уровнями оптимизации, выложу.
P.S.
Да, EXTI_ClearITPendingBit — это из SPL, но это уже после выставления флага, то есть на фронт не должно влиять.
Хотя, кстати, надо проверить — может оптимизатор пытается как раз этот вызов как-то переместить…
void __attribute((naked))EXTI0_IRQHandler()
{
GPIOB->BSRR=GPIO_Pin_2;
Log[ptr]=GPIOD->IDR;
ptr++;
EXTI_ClearITPendingBit(EXTI_Line0);
GPIOB->BRR=GPIO_Pin_2;
}
Вот весь код интеррапта. Сейчас сниму осциллограммы со всеми уровнями оптимизации, выложу.
P.S.
Да, EXTI_ClearITPendingBit — это из SPL, но это уже после выставления флага, то есть на фронт не должно влиять.
Хотя, кстати, надо проверить — может оптимизатор пытается как раз этот вызов как-то переместить…
Если посмотреть на асм-код вот этого:
GPIOB->BSRR=GPIO_Pin_2;
Log[ptr]=GPIOD->IDR;
наверняка можно узнать много нового для себя :)Это не объясняет, почему O3 дает худшие результаты, чем O1.
В O1 вполне все прозрачно,
В O3 компиллер местами меняет многие операции, видимо, пытаясь получить какой-то выигрыш, но на деле это наоборот сильно ударяет по производительности.
В O1 вполне все прозрачно,
0x08000390: ldr r3, [pc, #36]
0x08000392: mov.w r2, #4
0x08000396: str r2, [r3, #16]
В O3 компиллер местами меняет многие операции, видимо, пытаясь получить какой-то выигрыш, но на деле это наоборот сильно ударяет по производительности.
Ага, все, разобрался.
Не быстрее с O1, просто при O2, O3 компиллер начинает переставлять инструкции местами, и пин выставляется в 1 уже после того, как часть кода выполнилась. Поэтому если посмотреть на полную осциллограмму, то видно, что с О1 входит раньше (первой инструкцией реально выставляет 1), но зато выполняется дольше.
Жаль, кейл не установлен, интересно посмотреть, какой результат был бы с его компиллером.
Не быстрее с O1, просто при O2, O3 компиллер начинает переставлять инструкции местами, и пин выставляется в 1 уже после того, как часть кода выполнилась. Поэтому если посмотреть на полную осциллограмму, то видно, что с О1 входит раньше (первой инструкцией реально выставляет 1), но зато выполняется дольше.
Жаль, кейл не установлен, интересно посмотреть, какой результат был бы с его компиллером.
Кстати, а скорость ножек 50МГц, это же только когда ноги на выход работают, читать то их можно с любой скоростью? Или там в принципе получается что узкое место как раз эти 50МГц на ногах?
Познавательно и интересно.
Есть еще какие-то дальнейшие наработки? Когда ожидать продолжения?
В идеале хотелось бы, конечно, сделать эмулятор жесткого диска, работающий с SD-карточкой, но к этой цели будем идти постепенно.
Есть еще какие-то дальнейшие наработки? Когда ожидать продолжения?
Я бы в первую очередь посмотрел в сторону использования CompactFlash. Но тогда этого топика могло бы и не быть (:
Благодаря этому существуют переходники IDE-CF.
CompactFlash IDE mode defines an interface that is smaller than, but electrically identical to, the ATA interface. The CF device contains an ATA controller and appears to the host device as if it were a hard disk.
Благодаря этому существуют переходники IDE-CF.
> Потом подает команду 0x10, значение которой я так и не нашел
Recalibrate, сейчас это deprecated уже.
Recalibrate, сейчас это deprecated уже.
5.4.12 Recalibrate command
This command (command code 1xH, where xcan by any value from 0H
to FH) moves the read/write heads from anywhere on the disc to cylinder
0. Upon receipt of the command, the drive sets BSY and issues a seek
to cylinder zero. The drive then waits for the seek to complete before
updating status, clearing BSY and generating an interrupt.
If the drive cannot reach cylinder 0, a Track Not Found error is posted.
Drives with Power Managementfacilities that are in a low power state
when this command is received may signal completion of this command
without leaving the low power state.
Спасибо, испытал ностальгию. :) Хочу добавить, что в мою бытность радиолюбителя в наших журналах декодер называли дешифратором, а процесс получения сигнала CS — дешифрированием. Сам узел, формирующий CS из сигналов шины адреса и шины управления — дешифратором.
А ещё вы забыли при дешифрировании использовать сигнал AEN. Он активируется в процессе прямого доступа к памяти (DMA), который также использует линию IOR, при этом не обращаясь к портам. Если данный сигнал не учесть, у вас в регистрах могут (хотя и не обязательно) иногда появляться случайные данные.
А ещё вы забыли при дешифрировании использовать сигнал AEN. Он активируется в процессе прямого доступа к памяти (DMA), который также использует линию IOR, при этом не обращаясь к портам. Если данный сигнал не учесть, у вас в регистрах могут (хотя и не обязательно) иногда появляться случайные данные.
Отличная статья. Сам системный программист поэтому как сказал человек в первом комментарии — прочитал на одном дыхании.
Как жаль, что нашел статью только сейчас, искал информацию на эту тему. Очень интересно читать.
Только вот мучает вопрос — почему бы не снять данные сразу со шлейфа IDE?
Только вот мучает вопрос — почему бы не снять данные сразу со шлейфа IDE?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Трясем стариной: перехват потока данных между i386 и контроллером ATA средствами STM32