-
- На SPI stm32f0 вляпался, что 16-битная запись выводит 2 байта, а 8
битная - один. Это описано в RM, но не очевидно. Andreas(118 знак., 18.09.2020 12:14)
- Разумеется, нужно приведение типа, если вы хотите обратиться к
части регистра, например отдельно к старшей и младшей половине
BSRR. Но если вы пишете в регистр целиком, это лишнее. А
(uint32_t)0 - совсем лишнее. И это лишнее не безобидно: компилятору
насрать, а человека, который взялся это читать, шум отвлекает. - йцyкeн(18.09.2020 12:27)
- Я, собственно, именно из-за пестроты кода полез со всем этим
разбираться. В тексте постоянно встречаются директивы указания
разрядности. Причём мне непонятно, зачем надо заводить 16-разрядную
переменную и постоянно указывать разрядность операций. Можно же
взять 32-разрядную, работать с ней и только перед самой записью в
регистр указать разрядность. Но я же должен убедиться, что всё
правильно понимаю? Поэтому задаю вопросы. Приятно осознавать, что
таки да, правильно понимаю. - teap0t(18.09.2020 15:22)
- Указание разрядности необходимо в целочисленной арифметике. - VLLV(18.09.2020 15:32)
- Всё так, только "перед самой записью в регистр указать разрядность"
не надо, это лишнее. - SciFi(18.09.2020 15:27)
- Раскройте мысль. Я, конечно, понимаю, что в 16-разрядный регистр 32
разряда не поместятся, и записаны будут только младшие биты.
Собственно, для того и берётся максимальный размер переменной,
чтобы приведение шло исключительно с обрезанием старших разрядов.
Но для компилятора это разве не имеет значения? Может будет
неправильная ассемблерная команда передачи использоваться (пример
условный)? - teap0t(18.09.2020 17:00)
- На всякий случай скажу банальность: побитные логические операции на
то и побитные, что разряды друг на друга не влияют. Сложение,
вычитание и умножение порождают переносы, при которых младшие биты
влияют на старшие, но никогда наоборот. Только деление и сдвиг
вправо приводят к влиянию старших разрядов на младшие. Поэтому,
если выражение не содержит деления и сдвига вправо, вычисления с
"лишней" разрядностью в соответствии с правилами integer promotion
не влияют на результат. йцyкeн(150 знак., 18.09.2020 18:33)
- Мне хочется минимизировать неоднозначность операций и снизить
вмешательство компилятора до минимально необходимого. (Пока не
освоился со всем этим). - teap0t(18.09.2020 18:42)
- Язык Си очень близок к
железукремнию, вмешательство компилятора минимально. Если писать на ассемблере, операции всё равно будут производиться над 32-битными регистрам, операции над половинками и четвертинками отсутствуют за исключением очень специальных команд. По крайней мере в Cortex-M3; у M4 и M7 есть SIMD инструкции. - йцyкeн(18.09.2020 19:43)- Ну да, вмешательство компилятора минимально. А потом он всё
оптимизирует, и погромист недоумевает "где мой код"? :-) - SciFi(18.09.2020 20:00)
- Язык Си - возможно, самый низкоуровневый из языков высокого уровня, но это таки язык высокого уровня. Это не баг, а фичер. И оптимизация - фичер. - йцyкeн(18.09.2020 21:50)
- Сижу в отладчике, ставлю останов, а он не ставится. Бля. Хорошо, я
не совсем нуб. Убрал всю оптимизацию нафиг. И всё равно на части
кода остановиться нельзя. В ассемблере-то я честно пишу, что надо
что-то в Rn положить. Всё просто и однозначно. Эх. - teap0t(18.09.2020 20:25)
- Сделай переменную volatile. Тогда место кода, где с ней идёт
работа, не будет выоптимизированно. Когда отладку завершишь,
уберёшь. - Nikolay_Po(19.09.2020 14:05)
- В нормальных компиляторах на минимальном уровне оптимизации нет
разницы между volatile и non-volatile. - SciFi(19.09.2020 14:14)
- Наверное, я всегда веду отладку с максимальной оптимизацией. Больше
ошибок и предупреждений вылазит сразу. Уже не понимаю, зачем
собирать код без оптимизации, даже для отладки. Просто прицеплю
volatile-переменную к параметру, в который хочу заглянуть.
Оптимизацию не выключаю. - Nikolay_Po(19.09.2020 14:19)
- gcc -Os -flto такое выдаёт, что отладчиком туда заглядывать
бесполезно, можно сразу шарить в дизассемблере... - SciFi(19.09.2020 14:58)
- По-моему, после LTO, и в дизассемблере бесполезно. Заглянуть в душу оптимизатору может, пожалуй, только его разработчик. Отлаживаю проверяя осциллографом на отладочный выход, на вывод UART, на дисплей, если есть. Ну и само-собой, все предупреждения устраняю, так как жизнь научила, что предупреждение компилятора - латентный баг. - Nikolay_Po(23.09.2020 13:46)
- gcc -Os -flto такое выдаёт, что отладчиком туда заглядывать
бесполезно, можно сразу шарить в дизассемблере... - SciFi(19.09.2020 14:58)
- Наверное, я всегда веду отладку с максимальной оптимизацией. Больше
ошибок и предупреждений вылазит сразу. Уже не понимаю, зачем
собирать код без оптимизации, даже для отладки. Просто прицеплю
volatile-переменную к параметру, в который хочу заглянуть.
Оптимизацию не выключаю. - Nikolay_Po(19.09.2020 14:19)
- В нормальных компиляторах на минимальном уровне оптимизации нет
разницы между volatile и non-volatile. - SciFi(19.09.2020 14:14)
- Сделай переменную volatile. Тогда место кода, где с ней идёт
работа, не будет выоптимизированно. Когда отладку завершишь,
уберёшь. - Nikolay_Po(19.09.2020 14:05)
- Ну да, вмешательство компилятора минимально. А потом он всё
оптимизирует, и погромист недоумевает "где мой код"? :-) - SciFi(18.09.2020 20:00)
- Нет никакой неоднозначности операций. Правила вычислений строго изложены в стандарте. Вы можете пытаться структурировать выражения так, чтобы действовали правила, которые вы знаете, и не действовали те, которые вы не знаете. Но где гарантия, что вы не пропустите какое-нибудь из неизвестных правил? Выход один -- знать правила. - SciFi(18.09.2020 19:03)
- Язык Си очень близок к
- Мне хочется минимизировать неоднозначность операций и снизить
вмешательство компилятора до минимально необходимого. (Пока не
освоился со всем этим). - teap0t(18.09.2020 18:42)
- Не волнуйтесь за компилятор, у него всё будет хорошо. Он сам применит оптимальные инструкции. Ваша забота -- написать код без ошибок в вычислениях. SciFi(110 знак., 18.09.2020 17:34, ссылка)
- На всякий случай скажу банальность: побитные логические операции на
то и побитные, что разряды друг на друга не влияют. Сложение,
вычитание и умножение порождают переносы, при которых младшие биты
влияют на старшие, но никогда наоборот. Только деление и сдвиг
вправо приводят к влиянию старших разрядов на младшие. Поэтому,
если выражение не содержит деления и сдвига вправо, вычисления с
"лишней" разрядностью в соответствии с правилами integer promotion
не влияют на результат. йцyкeн(150 знак., 18.09.2020 18:33)
- Раскройте мысль. Я, конечно, понимаю, что в 16-разрядный регистр 32
разряда не поместятся, и записаны будут только младшие биты.
Собственно, для того и берётся максимальный размер переменной,
чтобы приведение шло исключительно с обрезанием старших разрядов.
Но для компилятора это разве не имеет значения? Может будет
неправильная ассемблерная команда передачи использоваться (пример
условный)? - teap0t(18.09.2020 17:00)
- Ессно, просто бывают случаи, когда приходится явно указывать разрядность. И только тогда это надо делать в исходниках, чтобы бросалось в глаза. Но такое бывает. - Andreas(18.09.2020 12:31)
- Я, собственно, именно из-за пестроты кода полез со всем этим
разбираться. В тексте постоянно встречаются директивы указания
разрядности. Причём мне непонятно, зачем надо заводить 16-разрядную
переменную и постоянно указывать разрядность операций. Можно же
взять 32-разрядную, работать с ней и только перед самой записью в
регистр указать разрядность. Но я же должен убедиться, что всё
правильно понимаю? Поэтому задаю вопросы. Приятно осознавать, что
таки да, правильно понимаю. - teap0t(18.09.2020 15:22)
- Да лааадно.. там же задается битность посылки при ините SPI - POV_(18.09.2020 12:21, )
- Можно цитату из RM? У меня не получается найти. - SciFi(18.09.2020 12:20)
- 27.5.8 Data transmission and reception procedures подраздел Data
packing - Andreas(18.09.2020 12:26)
- Да, кстати. Правильно ли я понимаю, что в этом случае надо
использовать что-либо подобное: (?) teap0t(51 знак., 18.09.2020 18:45)
- Нет, надо как йцукен написал. Но это редчайшее исключение, которое подтверждает правило, что нечего постоянно явно разрядность менять. Andreas(573 знак., 18.09.2020 20:02)
- Нет, неправильно. У вас приведение типа применяется к результату
чтения из регистра, то есть читаются 16 бит, которые потом
обрезаются до 8. Чтобы читать 8, нужно делать так uint8_t data =
*((volatile uint8_t *)&SPIx_DR); - йцyкeн(18.09.2020 19:48)
- Спасибо. А амперсанд зачем? Адрес же! Туплю. - teap0t(18.09.2020 20:38)
- Попробую объяснить подробнее. Приведение типов применяется к значениям, а не к переменным. Возможно, вы хотели бы написать float x; (int)x = 666; но в Си это недопустимо. Допустимо int ix = (int)x; значение x читается как float, потом преобразуется в int. Чтобы обратиться к переменной как к другому типу, нужно применить приведение типа не к самой переменной, а к указателю на неё (это грязный хак). Указатель концептуально состоит из двух частей: адрес некоторой переменной и её йцyкeн(500 знак., 18.09.2020 22:41)
- Спасибо. А амперсанд зачем? Адрес же! Туплю. - teap0t(18.09.2020 20:38)
- По логике - нет, приведение типов и так будет выполнено при
присвоении значения переменной. И дополнительное приведение типа
справа от знака присвоения значения смысла в этом выражении не
имеет. Другое дело если бы переменная была большего размера. Тут я
пока не представляю, как оно сработает. - Nikolay_Po(18.09.2020 19:19)
- ОК. Надо было 32-разрядную переменную заводить. - teap0t(18.09.2020 19:28)
- Офигенно. Спасибо. - SciFi(18.09.2020 13:00)
- Да, кстати. Правильно ли я понимаю, что в этом случае надо
использовать что-либо подобное: (?) teap0t(51 знак., 18.09.2020 18:45)
- 27.5.8 Data transmission and reception procedures подраздел Data
packing - Andreas(18.09.2020 12:26)
- Разумеется, нужно приведение типа, если вы хотите обратиться к
части регистра, например отдельно к старшей и младшей половине
BSRR. Но если вы пишете в регистр целиком, это лишнее. А
(uint32_t)0 - совсем лишнее. И это лишнее не безобидно: компилятору
насрать, а человека, который взялся это читать, шум отвлекает. - йцyкeн(18.09.2020 12:27)
- Если программисту платят за знаки, то вполне годный код. - VLLV(18.09.2020 11:59)
- На SPI stm32f0 вляпался, что 16-битная запись выводит 2 байта, а 8
битная - один. Это описано в RM, но не очевидно. Andreas(118 знак., 18.09.2020 12:14)