Перейти к содержанию
    

тогел потоко не защищённый. Осторожно, тут мины!! ))

Я же говорил, что к одному и тому же пину у меня в коде НИКОГДА нет обращения их РАЗНЫХ потоков.

Это исключено еще на этапе построения проекта.

Поэтому не будет ничего страшного, если кто-то прервет эту строчку с ODR.

В крайнем случае могу использовать CriticalSection, если нужно сохранить строгую последовательность некого пинодрыга, но пока еще с таким я не сталкивался.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ЕМНИП, в компиляторе Hi-Tech для PIC тип char был беззнаковый по умолчанию, но можно было задать знаковый. К спору об int не относится, с ним ясно всем, кроме одного. :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вы в одном потоке дергаете cs? который есть PA13, а в другом потомке маргаете диодом который сидит на PA5.

Ага, я понял к чему вы - я имел ввиду не порт, а пин.

Но и в данном случае проблем тоже не будет - в MODER пишется маска, меняющая всего лишь ОДИН соотв. бит, а не группу битов.

Ничего вы не поняли.

В вашем коде две проблемы:

1. Проблема с двухэтапной записью в MODER. Выше уже очень хорошо объяснили, что это нехорошо. Потому что ножка переводится в промежуточное состояние, которое может быть нежелательным. И при возникновении прерывания между двумя записями ножка может остаться в этом состоянии достаточно продолжительное время. Этого может быть достаточно, чтобы что-нибудь сжечь. Это реальная мина, потому что на столе может всё работать, а в продакшене может рвануть.

 

2. Проблема с неатомарностью операции GPIOA->ODR ^= bit. (Об этом вам пишет juvf). Дело в том, что если такие операции выполняются одновременно из разных потоков (к разным битам одного порта), то возможны сбои. Разжёвывать не буду, гуглите.

 

ЗЫ. Рано вы взялись за "Чистый код". Надо было сначала основы подтянуть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Проблема с двухэтапной записью в MODER. Выше уже очень хорошо объяснили, что это нехорошо. Потому что ножка переводится в промежуточное состояние, которое может быть нежелательным. И при возникновении прерывания между двумя записями ножка может остаться в этом состоянии достаточно продолжительное время. Этого может быть достаточно, чтобы что-нибудь сжечь. Это реальная мина, потому что на столе может всё работать, а в продакшене может рвануть.
В моих схемах ни одна ножка не висит в воздухе, всегда есть внешняя подтяжка, это связано с непредсказуемым поведение схемы, пока проц в состоянии сброса или прошивается.

Поэтому в моих проектах это не создает никаких проблем ))

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

 

2. Проблема с неатомарностью операции GPIOA->ODR ^= bit. (Об этом вам пишет juvf). Дело в том, что если такие операции выполняются одновременно из разных потоков (к разным битам одного порта), то возможны сбои. Разжёвывать не буду, гуглите.
Вы хотите сказать, что операция обращения к ODR неатомарнае, например, копирование из регистра R2 -> [R3], где R3 хранит адрес ODR-регистра?

Вы точно ничего не путаете?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я же говорил, что к одному и тому же пину у меня в коде НИКОГДА нет обращения их РАЗНЫХ потоков.

Это исключено еще на этапе построения проекта.

Поэтому не будет ничего страшного, если кто-то прервет эту строчку с ODR.

В крайнем случае могу использовать CriticalSection, если нужно сохранить строгую последовательность некого пинодрыга, но пока еще с таким я не сталкивался.

просто ужос!!!! такие элементарные вещи... вроде разживал все... выделил жирным шрифтом, что при изменении РАЗНЫХ ПИНОВ РАЗНЫХ!!!

ну не видите вы сами... я же вам привел пример... РА15 и РА5

 

пошагам.... пусть cs будет РА1, а led будет PA4. воспользуемся литералом b. для кратности пусть порт будет 8 бит. изночально в ODR 0b0000'0000

вы в одном поторке выитали ODR, он равен нулю. второй поток прервал первый. второй поток вычитал ODR и добавил туда cs, стало 0b0000'0010. теперь записал это в ODR. Сs стал "1". Вернулись в первый поток... 0b0000'0000 добавили бит светодиода, получили 0b0001'0000 - записали в ODR - всё!!! CS сбросился! Упс!!!

 

раз вы пишете на RTOS, должны знать про неатомарные операции

 

Вы хотите сказать, что операция обращения к ODR неатомарная, например, копирование из регистра R2 -> [R3], где R3 хранит адрес ODR-регистра?
БИНГО!!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

естественно.... так же как и в шаблонах/классах

Для класса ты пишешь всякие on/off один раз и они точно будут рабочие. На макросах ты пишешь намного больше и можешь случайно ошибиться:

#define csOn() (GPIOA->BSRR = GPIOA_BSRR_BR4)
#define csOff() (GPIOA->BSRR = GPIOA_BSRR_BS4)

#define led1On() (GPIOA->BSRR = GPIOA_BSRR_BR5)
#define led1Off() (GPIOA->BSRR = GPIOA_BSRR_BS5)
...

 

чего?

На радиокоте недавно спрашивали как записать 7 бит заданного байта в PD9, 5 бит в РВ4 и т.д.... Дали парочку ответов, лучший из которых выглядит так:

GPIOD->BSRR = b & 0x80 ? GPIO_BSRR_BS9 : GPIO_BSRR_BR9;
GPIOB->BSRR = b & 0x20 ? GPIO_BSRR_BS4 : GPIO_BSRR_BR4;

Шаблонный код мог бы быть таким:

GpioD<9>::write(b & 0x80);
GpioB<4>::write(b & 0x20);

Он понятнее и эффективнее, т.к. никаких проверок в нем нет.

 

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

Речь про инит, который уже написан, отлажен и привязан к конкретному пину. Возьмем, для примера, USART. У некоторых популярных мк их по 6 штук, каждому нужно инитить ноги, большинству нужно 3 параметра для каждого пина, у STM32F1 их 2, но там инициализация немного другая... Какая сущность должна всем этим заниматься? Должен ли я для каждого USARTа закопать инициализацию пинов в какой-то общей функции инициализации? Считаю, что не должен, потому делаю так:

Usart1<> usart1;
Usart6<> usart6;

usart1.init<PinA<9, 7>, PinA<10, 7>>(2457600);
usart6.init<PinC<6, 8>, PinC<7, 8>>(115200);

Не нравится прописывать пины прямо тут, выносим их куда угодно

using USART1_TX = PinA<9, 7>;
using USART1_RX = PinA<10, 7>;

usart1.init<USART1_TX, USART1_RX>>(2457600);

 

Я просто хочу сказать, что не нужно думать бинарно.... у вас либо 0, либо 1. Либо С++ с ООП в полный рост безоговорочно.... с оверинженерингом, либо если один макрос или литерал воткнут - то это непрофессионализм. Использование стандартного литерала х и b - это фу фу фу, магическая цифра.... зато SIGNED32 (при чем с миной) - это круть!!!!

Здорово, особенно учитывая, что про бинарные литералы в С++ тебе рассказал именно я :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

....
Даже коментировать тут нечего.... Полемика. Ну я же говорю, бинарно мыслите... при чем тут уарт? я вам сказал что макросы ВЕЗДЕ лучше классов/шаблонов?

 

 

На радиокоте недавно спрашивали как записать 7 бит заданного байта в PD9, 5 бит в РВ4 и т.д.... Дали парочку ответов, лучший из которых выглядит так:

GPIOD->BSRR = b & 0x80 ? GPIO_BSRR_BS9 : GPIO_BSRR_BR9;
GPIOB->BSRR = b & 0x20 ? GPIO_BSRR_BS4 : GPIO_BSRR_BR4;

Шаблонный код мог бы быть таким:

GpioD<9>::write(b & 0x80);
GpioB<4>::write(b & 0x20);

Он понятнее и эффективнее, т.к. никаких проверок в нем нет.

я бы не так сделал. была подобная задача.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...

Так глубоко в компилятор я не влезал, щас влез в asm код, который нагенерил компилятор для toggle() ...

Действительно, возможны глюки, надо переписывать!

Вот и баги нашлись :smile3046:

Хотя до сих пор, проблем не было, но это - вопрос времени, нужно обязательно переделать!

 

Есть идеи, как переделать void toggle() { port->ODR ^= pinMask; }, избежав критических секций?

 

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

К тому же этот Port сможет предоставить возможность массовой настройки пинов (например, подключена внешняя память на параллельной шине).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Даже коментировать тут нечего.... Полемика. Ну я же говорю, бинарно мыслите... при чем тут уарт? я вам сказал что макросы ВЕЗДЕ лучше классов/шаблонов?

Был тут уже один товарищ с критикой, я ему предложил написать аналог инициализации портов FSMC двумя строками, ты видел ответ? Так и тут... Начинается с того, что задефайнить csOn()/csOff() и прочие максросы проще простого, как и проинитить, а ты покажи полную инициализацию пинов хотя бы пары усартов, тогда будет с чем сравнивать. Имеется в виду количество кода который придется написать для каждого нового усарта в проекте.

 

я бы не так сделал. была подобная задача.

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

Изменено пользователем Reflector

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть идеи, как переделать void toggle() { port->ODR ^= pinMask; }, избежав критических секций?

Навскидку...

 

void toggle() { port->BSRR = (port->ODR & pinMask) == 0 ? pinMask : pinMask << 16; }

 

 

 

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

К тому же этот Port сможет предоставить возможность массовой настройки пинов (например, подключена внешняя память на параллельной шине).

!!! Извини.... но блин.... это всего лишь ногой дёрнуть!!! ))))))))))))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть идеи, как переделать void toggle() { port->ODR ^= pinMask; }, избежав критических секций?

Можно использовать bit-band для реализации cpl(). У меня так.

(К сожалению, для stm32L0x - не сработает, там нет bin-band для GPIO).

 

Да и ерунда всё это, на самом деле. Я лично не помню, чтобы где-то использовал cpl(), кроме тестов. Всегда нужно переводить ножку в какое-то определённое состояние.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да и ерунда всё это, на самом деле. Я лично не помню, чтобы где-то использовал cpl(), кроме тестов.

есть проект, где светодиод мигает, показывая живучесть системы. не было cpl, использовал с дополнительным флагом сет/ресет. А так бы было бы удобно cpl.

 

ps ещё програмный меандр выдавать.... можно найти применение cpl-ю

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Навскидку...

 

void toggle() { port->BSRR = (port->ODR & pinMask) == 0 ? pinMask : pinMask << 16; }

Ага, но только что я приводил пример практически такого-же кода, как не самого эффективного, т.к. там будет проверка.

redLed.write(!redLed.read());

То же самое, но без лишней инструкции ITE.

ps. Упс, сорри, это совсем не тоже самое, т.к. читает с IDR :) Но сути это не меняет, меняем IDR на ODR, но код прячем внутри класса.

 

gpio->BSRR = (0x10000 << pin) | (!(gpio->ODR & (1 << pin)) << pin);

У F0 ITE нет, там проверки еще более тяжелые.

Изменено пользователем Reflector

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void toggle() { port->BSRR = (port->ODR & pinMask) == 0 ? pinMask : pinMask << 16; }

Как вариант ))

 

Но я предпочитаю более читаемо:

void toggle() { if (isLow()) setToHigh(); else setToLow(); }

 

Впрочем, этот toggle (добавил совсем недавно) у меня пока что использовался лишь для моргания лампочкой, поэтому багов не было.

Но исправить все же нужно, дабы больше не возвращаться к этому вопросу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

есть проект, где светодиод мигает, показывая живучесть системы. не было cpl, использовал с дополнительным флагом сет/ресет. А так бы было бы удобно cpl.

 

ps ещё програмный меандр выдавать.... можно найти применение cpl-ю

 

Ну тогда bit-band. Есть везде, кроме L0.

 

ЗЫ. Я там вам ответил про варианты pin.h, возможно вы проглядели (тема растёт очень быстро).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...