halfdoom 0 27 сентября, 2010 Опубликовано 27 сентября, 2010 · Жалоба Это можно реализовать. Но я не уверен, что нужно. Это оптимизация под один частный случай использования под определенной семейство МК. В этой библиотеке есть более важные варианты использования, которые надо оптимизировать. Вот тут и возникает пресловутая избыточность, вместо того, чтобы использовать средства более высокого уровня которые в состоянии сгенерировать эффективный код на C или C++ для конкретного процессора, вы пытаетесь уложиться в прокрустово ложе ограниченных конструкций языка, неизбежно жертвуя оптимальностью полученного кода. Что касается атомарности, то это забота не этого класса. А снабженец закупивший MSP вместо AVR однозначно будет уволен. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
neiver 0 27 сентября, 2010 Опубликовано 27 сентября, 2010 · Жалоба Кстати, списки линий поддерживают и манипуляцию отделными битами из списка. Переводя на пример, который запросил Quasy это будет выглядеть так: #include <avr/io.h> #include "iopins.h" #include "pinlist.h" using namespace IO; typedef PinList<Pa0, Pb0, Pd3, Pd4> Pins; int main() { Pins::Pin<0>::Clear(); Pins::Pin<1>::Set(); Pins::Pin<2>::Clear(); Pins::Pin<3>::Set(); } Асм листинг: cbi 0x1b, 0; 27 sbi 0x18, 0; 24 cbi 0x12, 3; 18 sbi 0x12, 4; 18 Quasy, вы это хотели увидеть? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Segment 3 27 сентября, 2010 Опубликовано 27 сентября, 2010 · Жалоба 2 Andy Mozzhevilov Я говорил про то, что управление конкретными линиями GPIO должно быть только в одном потоке. Иначе вообще странная ситуация складывается - мы пытаемся двумя разными потоками управлять одним и тем же, при этом боимся где-то пересечься. Просто программист, который будет потом разбираться в коде, должен быть в курсе того, что есть такое пересечение потоков. Кстати, Вы сказали про "приходится настройку портов оборачивать в критические секции", но если это задается вначале программы, то зачем оборачивать в критическую секцию, когда прерывания от периферии еще не разрешены? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DimaG 0 27 сентября, 2010 Опубликовано 27 сентября, 2010 · Жалоба 2 Andy Mozzhevilov Я говорил про то, что управление конкретными линиями GPIO должно быть только в одном потоке. Иначе вообще странная ситуация складывается - мы пытаемся двумя разными потоками управлять одним и тем же, при этом боимся где-то пересечься. Согласен. ИМХО если есть какой-то разделяемый ресур ввода/вывода, то правильно будет ввести сущность "драйвер/менеджер" устройства, и все операции вести через него. Соответственно, вся забота о разделении доступа ложится на этот драйвер Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 27 сентября, 2010 Опубликовано 27 сентября, 2010 · Жалоба ввести сущность "драйвер/менеджер" устройства, и все операции вести через него. Соответственно, вся забота о разделении доступа ложится на этот драйвер Дык это - для синхронного вывода. Релюхами клацать :) А если у нас(Вас) случилась такая беда: используется 7 бит для LCD, и надо ж такому случиться - 1wire на последней ноге торчит... Что делать? ванварь-то требует довольно точных временных интервалов... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Andy_Mozzhevilov 0 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба 2 Andy Mozzhevilov Я говорил про то, что управление конкретными линиями GPIO должно быть только в одном потоке. Иначе вообще странная ситуация складывается - мы пытаемся двумя разными потоками управлять одним и тем же, при этом боимся где-то пересечься. Значит вы не поняли суть проблемы. Она в том, что для для модификации значения одного бита порта используется команда чтения значения всего порта (8 бит для avr), модификация нужного бита в регистре, и запись 8 бит обратно в порт. То есть модификация 1 бита фактически - это модификация всего порта. Следовательно, если на этом порту есть 2 разных линии, каждая из которых управляется из разных потоков, возможны трудноуловимые баги, обусловленный неатомарными операциями с 8-битным портом. В предыдущем сообщении я написал, как это решается в ARM NXP. Для avr предлагается использовать команды манипуляции отдельными битами (насколько я понял из их мненоники и описания). А то что вы писали - это управление одной линией из разных потоков (или прерываний и фона) - это другая тема. И такое тоже имеет место быть при необходимости - не надо кричать, что это бред. Например, в фоне выставляется запрос внешнему устройству на каком-то пине, ответ от устройства обрабатывается по прерыванию, в котором в том числе и запрос снимается. Только в этом случае автомат состояния делается общий для такого управления, и там где нужно, изменения состояния автомата оборачиваются в критические секции. Кстати, Вы сказали про "приходится настройку портов оборачивать в критические секции", но если это задается вначале программы, то зачем оборачивать в критическую секцию, когда прерывания от периферии еще не разрешены? Если это касается main - то не нужно. На я использую драйвера периферии на С++, где в конструкторе производится инициализация и настройка альтернативных режимов пинов. Все конструкторы закрыты в критические секции, поскольку объекты могут быть созданы не только глобально (конструкторы их будут вызваны до main), но и локально в функции (задаче). В этом случае конструктор будет вызван в месте создания, когда прерывания уже во всю имеют место быть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость DL36 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба xor.w TRISB // TRISB = 0x0022 --> один бит потеряли, должно быть 0x002A Так, что и тут есть подводные камни. Но только в случае, если модифицируется пересекающееся множество бит. Если модифицируемые биты различны, то проблем нет. Дело не в подводных камнях просто пример совершенно не корректный, скажу более он в принципе не имеет решения. С нашим устройством связаны биты о маска 0х000F и они должны меняться из одного места. Меняйте любые другие и все будет работать. Если подойти с логической стороны дела, выставляем требуемые биты и момент прерывания меняем один или несколько управляемых битов. Завершаем прерывание и продолжаем выставлять биты. Но вопрос в другом какое из состояний верное то которое выставляли или то которое изменили в прерывании? Если верны оба то только критические секции и скорее всего они тоже не помогут. Макросы прекрасно работают в реальных проектах под TNKernel и позволяют отказаться во многих местах от использования критических секций. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Segment 3 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба Если это касается main - то не нужно. На я использую драйвера периферии на С++, где в конструкторе производится инициализация и настройка альтернативных режимов пинов. Все конструкторы закрыты в критические секции, поскольку объекты могут быть созданы не только глобально (конструкторы их будут вызваны до main), но и локально в функции (задаче). В этом случае конструктор будет вызван в месте создания, когда прерывания уже во всю имеют место быть. Хорошо, ну а какой смысл вообще оборачивать конструкторы в критические секции? Ну сработало прерывание (не касающееся этой периферии, так как инициализация еще не завершилась), отработали его, вернулись к инициализации и поползли дальше по конструктору, что должно сломаться? ЗЫ: я не спорю, мне просто интересно Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Andy_Mozzhevilov 0 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба Хорошо, ну а какой смысл вообще оборачивать конструкторы в критические секции? Ну сработало прерывание (не касающееся этой периферии, так как инициализация еще не завершилась), отработали его, вернулись к инициализации и поползли дальше по конструктору, что должно сломаться? ЗЫ: я не спорю, мне просто интересно Так смысл абсолютно тот же, что и обсуждается сейчас здесь про неатомарные команды модификации битов порта. Поясню на примере с ARM NXP. Eсть регистр ввода-вывода (32 битный). В этом регистре настраиваются 16 линий порта на некоторые альтернативные функции, по 2 бита на пин. То есть, чтобы перенастроить некоторую линию (или группу линий) на другую функцию - нужно: 1. Считать значение IO регистра 2. Модифицировать значение нужным образом. 3. Записать новое значение в IO регистр. При этом в конкретном драйвере мне нужно (предположим) перенастроить только 2 IO линии из 16-ти, за которые отвечает этот регистр. Теперь - у меня RTOS с вытеснением (аналогичные рассуждения для прерываний). В другой задаче у меня так же есть код, который оперирует настройкой линий IO в пределах тех же 16-ти линий того же порта. Проследите, что будет, если где-то между 1. и 3. произойдет переключение контекста на другую задачу, которая решит также перенастроить линии порта (другие линии, но находящиеся в пределах этих 16-ти). 1a. Считать значение IO регистра --- контекст a->b 1б. Считать значение IO регистра 2б. Модифицировать значение нужным образом. 3б. Записать новое значение в IO регистр. --- контекст b->a 2a. Модифицировать значение нужным образом. 3a. Записать новое значение в IO регистр. В результате операции, выполненные в 1б, 2б, 3б - будут похерены. ЗЫ: Проблема в том, что подобные баги - трудноуловимы. Их проявление - стечение обстоятельств. То есть как правило - это нечто вроде: "У меня софт прекрасно работает месяц, но потом иногда затыкается обмен данными". Или: "У меня 1 раз из 100 устройство не включается, но после включения все 99 раз все дальше работает без сбоев". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Quasy 0 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба Асм листинг: cbi 0x1b, 0; 27 sbi 0x18, 0; 24 cbi 0x12, 3; 18 sbi 0x12, 4; 18 Quasy, вы это хотели увидеть? Для данной конфигурации - да. Остался, кажется, один шаг - заставить Вашу библиотечку разбирать: когда выводить побитно, а когда организовать критическую секцию с "Чтением-Модификацией-Записью". Это, кстати, нужно только для эффективного вывода констант (для переменных вывод побитный, там групповой вывод не работает). Если интересно, то скажу, что в моем тупом варианте это делается весьма легко: в препроцессоре макрос считает для константы биты на каждом порту, и препроцессор же делает выбор. #if (GROUP_0_COUNT_BITS_OF_PORTA < 4) && (PORTA_HAVE_BITS_ACCESS) Вот тут побитно SBI/CBI для порта А #else ENTER_ATOMIC Ну, для XMEGA критическая секция не нужна RMW PORTA RELEASE_ATONIC #endif ... и так для всех портов. Что для этого потребовалось? Ну, где-то сказать, что ПортА на битовом пространстве, ПортG - нет. (для ХМЕГИ это означает - сказать на какой виртуальный порт отображен PORTn) И макрос соорудить для подсчета бит. Это совсем легко. Негатив такого варианта: для каждой Группы нужен h-файл с макросами для подсчета бит.. Они у меня, собаки, здоровенные получились, но каши не просят :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MrYuran 18 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба Остался, кажется, один шаг - заставить Вашу библиотечку разбирать: когда выводить побитно, а когда организовать критическую секцию с "Чтением-Модификацией-Записью". Компилятор сам решит, он умный. Посчитает количество тактов либо количество занятых под программу байт - в зависимости от ключей оптимизации. А библиотека должна быть нейтральной. Кстати, насчёт пресловутой атомарности. В msp430 (моём любимом :) ) с этим никаких проблем. Зря я волновался. У него чтение-модификация-запись производится в пределах одной команды, засчёт ортогональной системы команд и адресации. Вот пример, выцепил из рабочей прошивки. static __inline__ void SwPortToSend(void) { LINE_DIR.out.LINE_DIR_PIN = LINE_DIR_TRANSMIT; 7a70: f2 f0 bf ff and.b #-65, &0x001d;#0xffbf 7a74: 1d 00 На порт по адресу 001d накладывается маска 0xffbf, и всё это за одну команду, которая не может быть прервана никаким прерыванием. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Quasy 0 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба Компилятор сам решит, он умный. Посчитает количество тактов либо количество занятых под программу байт - в зависимости от ключей оптимизации. А библиотека должна быть нейтральной. Как хорошо иметь компилятор, умеющий без лишнего кода различить, что PORTA |= 0x07 надо делать тремя SBI, а PORTA |= 0x0f с помощью RMW в критической секции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
neiver 0 28 сентября, 2010 Опубликовано 28 сентября, 2010 · Жалоба Остался, кажется, один шаг - заставить Вашу библиотечку разбирать: когда выводить побитно, а когда организовать критическую секцию с "Чтением-Модификацией-Записью". Это, кстати, нужно только для эффективного вывода констант (для переменных вывод побитный, там групповой вывод не работает). Меня больше интересует именно групповой вывод для переменных. Есть у кого нибудь предложеня по дальнейшей оптимизации этой операции? Какие ещё приёмы отображения битов из входного значения в соответствующие биты портов можно придумать? Эффективные приемы для частных случаев? А так-же какие есть предложения по дальнейшему развитию функционала? - Отдельная функция для гарантированно атомарного вывода - Управление подтяжкой линий - Управление режимами прерываний Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
neiver 0 30 декабря, 2010 Опубликовано 30 декабря, 2010 · Жалоба Доброго всем времени суток. В моей библиотеке произошло довольно много изменений: - поддержка МК Texas Instruments MSP430; - поддержка STM32; - поддерживаются компиляторы GCC, IAR, Keil; - новый подход к конфигурации портов; - убраны предупреждения компиляторов; - лучшая оптимизация; - исправлены ошибки; - автоматические тесты; - лиценизия изменена на BSD. Найти ее можно по старому адресу: https://github.com/KonstantinChizhov/AvrPro...e/master/mcucpp Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 30 декабря, 2010 Опубликовано 30 декабря, 2010 · Жалоба - лиценизия изменена на BSD.Вот это, пожалуй, самое важное :-) В отличие от, к примеру, портирования на STM32, это самостоятельно сделать возможности никакой не было. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться