Jump to content

    

gladov

Свой
  • Content Count

    169
  • Joined

  • Last visited

Community Reputation

0 Обычный

About gladov

  • Rank
    Частый гость
  • Birthday 12/10/1981

Контакты

  • Сайт
    Array

Информация

  • Город
    Array
  1. Дело в том, что NXP взял за основу UART 16650. Именно эта архитектура в точности повторена в контроллерах NXP, а, как известно, на этой архитектуре десятилетиями работали компьютеры. Так что оба подхода: "классический микроконтроллерный" и от NXP имеют право на жизнь и тут еще можно поспорить какой вариант более классический и распространенный.
  2. Все сильно зависит от архитектуры процессора, порта ОС на эту архитектуру и, конечно, правильности применения данной ОС. Насчет uCOS не согласен. Она будет пытаться перепланировать задачи при выходе из прерывания ТОЛЬКО в том случае, если в прерывании была вызвана функция C_ISR_ENTER(). Если необходимо 1000 раз выполнить прерывание без перепланирования и только на 1001-й передать управление другой задаче, так и вызовите C_ISR_ENTER() только на 1001 раз. Тогда и оверхеда не получите. С Cortex'ами, например, еще проще. Там даже не надо системе говорить, что началось прерывание. В любой ПРАВИЛЬНО портированной ОС перепланировка будет вызвана при выходе из прерывания ТОЛЬКО в случае активации в этом прерывании каких-либо механизмов межпроцессного взаимодействия, таких как взведение семафоров, флагов, передача сообщений и т.п. Так что при правильном использовании ОС оверхед минимален.
  3. Понадобилось мне в одной задаче приблизительно (но быстро) вычислять квадратный корень. Вся арифметика построена на целых числах, поэтому и корень тоже решено было считать без плавучки. Точность результата +- 1 меня вполне устраивает. На просторах интернета, да и на этом форуме, удалось найти много готовых решений, но их основная масса ИМХО немного устарела, т.к. заточена под АЛУ без умножителя. Меня же интересовал алгоритм для применения на АРМах. Решено было попробовать некоторые из найденных и оценить их скорость работы на АРМах. Для тестов использовался LPC1758, разогнанный до 100МГц. Отвлекающих от вычислений факторов нет, кроме таймера, отсчитывающего миллисекунды. uint32_t sqrt1 (uint32_t L) { int32_t temp, div; uint32_t rslt = L; if (L <= 0) return 0; else if (L & 0xFFFF0000L) if (L & 0xFF000000L) div = 0x3FFF; else div = 0x3FF; else if (L & 0x0FF00L) div = 0x3F; else div = (L > 4) ? 0x7 : L; while (1) { temp = L/div + div; div = temp >> 1; div += temp & 1; if (rslt > div) rslt = (uint32_t)div; else { if (L/rslt == rslt-1 && L%rslt==0) rslt--; return rslt; } } } uint32_t sqrt2 (uint32_t src) { uint32_t wrk; uint32_t dst; int i; dst = 0x8000; wrk = 0x8000; for(i=0; i<16; i++) { if(dst*dst>src) dst &= ~wrk; wrk >>= 1; dst |= wrk; } return dst; } uint32_t sqrt3 (uint32_t src) { uint32_t mask, sqr = 0, temp; int j=16; temp = 0xC0000000; do { if( src & temp ) break; temp>>=2; } while( --j); if( j==0 ) return 0; mask = temp & (temp>>1); do { temp = sqr | mask; sqr >>= 1; if( temp <= src ) { sqr |= mask; src -= temp; } mask >>= 2; } while( --j ); return sqr; } uint32_t sqrt4 (uint32_t Val) { unsigned int bitSqr = 0x40000000; unsigned int root = 0; while (bitSqr != 0) { if (Val >= (bitSqr + root)) { Val = Val - (bitSqr + root); root = (root >> 1) | bitSqr; } else root = (root >> 1); bitSqr = (bitSqr >> 2); } return(root); } int TestSqrt(uint32_t(*func)(uint32_t)) { tick_count_t starttime = get_tick_count(); for (uint32_t i = 0; i < 10000000; i++) { uint32_t s = func(i); //Check the value uint32_t sq = s * s; if (!((sq == i) || (sq > i) && (s-1)*(s-1) < i || (sq < i) && (s+1)*(s+1) > i)) { while (1); } } return get_tick_count() - starttime; } Проверка с бесконечным циклом ни на одном алгоритме не сработала - все вычислялось четко. Результаты замеров в миллисекундах приведены ниже. В скобках приведено время вычисления без проверки правильности, только вычисление корня в цикле. sqrt1() - 0x349d (0x296d) sqrt2() - 0x4286 (0x3986) sqrt3() - 0x4807 (0x3cca) sqrt4() - 0x4933 (0x44df) Явный лидер - sqrt1(). Получается, что среднее время вычисления кв. корня около 1 микросекунды. Алгоритм взят отсюда Меня результат вполне устраивает, но если у кого-то есть другие интересные алгоритмы, давайте и их проверим. Интересно же найти лучший.
  4. Мне тоже не хотелось, но таков LwIP. Цитата с LwIP wiki: Еще одна ссылка
  5. Только один: загнать все в один поток, т.к. LwIP не позволяет работать с одним и тем же соединением из разных потоков.
  6. Никакой ошибки нет. __disable_irq() не предназначена для Cortex-M3, о чем и я Вам выше написал. А как устроена CMSIS не знаю, не пользовался. Все таки правильно тут советовали, что начинать знакомство с новой архитектурой используя чью-то библиотеку неправильно, т.к. наступаете не только на собственные грабли, но еще и на чужие. Я хелп редко читаю. А вот в файле <intrinsics.h> в комментах совершенно четко описано какие функции для чего можно/нужно использовать.
  7. А можно поинтересоваться для чего нужны 2 копии таблицы векторов? Вы очень упорно копаете, но создается стойкое ощущение, что немного не туда :) У Вас же будет бутлоадер? Наверное, он ляжет в один-два сектора в начале ПЗУ, так? А ведь он туда ляжет со своей таблицей, так? Тогда зачем Вам иметь еще и две таблицы у приложения? Его нужно просто сдвинуть на N-е кол-во секторов вперед и все. Только сдвинуть целиком, вместе с таблицей векторов. Например, так: ... /*-Memory Regions-*/ define symbol __ICFEDIT_region_ROM_start__ = 0x00002000; define symbol __ICFEDIT_region_ROM_end__ = 0x0003FFFF; define symbol __ICFEDIT_region_RAM_start__ = 0x10000000; define symbol __ICFEDIT_region_RAM_end__ = 0x10007FFF; /*-Specials-*/ define symbol __ICFEDIT_intvec_start__ = __ICFEDIT_region_ROM_start__; /*-Sizes-*/ ...
  8. Если внимательно прочесть, то ничего дизасмить не придется. После стандартных 16 прерываний ядра Cortex-M3 лежат ВСЕ векторы, которые имеются в данном камне. Считате, умножаете на 4 и т.д. После векторов память используется ИАРом по своему усмотрению. Но имхо и это знать вовсе не обязательно. Какая Вам разница куда именно ИАР положит какой код? Если обязательно сделать "дырку" между векторами и кодом для служебной информации, так сделайте ее с помощью конфига линкера. Точка входа в приложение у ИАРа располагается произвольно и знать ее вовсе не обязательно. Достаточно вычитать адрес начала кода из образа (опять же, см. описание первых 0х40 байтов в кортексе).
  9. Если речь идет про ИАР, то Вы путаете __disable_irq(), которое действительно вызовет проблему на кортексе, и __disable_interrupt(), о котором упоминал Alechek. Последнее на кортексе работает нормально.
  10. Да, придется спецтаблицу передвинуть за таблицу векторов. Но проблемы не вижу, т.к. со сменой ядра Вам обязательно пересобирать как загрузчик, так и основной софт. Вот и сдвиньте все дальше. Адреса 0х40 и выше конечно можно использовать как угодно (и объявлять тоже), но только есть ли гарантия, что не произойдет прерывания, адрес вектора которого попадет на ваши личные данные? Описание на области памяти ищите в DS на контроллер. Cortex-M3 стандартизует лишь область векторов прерываний, да и то не строго, а остальное, как правило, отдано под пользовательский код.
  11. Не верю. Совсем не верю. Такая проблема есть. Сегодня наткнулся. Исследования показали следующее: Допустим, есть массив: static int BigArray[QuiteLargeValue] = 0; Можно "=0" и убрать, разницы никакой. В конфиге ICF имеем строку: place in RAM_region { readwrite, block CSTACK, block HEAP }; Однозначно видно, что линкер пытается разложить блоки в регионе по убыванию размера. Так вот если массив оказывается большего размера, чем CSTACK или HEAP, то видим такую картину: "P2", part 1 of 5: 0x3840 .bss zero 0x1000001c 0x3840 Array.r79 [1] - 0x1000385c 0x3840 "P2", part 2 of 5: 0x2480 HEAP 0x10003860 0x2000 <Block> HEAP uninit 0x10003860 0x2000 <Block tail> CSTACK 0x10005860 0x300 <Block> CSTACK uninit 0x10005860 0x300 <Block tail> .iar.dynexit 0x10005b60 0x180 <Block> .iar.dynexit uninit 0x10005b60 0xc cppinit.o [15] .iar.dynexit uninit 0x10005b6c 0x174 <Block tail> - 0x10005ce0 0x2480 "P2", part 3 of 5: 0xc P2 s0 0x10005ce0 0xc <Init block> .data inited 0x10005ce0 0x4 file1.r79 [4] .data inited 0x10005ce4 0x4 file2.r79 [9] .data inited 0x10005ce8 0x4 cppinit.o [15] - 0x10005cec 0xc "P2", part 4 of 5: 0x217c .bss zero 0x10005cec 0x1024 mem.r79 [9] ... Наш блок Array попал в сегмент .bss, чего мы и хотели, однако, код для его инициализации не был сгенерирован линкером! Линкер начал забивать нулями область, начиная в данном случае с адреса 0x5cec. Если же уменьшить размер массива так, чтобы он оказался меньше кучи и стека, то он попадет к "остальным" членам .bss и все переменные проинициализируюутся. Конечно, уменьшать массив это не выход, поэтому есть другой вариант обхода проблемы в конфиге линкера: place in RAM_region { readwrite }; place in RAM_region { block CSTACK, block HEAP }; Тогда сегмент .bss не будет разорван данными с другими атрибутами и инициализация пройдет нормально.
  12. Начну со второго: да, возможно я излишне строго приравнял C++ и ООП. Это конечно не так, я немного не то имел ввиду. Конечно, C++ дает нам много вкусностей помимо "классического" ООП. Но, согласитесь, основные достоинства языка С++ заключаются в его возможности писать ОО-код. Именно поэтому я не приравнял С++ и ООП, но поставил их совсем рядом и позволил себе в первом посте сместить акцент в сторону ООП. Отношение ООП к динамике? Да никакого! Но во многих учебниках, а также в ВУЗах, преподается ООП (позвольте я все же буду тут писать про ООП, коль уж мой первый пост был де-факто про него) в тесной свзяке с динамической памятью, ибо так легче показать виртуализацию и полиморфизм. Поэтому и написал, что "ООП пытается тянуть за собой ....". Согласитесь, многие вещи удобнее реализовываются если использовать динамику? Однако этого лучше не делать, либо делать с умом, понимая механизмы и возможные последствия. Паттерны? А разве плохо знать о них? А к С++ они имеют прямое отношение: их можно реализовать используя С++, а вот на С сделать то же самое гораздо сложнее.
  13. С++ плохо подходит для ARM. Серьезно! Появляются накладняки на требуемую память, ООП пытается тянуть за собой в проект использование динамической памяти и еще много всяких неудобств. Зачем это Вам? А если серьезно, то я сам пишу под АРМ на С++, но чтобы к этому прийти, надо сначала понять что такое ООП вообще, зачем оно нужно, почему иногда оно удобнее, и лишь потом, если придет просветление (для ускорения процесса можно почитать, например, про шаблоны ООП) можно пытаться прикрутить объекты к АРМам.
  14. Я с EMAC плотно пока не работал, поэтому есть лишь догадка: в первом случае INTSTATUS вычитывается ПОСЛЕ первого обнуления в INTCLEAR, а во втором СНАЧАЛА читается статус, потом очищается прерывание. Может быть тот самый упомянутый выше "спусковой крючок" находится в INTSTATUS и сначала надо его прочитать (как в некоторых self-clear прерываниях), а потом уже принудительно прописать бит в INTCLEAR?
  15. Именно поэтому таймер лишь генерирует запрос на переключение. Аналогичный запрос может быть сгенерирован и "изнутри" ОС, например, при освобождении какого-то ресурса, ожидаемого процессом. А вот обработка запроса переключения производится из PendSV. Операция вынесена в прерывание чтобы была возможность обеспечить атомарность действий.