Jump to content

    

KnightIgor

Участник
  • Content Count

    755
  • Joined

  • Last visited

Everything posted by KnightIgor


  1. Не пробовали задать вопрос непосредственно производителю (ARM/KEIL)? Там и форум есть https://community.arm.com/developer/tools-software/tools/f/keil-forum. Будет интересно услышать ответ, но я сомневаюсь, что ответят: вероятно, такого рода оптимизации являются know how или такими косяками, что признаться будет стыдно .
  2. Тогда я лично в потемках. Явно кто-то грузит процессор так, что прерывание не успевает выбрать регистр данных, и возникает переполнение. Это может быть связано с длинной пост-обработкой принятого прерыдущего байта в самом прерывании. Попробуйте "зациклиться" в прерывании по приему, пока не упадет флаr RXNE: то есть, не "сработало прерывание по RXNE - байт выбран, обработали, вышли", а "сработало прерывание по RXNE - выбираем байты в цикле с проверкой RXNE, пока он не упадет, потом вышли". Еще идеи: 1. Наверное AT_ExecuteCommand() посылает что-то через UART/SPI? Это то, о чем я говорил в части интенсивной передачи и DMA. 2. Может ваш приемный буфер, куда складываются принятые байты, по глубине равен 1? Типа недоглядели какой #define...
  3. 1. Кто писал _ReceiveData? Может там есть код, который запрещает прерывания на время? 2. _SendInt посылает через прерывания? Если да, то может приоритет этого прерывания выше приема UART, да еще в прерывании достаточно длительная предобработка ведется? Попробуйте закомментировать именно _SendInt, а если есть полный контроль над этой функцией, попробовать передавать с помощью DMA.
  4. Как я понял, есть два источника данных. Оба работают по прерыванию. Один из источников переполняет буфер приема. Может с приоритетами прерываний поиграть?
  5. А что там за тема с PLL в GD32? Бинарник от STM32 не попадет в цель?
  6. Кстати, о совместимости. STM нумерует периферию с 1 (ADC1, ADC2...), а GD32 - c 0. Это будет веселье на уровне исходников адаптировать под GD32. Кто-нибудь грузил бинарник от STM32 в аналогичный GD32?
  7. Я в описании процессоров интересующей меня линейки GD32F103 с удивлением обнаружил, что у них нет.... USB! https://www.gigadevice.com/microcontroller/gd32f103rct6/ Хотя в описании драйверной библиотеки есть поддержка USBD... Не ясно, где недоразумение.
  8. Шутку я знаю. Спасибо за общие фразы.
  9. Не поверите, но работая полный день над другими проектами, остается мало времени, и я пытаюсь найти ошибку самостоятельно, поскольку здесь, кроме общих поучений в виде введения в принципы FIFO и иных заявлений типа "она неправильно построена", надеяться на совет не приходится.
  10. Админ убил мою вставку, она была слишком длиной. По поводу "нормального подхода" с общим запретом прерываний - у меня тут принципиальная позиция, что это топорно. Меня так учили. Во времена, когда со всеми ресурсами было плохо.
  11. Эксклюзивный доступ в Cortex не подходит для моих целей: внутри прерывания он смысла не имеет, а для синхронного потока в данном приложении - тоже. В Cortex эксклюзивный доступ работает топорно: если после ldrex до strex произошло ЛЮБОЕ прерывание, strex вернет "ошибку". С точки зрения синхронной процедуры, при ее попытке что-то изменить невовремя, она получит отлуп от strex и будет вынуждена зациклиться, пытаясь снова и снова. Пусть это фобия, но я не люблю зацикливать на непонятно сколько времени куски синхронного кода в моей системе кооперативной многопоточности. Кроме того, ЛЮБОЕ прерывание, даже не относящееся к области интереса конкретного "драйвера" периферии, будет порождать отлупы. В результате, все становится не лучше запрета-разрешения прерываний из синхронного цикла, что я тоже считаю топорным подходом. Есть вариант через SVC. В моей системе я это действительно использую для некоторых специфических целей, когда уж точно надо что-то исполнить эксклюзивно в синхронной части (например, атомарное вычисление, или надо ткнуть какой-то процесс, и чтобы не влезло прерывание между делом), но конкретно для "драйвера" UART|SPI|общего потокового устройства это overkill, если тема решена уже проще. Еще раз вернемся к теме: оптимизация под gcc что-то рушит. А оптимизация под KEIL - нет! С бОльшей вероятностью - какая-то глубоко законспирированная ошибка в моем коде. Но есть вероятность и того, что это косяк в gcc: кто там писал о проблемах в IAR?
  12. Дело не в потере значения R1, а в том, что [R1] указывает на разделяемый ресурс, как-то счетчик, индекс или указатель. Например, пусть в str R0,[R1] R0 содержит новое значение, которое планируется записать по адресу [R1], равное 1. Перед str произошло прерывание, которое запишет по адресу [R1] значение 2, а после возврата str запишет туда 1. И все рухнуло. Я должен уточнить, что мой код предполагает не просто FIFO с одним писателем и одним читателем, а по меньшей мере двумя писателями. Возможно, вначале я не достаточно ясно выразился - сорян, - в результате чего мне и пишут, что "Вариант с двумя указателями позволяет строить кольцевые буфера с одним писателем и одним читателем без дополнительных средств синхронизации потоков (типа запрета прерываний)", хотя речь с моей точки зрения идет о двух писателях. Дело в том, что изначально код был написан для поддержки stdio (терминала), когда устройство подключено как непосредственно по UART, так и по USB с поддержкой виртуального COM-Port (CDC). То есть, символы могут приходить как от терминала, так и по USB. Конечно, с точки зрения реального управления вряд ли кто-то будет одновременно писать левой рукой в терминал, а правой - в другой терминал на виртуальном COM-Port, и пытаться выяснить, какая рука у него быстрее, но технически такое возможно, и нужно обезопаситься, чтобы система в целом не рухнула. Вот функция bufio_StoreChar(bufio_FIFO *FIFO, uint16_t c) как раз для этого и предназначена, и я не хотел внутри ее, если она вызвана из основного потока, запрещать какие-либо прерывания. Поэтому функция защищает критическую секцию флагом, а вот уже прерывание, которое имеет полный контроль над самим собой, в том числе - себя отложить, этот флаг анализирует и действует соответственно. Функция bufio_StoreChar() приведена еще раз ниже (сорри, админ потер мою вставку со всем кодом в предыдущих постах, т.к. она была слишком длиной): // ----------------------------------------------------------------------------- // // Stores a value to the software driven input (PC -> Device) FIFO buffer. // Returns -1 if no more place in the FIFO. // // CALLED FROM THE INTERRUPT HANDLER or // an external routine that wanna insert a value into the input buffer // int32_t bufio_StoreChar(bufio_FIFO *FIFO, uint16_t c) { int32_t res = -1; if (bufio_RXBufferReady()) { bufio_DRIVER* h = FIFO->HD; // to shorten the script if (FIFO->RX.size < 2) // store as byte _CAST_DATA_AS_B(FIFO->RX.data, FIFO->RX.idx) = res = (char)bufio_InputFilter(c); else // store as word _CAST_DATA_AS_W(FIFO->RX.data, FIFO->RX.idx) = res = bufio_InputFilter(c); idxplus(&FIFO->RX); // move index/counter within a critical section // (re)enable RX interrupt if being called not from an interrupt above if (!Called_From_ISR() && h && h->RIE) h->RIE(1); } return res; } Получалось, что если внутри критической секции сработало прерывание, оно увидит флаг и отложит себя (запретом), а функция выше при выходе просто переразрешает прерывание, и если оно было отложено, оно тут же сработает и доделает свое дело. Конечно, без запрета прерывания не обошлось, но это происходит в нем самом и действительно только тогда, когда это необходимо, а не каждый раз, когда происходит вызов к bufio_StoreChar() из основного потока. Это была моя основная идея "невмешательства" синхронного потока в систему управления прерываниями.
  13. Вот я уже заинтригован. Это в 8051 была команда xch, которая атомарная. В кортексе такого нет.
  14. например, читает прерывание, а пишет синхронный цикл. Что будет, если синхронный цикл выполняет ldr r0,[r1] add r0,#1 str r0,[r1], а прямо перед str рубануло прерывание, которое использует то, куда указывает [r1]?
  15. Даже не смешно. Я писал: "2. У меня не просто FIFO, но с атомарным доступом, который достигается флагами и основан на свойстве прерываний в 8051 и CMx, когда их можно, скажем так, отложить. При этом не нужно запрещать/разрешать прерывания глобально ( __enable_irq(), __disable_irq()) ". Конечно, чтобы двигать указатели/счетчик ВНЕ прерывания, я флаг устанавливаю, отмечая критическую секцию. В самом прерывании этот флаг анализируется и прерывание откладывается. Когда критическая секция завершается, она прерывание просто (пере-)разрешает. Происходит влет в прерывание и работа уже с новыми значениями указателей/счетчиков. То есть, запрет прерывания есть, но он происходит внутри самого прерывания, а не в синхронной части программы как бы извне.
  16. 1. Существует две основные концепции построения кольцевых буферов: указатель и счетчик или два указателя. В первом случае счетчик сразу дает количество элементов в FIFO (мне было так удобней), но второй указатель надо вычислять; во втором случае указатели готовы всегда, но количество элементов надо каждый раз вычислять, если опрашивать. Эти концепции совершенно равноправны. Спорить по этому поводу равносильно тому, разбивать ли яйца с тупой или острой стороны. 2. У меня не просто FIFO, но с атомарным доступом, который достигается флагами и основан на свойстве прерываний в 8051 и CMx, когда их можно, скажем так, отложить. При этом не нужно запрещать/разрешать прерывания глобально ( __enable_irq(), __disable_irq()). Эта реализация может показаться несколько навороченной, но она хорошо работает без влияния на другие подсистемы или на всю подсистему прерываний. 3. Код реентерабельный, т.к. работает с внешними структурами данных.
  17. Уфф, если хотите повозиться, нет проблем:
  18. Это интересная мысль. В моем (проблемном) коде нет таких переменных, хотя есть буферы, объявленые как static, то есть, доступные локально или по ссылке глобально. Кстати, тема кэширования и многопоточности. Об этом много писалось, что при выходе из прерываний в cortex следует подумать о __DSB(), иначе можно влететь в то же прерывание после выхода из него. Выключенная оптимизация добавляет в код достаточно большую преамбулу и хвост: в gcc это какое-то жонглирование с R3. Оптимизация сокращает эти операции, что ускоряет выход из прерывания, но добавление __DSB() (а также __ISB() и __DMB() и всяких __NOP()) таки не решило мою проблему.
  19. За ответ, даже если он не помогает мне конкретно, просто 5+, особенно за цирроз печени!!!
  20. Это явно так, но как оптимизация может порушить код, который до этого работал годы?! Как я указывал, оптимизация под KEIL не портила результат, горя не знал, только под gcc сейчас. Я даже не представляю, где копать. @haker_fox: я изначально писал под CM3, предпринял соответствующие меры для атомарности (даже описывал здесь на формуме в обсуждении подобной темы, как, но очень давно).
  21. Привет, коллеги. Немного предыстории. С CMx начал работать еще с самого начала их появления (конец нулевых). Когда не было еще всяких HAL, а CMSIS в зародыше, написал свою HAL, которой пользуюсь до сих пор, причем и для CM3, и для CM0. До поры работал под KEIL, теперь частично и в STMCubeIDE, то есть gcc. В моем HAL есть код типа FIFO, работающий с UART. Это была и есть оcнова основ: всякие терминалы, DMX, поддержка других протоколов. Короче, коду сто лет в обед, проверен многократно на STM32 CM3/CM0, EnergyMicro/Silabs EFM32, ATMEL SAM3D. Я в код уже и не заглядываю. И вот нонче, завершив более-менее проект под SMTCubeIDE, где моя HAL используется как странслированная в библиотеку *.a, я собрал его release, при этом подключил HAL.a тоже release, оптимизация -O2. И тут начались непонятки: протокол по UART не работает толком. printf() вообще ведет себя странно: спорадически(!) происходит как бы добавление символов. Например, вместо "V1.0" выводится "V.1.0", вместо, скажем, FPxA - FxPxA, то есть какой-нибудь символ "копируется" на две позиции вперед. Если подключить к проекту release мою HAL.a debug (-O0), то непонятки уходят. Интересно, что HAL.lib под KEIL, тоже с -O2, работает в проектах под KEIL одинаково хорошо с HAL.lib -O0. То есть, проблема только под STMCubeIDE gcc и -O2. Есть у кого идеи/опыт? Ага, STMCubeIDE 1.6.1.
  22. Устаревшим, но все последние версии STMCubeIDE копируют в проект именно *.s файлы. Работаем с тем, что есть.
  23. Мне нравится фраза "есть мнение". Попахивает... историей, богатой бездоказательными утверждениями. Ну, это так, ничего личного, просто ассоциации. Ничто не мешает. Однако производители изначально приняли решение в пользу *.asm. И кто-то в процессе накосячил, добавив (или убрав) цифирьку в имени вектора. Вся история, однако тема длится уже три страницы. Если бы это был Instagram, я бы уже деньжат срубил