Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Библиотеки для STM32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3, 4, 5, 6, 7, 8
Шаманъ
Цитата(Reflector @ Apr 19 2017, 17:59) *
Здорово, но раз есть csOn(), то как минимум должен быть и csOff(), потом захочется записать битик и дополнительно придется делать проверки... А инициализация, она ведь тоже нужна? Итого сколько всего будет таких макросов для одного пина?

Не могу таки понять в чем проблема - инициализация всего собирается в одном месте, там и макросы не нужны (для доступа к портам они тоже кстати не слишком нужны wink.gif). Обсуждается какой-то конь в вакууме.

По поводу переносимости, это не проблема - инициализация правится отдельно, обращение к портам отдельно.
AHTOXA
Цитата(Forger @ Apr 19 2017, 19:43) *
Код
    volatile UNSIGNED8 portIndex;
    volatile UNSIGNED8 pinIndex;
    volatile UNSIGNED32 pinMask;

juvf уже спрашивал, я удваиваю его вопрос: какой смысл использовать странные UNSIGNED8/UNSIGNED32 при наличии замечательных (а главное - стандартных) типов из <stdint.h>?
И второй вопрос - зачем тут volatile?

Цитата(Шаманъ @ Apr 19 2017, 20:29) *
Не могу таки понять в чем проблема - инициализация всего собирается в одном месте, там и макросы не нужны (для доступа к портам они тоже кстати не слишком нужны wink.gif). Обсуждается какой-то конь в вакууме.

Так ещё хуже - инициализация в одном месте, остальное в другом. Если надо поменять порт и ножку, то будет морока - править в нескольких местах. Вероятность ошибки больше.

Тут не конь в вакууме. Тут на примере довольно простого класса для доступа к ножкам микроконтроллера обсуждается подход к программированию в целом. И уже продемонстрировано несколько подходов. Конечно, каждый участник считает, что его подход самый лучший, и переубедить друг друга скорее всего не удастся. Но, думаю, кое-что полезное из обсуждения можно почерпнуть.
Forger
Цитата(AHTOXA @ Apr 19 2017, 18:31) *
juvf уже спрашивал, я удваиваю его вопрос: какой смысл использовать странные UNSIGNED8/UNSIGNED32 при наличии замечательных (а главное - стандартных) типов из <stdint.h>?

Форма написание "стандартных" типов меня не устраивает - не соответствует моей концепции именования.
Поэтому в соотв. местах существуют соотв. typedef-ы в зависимости от платформы (в файле выше нет соотв. инклуда, он подключается в другом месте).

Цитата
И второй вопрос - зачем тут volatile?
Не помню зачем их ставил. А рыться в истории svn-базы как-то нет особого желания.
AHTOXA
Цитата(Forger @ Apr 19 2017, 20:39) *
Форма написание "стандартных" типов меня не устраивает

Мне кажется, это противоречит концепции "чистого кода" в смысле "кода, понятного для других". И вы зря взяли слово "стандартных" в кавычки - <stdint.h>/<cstdint> действительно входит в стандарт языка.

Цитата(Forger @ Apr 19 2017, 20:39) *
Не помню зачем их ставил. А рыться в истории svn-базы как-то нет особого желания.

Так уберите. Я понимаю, памяти вам не жалко. Но быстродействие-то вам наверняка не помешает? sm.gif
Forger
Цитата(AHTOXA @ Apr 19 2017, 20:27) *
Мне кажется, это противоречит концепции "чистого кода" в смысле "кода, понятного для других". И вы зря взяли слово "стандартных" в кавычки - <stdint.h>/<cstdint> действительно входит в стандарт языка.

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

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

Мне ломает глаз эта uint32_t, мне лично удобнее U32 (постепенно перехожу на такую форму записи со слишком длинной UNSIGNER32).

Я привел файл Pin.hpp в качестве примера, т.е. as is. Если что-то не нравится или кажется неудобным - переписывайте под себя, я не против )))

Буду рад если найдете баги или еще более лучшие решения, но придирки к оформлению и мелочам предлагаю все же оставить за кадром.
Reflector
Цитата(AHTOXA @ Apr 19 2017, 20:27) *
Так уберите. Я понимаю, памяти вам не жалко. Но быстродействие-то вам наверняка не помешает? sm.gif

Кстати, касательно volatile... Forger, как думаешь что происходит, когда ты в своем классе делаешь так?
Код
port->MODER &= ~(((UNSIGNED32)0x03) << (pinIndex * 2));
port->MODER |= (((UNSIGNED32)0x01) << (pinIndex * 2));

Компилятор видит, что MODER имеет квалификатор volatile, потому в каждой строке он читает из MODER и потом сохраняет полученное значение обратно. Объедини строки, сэкономишь две команды sm.gif
Код
port->MODER = port->MODER  & ~(((UNSIGNED32)0x03) << (pinIndex * 2)) | (((UNSIGNED32)0x01) << (pinIndex * 2));
Forger
Цитата(Reflector @ Apr 19 2017, 20:43) *
Кстати, касательно volatile... Forger, как думаешь что происходит, когда ты в своем классе делаешь так?....

Я так понимаю, оптимизация для многих тут - это как позавтракать: не поел с утра нормально, весь день на смарку ))

Цитата
Объедини строки, сэкономишь две команды sm.gif

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


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

AHTOXA
Цитата(Forger @ Apr 19 2017, 22:41) *
Чистый код - это прежде всего код, который хорошо понятен для того, кто его пишет и сопровождает.

Да. И не всегда его сопровождает тот, кто писал изначально.
Цитата(Forger @ Apr 19 2017, 22:41) *
Но, если удастся себя переучить под большинство, это будет только на пользу коду.

Да.
Цитата(Forger @ Apr 19 2017, 22:41) *
Убежден, что "общепринятый стандарт" придуман для тех, у кого нет своих правил и стандартов. У меня есть свой стандарт, долго его формировал из чужого кода и книжек.

Это не "общепринятый стандарт", это стандарт языка.
Цитата(Forger @ Apr 19 2017, 22:41) *
Мне ломает глаз эта uint32_t, мне лично удобнее U32

Понятно. То есть, вам не удалось "переучить себя под большинство". Чем же тут гордиться?
Цитата(Forger @ Apr 19 2017, 22:41) *
Буду рад если найдете баги или еще более лучшие решения, но придирки к оформлению и мелочам предлагаю все же оставить за кадром.

Это не мелочи. Вы же сами тут выше в теме много рассуждали о "чистом коде", учили всех, как надо. А когда привели пример - оказалось, что пример ваш - совсем не образчик чистого кода. Вот именно на этом я и хотел акцентировать внимание.
А так - конечно, он у вас работает, он вас устраивает, это всё нормально. Но это - не образец чистого кода.
Forger
Цитата(AHTOXA @ Apr 19 2017, 22:06) *
Да. И не всегда его сопровождает тот, кто писал изначально.

Именно, поэтому я сопровождаю код, если его приходится отдавать на сторону, неким readme, где указано что и как именуется в моем коде (см. чуть ниже).

Цитата
Это не "общепринятый стандарт", это стандарт языка.

Не путайте мух с котлетами: некие "стандарты" именования, принятые когда-то негласно в неких библиотеках и Стандарты Языка - абсолютно разные вещи!

Ничто не мешает использовать свои типы. Лишь бы все подчинялось некой единой принятой программистом идеологии, а не выглядело, как сборная солянка чужих и своих типов.
Именно поэтому для себя я принял четыре простых правила именования:

1) Типы, классы, структуры, перечисления - ColorIndex
2) Поля и методы классов/структур, экземпляры классов/структур, методы классов, локальные переменные функций и методов классов - colorIndex, getColorIndex()
3) Макросы, замены “магических” чисел, поля перечислений - STARTUP_DELAY_MS
4) Элементарные (платформозависимые) типы - UNSIGNED16, FLOAT32 - возможно, буду сокращать такие длинные имена, например: U16, F32 ... но пока это под вопросом.


Цитата
Чем же тут гордиться?

Гордится? Это где ж я озвучивал подобные потребности?

Цитата
Но это - не образец чистого кода.
Где я сказал, что этот кусок кода именно такой?
У меня код постоянно эволюционирует. Есть старые куски кода, которые внешне прекрасно выполняют свою функцию, но внутренне содержимое требует допила.
Например, код Pin, который я привел выше, именно такой - функционалом я пока что доволен, а внутренне содержание под сомнением. Как дойдут руки до него, допилю.
Эдди
Цитата(Forger @ Apr 19 2017, 20:41) *
Мне ломает глаз эта uint32_t

Хе-хе...
Forger, надо тебе букву 't' добавить. И забыть как о страшном сне! Вообще полное деление на нуль!
AHTOXA
Цитата(Forger @ Apr 20 2017, 00:39) *
Не путайте мух с котлетами: некие "стандарты" именования, принятые когда-то негласно в неких библиотеках и Стандарты Языка - абсолютно разные вещи!

Это не "некие стандарты, принятые в неких библиотеках", а стандартный (прописанный в стандарте языка) заголовок из стандартной (прописанной в стандарте языка) библиотеки. Типы из которого безо всяких дополнительных readme понятны всем программистам. То, что вы используете вместо этих стандартных типов какие-то свои - усложняет сопровождение. Вместо int вы тоже что-то используете? А то у него буковки маленькие, не вписывается в ваш способ наименованияsm.gif
Цитата(Forger @ Apr 20 2017, 00:39) *
Где я сказал, что этот кусок кода именно такой?

Ну, это подразумевалось. После стольких лекций про чистый код вы выкатили пример. Или это был "антипример", и я просто не понял идеи?
Цитата(Forger @ Apr 20 2017, 00:39) *
Например, код Pin, который я привел выше, именно такой - функционалом я пока что доволен, а внутренне содержание под сомнением.

Это слабо сказано - "под сомнением". Я бы сказал - так себе код. Очень неоптимальный, с какими-то самопальными типами, с нелогичной иерархией классов.
Forger
Цитата
Вместо int вы тоже что-то используете?

Разумеется! Но причина не в буковках, а в том, что в разных платформах int имеет различную разрядность - в PIC/AVR/STM8 он 16-битный, во ARM - 32-битный
Более того, в различных компиляторах по-умолчанию int - знаковый, а в некоторых - нет.
float тоже может иметь различную разрядность на разных платформах, поэтому я явно указываю в платформозависимых типах разрядность типа числом, это оказалось очень полезным.

выдержка из википедии:

Цитата
Реальный размер целочисленных типов зависит от реализации. Стандарт лишь оговаривает отношения в размерах между типами и минимальные рамки для каждого типа:

Так long long не должен быть меньше long, который в свою очередь не должен быть меньше int, который в свою очередь не должен быть меньше short. Так как char — наименьший из возможных адресуемых типов, другие типы не могут иметь размер меньше него.

Минимальный размер для char — 8 бит, для short и int — 16 бит, для long — 32 бита, для long long — 64 бита.

Желательно, чтобы тип int был таким целочисленным типом, с которым наиболее эффективно работает процессор. Это позволяет достигать высокой гибкости, например, все типы могут занимать 64 бита. Однако, есть популярные схемы, описывающие размеры целочисленных типов.[7]

На практике это означает, что char занимает 8 бит, иshort 16 бит (также, как и их беззнаковые аналоги). int на большинстве современных платформ занимает 32 бита, а long long 64 бита. Длина long варьируется: для Windows это 32 бита, для UNIX-подобных систем — 64 бита.


Цитата
Это слабо сказано - "под сомнением". Я бы сказал - так себе код. Очень неоптимальный, с какими-то самопальными типами, с нелогичной иерархией классов.

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

Вам не годится мой подход, мне - ваш.
Врядли дальнейшая наша болтовня полемика это как-то изменит wink.gif
Поэтому предлагаю переключить внимание на что-то другое ....


Вот до кучи мои типы данных (платформа ARM Cortex-M)

Код
typedef unsigned            UNSIGNED1;
typedef unsigned char        UNSIGNED8;
typedef unsigned short        UNSIGNED16;
typedef unsigned int            UNSIGNED32;
typedef unsigned long long         UNSIGNED64;
typedef signed char            SIGNED8;
typedef signed short            SIGNED16;
typedef signed int            SIGNED32;
typedef signed long long         SIGNED64;
typedef float                FLOAT32;
typedef double                FLOAT64;


Вот эти макросы считаю очень полезными (макросы применяю крайне редко, вообще, стараюсь их заменять функциями, если это возможно):
Код
#define MAKE_UNSIGNED32(high,low)        ((((UNSIGNED32)high) << 16) + low)
#define LOW_UNSIGNED16(unsigned32)        ((UNSIGNED16)((UNSIGNED32)(unsigned32) & 0x0000FFFF))
#define HIGH_UNSIGNED16(unsigned32)        ((UNSIGNED16)((UNSIGNED32)(unsigned32) >> 16))

#define MAKE_UNSIGNED16(high,low)        ((((UNSIGNED16)high) << 8) + low)
#define MAKE_SIGNED16(high,low)            ((SIGNED16)MAKE_UNSIGNED16(high,low))
#define LOW_UNSIGNED8(unsigned16)        ((UNSIGNED8)((UNSIGNED16)(unsigned16) & 0x00FF))
#define HIGH_UNSIGNED8(unsigned16)        ((UNSIGNED8)((UNSIGNED16)(unsigned16) >> 8))


Еще раз на всякий случай повторюсь для потомственных "танкистов": не нравится моя реализация, не пользуйтесь, обещаю, что настаивать не буду sm.gif
juvf
Цитата(AHTOXA @ Apr 19 2017, 19:18) *
Насчёт быстрее - вряд ли, скорее будет паритет. Насчёт удобнее - всяко. Сравните:

Код
#define csOn() (GPIOA->BSRR = (1<<4))
#define csOff() (GPIOA->BSRR = (1<< (4 + 16)))
#define csCpl() (GPIOA->ODR ^ (1<<4))

vs
Код
using CS = Pin<'A', 4>;
CS::On();
CS::Off();
CS::Cpl();
АНТОХА... не путайте мухи с котлетами.... вы сравниваете определение vs использование.
Вот использование vs использование
Цитата
csOn();
csOff();
//или
CS::On();
CS::Off();

при использовании с дефайнами даже объявление не нужно, т.е. нет строки using CS = Pin<'A', 4>;

давайте сравним опеределение vs определение
Цитата
#define csOn() (GPIOA->BSRR = GPIOA_BSRR_BR4)
#define csOff() (GPIOA->BSRR = GPIOA_BSRR_BS4)
//или
.....


2Forger
Цитата
Более того, в различных компиляторах по-умолчанию int - знаковый, а в некоторых - нет.
пруфлинк? Стандарт строго оговаривает, что int - знаковый.
Цитата
float тоже может иметь различную разрядность на разных платформах
пруф? Стандарт оговаривает 4 байта в формате IEEE754

Цитата
Код
typedef unsigned            UNSIGNED1;
wtf? Это bool чтоли?
Цитата
signed int SIGNED32;
я высказывался за свой вкус про всякие SIGNED32, U32.... тут даже не вкус. почему мне не нравиться: если скописастить кусок кода из другово проекта, то не соберётся, нужно тащить до кучи мои типы данных. Это напрегает. в коде могут быть заимствования из 3-х 4-х проектов. получается для каждого стиля до кучи нужно тащить типы данных. В одном проекте можно увидеть весь зоопарк определений.
во вторых.... Forger я понял, что для вас литералы - это магические цыфры.... 0x10 или 0b1010110- это что-то плохое, что мешает чтению кода. есть стандартный uint32_t. А использование своих типов взамен стандартных - вы считаете это тру стиль?

в третих.... ну даже если там глаз режет uint32_t. вам милее U32. Дело вкуса. Но, у вас в тайпдефе мина. например
typedef signed int SIGNED32;
вы пишете какойнибудь код.... допусим расчет CRC на ARM. Один раз написал и забыл. Но встала задача посчитать CRC на Atmega. там int не 32. Вы/коллега/ученик перенёс на АВР ваш код... и упс!!!
почему бы не определить так?
typedef int32_t SIGNED32;

Цитата
Здорово, но раз есть csOn(), то как минимум должен быть и csOff()
естественно.... так же как и в шаблонах/классах

Цитата
потом захочется записать битик и дополнительно придется делать проверки...
чего?

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

Alechek
Цитата(juvf @ Apr 20 2017, 08:50) *
Либо С++ с ООП в полный рост безоговорочно.... с оверинженерингом, либо если один макрос или литерал воткнут - то это непрофессионализм. Использование стандартного литерала х и b - это фу фу фу, магическая цифра.... зато SIGNED32 (при чем с миной) - это круть!!!!

+1
еще я улыбнулся над миной
Код
class PinBase
{
public:
....
    inline void toggle(void) { port->ODR ^= pinMask; }

C++ это круто, но про многопоточность мы не слышали.
Timmy
Цитата(Reflector @ Apr 19 2017, 20:43) *
Кстати, касательно volatile... Forger, как думаешь что происходит, когда ты в своем классе делаешь так?
Код
port->MODER &= ~(((UNSIGNED32)0x03) << (pinIndex * 2));
port->MODER |= (((UNSIGNED32)0x01) << (pinIndex * 2));

Компилятор видит, что MODER имеет квалификатор volatile, потому в каждой строке он читает из MODER и потом сохраняет полученное значение обратно. Объедини строки, сэкономишь две команды sm.gif
Код
port->MODER = port->MODER  & ~(((UNSIGNED32)0x03) << (pinIndex * 2)) | (((UNSIGNED32)0x01) << (pinIndex * 2));

Независимо от читабельности и эффективности первый вариант крайне не рекомендуется к использованию, так как он порождает промежуточные состояния аппаратуры, каждое из которых должно быть тщательно проверено на отсутствие побочных эффектов.
В процитированном примере возможен следующий сценарий: некий пин переключается между режимами output и alternate. Первый вариант на некоторое время поставит пин в input mode. Если между двумя записями в MODER произойдёт прерывание, то пин зависнет в input mode надолго, и подтяжка может переключить его в неожиданное для разработчика состояние - здравствуй, трудноуловимый глюк!
Кстати, в стандартном HAL такого ляпа с MODER нет.
AHTOXA
Цитата(Forger @ Apr 20 2017, 02:46) *
Более того, в различных компиляторах по-умолчанию int - знаковый, а в некоторых - нет.
...
typedef unsigned UNSIGNED1;

Ну это всё, приплыли.
Forger
Цитата(Alechek @ Apr 20 2017, 08:22) *
+1
еще я улыбнулся над миной
Код
class PinBase
{
public:
....
    inline void toggle(void) { port->ODR ^= pinMask; }

C++ это круто, но про многопоточность мы не слышали.

А вот я слышал и не по наслышке, т. к. практически везде, где используется с++, у меня стоит rtos.
Что по-вашему в этом куске кода не так?

Цитата(AHTOXA @ Apr 20 2017, 09:08) *
Ну это всё, приплыли.

Это было сделано для обозначения битовых полей различной ширины в структурах, осталось в наследство, в настоящее время практически не используется.
AHTOXA
Цитата(juvf @ Apr 20 2017, 08:50) *
давайте сравним опеределение vs определение


Вот определение vs определение:
Код
#define csOn() (GPIOA->BSRR = (1<<4))
#define csOff() (GPIOA->BSRR = (1<< (4 + 16)))
// или
using CS = Pin<'A', 4>;


Вот использование vs использование:
Код
csOn();
csOff();
//или
CS::On();
CS::Off();
Forger
Цитата(juvf @ Apr 20 2017, 06:50) *
пруфлинк?
Все было указано выше. Читайте внимательнее.

Цитата
Стандарт строго оговаривает, что int - знаковый.
пруф? Стандарт оговаривает 4 байта в формате IEEE754

По факту все иначе, читайте внимательнее.

Цитата
wtf? Это bool чтоли?

НЕТ, читайте стандарт.

Цитата
почему бы не определить так?
typedef int32_t SIGNED32;

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





juvf
Цитата(AHTOXA @ Apr 20 2017, 11:16) *
Вот определение vs определение:
Код
#define csOn() (GPIOA->BSRR = (1<<4))
#define csOff() (GPIOA->BSRR = (1<< (4 + 16)))
// или
using CS = Pin<'A', 4>;
где определение шаблона Pin<>? ещё 100500 строк!!!

Цитата
Что по-вашему в этом куске кода не так?
ну вы не видите, что ваш тогл, при "одновременном" переключении разных бит, в одном порте из разных потоков не будет работать?

Цитата(Forger @ Apr 20 2017, 11:22) *
Потому что в самом голом компиляторе нет такого типа, он создан в виде одного из typedef в одном из библиотечных инклклудов.
Т.е. нужно еще и подключать некий библиотечный файл, где этот тип описан.
В целом это все придирки.
Т.е. вы не оспариваете что у вас мина в коде, вам предлагают её разминировать, на что ответ - это придирки. ))) Профессиональный подход, чистый код, легкочитаемый и переносимый .... ну ну .. )))


Цитата
читайте внимательнее.
225 постов.... не увидел где была ссылка или упоминание на стандарт, в котором int беззнаковый. Не могли бы вы меня ткнуть носом, плииз.... приходится унижаться, чтоб получить знания, ДОЖИЛИ!!!
И о каком стандарте вы говорите, в котором всё иначе? может мы на разных языках пишем? Я думал мы тут делимся опытом, а не писками меримся. Просто отказ подкрепить свои слова пруфлинком выглядит как пустые слова... у меня длиньше, но я не покажу
AHTOXA
Цитата(Forger @ Apr 20 2017, 11:22) *
Все было указано выше. Читайте внимательнее.

То есть, вы продолжаете утверждать, что int может быть беззнаковым?! Жесть.


Цитата(juvf @ Apr 20 2017, 11:24) *
где определение шаблона Pin<>? ещё 100500 строк!!!

А где определение GPIOA? Ещё 100500 строк! sm.gif
Мы же говорим про использование. То есть, библиотеки считаются уже написанными и оттестированными. Это, кстати, тоже большой их плюс.
jcxz
Цитата(AHTOXA @ Apr 20 2017, 08:37) *
То есть, вы продолжаете утверждать, что int может быть беззнаковым?! Жесть.

char - может быть sm.gif
Forger
Цитата(AHTOXA @ Apr 20 2017, 09:37) *
То есть, вы продолжаете утверждать, что int может быть беззнаковым?! Жесть.

В некоторых компиляторах, особенно под мелкие 8-битные мк может быть все что угодно.
Я уже наступал на грабли, где по-умолчанию char - знаковый.
Дабы избежать этого, везде писал явно unsigned/signed.
Потом перешел на свои типы (привел выше).
Мне так стало гораздо удобнее, меньше головной боли и ненужных переживаний.
juvf
Цитата(AHTOXA @ Apr 20 2017, 11:37) *
Мы же говорим про использование. То есть, библиотеки считаются уже написанными и оттестированными. Это, кстати, тоже большой их плюс.
ну вот у меня новая задача. stm32l052. от чего я эту тему и открыл. Нужно быстро код написать....
цепляю #include "stm32l052xx.h"
написал макрос, т.е. написал определение

#define csOn() (GPIOA->BSRR = (1<<4))
использую
csOn();
если нет stm32l052xx.h - можно заглянуть в даташит (а в него всё равно глядеть) и написать
#define csOn() (*(uint32_t*)0x1234'5678 = (1<<4))
не камельфо, но всёже... один раз определил и забыл.


Но, есть замечательный тру с++ с ооп. чо как лох буду макросы. Нада же легкочитаемый код....
можно через Pin<>. Где его взять? вместе с stm32l052xx.h он не поставляется. писать свой? отлаживать? скаченный с гитхаба для Ф4 серии. а если вообще решили на msp430? Я говорю - это 100500 строк кода. Причем, в этом pin используется всё тотже stm32l052xx.h.
AHTOXA
Цитата(Forger @ Apr 20 2017, 11:55) *
В некоторых компиляторах, особенно под мелкие 8-битные мк может быть все что угодно.
Я уже наступал на грабли, где по-умолчанию char - знаковый.

Вы не сворачивайте на char. Вы про int скажите.
Forger
Цитата(juvf @ Apr 20 2017, 09:36) *
ну вы не видите, что ваш тогл, при "одновременном" переключении разных бит, в одном порте из разных потоков не будет работать?

Я никогда не обращаюсь к одним и тем же пинам из разных потоков, в моем коде это невозможно, т.к. каждый пин - не глобальный ни разу, а является приватным полем какого-нить класса.
У меня совсем иной принцип построения кода - ни одной глобальной переменной/объекта, даже Pin чей-то.
Более того, работа с пинами скрыта внутри реализации какого-то из модулей и модуль сам решает, что и как у него взять/дать.
Это дает возможность прямо в модуле реализовывать механизмы блокировки (мьютексы), чтобы избежать конкуррентного доступа к каким-то объектам.
Поймите, я приучил себя думать иначе, поэтому повторюсь еще раз для потомственных "танкистов": каждая сущность кому-то принадлежит, не НИ ОДНОГО ГЛОБАЛЬНОГО ОБЪЕКТА.

Цитата
Т.е. вы не оспариваете что у вас мина в коде, вам предлагают её разминировать, на что ответ - это придирки. )))

У меня эта "мина" никогда не сработает, проекты изначально построены иначе. Поэтому подобные "затычки" просто не нужны.
Это позволяет строить код более свободно, не ломая голову над такими граблями.

Цитата
225 постов.... не увидел где была ссылка или упоминание на стандарт, в котором int беззнаковый.

Стандарт тут ни при чем, я говорю про особенности некоторых компиляторов под некоторые МК. Я сталкивался с таким.
В частности под PIC-контроллеры: то ли PICC-компилятор, то ли MCC, уже не упомню где именно.
Поэтому проверять так это или нет в новом компиляторе не хочу, мне проще прикрутить несколько строк, которые ЯВНО тайпдефят эти типы на привычные МНЕ.

Цитата(AHTOXA @ Apr 20 2017, 10:01) *
Вы не сворачивайте на char. Вы про int скажите.

Не скажу, давно это было, не помню, где именно. Но почему-то запомнилось что int там был 16-битный.
AHTOXA
Цитата(juvf @ Apr 20 2017, 12:00) *
ну вот у меня новая задача. stm32l052. от чего я эту тему и открыл. Нужно быстро код написать....

Ну, выбор, конечно, за вами. Вы каждый раз готовы писать
GPIOA->MODER = (GPIOA->MODER & ~(3UL << pin * 2)) | (2 << pin * 2);
и лазать в даташит на каждом проекте. (Или, может быть, вы способны выучить все режимы ножек и перечень альтернативных функций для каждой ножки - тогда не нужно лазать). Я лично потратил некоторое время на написание модуля, который сам знает про все эти подробности, и теперь пишу CS::Mode(INPUT_PULLUP) и не парюсь.
Я думаю, что в долгосрочной перспективе мой подход лучше. Но выбор, естественно, за вами.

ЗЫ. Для L0/F0 серии тоже есть pin.h sm.gif
juvf
Цитата(Forger @ Apr 20 2017, 11:55) *
Я уже наступал на грабли, где по-умолчанию char - знаковый.
По стандарту char/int/long - без указания знаковости считаются знаковые. Во всех компиляторах. Нет других компиляторов. По крайней мере я не встерчал. если встретите - маякните, поизучаю.

что касательно этих граблей.... можно дать ключ компилятору, считать char без явного указания unsigned/signed как беззнаковый. у int/short/long это не поменять, только у char.
я char использую всегда как занковый, как стандартный дефолтный. ибо если собрать на другой платформе без ключа - то упс!!! Но, в идэ, например в IAR в гуях есть галочка "char как беззнаковый". При создании нового проекта, эта галочка установлена, т.е. иар в тихушку просовывает этот ключ компиялтору меняя у чара знак. Я тоже на это наступал.... решил проблему отказом от char взамен на uint8_t в качестве байтовой переменной. или же всегда указываю у чара явно знаковость. а если мне нужно хранить текст, например char *p = "hello world"; - тут без разницы - есть знак или нет, тут можно упустить знак.

Цитата
Дабы избежать этого, везде писал явно unsigned/signed.
Для чара это тру!!!
из-за таких тихих подстав от IDE у некоторых складывается впечатление, что char по дефолту беззнаковый.


Цитата(AHTOXA @ Apr 20 2017, 12:14) *
ЗЫ. Для L0/F0 серии тоже есть pin.h sm.gif
Спасибо большое!!!! А есть для f1 и вообще... огласите полный список? )))) может и для авр кто написал такие классы? ))
AHTOXA
Цитата(Forger @ Apr 20 2017, 12:14) *
Не скажу, давно это было, не помню, где именно. Но почему-то запомнилось что int там был 16-битный.

Беззнаковый?
juvf
Цитата(Forger @ Apr 20 2017, 12:14) *
Я никогда не обращаюсь к одним и тем же пинам из разных потоков, в моем коде это невозможно, т.к. каждый пин - не глобальный ни разу, а является приватным полем какого-нить класса.
пишете мне Читайте внимательней, а сами невнимательны wink.gif. Я писал
Цитата
ну вы не видите, что ваш тогл, при "одновременном" переключении разных бит, в одном порте из разных потоков не будет работать?
давайте перефразирую

Цитата
ну вы не видите, что ваш тогл, при "одновременном" переключении разных пинов, в одном порте из разных потоков не будет работать?

вы в одном потоке дергаете cs? который есть PA13, а в другом потомке маргаете диодом который сидит на PA5.
Forger
Цитата(juvf @ Apr 20 2017, 10:17) *
можно дать ключ компилятору

В моей явной реализации типов вообще не нужно разбираться с особенностями конкретного компилятора, галочками и т.п.
Один раз составил эти тайпдефы под новый компилятор, проверил соответствие разрядности (при сомнениях) и ЗАБЫЛ.
При написании очередного кода категорически не хочу держать в голове, что там у компилятора по-умолчанию, а что нет. У меня других забот хватает )))

Цитата(juvf @ Apr 20 2017, 10:21) *
вы в одном потоке дергаете cs? который есть PA13, а в другом потомке маргаете диодом который сидит на PA5.

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


juvf
Цитата(Forger @ Apr 20 2017, 12:22) *
В моей явной реализации типов вообще не нужно разбираться с особенностями конкретного компилятора, галочками и т.п.
я вам не говорю, что явно не надо задавать. я вам говорю, что int - всегда знаковый. и объяснил вам от куда у вас были грабли с чаром. и что компиляторы одинакого компилят.
Forger
Цитата(juvf @ Apr 20 2017, 10:28) *
я вам не говорю, что явно не надо задавать. я вам говорю, что int - всегда знаковый. и объяснил вам от куда у вас были грабли с чаром. и что компиляторы одинакого компилят.

У меня нет граблей с char-ом и другими типами уже давно, очень давно )))
AHTOXA
Цитата(juvf @ Apr 20 2017, 12:17) *
Спасибо большое!!!! А есть для f1 и вообще... огласите полный список? )))) может и для авр кто написал такие классы? ))

Вот собственно главный pin.h, который подключает уже нужный pin_xxx.h, в зависимости от контроллера. Список поддерживаемых контроллеров - там же. Это для STM32.
Для AVR есть вот такой набор макросов. Это знаменитые в узких кругах "Макросы Аскольда Волкова". Собственно, я от них отталкивался, когда писал свой pin.h.

Ещё известные мне варианты pin.h:
juvf
Цитата(Forger @ Apr 20 2017, 12:28) *
Но и в данном случае проблем тоже не будет - в MODER пишется маска, меняющая всего лишь ОДИН соотв. бит, а не группу битов.
Даже если переключение задач произойдет прямо посреди переписывания MODER или формирования этой маски, ничего страшного не будет - доступ к MODER атомарный, он не переписывается кусками.

бррррр... а при чем тут модер? )))) от куда вброс про многопоточность? вот от куда

Цитата
Код
inline void toggle(void) { port->ODR ^= pinMask; }


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

Цитата(Forger @ Apr 20 2017, 12:30) *
У меня нет граблей с char-ом и другими типами уже давно, очень давно )))

я вам про фому - вы мне про ерёму ))))
Forger
Цитата(juvf @ Apr 20 2017, 10:32) *
тогел потоко не защищённый. Осторожно, тут мины!! ))

Я же говорил, что к одному и тому же пину у меня в коде НИКОГДА нет обращения их РАЗНЫХ потоков.
Это исключено еще на этапе построения проекта.
Поэтому не будет ничего страшного, если кто-то прервет эту строчку с ODR.
В крайнем случае могу использовать CriticalSection, если нужно сохранить строгую последовательность некого пинодрыга, но пока еще с таким я не сталкивался.
ViKo
ЕМНИП, в компиляторе Hi-Tech для PIC тип char был беззнаковый по умолчанию, но можно было задать знаковый. К спору об int не относится, с ним ясно всем, кроме одного. rolleyes.gif
AHTOXA
Цитата(Forger @ Apr 20 2017, 12:28) *
Цитата(juvf @ Apr 20 2017, 12:21) *

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

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

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

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

ЗЫ. Рано вы взялись за "Чистый код". Надо было сначала основы подтянуть.
Forger
Цитата(AHTOXA @ Apr 20 2017, 10:42) *
1. Проблема с двухэтапной записью в MODER. Выше уже очень хорошо объяснили, что это нехорошо. Потому что ножка переводится в промежуточное состояние, которое может быть нежелательным. И при возникновении прерывания между двумя записями ножка может остаться в этом состоянии достаточно продолжительное время. Этого может быть достаточно, чтобы что-нибудь сжечь. Это реальная мина, потому что на столе может всё работать, а в продакшене может рвануть.
В моих схемах ни одна ножка не висит в воздухе, всегда есть внешняя подтяжка, это связано с непредсказуемым поведение схемы, пока проц в состоянии сброса или прошивается.
Поэтому в моих проектах это не создает никаких проблем ))
Внутренние пуллапы может быть и полезны разве что для входных пинов, т.е. те, которые всегда настроены на вход.

Цитата
2. Проблема с неатомарностью операции GPIOA->ODR ^= bit. (Об этом вам пишет juvf). Дело в том, что если такие операции выполняются одновременно из разных потоков (к разным битам одного порта), то возможны сбои. Разжёвывать не буду, гуглите.
Вы хотите сказать, что операция обращения к ODR неатомарнае, например, копирование из регистра R2 -> [R3], где R3 хранит адрес ODR-регистра?
Вы точно ничего не путаете?
juvf
Цитата(Forger @ Apr 20 2017, 12:37) *
Я же говорил, что к одному и тому же пину у меня в коде НИКОГДА нет обращения их РАЗНЫХ потоков.
Это исключено еще на этапе построения проекта.
Поэтому не будет ничего страшного, если кто-то прервет эту строчку с 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-регистра?
БИНГО!!!!
Reflector
Цитата(juvf @ Apr 20 2017, 06:50) *
естественно.... так же как и в шаблонах/классах

Для класса ты пишешь всякие 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 (при чем с миной) - это круть!!!!

Здорово, особенно учитывая, что про бинарные литералы в С++ тебе рассказал именно я sm.gif
juvf
Цитата(Reflector @ Apr 20 2017, 12:56) *
....
Даже коментировать тут нечего.... Полемика. Ну я же говорю, бинарно мыслите... при чем тут уарт? я вам сказал что макросы ВЕЗДЕ лучше классов/шаблонов?


Цитата(Reflector @ Apr 20 2017, 12:56) *
На радиокоте недавно спрашивали как записать 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);

Он понятнее и эффективнее, т.к. никаких проверок в нем нет.
я бы не так сделал. была подобная задача.
Forger
Цитата(juvf @ Apr 20 2017, 10:51) *
...

Так глубоко в компилятор я не влезал, щас влез в asm код, который нагенерил компилятор для toggle() ...
Действительно, возможны глюки, надо переписывать!
Вот и баги нашлись smile3046.gif
Хотя до сих пор, проблем не было, но это - вопрос времени, нужно обязательно переделать!

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

зы. Пока писал, нашел простое на мой взгляд решение - некий более старший в иерархии класс Port, который уже будет предоставлять функционал Pin более потоко-безопасно.
К тому же этот Port сможет предоставить возможность массовой настройки пинов (например, подключена внешняя память на параллельной шине).
Reflector
Цитата(juvf @ Apr 20 2017, 11:11) *
Даже коментировать тут нечего.... Полемика. Ну я же говорю, бинарно мыслите... при чем тут уарт? я вам сказал что макросы ВЕЗДЕ лучше классов/шаблонов?

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

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

Не знаю какая там была задача в целом, потому исходил из того, что нужно записывать по одном биту. В любом случае тебе придется делать новый макрос, или несколько.
juvf
Цитата(Forger @ Apr 20 2017, 13:28) *
Есть идеи, как переделать void toggle() { port->ODR ^= pinMask; }, избежав критических секций?

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

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




Цитата
зы. Пока писал, нашел простое на мой взгляд решение - некий более старший в иерархии класс Port, который уже будет предоставлять функционал Pin более потоко-безопасно.
К тому же этот Port сможет предоставить возможность массовой настройки пинов (например, подключена внешняя память на параллельной шине).
!!! Извини.... но блин.... это всего лишь ногой дёрнуть!!! ))))))))))))
AHTOXA
Цитата(Forger @ Apr 20 2017, 13:28) *
Есть идеи, как переделать void toggle() { port->ODR ^= pinMask; }, избежав критических секций?

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

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

juvf
Цитата(AHTOXA @ Apr 20 2017, 13:56) *
Да и ерунда всё это, на самом деле. Я лично не помню, чтобы где-то использовал cpl(), кроме тестов.

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

ps ещё програмный меандр выдавать.... можно найти применение cpl-ю
Reflector
Цитата(juvf @ Apr 20 2017, 11:55) *
Навскидку...

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

Ага, но только что я приводил пример практически такого-же кода, как не самого эффективного, т.к. там будет проверка.
Код
redLed.write(!redLed.read());

То же самое, но без лишней инструкции ITE.
ps. Упс, сорри, это совсем не тоже самое, т.к. читает с IDR sm.gif Но сути это не меняет, меняем IDR на ODR, но код прячем внутри класса.

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

У F0 ITE нет, там проверки еще более тяжелые.
Forger
Цитата(juvf @ Apr 20 2017, 11:55) *
Код
void toggle() { port->BSRR = (port->ODR & pinMask) == 0 ? pinMask : pinMask << 16; }

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

Но я предпочитаю более читаемо:
Код
void toggle() { if (isLow()) setToHigh(); else setToLow(); }


Впрочем, этот toggle (добавил совсем недавно) у меня пока что использовался лишь для моргания лампочкой, поэтому багов не было.
Но исправить все же нужно, дабы больше не возвращаться к этому вопросу.
AHTOXA
Цитата(juvf @ Apr 20 2017, 14:08) *
есть проект, где светодиод мигает, показывая живучесть системы. не было cpl, использовал с дополнительным флагом сет/ресет. А так бы было бы удобно cpl.

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


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

ЗЫ. Я там вам ответил про варианты pin.h, возможно вы проглядели (тема растёт очень быстро).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.