Работа с портами пинам. Макросы, X-macro

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Сообщения: 647
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

AQ29 писал(а): Пт июл 31, 2026 22:06:30 Эти записи, на мой взгляд, проще и нагляднее, чем на СИ. Насчёт того, что СИ проще и компактнее – вопрос.
Я ж говорю - это до тех пор, пока вы не пишите ничего сложнее дергания ног на слабеньком микроконтроллере :)
Но чем сложнее задачи и "железо", тем больше требований к возможностям языка программирования. Бывает, что даже чистый Си не справляется, приходится брать его продвинутую версию - С++.

Вот например сравнительно несложный, но показательный пример:

Код: Выделить всё

Layer1::Window::Configure(
           start, end,
           LayerPF::RGB888,
           layer.getBuf(),
           layer.getSize().x);
на вашем "вменяемом" макроассемблере вызовет бурю эмоций при реализации этого, поскольку одна функция выполняет достаточно много действий. А С/С++ умеет раскладывать действия по полочкам и не валить в одну кучу.
То есть, показанная выше функция имеет внутри себя вложенные функции:

Код: Выделить всё

static bool Configure(const PixCoord& start, const PixCoord& end,
                        LayerPF pf, uint32_t bufAddress, uint16_t linePitch)
{
    if(Window::SetPosition(start, end) == false ||
          Buffer::Configure(pf, linePitch, end - start + (PixCoord){1, 1}) == false)
        return false;

     Buffer::SetAddress(bufAddress);
     return true;
}
которые, в свою очередь, так же имеют вложенные функции:

Код: Выделить всё

static bool SetPosition(PixCoord start, PixCoord end)
{
    PixCoord firstVisiblePixel = Ltdc::Scan::GetFirstVisiblePixel();
    start += firstVisiblePixel;
    end += firstVisiblePixel;

    if(end < start || end > Ltdc::Scan::GetLastVisiblePixel())
        return false;

    lay->WHPCR = ((start.x << LTDC_LxWHPCR_WHSTPOS_Pos) & LTDC_LxWHPCR_WHSTPOS_Msk) |
                          ((end.x << LTDC_LxWHPCR_WHSPPOS_Pos) & LTDC_LxWHPCR_WHSPPOS_Msk);

     lay->WVPCR = ((start.y << LTDC_LxWVPCR_WVSTPOS_Pos) & LTDC_LxWVPCR_WVSTPOS_Msk) |
                          ((end.y << LTDC_LxWVPCR_WVSPPOS_Pos) & LTDC_LxWVPCR_WVSPPOS_Msk);

     return true;
}
которая тоже имеет вложенную функцию:

Код: Выделить всё

static PixCoord GetFirstVisiblePixel()
{
    return {(uint16_t)(((LTDC->BPCR & LTDC_BPCR_AHBP_Msk) >> LTDC_BPCR_AHBP_Pos) + 1),
            (uint16_t)(((LTDC->BPCR & LTDC_BPCR_AVBP_Msk) >> LTDC_BPCR_AVBP_Pos) + 1)};
}
И всё это сделано как раз ради уменьшения как размера текста программы, так и размера бинарника за счет повторного использования функций.

Вооот, а вы говорите, что нагляднее пины дергать на макроассеблере и присваивать V = A. Попробуйте хотябы что-то подобное, и наглядность макроассемблера быстро превратится в крутозамешанную кашу.
А на языке С/С++ вот мне пофик, какие инструкции и как там используются. Компилятор сам их подберет в соответствии с настройками компиляции и оптимизации. Это его задача и пусть он делает свою работу. А я делаю свою, более высокую работу.
Реклама
Прорезались зубы
Сообщения: 232
Зарегистрирован: Сб июл 30, 2011 21:00:24

Сообщение AQ29 »

Adrift
Как понял, РА0 – бит порта. У меня в среде уже нет встроенных битовых переменных периферийных регистров для новых МК АВР, не имеет смысла.
Их слишком много (только периферийных регистров около 550 штук), много труда для разработчика среды.
Кроме того, увеличивается время компиляции, поскольку больше время поиска переменной.
Зачем это, когда можно просто написать через регистр с точкой PORTA.5 = 1. А остальная периферия настраивается через картинку.
Откуда взялся в примере r24? Если компилятор сам выбирает, то тут возникают вопросы.

Rapra
В среде не одна команда V = A, есть много других. Собственно, в тексте программы очень мало ассемблерных команд, в основном макрокоманды и функции. Да и команды типа PORTA.5 = 1 тоже обычно не бывает. Если эта команда зажигает второй светодиод, то для лучшей читаемости лучше написать макрос типа Led2_On.
Вызов из одной встроенной программы другой - это нередкая ситуация.
Например, у меня среде есть математические функции - корень, логарифм и т.д.
Функции рассчитываются на основе кусочно-линейной аппроксимации. Алгоритм простой, вначале выбирается нужный интервал, затем на основе линейной аппроксимации рассчитывается результат. Соответственно, основная программа вызывает две встроенных программы: выбор интервала и умножение. После компиляции эти программы появляются в конце программы.
Интересно, в СИ где располагаются встроенные программы.
Реклама
Вымогатель припоя
Сообщения: 647
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Да че вы со своим портом носитесь то. Я ж говорю - попробуйте что-то посложнее мигания светодиодом на старом дохленьком микроконтроллере!
Ассемблер, пусть даже и "вменяемый" макро, он давно уже изжил себя. Он просто не тянет современные микроконтроллеры и современные задачи. И бесполезно с этим спорить. Это как говорить, что кнопочный телефон круче смартфона, потому что там кнопки механические. Но кнопочный телефон - это только звонилка, и ничего более.
Вымогатель припоя
Сообщения: 585
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение Adrift »

AQ29 писал(а): Вс авг 02, 2026 22:18:23Как понял, РА0 – бит порта. У меня в среде уже нет встроенных битовых переменных периферийных регистров для новых МК АВР, не имеет смысла.
Их слишком много (только периферийных регистров около 550 штук), много труда для разработчика среды.
Вы себе сами эти проблемы придумали, у тех кто пользуется нормальными компиляторами все нужные определения уже есть в готовом виде, от производителей мк. И да, там файлы по несколько MB могут быть.
AQ29 писал(а):Кроме того, увеличивается время компиляции, поскольку больше время поиска переменной.
В простеньком C++ проекте для ARM, который компилируется пару секунд, с учетом стандартной библиотеки запросто может быть больше 100 тыс. строк, а ваш макроассемблер для AVR должен за доли секунды справляться, если он, конечно, грамотно написан.
AQ29 писал(а):Зачем это, когда можно просто написать через регистр с точкой PORTA.5 = 1. А остальная периферия настраивается через картинку.
Откуда взялся в примере r24? Если компилятор сам выбирает, то тут возникают вопросы.
Компилятор сам регистры выбирает, какие к нему могут быть вопросы? Вот пример, нигде явно регистры не указаны даже если вставки на ассме делать:
Спойлер

Код: Выделить всё

uint64_t umul_32_64(uint32_t u, uint32_t v)
{
	uint32_t a, b, c;

	__asm volatile("uxth %[a], %[u]\n"
				   "lsrs %[u], %[u], #16\n"
				   "lsrs %[b], %[v], #16\n"
				   "uxth %[v], %[v]\n"
				   "movs %[c], %[v]\n"
				   "muls %[v], %[a]\n"
				   "muls %[c], %[u]\n"
				   "muls %[u], %[b]\n"
				   "muls %[b], %[a]\n"
				   "lsls %[a], %[c], #16\n"
				   "lsrs %[c], %[c], #16\n"
				   "adds %[v], %[a]\n"
				   "adcs %[u], %[c]\n"
				   "lsls %[a], %[b], #16\n"
				   "lsrs %[b], %[b], #16\n"
				   "adds %[v], %[a]\n"
				   "adcs %[u], %[b]\n"
				   : [u] "+l" (u), [v] "+l" (v), [a] "=l" (a), [b] "=l" (b), [c] "=l" (c) :: "cc"
	);

	return uint64_t(u) << 32 | v;
}
AQ29 писал(а):В среде не одна команда V = A, есть много других. Собственно, в тексте программы очень мало ассемблерных команд, в основном макрокоманды и функции. Да и команды типа PORTA.5 = 1 тоже обычно не бывает. Если эта команда зажигает второй светодиод, то для лучшей читаемости лучше написать макрос типа Led2_On.
Я как бы на то и намекал, что PORTA.5 = 1 обычно никто не пишет, как и PORTA_OUTSET = &H21... А если у вас будет два определения Led1 и Led2, или макросы Led1_On/Off и Led2_On/Off, то как вы придете к записи в PORTA_OUTSET? В то же время мой код ее задействовал просто потому, что я объединил три пина и два из них оказались на одном порту.
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 647
Зарегистрирован: Пн фев 16, 2026 17:30:02

Сообщение Rapra »

Судя по синтаксису PORTA_OUTSET = &H21 - возможно, это BASCOM-AVR. В любом случае, это чрезвычайно устаревший инструмент, давно изживший себя. Разумеется, это ни коим боком не ассемблер, а диалект языка Basic.
Впрочем, если человек привык, то даже морально устаревший инструмент ему будет казаться идеалом совершенства. Вот только не стоит навязывать другим эти "древние окаменелости мамонта" :)
Реклама
Вымогатель припоя
Сообщения: 585
Зарегистрирован: Вт окт 01, 2024 15:22:33

Сообщение Adrift »

Rapra писал(а): Пн авг 03, 2026 15:17:09Судя по синтаксису PORTA_OUTSET = &H21 - возможно, это BASCOM-AVR.
Так AQ29 же C не знает, там видимо и сам ассемблер, если он есть, на бейсике написан, отсюда и заимствованный синтаксис )
Реклама
Ответить

Вернуться в «AVR»