реклама на сайте
подробности

 
 
6 страниц V  < 1 2 3 4 5 > »   
Reply to this topicStart new topic
> Странное предупреждение
jcxz
сообщение Jun 21 2018, 07:05
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(juvf @ Jun 21 2018, 07:24) *
Как вы можете знать, как работает memcpy() у ТС, если memcpy реализуется разработчиками каждого компилятора под каждую архитектуру? Вы знаете как каждый memcpy() реализован? У каждого своя реализация.

"из кода видно, что с вероятностью близкой к 100..." где-то я это уже слышал недавно? wacko.gif
Так вот - у ТС-а IAR, и я им пользуюсь; у ТС-а (согласно строки выше) Cortex-M - и я под него сейчас отлаживаю. Аргументов достаточно?

Цитата(juvf @ Jun 21 2018, 07:24) *
Как правило, memcpy() реализован так, что из всех возможных реализаций код memcpy будет самый оптимальный, вплоть до ухода в асм. Если пользователь компилятора/библиотеки и решит написать свой копипаст, то он будет менее эффективный, в лучшем случае будет такойже, поэтому при копировании памяти не нужно замарачиваться и изобретать скоростной велосипед, а просто использовать memcpy().

С этим категорически не согласен! Попробуйте когда-нить не теоретизировать внустую, а скомпилировать и посмотреть разные варианты с копированием в цикле на разных компиляторах с включённой полной оптимизацией по скорости и с разными условиями цикла (короткий цикл/длинный, условия окончания и указатели - переменные или известны на этапе компиляции). И будете удивлены.
Вариант с memcpy() на коротких циклах, где кол-во проходов и/или указатели заданы переменными, проиграет варианту с простым for, так как ему не надо: a) сохранять содержимое из scratch регистров; б) делать вызов memcpy() и возврат; в) внутри memcpy() выполнять ветвление выбирая нужный вариант цикла копирования по условию длины цикла, выравниваний первого и второго аргумента и т.п.
На циклах с заранее (на этапе компиляции) известными условиями выполнения, for-вариант опять же будет как минимум не хуже, просто хотя-бы потому что компилятор зная условия выполнения цикла может подставить нужную последовательность команд (подобную оптимальному копированию внутри memcpy()), но с другими более удобными регистрами и их количеством - удобными для данной точки кода.
А некоторые компиляторы, так и вообще цикл for так оптимизируют (при определённых условиях) что готовому memcpy() и не снилось - в разы быстрее по скорости. Смотрим на компиляторы для DSP-ядер.

Цитата(juvf @ Jun 21 2018, 07:24) *
Посмотрите сколько лишних операций в for у ТС! какие-то приведения типов, операторы, << и |, дополнительный j, операции j++!!! УЖАС!!!

И что? Современные оптимизаторы творят чудеса. И им по-барабану Ваши жалкие потуги заменить операции индексирования на указатели и подобное - они это и сами хорошо делают, даже ещё и лучше. Так что если бы код автора не был такой кривой, результат работы оптимизирующего компилятора мог быть лучше memcpy().
Я в своё время, разрабатывая для DSP, немало заменил копирований через memcpy() на циклы for - это давало внушительный прирост скорости.

Цитата(juvf @ Jun 21 2018, 07:24) *
(кстати.... j++ достаточно медленный, по сравнению с ++j).

Опять чушь! Если предположить, что автор использует ARM, то что пре- что пост-инкремент - без разницы, и то и другое на ARM можно сделать в пределах одной команды выборки из памяти. Откройте мануал по системе команд и найдите разницу между: LDRB Rx, [Ry], #1 и LDRB Rx, [Ry, #1]!

Цитата(juvf @ Jun 21 2018, 07:24) *
В каких случаях? какие неточности?

Во-первых: memcpy там не к месту как я писал выше;
во-вторых: ничего не известно о значении size_to_take, а если она перед началом цикла может быть отрицательной (и i - тоже знаковое), что будет с вашим вариантом на memcpy()? biggrin.gif
в-3-х: с чего Вы приводите входные аргументы к типу void *? А если у ТС-а DataBuffer и data_out объявлены к примеру с модификатором volatile, т.е. указывают на strong ordered memory? Например DataBuffer или data_out - это FIFO-буфера в некоей периферии, чувствительные к размерности и последовательности операций записи/чтения.
Я уж не говорю о том, что эта память может позволять только доступы определённой разрядности...

Цитата(juvf @ Jun 21 2018, 07:24) *
вы сами себе противоречите, причем сразу в одном посте.....

В чём именно противоречие? wacko.gif

Цитата(adnega @ Jun 21 2018, 08:32) *
Если по исходнику понятно, что источник шире 8 байт приведет к перемешиванию бит, а в приемнике в итоге получается только 16 значащих бит,
то с уверенностью можно принять за факт их размеры 8 и 16 бит соответственно, и при необходимости заявлять "сам дурак",

Из "исходника" даже не ясно, что именно нужно этому горе-программисту (если data_out указывает на unsigned char) - поменять местами байты при копировании или может он хочет продублировать байты. Т.е. сделать так:
1. *(u16 *)&DataBuffer[i] = __REVSH(*(u16 __packed *)&data_out[j]); j += 2;
или так:
2. *(u16 *)&DataBuffer[i] = (uint)*(u8 *)&data_out[j++] * 0x101u;
а может и что другое.....
Go to the top of the page
 
+Quote Post
VladislavS
сообщение Jun 21 2018, 07:27
Сообщение #32


Местный
***

Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140



Цитата(Сергей Борщ @ Jun 21 2018, 09:22) *
К сожалению, аборигены запомнили только, что нужно хлопать при приземлении.

Продвинутые еще впп научились строить, чтобы их посещали.
Go to the top of the page
 
+Quote Post
juvf
сообщение Jun 21 2018, 07:50
Сообщение #33


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



ну на конец то предметный разговор, а не "слепая вера"

Цитата
Попробуйте когда-нить
попробую обязательно.

Цитата
Современные оптимизаторы творят чудеса. И им по-барабану Ваши жалкие потуги заменить операции индексирования на указатели и подобное - они это и сами хорошо делают, даже ещё и лучше.
Это я слышал и/или знаю.... Но, во первых, современные оптимизаторы иногда портят код так, что он не работает как надо, приходится либо отключать оптимизацию полностью, либо на отдельной функции. Во вторых про потуги вы зря.... когда мой код перестал влазить в флешь, а в прерываниях стал долго задерживаться, то сделал рефакторинг - код и влез и стал быстрее работать. Одна строчка до рефакторинга была 6 машинных команд, стала 2 или 4.
Убрал всякие лишние << |, на каждом участке экономил где по 10-20 байт флеша, где по 100.

Цитата
во-вторых: ничего не известно о значении size_to_take, а если она перед началом цикла может быть отрицательной (и i - тоже знаковое)

Морите!? О чем тут дискутировать, если вы не знаете как работает for? Если size_to_take отрицательная и i тоже знаковое, то в примере ТС в тело цикла for не разу не зайдем. Это вообще букварь Си.

Цитата
с чего Вы приводите входные аргументы к типу void *?
Да, согласен, неточность есть. Если быть скрупулёзным к явным преобразованиям, то нужно так
memcpy((void*)DataBuffer, (const void*)&data_out[j], 2*size_to_take);
Я не утверждаю, я всего лишь предположил, что копировать память лучше через memcpy. Если это не 8 и 16 бит, то забыли про мой совет. О чем спор?

Цитата
А если у ТС-а DataBuffer и data_out объявлены к примеру с модификатором volatile
И что? в чем разница вот в таких кодах с volatile (архитектура ст первый, без перевёртывания):
Вариант 1:
Код
volatile uint16_t DataBuffer[100];
volatile uint8_t data_out [1024];
uint16_t size_to_take = 100;
uint8_t j = 17;
for(uint16_t  i=0; i<size_to_take; i++ )
{
   DataBuffer[i] = (data_out[j] << 8)| data_out[j+1];
   j += 2;
}


Вариант 2:
Код
volatile uint16_t DataBuffer[100];
volatile uint8_t data_out [1024];
uint16_t size_to_take = 100;
memcpy((void*)DataBuffer, (const void*)&data_out[17], 2*size_to_take);


Или по вашему 1-ый вариант работать будет, а второй нет?



Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2018, 08:03
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(juvf @ Jun 21 2018, 10:50) *
Но, во первых, современные оптимизаторы иногда портят код так, что он не работает как надо, приходится либо отключать оптимизацию полностью, либо на отдельной функции.

За такую ересь - пожизненный эцих с гвоздями maniac.gif
Подсказка: вы просто не умеете их готовить.
Go to the top of the page
 
+Quote Post
juvf
сообщение Jun 21 2018, 08:17
Сообщение #35


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата(scifi @ Jun 21 2018, 13:03) *
За такую ересь - пожизненный эцих с гвоздями maniac.gif
Я же говорю - тут церковь какая-то, пропитанная религией ))). Если вы с таким не встречались - это не значит, что такого нет.

ps Открою вам тайну, земля круглая!


Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2018, 08:41
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(juvf @ Jun 21 2018, 10:50) *
Морите!? О чем тут дискутировать, если вы не знаете как работает for? Если size_to_take отрицательная и i тоже знаковое, то в примере ТС в тело цикла for не разу не зайдем. Это вообще букварь Си.

и....? Продолжаем думать дальше. Подсказываю ещё раз: А что будет с Вашим вариантом на memcpy()?

Цитата(juvf @ Jun 21 2018, 10:50) *
И что? в чем разница вот в таких кодах с volatile (архитектура ст первый, без перевёртывания):
Или по вашему 1-ый вариант работать будет, а второй нет?

В каких-то случаях - да. Читайте мои посты внимательнее. Мы не знаем в какой памяти находятся исходный и целевой адреса. Возможно они находятся в памяти, требующей строго определённого порядка доступа и определённой разрядности доступа (strong ordered memory). Или в памяти при доступе к которой происходят прочие события (например FIFO-буфера периферии (SPI например) при записи/чтении данных в/из них производят другие действия: обмен с регистрами сдвига, удаление данных из FIFO и т.д.; а также чувствительны к разрядности операций чтения/записи - при доступе недопустимой разрядности получите fault; и чувствительны к выравниванию (хотя основная память МК может допуcкать невыровненный доступ, но некоторые регионы - могут генерить fault при невыровненном доступе)).
А какие именно операции доступа к памяти будут использованы внутри memcpy() - нет никакой гарантии. Если например DataBuffer указывает на 16-разрядный SPI-FIFO и size_to_take>=2, то внутри memcpy() может объединить доступы в 32-разрядные и в результате получим bus-fault.
Так что бездумно использовать memcpy() нельзя.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2018, 08:42
Сообщение #37


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(juvf @ Jun 21 2018, 10:50) *
Или по вашему 1-ый вариант работать будет, а второй нет?

Тема больших и малых индейцев не раскрыта. А именно, у больших индейцев memcpy с успехом заменяет тот самый цикл копирования, а у малых - нет. ТС про индейцев ничего не говорил, отчего ваш $рачЪ на ровном месте выглядит особенно забавно laughing.gif
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2018, 08:44
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(juvf @ Jun 21 2018, 10:50) *
Но, во первых, современные оптимизаторы иногда портят код так, что он не работает как надо, приходится либо отключать оптимизацию полностью

А вот здесь: код в студию!
Ибо в 99.9% таких случаев причина - баг в коде. smile3046.gif
Я даже скажу больше: я при отладке кода проверяю его работу с включенной и отключенной оптимизацией - это помогает находить скрытые баги в коде.
Go to the top of the page
 
+Quote Post
juvf
сообщение Jun 21 2018, 09:01
Сообщение #39


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата
Продолжаем думать дальше. Подсказываю ещё раз: А что будет с Вашим вариантом на memcpy()?
Что за глупость? при чем тут memcpy с отрицатеольными size_to_take? В коде ТС явно size_to_take > 0.
Цитата(jcxz @ Jun 21 2018, 13:44) *
А вот здесь: код в студию!

Код
#pragma optimize=none
unsigned int crc16_byte(unsigned int crc, unsigned int data)
{
    //const unsigned int Poly16=0xA001;
    unsigned int LSB;
    crc = ((crc^data) | 0xFF00) & (crc | 0x00FF);
    for (uint8_t i=0; i<8; i++)
    {
        LSB=(crc & 0x0001);
        crc >>= 1;
        if(LSB)
            crc=crc^0xA001;
    }
    return crc;
}
Такой код работает, если убрать прагму, то црц считается не правильно. Для фантазёров, видящих за рамками кода всякое ООП, перегрузку операторов, переопределение типов и прочую фуе ту.... перегрузки операторов нет, переопределений типов и чего либо ещё нет. тип unsigned int 16 бит!
Go to the top of the page
 
+Quote Post
adnega
сообщение Jun 21 2018, 09:06
Сообщение #40


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(jcxz @ Jun 21 2018, 11:44) *
Ибо в 99.9% таких случаев причина - баг в коде. smile3046.gif

Да, но 0.1% все же баг в компиляторе.
У меня есть проект, который собирается и работает при O2 и не собирается при Os. Интересно?
Код
C:\Users\user\AppData\Local\Temp\ccShzzAY.s: Assembler messages:
C:\Users\user\AppData\Local\Temp\ccShzzAY.s:3151: Error: value of 256 too large for field of 1 bytes at 000000000000103a
make.EXE: *** [obj_sw/esp8266.o] Error 1

В asm
Код
.L276:
    .byte    (.L274-.L276)/2 - переполнение

Меняешь две строчки в Си-исходнике и проект начинает собираться.
Go to the top of the page
 
+Quote Post
scifi
сообщение Jun 21 2018, 09:07
Сообщение #41


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(juvf @ Jun 21 2018, 12:01) *
Такой код работает, если убрать прагму, то црц считается не правильно. Для фантазёров, видящих за рамками кода всякое ООП, перегрузку операторов, переопределение типов и прочую фуе ту.... перегрузки операторов нет, переопределений типов и чего либо ещё нет. тип unsigned int 16 бит!

Не видно в этом коде никакого криминала. Конечно, нельзя исключить того, что криминал возникает вне этой функции (она же не в вакууме существует). Опять же, не исключён глюк компилятора. У меня яр для coldfire неправильно считал MD5 при включенной оптимизации. Поймать его за руку на конретной инструкции сложно, так как код MD5 зубодробительный.
Go to the top of the page
 
+Quote Post
juvf
сообщение Jun 21 2018, 09:24
Сообщение #42


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата(scifi @ Jun 21 2018, 14:07) *
Конечно, нельзя исключить того, что криминал возникает вне этой функции (она же не в вакууме существует).
Я тоже про это думал. На весь проект стоит максимальная оптимизация по размеру кода. Дебажил на уровне Си, в асм углубляться не стал. Одна строчка #pragma optimize=none давала правильную работу расчета црц. Поэтому врят-ли что-то в остальном коде не так. Времени не было искать глюк в компиляторе или ещё где.... Видимо это был 0,1%.

кому интересно, компилятор IAR C/C++ for STM8 из иара 3,10,1
Go to the top of the page
 
+Quote Post
jcxz
сообщение Jun 21 2018, 10:18
Сообщение #43


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(juvf @ Jun 21 2018, 12:01) *
Что за глупость? при чем тут memcpy с отрицатеольными size_to_take? В коде ТС явно size_to_take > 0.

Где это "явно указано"? Ни объявления ни присвоения значения size_to_take там нету. А это означает, что size_to_take к началу цикла может принимать любое значение. И алгоритм вполне может быть рассчитан на то, что при size_to_take<=0 не должно выполняться ни одной итерации.
Глупость - это видеть то, чего нет.

Цитата(juvf @ Jun 21 2018, 12:01) *
Такой код работает, если убрать прагму, то црц считается не правильно.

В исходнике вроде криминала нет. Но это ничего не доказывает.
Без анализа ассемблерного результата ничего сказать нельзя.
Да даже анализ ассемблерного варианта может ничего не дать. Элементарная причина "неверной работы оптимизированного варианта" при работе оптимизированного например: переполнение стека в вызывающей задаче. Оптимизированные варианты, как правило расходуют больше стека (больше регистров используют, соответственно - больше их сохраняют на входе в функции; заменяют некоторые повторяющиеся куски кода на дополнительные подпрограммы, что опять же ведёт к увеличению расхода стека и т.п.), а в неоптимизированном варианте стека ещё хватает.
Другой вариант: при вкл. оптимизации функция может инлайниться в точки вызова, вызывая перераспределение регистров (увеличение их использования), что может приводить к проявлению скрытых багов в вызывающих функциях, которые при меньшем кол-ве используемых регистров не проявляются.
Так что наиболее вероятный диагноз остаётся тем же: с вероятностью 99.9% - баги в коде. laughing.gif И необязательно что в этой процедуре.

Цитата(adnega @ Jun 21 2018, 12:06) *
Да, но 0.1% все же баг в компиляторе.
У меня есть проект, который собирается и работает при O2 и не собирается при Os. Интересно?

В приведённом Вами примере баг в Вашем коде, а не в компиляторе. О чём компилятор Вам и сообщает.
Вы вычисляете выражение, результат которого зависит от взаимного расположения меток. Их взаимное расположение видимо определяется на этапе компиляции (в зависимости от результата компиляции кода, который между ними - размер его меняется). Естественно - когда результат не влазит в байт, компилятор Вам об этом сообщает. В чём его ошибка? wacko.gif
А писать так код - это выстрел себе в ногу: сегодня компилится, завтра - нет.

Цитата(juvf @ Jun 21 2018, 12:24) *
Я тоже про это думал. На весь проект стоит максимальная оптимизация по размеру кода. Дебажил на уровне Си, в асм углубляться не стал. Одна строчка #pragma optimize=none давала правильную работу расчета црц. Поэтому врят-ли что-то в остальном коде не так. Времени не было искать глюк в компиляторе или ещё где.... Видимо это был 0,1%.

Ну да - обычное оправдание багописателей в таких случаях: "не было времени искать баг, поэтому я закопал его поглубже". Это ничего, что потом, через неопределённой время он опять проявится и вдарит по лбу в самом неожиданном месте. Когда совершенно безобидный код станет глючить. И опять виноват конечно будет компилятор, ну кто-ж ещё! smile3009.gif

При отладке одно из главнейших правил: ПРИ ПРОЯВЛЕНИИ БАГА НЕ СЛЕДУЕТ СТАРАТЬСЯ ДОБИТЬСЯ ТОГО, ЧТОБЫ ОН НЕ ПРОЯВЛЯЛСЯ. НАДО НАОБОРОТ - ЗАКРЕПИТЬ УСЛОВИЯ, ПРИ КОТОРЫХ ОН ПРОЯВЛЯЕТСЯ, ДОБИТЬСЯ ЕГО ПОВТОРЯЕМОСТИ И ИСКАТЬ ЕГО ПРИЧИНУ И УСТРАНИТЬ! И пока этого не сделано - двигаться дальше нельзя.
Ведь не тот баг страшен, который чётко проявляется, а тот - что проявляется иногда, внезапно и хаотично.

Цитата(scifi @ Jun 21 2018, 12:07) *
Поймать его за руку на конретной инструкции сложно, так как код MD5 зубодробительный.

Один из вариантов действий в такой ситуации:
Скомпилить подозреваемую функцию с оптимизацией. Взять ассемблерный результат её компиляции, оформить в виде асм-функции. И вставить в исходник вместо вызова си-функции. Выключить оптимизацию и проверить работу кода. Если теперь глюк появился и в неоптимизированном варианте, то только в этом случае можно предполагать, что проблема в данной оптимизированной функции. Далее - только анализ этой ассемблерной функции.
Go to the top of the page
 
+Quote Post
juvf
сообщение Jun 21 2018, 10:24
Сообщение #44


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Цитата(jcxz @ Jun 21 2018, 14:53) *
Где это "явно указано"?
Дальше в эту сторону дискутировать не выжу смысла. Учитесь читать исходный код.

Цитата
Так что наиболее вероятный диагноз остаётся тем же: с вероятностью 99.9% - баги в коде.
Если не на кофейной гуще гадать, а на картах Таро, то баг в ОС, на которой кросскомпиляция идет.

Вот ещё пример
Код
#define     __IO    volatile         /*!< defines 'read / write' permissions  */
typedef struct SPI_struct
{
  __IO uint8_t SR;     /*!< SPI status register */
}
SPI_TypeDef;
...
#define SPI1                        ((SPI_TypeDef *) SPI1_BASE)
SPI_FLAG_BSY    = (uint8_t)0x80
...





#pragma optimize=none //без прагмы waitSpi(); не дожидается выполнения
inline void waitSpi() {       while( (SPI1->SR & (uint8_t)SPI_FLAG_BSY));}
Тут без прагмы вход в waitSpi и мгновенный выход, не зависимо от флага SPI_FLAG_BSY.

Цитата
переполнение стека в вызывающей задаче.
ээээ.... а разве при переполнении стека программа аварийно не завершается? В моём случае с crc16_byte() идет подсчет црц, но на выходе он не вырный, падения программы нет. Програма продолжает работать, но бракует пакет по црц. Принятые данные не портятся во время работы crc16_byte() и во время работы программы в целом. Хотел подебажить crc16_byte(), но с оптимизацией код не шагается по строчками си. А без оптимизации шагается но и работает без ошибок.

Цитата
Да даже анализ ассемблерного варианта может ничего не дать. Элементарная причина "неверной работы оптимизированного варианта" при работе оптимизированного например: переполнение стека в вызывающей задаче.
Что-то я не пойму.... Вот, вы же сами утверждаете, что оптимизатор может сломать работу программы написанной без ошибок. Я о том же.
Go to the top of the page
 
+Quote Post
adnega
сообщение Jun 21 2018, 10:25
Сообщение #45


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(jcxz @ Jun 21 2018, 13:09) *
В приведённом Вами примере баг в Вашем коде, а не в компиляторе. О чём компилятор Вам и сообщает.

Вот мой код. Это участок типа
Код
if(0){}
else if(состояние_1){сделать_1;}
else if(состояние_2){сделать_2;}

Так не собирается.
А так
Код
if(0){}
else if(состояние_2){сделать_2;}
else if(состояние_1){сделать_1;}

нет проблем.
Это чисто косяк компилятора.

Вот полный код:
CODE
//-------------------------------------------
// ESP8266_ST_UDP0_START
//- - - - - - - - - - - - - - - - - - - - - -
else if(esp8266_state == ESP8266_ST_UDP0_START)
{
if(esp8266_cmd_flag == ESP8266_CMD_START)
{
send_cmd("AT+CIPSTART=0,\"UDP\",\"255.255.255.255\",5002,5001,2");
}
if(esp8266_to > 1000)
{
SEND_TO;
esp8266_to_cmd(ESP8266_ST_IDLE);
}
}
//-------------------------------------------
// ESP8266_ST_UDP0_SEND
//- - - - - - - - - - - - - - - - - - - - - -
else if(esp8266_state == ESP8266_ST_UDP0_SEND)
{
if(esp8266_cmd_flag == ESP8266_CMD_START)
{
esp8266_cmd_flag = ESP8266_CMD_ST + 0;
esp8266_to = 0;
esp8266_last_cmd[0] = 0;
bl_export.bl_sp_str(&esp8266, "AT+CIPSEND=0,");
bl_export.bl_sp_dec(&esp8266, esp8266_udp_send_len);
bl_export.bl_sp_str(&esp8266, "\r\n");
bl_export.bl_sp_start(&esp8266);
}
if(esp8266_to > 1000)
{
SEND_TO;
esp8266_to_cmd(ESP8266_ST_IDLE);
}
}

Если соответствующие блоки ESP8266_ST_UDP0_START и ESP8266_ST_UDP0_SEND в исходнике переставить местами, то
компилятор генерит правильный s-файл. Иначе генерит таблицу, в которой смещения не помещаются.
Где тут моя ошибка? Где ошибка компилятора я разобрался и на всякий случай сменил компилятор (была сборка arm-kgp-eabi-procyon).
Go to the top of the page
 
+Quote Post

6 страниц V  < 1 2 3 4 5 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd April 2024 - 12:09
Рейтинг@Mail.ru


Страница сгенерированна за 0.01553 секунд с 7
ELECTRONIX ©2004-2016