Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Библиотеки для STM32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3, 4, 5, 6, 7, 8
Шаманъ
Цитата(juvf @ Apr 21 2017, 12:06) *
Если у бабки были бы яйца... Только я в своем примере указал GPIO_ToggleBits() от стм, а они пользуют ODR, а не BSRR. а так согласен, запись в BSRR не создаст колизии, и тем не мение, осутствие аппаратного тогла требует лишней проверки выхода.

Что у стм не знаю, извиняюсь, но не пользовался никогда. Проверка (если Вы про ? или if) не обязательна, я уже приводил пример:
Цитата(Шаманъ @ Apr 21 2017, 11:42) *
Для внешнего устройства по идее достаточно (скажем для битов 0 и 7):
GPIOx->BSRR = (~GPIOx->IDR & 0x81) | 0x00810000;


Если же Вы про чтение порта, то я уже писал, что это плюс для аппаратного тоггла.

Цитата(jcxz @ Apr 21 2017, 12:08) *
Ну вот например:
У Вас параллельная шина от Вашего МК к другому устройству, работает через GPIO, несколько сигналов данных и один - квитирования.
Работает как шина DDR - т.е. обновление данных на шине фиксируется не по фронту или спаду, а по перепаду сигнала квитирования. Так получается можно быстрее данные передавать.
А теперь представим, что для быстрого вывода на эту шину мы и линии данных и сигнал квитирования расположили в одном порту.
Тогда чтобы вывести данные на эту шину достаточно одной операции записи. И никакие дополнительные средства обеспечения атомарности не нужны (типа запретов прерываний).

Пример несколько футуристический и вызывает много вопросов "зачем?", самый главный - зачем писать данные из двух потоков в один порт без синхронизации (порт в данном случае не GPIO порт, а Ваш "виртуальный" а-ля DDR канал)? Мне кажется такое построение это некоторая ошибка в построении всей архитектуры системы или "синтетический пример".
Reflector
Цитата(Шаманъ @ Apr 21 2017, 12:40) *
Пример несколько футуристический и вызывает много вопросов "зачем?", самый главный - зачем писать данные из двух потоков в один порт без синхронизации? Мне кажется такое построение это некоторая ошибка в построении всей архитектуры системы или "синтетический пример".

Если запись любого числа битов в порт через BSRR атомарна, а она именно такова, то в принципе не нужно задумываться с каким портом в данный момент работаешь.
Шаманъ
Цитата(Reflector @ Apr 21 2017, 12:46) *
Если запись любого числа битов в порт через BSRR атомарна, а она именно такова, то в принципе не нужно задумываться с каким портом в данный момент работаешь.

Не, я не про то, подредактировал свой вопрос и уточнил про какой "порт" я говорил:
Цитата(Шаманъ @ Apr 21 2017, 12:40) *
Пример несколько футуристический и вызывает много вопросов "зачем?", самый главный - зачем писать данные из двух потоков в один порт без синхронизации (порт в данном случае не GPIO порт, а Ваш "виртуальный" а-ля DDR канал)?
juvf
Цитата(Шаманъ @ Apr 21 2017, 14:40) *
Что у стм не знаю, извиняюсь, но не пользовался никогда. Проверка (если Вы про ? или if) не обязательна, я уже приводил пример:

Цитата
Для внешнего устройства по идее достаточно (скажем для битов 0 и 7):
GPIOx->BSRR = (~GPIOx->IDR & 0x81) | 0x00810000;
а это разве не проверка?
1)читаем GPIOx->IDR (только правильнее будет ODR)
2)инвертируем ~GPIOx->IDR
3)& 0x81
4)| 0x00810000
5)записываем BSRR
хотя согласен, для более одного пина, ваш вариант лучше, чем явные ? и if


с аппаратным тогл, как в XMC4700/4800
1)GPIOx->BSRR = 0x0081'0081;//одна операция!!!
jcxz
Цитата(Reflector @ Apr 21 2017, 11:46) *
Если запись любого числа битов в порт через BSRR атомарна, а она именно такова, то в принципе не нужно задумываться с каким портом в данный момент работаешь.

Запись атомарна, но в условии задачи указано "сигнал квитирования надо инвертировать". А значит на STM одной операцией записи не обойтись.
Reflector
Цитата(jcxz @ Apr 21 2017, 12:55) *
Запись атомарна, но в условии задачи указано "сигнал квитирования надо инвертировать". А значит на STM одной операцией записи не обойтись.

Это да, но атомарную запись можно получить именно благодаря тому, что при одновременных установке и сбросе бита никакой инверсии нет. Если бы она была пришлось бы добавлять еще один регистр, так что при условии, что подобный регистр всего один была выбрана более полезная его функциональность.
jcxz
Цитата(Шаманъ @ Apr 21 2017, 11:40) *
Пример несколько футуристический и вызывает много вопросов "зачем?", самый главный - зачем писать данные из двух потоков в один порт без синхронизации (порт в данном случае не GPIO порт, а Ваш "виртуальный" а-ля DDR канал)? Мне кажется такое построение это некоторая ошибка в построении всей архитектуры системы или "синтетический пример".

Понятно, что пример синтетический. В реальной практике у меня такой задачи не было.
Но вот например у Вас есть внешняя память (SDRAM) скажем на нормальной шине. Вы же пишете в неё из разных задач/ISR не задумываясь об атомарности - это всё сделано на аппаратном уровне. Полезность такой записи из разных задач очевидна?
А теперь представьте, что в МК нет внешней шины, или что эта шина не поддерживает устройство в которое надо писать. А это устройство имеет интерфейс, подобный DDR.
И пакетные записи не нужны - каждая запись имеет значение (собственно этой записью передаётся некая команда в устройство).
Все возможные схемы представить сложно, но имхо это - вполне жизненный вариант.

У меня когда-то давно была практическая задача подобная этой, но там правда не надо было обращаться к шине из разных задач, но нужно было как можно быстрее передавать по такой шине. И при этом - на данном порту были ещё другие пины, которые трогать было нельзя.
И в таком случае с регистром BSRR STM32 можно конечно реализовать такую передачу, но реализация получается более громоздкой чем на Infineon или LPC.

Цитата(Reflector @ Apr 21 2017, 12:06) *
Это да, но атомарную запись можно получить именно благодаря тому, что при одновременных установке и сбросе бита никакой инверсии нет. Если бы она была пришлось бы добавлять еще один регистр, так что при условии, что подобный регистр всего один была выбрана более полезная его функциональность.

Зачем добавлять??? На Infineon я прекрасно и устанавливаю и сбрасываю и инвертирую пины одной операцией записи.
BSRR = 1 << pin; //установка
BSRR = 1 << pin + 16; //сброс
BSRR = 0x10001 << pin; //инверсия
Reflector
Цитата(jcxz @ Apr 21 2017, 13:08) *
Зачем добавлять??? На Infineon я прекрасно и устанавливаю и сбрасываю и инвертирую пины одной операцией записи.

Речь про STM32, у него только BSRR который дает возможность атомарно записать группу битов не затрагивая остальные пины. Если эту его способность заменить атомарной инверсией, то пользы будет меньше.
jcxz
Цитата(Reflector @ Apr 21 2017, 12:11) *
то пользы будет меньше.

Почему? Не понимаю.
Шаманъ
Цитата(jcxz @ Apr 21 2017, 13:08) *
Все возможные схемы представить сложно, но имхо это - вполне жизненный вариант.

Да, если пакет помещается в одну операцию, то возможно, хотя и несколько "притянуто". В этом варианте аппаратный тоггл рулит.
Reflector
Цитата(jcxz @ Apr 21 2017, 13:08) *
BSRR = 1 << pin; //установка
BSRR = 1 << pin + 16; //сброс
BSRR = 0x10001 << pin; //инверсия

Допустим нужно записать данные только в младшие 4 бита порта, пусть это будет 3. Тогда пишем в BSRR такое число, которое бы, во-первых, сбросило эти 4 бита(0xF << 16), во вторых выставило только нужные(3), итого получает 0x000F0003. Для двух пинов единица там и там, значит будет инверсия...
Шаманъ
Цитата(jcxz @ Apr 21 2017, 13:15) *
Почему? Не понимаю.

Тут было много примеров, где использовалась перманентная установка битов сброса и запись данных в биты установки. В таком варианте фактически получаем регистр ODR с маской или атомарный доступ к любой группе битов. Если ввести аппаратный тоггл, то эту полезность потеряем.
juvf
Цитата(Reflector @ Apr 21 2017, 15:11) *
Речь про STM32, у него только BSRR который дает возможность атомарно записать группу битов не затрагивая остальные пины. Если эту его способность заменить атомарной инверсией, то пользы будет меньше.
Ни кто не предлагает заменить BSRR на инверсию. Предлагают дополнить BSRR ещё и инверсией.

Цитата
Тут было много примеров, где использовалась перманентная установка битов сброса и запись данных в биты установки. В таком варианте фактически получаем регистр ODR с маской или атомарный доступ к любой группе битов. Если ввести аппаратный тоггл, то эту полезность потеряем.
не понятно - что теряем. Задача - перманентно выставлять РА1 и сбрасывать в одной задаче, и переключать РА5 в другой задаче. Если добавить регистр апаратного тогл, какую полезность теряем?
Forger
Цитата(Шаманъ @ Apr 21 2017, 13:18) *
.... аппаратный тоггл ...

Читаю тему и никак не могу вкурить где может потребоваться именно аппаратный тогл, да и вообще тогл?
Мне тоггл понадобился недавно и лишь раз - моргать лампочкой (blink-режим), т. е. случай, где "до лампочки" предыдущее состояние пина.
А во всех остальных случаях нужна явная установка битов в нужное состояние, например: софтовые интерфесы, софтовый ШИМ, софтовое управление шаговым мотором и т. п.
Просветите, кто сталкивался с нуждой тогла как таковой wink.gif
jcxz
Цитата(Шаманъ @ Apr 21 2017, 12:16) *
Да, если пакет помещается в одну операцию, то возможно, хотя и несколько "притянуто". В этом варианте аппаратный тоггл рулит.

Есть и непритянутый пример:
Когда-то реализовывал передачу пакетов данных (1-2 КБ) из LPC17xx по 8-битной шине (GPIO) в CY7C68013A (это чип HS USB с подключением по внешней параллельной шине 8/16 бит с протоколом обмена, который можно запрограммировать самостоятельно написав диаграмму работу внутреннему GPIF).
Главное требование там было - скорость передачи - надо было выплюнуть пакет как можно быстрее. Частота GPIO у LPC ограничена (как и у других МК), у LPC это было что-то около 10МГц. Соответственно - желательно было так построить схему обмена и протокол, чтобы выполнить передачу с минимальным числом записей в GPIO. CY7C68013A работала у меня на частоте то ли 30МГц то ли 48МГц - точно не помню, но помню, что написал диаграмму GPIF так, что она успевала принимать с LPC даже если он будет писать байт за байтом в порт непрерывно (10МГц).
Я поместил сигнал квитирования и 8 линий данных в один порт (на этом порту были также другие сигналы, которые нельзя было трогать при передаче пакета).
Как реализовать такую передачу?
На STM32 её тоже можно реализовать, но на Infineon (и на LPC) код такой передачи получается проще и быстрее.

Цитата(Reflector @ Apr 21 2017, 12:17) *
Тогда пишем в BSRR такое число, которое бы, во-первых, сбросило эти 4 бита(0xF << 16), во вторых выставило только нужные(3), итого получает 0x000F0003

Неверно. Писать нужно 0xC0003.
Reflector
Цитата(jcxz @ Apr 21 2017, 13:33) *
Неверно. Писать нужно 0xC0003.

Ок, в порту было 0xF, очищаем 2 бита, становится 3, пишем 3, остается 3. А если пишем 2? Откуда ты знаешь какое число запишешь? Может оно из массива читается или генерится весьма сложным образом.
juvf
Цитата
Читаю тему и никак не могу вкурить где может потребоваться именно аппаратный тогл, да и вообще тогл?
программный вывод миандра на порт. в прерывании по таймеру дёргать переключать пин.
jcxz
Цитата(Шаманъ @ Apr 21 2017, 12:18) *
Тут было много примеров, где использовалась перманентная установка битов сброса и запись данных в биты установки. В таком варианте фактически получаем регистр ODR с маской или атомарный доступ к любой группе битов. Если ввести аппаратный тоггл, то эту полезность потеряем.

Ну в этом случае - да.
Forger
Цитата(juvf @ Apr 21 2017, 13:36) *
программный вывод миандра на порт. в прерывании по таймеру дёргать переключать пин.

А зачем нужен это меандр? Тоже моргать лапочкой? biggrin.gif
jcxz
Цитата(Reflector @ Apr 21 2017, 12:35) *
Откуда ты знаешь какое число запишешь? Может оно из массива читается или генерится весьма сложным образом.

Не понял Вашу мысль.... wacko.gif
В чём проблема-то? Что именно нельзя сделать? Если не нужно знать предыдущее состояние какого-то пина на порту, но состояние всех остальных можно установить в нужное одной операцией записи. Каким бы сложным ни был генератор.
void SetPins(uint value)
{
BSRR = (value & 255) | (~value << 16);
}

Цитата(Forger @ Apr 21 2017, 12:24) *
Читаю тему и никак не могу вкурить где может потребоваться именно аппаратный тогл, да и вообще тогл?

Я же привёл пример: передача по параллельной шине с квитированием инверсией пина.
juvf
Цитата(Forger @ Apr 21 2017, 15:41) *
А зачем нужен это меандр? Тоже моргать лапочкой? biggrin.gif
есть вопрос - есть ответ. например передача параметра. параметр меняется от p0 - до p100, частота линейно должна меняться от f1 до f2. только не нужно спрашивать - "А это для чего"? или"А почему аппаратно не заюзать выход таймера?".
Или выдаем байт последовательно, как уарт, только биты кодирутся не 0 и 1, а частотой f0 и f1.
Forger
Цитата(jcxz @ Apr 21 2017, 13:47) *
Я же привёл пример: передача по параллельной шине с квитированием инверсией пина.

Полагаю, что это было очень давно, а в данный момент с подобной задачей вы бы справились совсем иначе. Или я не прав? wink.gif


Цитата(juvf @ Apr 21 2017, 13:49) *
Или выдаем байт последовательно, как уарт, только биты кодирутся не 0 и 1, а частотой f0 и f1.

Что-то типа DTMF ? sm.gif
jcxz
Цитата(Forger @ Apr 21 2017, 12:51) *
Полагаю, что это было очень давно, а в данный момент с подобной задачей вы бы справились совсем иначе. Или я не прав? wink.gif

Если с теми же исходными данные - так же. А какое ещё решение?
Если бы была возможность изменить схемотехнику - сейчас может использовал бы МК с HS USB.
В той задаче скорости FS USB не хватало поэтому и поставили CY7C68013A.
juvf
Цитата(Forger @ Apr 21 2017, 15:53) *
Что-то типа DTMF ? sm.gif
нет
Forger
Цитата(jcxz @ Apr 21 2017, 13:55) *
А какое ещё решение?


Цитата
сейчас может использовал бы МК с HS USB.


Я как раз про это - примеры, приведенные тут, как минимум устарели.
В настоящее время и такую задачу найти сложно - дергать целиком порты для реализации некого интерфейса.
Порой выгоднее воткнуть в довесок к основному толстому процу какой-нить копеешный М0/M0+, чтобы тот занимался подобным ногодрыгом.
jcxz
Цитата(Forger @ Apr 21 2017, 13:07) *
Порой выгоднее воткнуть в довесок к основному толстому процу какой-нить М0+.

Т.е. - взять LPC43xx? Это да... biggrin.gif
И решение той задачи мы потом переделали взяв более жирный многоядерный проц. Ибо на LPC1758 хоть и успевало, но работало на пределе и больше почти ничего проц не успевал делать.
Но на тот момент задача стояла так: железо было уже сделано без меня (на LPC1758 + ПЛИС + CY7C68013A), был инвестор с кешем, и надо было ему показать рабочее железо, пускай выполняющее только часть функций. Так что - или сделать на том что есть, или потерять проект вообще. А через годик мы поменяли элементную базу на другой проц и всё cool.gif
Reflector
Цитата(jcxz @ Apr 21 2017, 13:47) *
Не понял Вашу мысль.... wacko.gif
В чём проблема-то? Что именно нельзя сделать? Если не нужно знать предыдущее состояние какого-то пина на порту, но состояние всех остальных можно установить в нужное одной операцией записи. Каким бы сложным ни был генератор.
void SetPins(uint value)
{
BSRR = (value & 255) | (~value << 16);
}

Да, похоже ты прав, при таком подходе можно сделать и инверсию... но это не бесплатно. Для начала нужно код доработать:
Код
BSRR = value | ((~value & 255) << 16);

Смотрим что нагенерит компилятор. Один вызов:
Код
0x2000084c  ldr r3, [sp, #4]
0x2000084e  ldr r2, [pc, #96]
0x20000850  orr.w r3, r3, #16711680
0x20000854  str r3, [r2, #24]
0x20000856  ldr r3, [sp, #4]
0x20000858  orr.w r3, r3, #16711680
0x2000085c  str r3, [r2, #24]

Два вызова подряд:
Код
0x2000084c  ldr r1, [sp, #4]
0x2000084e  ldr r2, [pc, #108]    
0x20000850  mvns r3, r1
0x20000852  lsls r3, r3, #16
0x20000854  and.w r3, r3, #16711680
0x20000858  orrs r3, r1
0x2000085a  str r3, [r2, #24]
0x2000085c  ldr r1, [sp, #4]
0x2000085e  mvns r3, r1
0x20000860  lsls r3, r3, #16
0x20000862  and.w r3, r3, #16711680    
0x20000866  orrs r3, r1
0x20000868  str r3, [r2, #24]

Я же предлагал такой код:
Код
static void write(uint32_t data) { base()->BSRR = (pinsMask << 16) | data; }

Тут очищаются все биты сразу, по константной маске, ее не нужно инвертировать, обрезать и сдвигать, а если было бы нужно, то она так константой бы и осталась.
Один вызов:
Код
0x2000084c  ldr r3, [sp, #4]
0x2000084e  ldr r2, [pc, #88]
0x20000850  orr.w r3, r3, #16711680
0x20000854  str r3, [r2, #24]

Два вызова подряд:
Код
0x2000084c  ldr r2, [sp, #4]
0x2000084e  ldr r1, [pc, #92]
0x20000850  mvns r3, r2
0x20000852  lsls r3, r3, #16
0x20000854  and.w r3, r3, #16711680
0x20000858  orrs r3, r2
0x2000085a  str r3, [r1, #24]


Update: Претензия снимается, специально объявил записываемую переменную как volatile, чтобы компилятор ее не рассматривал как константу, то в твоем коде она читается 2 раза и ественно компилятор это продублировал sm.gif Разница есть, но она всего 4 байта sm.gif
Forger
Цитата(jcxz @ Apr 21 2017, 14:10) *
Т.е. - взять LPC43xx?

Типа того, но по отдельности порой выходит даже дешевле, да и выбор ничем не ограничем.

Но LPC4300 уже устарел, уже есть более злобные: http://www.microchip.com/wwwproducts/en/ATSAM4C16
jcxz
Цитата(Reflector @ Apr 21 2017, 13:17) *
Да, похоже ты прав, при таком подходе можно сделать и инверсию...

Инверсию за одну операцию на STM ни при каком подходе сделать нельзя.
Мой код не инвертирует, а устанавливает значение всех пинов за одну операцию записи для любого числа. Инверсии там нет.
Reflector
Цитата(jcxz @ Apr 21 2017, 14:24) *
Инверсию за одну операцию на STM ни при каком подходе сделать нельзя.

Имеется в виду, что в таком случае инверсию в принципе возможно сделать оставив и атомарную запись, пусть и немного более медленную. В данный момент железо это не поддерживает, но все может измениться в будущем.
jcxz
Цитата(Forger @ Apr 21 2017, 13:21) *
Типа того, но по отдельности порой выходит даже дешевле, да и выбор ничем не ограничем.

Одно ПО разрабатывать/сопровождать/обновлять проще и дешевле. В этом плане многоядерный проц лучше нескольких одноядерных.
Я, когда писал прошивку для LPC1758 + параллельно для CY7C68013A, это почувствовал на себе. И документации читать больше и в отладке сложнее. А уж когда оказалось, что прошивку и того и другого надо ещё у заказчика обновить.... smile3009.gif
Forger
Цитата(jcxz @ Apr 21 2017, 14:29) *
Одно ПО разрабатывать/сопровождать/обновлять проще и дешевле. В этом плане многоядерный проц лучше нескольких одноядерных.
Я, когда писал прошивку для LPC1758 + параллельно для CY7C68013A, это почувствовал на себе. И документации читать больше и в отладке сложнее. А уж когда оказалось, что прошивку и того и другого надо ещё у заказчика

Как обычно, все сводится к деньгам, поэтому нужно считать, что выгоднее - использовать один толстый мудрёный проц или два обычных. Главное, что есть выбор ))
jcxz
Цитата(Forger @ Apr 21 2017, 13:21) *
Но LPC4300 уже устарел, уже есть более злобные: http://www.microchip.com/wwwproducts/en/ATSAM4C16

По сравнению с этим - не устарел.
LPC4370 (который у меня был) - 3 ядра на 204МГц: M4F + M0*2.
Здесь же только 2 ядра, пускай и M4 (но одно ядро - просто M4 без F как я понял), но на 120МГц.
Это ещё посмотреть кто быстрее будет wink.gif
Да и ОЗУ в LPC4370 побольше почти в 2 раза - 282кБ. Правда флеши нет laughing.gif

Итого: 120*2=240МГц против 204*3=612МГц cool.gif
А уж про АЦП LPC-ки я вообще молчу wink.gif

PS: Да, кстати - для второго ядра ещё и частота не указана. Может она в 2 раза ниже?
Forger
Цитата(jcxz @ Apr 21 2017, 14:39) *
По сравнению с этим - не устарел.
LPC4370 (который у меня был) - 3 ядра на 204МГц: M4F + M0*2.

Гы, я не знал про такие laughing.gif
Похоже, семейство это развивают во всю ))
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.