HardWareMan 10 June 3 Posted June 3 · Report post 57 minutes ago, jcxz said: Не понимаю - чего вы пытаетесь доказать всеми этими намалёванными красными линиями? Тем более теми, на которых показаны шины к AHB-периферии? Где в теме речь шла об AHB-периферии? Букварь вы может и читали, но похоже - не поняли его.... Успокойтесь уже - вопрос уже решён. Я предельно спокоен. APB сидит на AHB через мост. И на схеме видно, что у DMA1 нет пересечения с AHB периферии (отсутствует точка) а вторая шина подключена эксклюзивно к APB1. В то время как у DMA2 есть эти пересечения на обоих шинах, даже на выделенной связи с APB2. Это картинка про отношения шин. Всех шин. А вы так и не поняли этого посыла. Печально. То, что вопрос решён я видел, просто хотел дополнить ваш ответ о найденной причине... Quote Share this post Link to post Share on other sites More sharing options...
x893 76 June 3 Posted June 3 · Report post 21 minutes ago, HardWareMan said: просто хотел дополнить ваш ответ о найденной причине... Зачем ? Quote Share this post Link to post Share on other sites More sharing options...
HardWareMan 10 June 3 Posted June 3 · Report post 49 minutes ago, x893 said: Зачем ? Потому что утверждение Quote Странно, что говорит об этом только картинка (Figure 23 RM) не совсем верное. Ну да ладно, всем пофиг же, да? Quote Share this post Link to post Share on other sites More sharing options...
x893 76 June 3 Posted June 3 · Report post 9 minutes ago, HardWareMan said: Потому что утверждение Забейте Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 278 June 4 Posted June 4 · Report post @jcxz, Вы на макетке отлаживаете? Просто интересно, как Вы так лихо вывод таймера заменили. Вспомнил тут, как сравнительно давно тоже делал похожий алгоритм, но промахнулся с распределением ресурсов и идея не взлетела. Quote Share this post Link to post Share on other sites More sharing options...
amaora 29 June 4 Posted June 4 (edited) · Report post Вместо выхода таймера можно использовать запись в GPIO, тогда ограничений по выбору пина для CS нет. Делал так, но без привязки к событиям SPI, все по событиям таймера. Edited June 4 by amaora Quote Share this post Link to post Share on other sites More sharing options...
jcxz 307 June 4 Posted June 4 · Report post 2 часа назад, Arlleex сказал: @jcxz, Вы на макетке отлаживаете? Просто интересно, как Вы так лихо вывод таймера заменили. Это нога PB.0. На неё в F401 выходит и TIM1_CH1N и TIM3_CH2. Поэтому - заменить было не сложно. А исходники я стараюсь так писать, чтобы из "#define PIN_RFM_CS B, 0" по максимуму вычислялись все возможные смещения нужных полей в регистрах типа: timrcsU->CCER = (B0 | B1) << CH_IX_TIM_PIN(nTIM_rfmcs, PIN_RFM_CS) * 4 + CH_NEG_TIM_PIN(nTIM_rfmcs, PIN_RFM_CS) * 2; Здесь и менять ничего не приходится - макросы сами всё пересчитывают и в нужные биты пишут. Даже если бы пришлось ногу менять - должно всё нормально пересчитаться автоматом. 2 часа назад, Arlleex сказал: Вспомнил тут, как сравнительно давно тоже делал похожий алгоритм, но промахнулся с распределением ресурсов и идея не взлетела. После последнего моего поста вылезла ещё одна проблема: Так как запуски DMA-передач, пишущих в SPI_DR, происходят от таймера, и на картинке (в конце) видно начало одного лишнего кадра. Но длина последовательности (общее число SPI-кадров) задана длиной блока DMA. То получается, что генерится один лишний DMA-запрос. Когда блок уже исчерпан. Этот DMA-запрос повисает необслуженным на отключенном DMA-потоке. И если его не выфлушить, вылезает при запуске следующей последовательности и всё ломает. Причём - этот запрос не сбрасывается ничем: ни выкл. DMA-потока, ни выкл. генератора запросов (таймер). Опять - маты в сторону убогой периферии STM32 и её создателей: они не предусмотрели штатного способа сброса DMA-запросов! Как так можно??? Или я про него не знаю? Если кто знает - подскажите, плиз. У XMC4xxx есть спец.регистр, через который можно сбросить ненужные DMA-запросы перед активацией DMA-канала, если они почему-либо остались висеть после предыдущего использования. И процедура сброса описана в документации (она элементарная). Почему о таком не задумались инженеры STM - не знаю. Вобщем - пришлось городить ещё выфлушивание зависших DMA-запросов перед запуском новой последовательности кадров. Посредством выполнения фейковой DMA-передачи. Теперь картинка выглядит так: Здесь 2 последовательности (цепочки) SPI-кадров. Алгоритм запускает 1-ю последовательность кадров. После неё - IRQ и в его ISR - обработка принятых данных из DMA-буфера. Затем - запуск 2-й последовательности. Как видно на картинке - теперь и 2-я последовательность корректная, как 1-я. Красными стрелками показаны места формирования лишних DMA-запросов. Которые лежат за пределами блоков передаваемых данных. Если их не выфлушить, то следующая последовательность ломается. Но здесь уже всё корректно флушится. Возможно есть какой-то способ, чтобы вообще исключить этот последний лишний импульс CS? Нужно проглядеть возможности сцепки таймеров. В STM32 конечно все эти возможности очень убогие (на XMC4xxx куча возможностей сцепок сигналов разных периферийных блоков, в разных комбинациях), но возможно получится что-то придумать и здесь. А может забью и оставлю текущий вариант с выфлушиванием лишнего DMA-запроса. 1 час назад, amaora сказал: Вместо выхода таймера можно использовать запись в GPIO, тогда ограничений по выбору пина для CS нет. Наверное можно, но потребуется ещё больше DMA-потоков задействовать. Причём - потоков на контроллере DMA2. А там уже их дефицит. Ведь DMA1 как я понимаю - не имеет доступа к AHB-периферии (GPIO). А генерация CS при помощи таймера, экономит DMA-каналы. Полноценный получается только DMA2. DMA1 - ограниченный. 1 час назад, amaora сказал: Делал так, но без привязки к событиям SPI, все по событиям таймера. Считаю это рискованным. Из-за джиттера, возникающего из-за непредсказуемой занятости шины. Потому и делал с обязательной привязкой к событиям SPI.RX. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 278 June 4 Posted June 4 · Report post DMA.LIFSR/HIFSR чистите после завершения всех передач? Может (если не чистите) DMA не раздупляется правильно, хз. И еще. У таймера передерните регистр DIER (запомните, что в нем было, потом сбросьте в 0, потом снова восстановите), потом можете запустить следующий цикл с DMA. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 307 June 5 Posted June 5 · Report post 16 часов назад, Arlleex сказал: DMA.LIFSR/HIFSR чистите после завершения всех передач? Может (если не чистите) DMA не раздупляется правильно, хз. Естественно я их чищу. Только не после, а перед инициализацией для новой передачи. Что-ж вы меня за совсем чайника считаете? С STM (разными) я уже довольно много работал, и DMA использую во всех проектах. Да и какое отношение эти регистры имеют к DMA-запросам? Это регистры флагов DMA, выставляемых по результатам выполнения передач. Про запросы там флагов нет. 16 часов назад, Arlleex сказал: И еще. У таймера передерните регистр DIER (запомните, что в нем было, потом сбросьте в 0, потом снова восстановите), потом можете запустить следующий цикл с DMA. Это я тоже пробовал - не помогает. Да и этот регистр - он отвечает за генерацию новых DMA-запросов. Как я понимаю - после генерации DMA-запроса, он защёлкивается и хранится в триггере. Поэтому сброс источника генерации запроса на него уже не влияет. В XMC4xxx кстати организовано аналогично - каждый DMA-запрос защёлкивается и хранится в триггере. Но там об этом явно сказано в документации. И описан способ сброса этих триггеров (есть спец.регистр). В STM32F4xx возможно тоже есть какой-то способ сброса этого триггера, но в мануале ничего не нашёл об этом. И ЧатГПТ тоже не знает. В NXP (LPC17xx) тоже запросы защёлкиваются на триггерах. Там тоже приходилось выфлушивать зависшие DMA-запросы подобным же образом. Вот в Tiva, там если не изменяет склероз - обошлись без триггеров, и если причина DMA-запроса снимается до её захвата DMA-каналом, то DMA-запрос теряется. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 278 June 5 Posted June 5 · Report post 40 минут назад, jcxz сказал: Это я тоже пробовал - не помогает. Да и этот регистр - он отвечает за генерацию новых DMA-запросов. Как я понимаю - после генерации DMA-запроса, он защёлкивается и хранится в триггере. Поэтому сброс источника генерации запроса на него уже не влияет. Вот тут чел похожую проблему озвучивал и решал: https://community.st.com/t5/stm32-mcus-products/how-to-clear-pending-dma-request/td-p/551646. 2 Quote Share this post Link to post Share on other sites More sharing options...
jcxz 307 June 5 Posted June 5 · Report post 17 минут назад, Arlleex сказал: Вот тут чел похожую проблему озвучивал и решал: https://community.st.com/t5/stm32-mcus-products/how-to-clear-pending-dma-request/td-p/551646. Ну ок - позже попробую ещё раз пообнулять DIER. Может действительно что-то не так делал. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 278 June 5 Posted June 5 · Report post 3 часа назад, jcxz сказал: Естественно я их чищу. Только не после, а перед инициализацией для новой передачи. Обычно по их выставлению возникает прерывание, и будет возникать снова, пока их не сбросите. Поэтому по прерыванию завершения транзакций Вы их чистите, а вот зачем их чистить перед инициализацией другой передачи - не понятно. Но да ладно. Касательно проблемы - я ловил ровно то же самое, только с модулем UART. И да, оно полечилось ровно таким же способом, как по ссылке с таймером. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 307 June 5 Posted June 5 · Report post 18 минут назад, Arlleex сказал: Обычно по их выставлению возникает прерывание, и будет возникать снова, пока их не сбросите. Поэтому по прерыванию завершения транзакций Вы их чистите Нет, не чищу. Я же писал. Если не верите - вот ISR того DMA-потока: //Должно быть на том же уровне приоритета, что и IsrSPI. extern "C" void concat(IsrDMA, nDMASTR_rfmcs_R)() { AtomicXorI(&GPIO[concat(PIOIX_, PORT(PIN_RFM_CS))].MODER, 3u << PIN(PIN_RFM_CS) * 2); if (s0dmaU->ISR[nDMASTR_rfmcs_R >> 2 & 1] & (B2 | B3) << (nDMASTR_rfmcs_R & 3) * 6 << (nDMASTR_rfmcs_R & B1) * 2) trap(TRAP_DMA, TRAPR_SPI); timrcsU->CR[0] = 0; spiU->CR[0] = RFM_SPI_CR0 | B11; IntDis(concat(NVIC_DMA, concat(DMASTR, nDMASTR_rfmcs_R))); OsFlagSet(&evTask); IsrExit(); } Код рабочий, с его помощью получены осциллограммы выше. Я в ISR делаю запрет прерываний от данного вектора (в NVIC). И всё. Запрет - 5 строка кода ISR, проверка флагов DMA-потока - 2 строка. Если найдёте где в этом ISR я чищу флаги DMA - обязуюсь что-нить съесть.... например этот код. в напечатанном виде 18 минут назад, Arlleex сказал: , а вот зачем их чистить перед инициализацией другой передачи - не понятно. Но да ладно. Всегда перед инитом любой операции предварительно чищу все флаги. Поэтому - зачем чистить после, если чистится перед? Хотя можно конечно в ISR очистить флаги в периферии, а в NVIC - не трогать. Так тоже иногда делаю. Без разницы. Как удобнее, так и делаю. 18 минут назад, Arlleex сказал: Касательно проблемы - я ловил ровно то же самое, только с модулем UART. И да, оно полечилось ровно таким же способом, как по ссылке с таймером. Дьявол как известно - кроется в деталях. Посмотрим. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 307 June 6 Posted June 6 · Report post 20 часов назад, Arlleex сказал: Вот тут чел похожую проблему озвучивал и решал: https://community.st.com/t5/stm32-mcus-products/how-to-clear-pending-dma-request/td-p/551646. Да, сброс битов разрешения генерации DMA-запросов - помог. Код: timrcsU->DIER = 0; RDMB(timrcsU->DIER); timrcsU->DIER = B9 << nTIMCH_rfmcs_R | B9 << nTIMCH_rfmcs_F; сбрасывает DMA-запросы от DIER. (где RDMB - обратное чтение соответствующего регистра) Странно - я точно пробовал даже полный сброс в дефолт и переинициализацию всех регистров таймера перед новой передачей - не помогало. Возможно было что-то ещё, так как код был в разработке. Спасибо! Так теперь код старта стал короче на несколько команд (чем в варианте выфлушивания дополнительной DMA-передачей). PS: Для полной ляпоты, осталось только придумать способ избавиться полностью от финального лишнего импульса CS=0. Тогда и очистка лишних DMA-запросов не нужна будет. Quote Share this post Link to post Share on other sites More sharing options...