Jump to content

    
KnightIgor

CubeIDE: оптимизация выше -O0 нарушает работу программы

Recommended Posts

 

35 minutes ago, KnightIgor said:

а прямо перед str рубануло прерывание, которое использует то, куда указывает [r1]?

Ну и пусть использует. Модифицировать не надо, а использовать - пожалуйста.

Share this post


Link to post
Share on other sites
4 hours ago, KnightIgor said:

Как двинуть указатель атомарно?

Ну, проблемы могут возникнуть только у тех чипов, где размер регистра меньше указателя. Например на восмибитном мк опасно делать указатель более 256. И да, это не совсем указатель в классическом варианте (полный адрес) - это смещение от первого элемента буфера(индекс). То-есть на 32b системах очень трудно споткнуться.

Алгоритм записи в фифо: проверить свободное место, записать данные, изменить указатель "головы". Повторить до окончания данных.

Алгоритм чтения: прочитать указатели, если не равны - то сначала прочитать данные по указателю "хвост", потом обновить указатель. Повторить до совпадения указателей.

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

 

Share this post


Link to post
Share on other sites
On 6/9/2021 at 4:14 PM, Arlleex said:

Когда рубанет прерывание, R1 автоматом сохранится в стеке и ничего испорчено не будет.

Дело не в потере значения 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() из основного потока. Это была моя основная идея "невмешательства" синхронного потока в систему управления прерываниями.

Share this post


Link to post
Share on other sites
27 минут назад, KnightIgor сказал:

хотя речь с моей точки зрения идет о двух писателях.

Ну вот - только к 3 странице треда начинаем выяснять существенные вещи, которые должны были быть изложены ещё в заглавном сообщении треда.....  :russian_ru:

Я не зря многократно подчёркивал про "с одним писателем и одним читателем", потому как от этого очень многое зависит.

Цитата

Дело в том, что изначально код был написан для поддержки stdio (терминала), когда устройство подключено как непосредственно по UART, так и по USB с поддержкой виртуального COM-Port (CDC). То есть, символы могут приходить как от терминала, так и по USB.

В этом случае самым логичным решением будет сделать 2 FIFO (отдельно для каждого интерфейса). Какой смысл лепить франкенштейна?

А если уж очень хочется франкенштейна, то: просто добавить к классическому алгоритму кольцевого буфера критические секции с одной из сторон (там где 2 писателя).

Не понимаю - почему Вы так боитесь критических секций (запрета прерываний)? Напоминает субъективную фобию....  :crazy:

 

PS: Если уж очень сильно хочется именно без запрета прерываний (чтоб вообще), то классический алгоритм кольцевого буфера можно и так модифицировать. Например - через механизм эксклюзивного доступа (Cortex-M). Но будет сложнее.

 

27 минут назад, KnightIgor сказал:

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

Глубоко не вчитывался, но по описанию складывается ощущение, что Вы здесь пытаетесь эмулировать механизм эксклюзивного доступа Cortex-M. Зачем??? Может просто стоит его изучить и применить?  :unknw:

Если уж так не нравится запрет прерываний...

Share this post


Link to post
Share on other sites
55 minutes ago, jcxz said:

Глубоко не вчитывался, но по описанию складывается ощущение, что Вы здесь пытаетесь эмулировать механизм эксклюзивного доступа Cortex-M. Зачем??? Может просто стоит его изучить и применить?  :unknw:

Если уж так не нравится запрет прерываний...

Эксклюзивный доступ в Cortex не подходит для моих целей: внутри прерывания он смысла не имеет, а для синхронного потока в данном приложении - тоже. В Cortex эксклюзивный доступ работает топорно: если после ldrex до strex произошло ЛЮБОЕ прерывание, strex вернет "ошибку". С точки зрения синхронной процедуры, при ее попытке что-то изменить невовремя, она получит отлуп от strex и будет вынуждена зациклиться, пытаясь снова и снова. Пусть это фобия, но я не люблю зацикливать на непонятно сколько времени куски синхронного кода в моей системе кооперативной многопоточности. Кроме того, ЛЮБОЕ прерывание, даже не относящееся к области интереса конкретного "драйвера" периферии, будет порождать отлупы. В результате, все становится не лучше запрета-разрешения прерываний из синхронного цикла, что я тоже считаю топорным подходом.

Есть вариант через SVC. В моей системе я это действительно использую для некоторых специфических целей, когда уж точно надо что-то исполнить эксклюзивно в синхронной части (например, атомарное вычисление, или надо ткнуть какой-то процесс, и чтобы не влезло прерывание между делом), но конкретно для "драйвера" UART|SPI|общего потокового устройства это overkill, если тема решена уже проще.

Еще раз вернемся к теме: оптимизация под gcc что-то рушит. А оптимизация под KEIL - нет! С бОльшей вероятностью - какая-то глубоко законспирированная ошибка в моем коде. Но есть вероятность и того, что это косяк в gcc: кто там писал о проблемах в IAR?

Edited by KnightIgor

Share this post


Link to post
Share on other sites
9 minutes ago, KnightIgor said:

Еще раз вернемся к теме

Вы так и не привели свой код (простыни комментариев и отдельные фрагменты не в счет). Куда возвращаться?

 

11 minutes ago, KnightIgor said:

запрета-разрешения прерываний из синхронного цикла, что я тоже считаю топорным подходом

Нормальный подход. Главное, 100% рабочий. Если система критична к запрету прерываний на время доступа к 1-2 переменным, значит, она неправильно построена.

Share this post


Link to post
Share on other sites
1 minute ago, aaarrr said:

Вы так и не привели свой код (простыни комментариев и отдельные фрагменты не в счет). Куда возвращаться?

Нормальный подход. Главное, 100% рабочий. Если система критична к запрету прерываний на время доступа к 1-2 переменным, значит, она неправильно построена.

Админ убил мою вставку, она была слишком длиной.

По поводу "нормального подхода" с общим запретом прерываний - у меня тут принципиальная позиция, что это топорно. Меня так учили. Во времена, когда со всеми ресурсами было плохо.

Share this post


Link to post
Share on other sites
42 минуты назад, KnightIgor сказал:

Эксклюзивный доступ в Cortex не подходит для моих целей: внутри прерывания он смысла не имеет,

Имеет. Ведь может произойти вложенное прерывание.

Эксклюзивный доступ нужен для обнаружения фактов нарушения последовательности потока выполняемых команд.

Цитата

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

В реальности вероятность того, что между LDREX и STREX произойдёт прерывание, должна быть предельно мала. А тем более того, что несколько прерываний подряд.

А непрерывно следующие друг за другом прерывания с большой частотой, из-за которых цикл LDREX/STREX зациклится - говорит только о том, что система неправильно построена. Просто не должно быть таких случаев в системе.

Цитата

Есть вариант через SVC. В моей системе я это действительно использую для некоторых специфических целей, когда уж точно надо что-то исполнить эксклюзивно в синхронной части (например, атомарное вычисление, или надо ткнуть какой-то процесс, и чтобы не влезло прерывание между делом), но конкретно для "драйвера" UART|SPI|общего потокового устройства это overkill, если тема решена уже проще.

Можно через SVC. Но накладные расходы будут гораздо больше чем на запрет/разрешение прерываний. А значит и смысла нет так делать (так как задержка в обработке каких-то аппаратных прерываний при таком механизме будет ещё больше чем при тупом запрете/разрешении прерываний).

Цитата

Но есть вероятность и того, что это косяк в gcc: кто там писал о проблемах в IAR?

Вероятность конечно всегда есть. Но доказать это можно только приведя конкретный участок asm-листинга. Пока этого не сделано - предполагаем что ошибка в вашем коде (default).  :unknw:

Когда я описывал косяки в IAR, я это всегда доказывал конкретным листингом.

 

28 минут назад, aaarrr сказал:

Если система критична к запрету прерываний на время доступа к 1-2 переменным, значит, она неправильно построена.

:good2:

Share this post


Link to post
Share on other sites

KnightIgor - ваш стиль впадения в анабиоз на пару дней - не способствует продуктивной беседе. 

FIFO - это мост, ставить на него полицейских - не лучшая идея. Нам нужно чтобы движение через мост было максимально быстрым, а в случае внутреннего арбитража внешних писателей - движение будет прерывистым, с полным очищением перед сменой писателя. То-есть смысл использования fifo теряется, тогда-уж проще обмениваться ссылками на готовые данные.

Арбитраж должен быть внешним, за пределами fifo. Самый простой вариант - контроль занятого ресурса. Чуть сложнее, но более продуктивнее - сборка пакетов данных в минимальном конфиге с адресом. В этом случае можно заметно упростить и ускорить механизм fifo, когда он будет вмещать чётное количество пакетов фиксированного размера, и писать уже не по одному байту - а много и сразу.

Таким образом сохраняется главное преимущество fifo перед остальными вариантами связи - удаление или многократное уменьшение времени взаимных блокировок.

Кстати, связь через порт отладки SWO - на аппаратном уровне поддерживает разделение на каналы, и это очень удобно. Особенно когда скорость потоков не равномерна - позволяет не валить всё в одну кучу, а аккуратно раскладывать по полочкам. Кроме того, требования к программному обеспечению на стороне мк - получаются самыми малыми по размеру, буквально несколько строк.

Share this post


Link to post
Share on other sites
On 6/11/2021 at 3:58 PM, AVI-crak said:

KnightIgor - ваш стиль впадения в анабиоз на пару дней - не способствует продуктивной беседе. 

 

Не поверите, но работая полный день над другими проектами, остается мало времени, и я пытаюсь найти ошибку самостоятельно, поскольку здесь, кроме общих поучений в виде введения в принципы FIFO и иных заявлений типа "она неправильно построена", надеяться на совет не приходится.

Edited by KnightIgor

Share this post


Link to post
Share on other sites
14 hours ago, KnightIgor said:

я пытаюсь найти ошибку самостоятельно, поскольку здесь, кроме общих поучений в виде введения в принципы FIFO и иных заявлений типа "она неправильно построена", надеяться на совет не приходится

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

Share this post


Link to post
Share on other sites
2 minutes ago, AVI-crak said:

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

Шутку я знаю. Спасибо за общие фразы.

Share this post


Link to post
Share on other sites
14 часов назад, KnightIgor сказал:

здесь, кроме общих поучений в виде введения в принципы FIFO и иных заявлений типа "она неправильно построена", надеяться на совет не приходится.

Интересно - а чего вы ожидали? Телепатов, которые удалённо увидят ваши исходники и удалённо же найдут в них баги?

И "здесь, кроме общих поучений", вам даже выкладывали пример реализации FIFO. Корректный. Конкретный рабочий пример, не "общие фразы".

Т.е. - уже и в рот положили, теперь ещё и прожевать за вас???   :unknw:

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.