IgorAVR2 1 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба Пытаюсь скопировать в переменную uint_64t восемь байт из массива с определённого его индекса. Конструкция такая: ((uint64_t*)&write_key)[0]=(((uint64_t*)(rx_buffer+5))[0]); write_key - переменная 64 бита. rx_buffer - байтовый массив. В строчке пытаюсь копировать с 5 элемента и программа вылетает в Hard Fault. Если копировать с 0 или 4 элемента то всё ок. Понимаю что что связанно с адресацией но что именно? Микроконтронтроллер STM32f0, среда IAR. На PC эта же строчка с 5 индексом прокатывает. Что делаю не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 77 9 апреля, 2018 Опубликовано 9 апреля, 2018 · Жалоба memcpy(&write_key, &rx_buffer[5], 8); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба а так? *((uint64_t *)write_key)) = *((uint64_t *)(rx_buffer+5))); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vadon 0 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба Понимаю что что связанно с адресацией но что именно? unaligned access Используйте memcpy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorAVR2 1 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба а так? *((uint64_t *)write_key)) = *((uint64_t *)(rx_buffer+5))); Так тоже не прокатило. Туда же в ошибку и улетает. Да, memcopy то я туда и поставил, только memcopy побайтно копирует, а хотелось по словам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба Да, memcopy то я туда и поставил, только memcopy побайтно копирует, а хотелось по словам. memcpy копирует не побайтно, а оптимально с учетом выравнивания. Довольно сложная процедура. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба а так? *((uint64_t *)write_key)) = *((uint64_t *)(rx_buffer+5))); Прежде чем что-то советовать надо научиться читать и понимать то, что пишут. Чтобы не писать ерунду. Из контекста исходного сообщения автора видно, что write_key - это не указатель, а переменная в которую нужно записать. Это во-первых. А во-вторых - читайте про невыровненный доступ в Cortex-M. Так тоже не прокатило. Туда же в ошибку и улетает. Для IAR (а может и других компиляторов): typedef unsigned long long u64; typedef __packed u64 u64p8; *(u64p8 *)&write_key = *(u64p8 *)&rx_buffer[5]; ...и уже сам компилятор решит какие команды использовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба А можно просто выровнять буфер если считываемые слова выравнены относительно друг друга. Если нет, делайте memcpy - так правильней всего и компилятор оптимизирует вызовы обычно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба А можно просто выровнять буфер если считываемые слова выравнены относительно друг друга. Если нет, делайте memcpy - так правильней всего и компилятор оптимизирует вызовы обычно. В случае с __packed u64 если в buildtime известно, что ((uint)(rx_buffer+5) & 3) == 0, то компилятор для чтения сгенерит одну команду LDRD (если она есть в данном ядре, ну или две LDR). А про memcpy() я совсем не уверен, что получится так же оптимально. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorAVR2 1 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба typedef unsigned long long u64; typedef __packed u64 u64p8; *(u64p8 *)&write_key = *(u64p8 *)&rx_buffer[5]; ...и уже сам компилятор решит какие команды использовать. Да, спасибо. Ваш способ подошёл. Но я так понимаю, что так как переменные не выровнены в памяти, то он всё рано будет копировать побайтно. А если делать через memcpy, как советует Kabdim, то компилятор разве не будет побайтно копировать? Пока писал вопрос уже ответили - и я вот сомневаюсь насчёт memcpy. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба Зря не верите, все современные компиляторы насколько я знаю оптимизируют это в релизбилде. Другое дело что они не всегда по коду могут сказать что ((uint)(rx_buffer+5) & 3) == 0. Но в этом случае ни один, ни второй метод не будут соптимизирован. Можно сделать аля: uint64_t inner_buffer[x]; uint8_t *rx_buffer = static_cast<uint8_t*>(&inner_buffer[0]) + 3; И продолжать жечь в духе первого поста. Только возможно еще и с индексами, а не с адресной арифметикой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба так как переменные не выровнены в памяти, то он всё рано будет копировать побайтно. Нет, если компилятор на этапе сборки кода будет знать, что ((uint)(rx_buffer+5) & 3) == 0, то он использует LDRD или пару LDR. Если нет, но ((uint)(rx_buffer+5) & 1) == 0, то он может использовать LDRH,LDR,LDRH. Если на этапе сборки кода значение rx_buffer неизвестно, то будет использовать побайтный доступ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorAVR2 1 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба Понял, спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorAVR2 1 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба Вычитал в в аналогичном топике, что оказывается STM32f4 об этом думать не нужно. Вот и у меня видимо до этого так раньше работало в других проектах. https://electronix.ru/forum/lofiversion/ind...hp/t140216.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 10 апреля, 2018 Опубликовано 10 апреля, 2018 · Жалоба Вычитал в в аналогичном топике, что оказывается STM32f4 об этом думать не нужно. Вот и у меня видимо до этого так раньше работало в других проектах. Нет, не поэтому. Не нужно для операций LDR/STR - только они поддерживают невыровненный доступ на M3/M4. А если Вы пишете тип u64, то для работы с таким типом компилятор может применить LDRD/STRD, а эти команды не поддерживают невыровненный доступ даже в M4. Хотя может какой-то конкретный, не очень оптимизирующий компилятор, вместо одной LDRD, может применить пару LDR, тогда прокатит. Но чтобы не гадать, хорошим тоном является явное указание невыровненности переменной (__packed), тогда компилятор сам решит как нужно работать с данной переменной на данном ядре. И не будет сюрпризов при переносе кода на другое ядро. PS: Да и учиться нужно не по "топикам" где могут нести какую угодно чушь, а по мануалам на ядро. Там всё разжёвано. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться