-
Постов
815 -
Зарегистрирован
-
Посещение
-
Победитель дней
4
Весь контент amaora
-
USB volatile storage device
amaora опубликовал тема в В помощь начинающему
Интересует сущетсвует ли такое. Если нет, то любые идеи из чего дешевле/проще сделать. Сам пока думаю так, ARM/MIPS SoC + SDRAM. Но насколько знаю, таким образом больше 512 Мб не будет, да и для 512 ещё надо какой-то SoC найти. А это мало. volatile по тому, что только такая память умеет неограниченое кол-во перезаписей, важно именно это, а сохранять данные без питания не надо. Спасибо. -
Синтез управления
amaora опубликовал тема в Математика и Физика
Вторую неделю не могу понять, в чем дело. Есть следующая дискретная система, x(n+1) = A x(n) + B u(n) z(n) = C x(n) ищем функцию Ляпунова в виде V(x) = x^T H x H > 0 (положительно определена) условие устойчивости, V(x(n+1)) - V(x(n)) < 0 в виде матричных неравенств, (A + B K C)^T H (A + B K C) - H < 0 это сводится к ЛМН, X = H^{-1} C X = Z C [ (X - Q) (A X + B Y C) ] [ ] > 0 [ (A X + B Y C) X ] решается численными методами, и находиться управление, K = Y Z^{-1} Итак, что не так, для некоторых систем LMI решатель (пробовал не один) не может найти решения, хотя у меня уже есть K которая стабилизирует систему. Такие некоторые системы я получаю вот так, [ A 0 ] Ab = [ ] [ I 0 ] [ B ] Bb = [ ] [ 0 ] Cb = [ 0 C ] это расширенная система включающая запаздывание. Спасибо. -
Создание прикладных программ под Linux
amaora ответил smk тема в В помощь начинающему
Не нужно создавать приложения, для запуска чего либо в определенное время есть cron, для изменения громкости ... тут все завист от того, что вы используете для вывода звука, для ALSA - amixer, для OSS - ossmix. Задача вероятно решается даже без текстового редактора, однострочным скриптом и добавлением его в crontab. -
Уменьшение картинки
amaora ответил amaora тема в Программирование
>У Вас всегда будет 320x240 -> 130x130 ? Да, но хардкодить под эти числа не хотелось бы, и есть ещё второй режим 256x224 -> 130x130. У меня есть код работающий подобным образом, тоже считает таблицы 130x3 и 130x2, но обход делается по dst, и работает в два раза дольше. Как его переписать, так чтобы обходить src и делать это только один раз, не очень ясно. Для этого надо предварительно занулить все пиксели в dst, и добавлять туда цвет умноженный на соответствующий вес при обходе src. Такой способ мне не кажется быстрым. По поводу разбиения, оно может быть полезно, ведь веса в таблицах будут (могут) повторяться с некоторым периодом, можно перейти к работе с блоками размером равным этому периоду и сильно уменьшить размер таблиц. В моем случае это привело к уменьшению времени преобразования на ~15% при 10x10 разбиении, хотя у меня совсем другие таблицы. -
Уменьшение картинки
amaora опубликовал тема в Программирование
Есть растровое графическое изображение, разрешение 320x240, цвет r5g6b5, надо его отскэйлить в 130x130, с хорошим качеством (читаемость текста) и быстро, нужно много кадров в секунду. Сейчас имеется решение делающее изменение размера за ~32 мсек на целевой системе, надо раза в 2 быстрее. Все что смог придумать сам и подсказали другие люди, реализовал. Изображение сейчас разбивается на независимые блоки, которые обрабатываются отдельно. Для каждого пикселя блока заранее вычисляются веса влияющих на него пикселей исходного изображения. Что еще можно сделать? union weight { struct { int16_t diff; uint16_t fract; } val; uint32_t raw; }; struct scale { /* Main * */ int src_width; int src_height; int dst_width; int dst_height; void *src; void *dst; union weight *weights; /* Blocks * */ int src_blk_w; int src_blk_h; int dst_blk_w; int dst_blk_h; int dst_blksz_nb; /* Helper * */ int pt_x; int pt_y; int scan_w; int scan_h; union weight *wp; }; #define FX_ZERO 0x00000000 #define FX_ONE 0x00010000 #define FX_ONEW 0x0000ffff #define FX_HALF 0x00008000 #define FX_ILD(i) (((int32_t)(i)) << 16) #define FX_FLD(i) ((int32_t)(i)) #define FX_STI(fx) ((int)((fx) >> 16)) #define FX_STF(fx) ((uint16_t)(fx & 0x0000ffff)) #define FX_FLOOR(fx) ((int32_t)((fx) & 0xffff0000)) #define FX_FRACT(fx) ((int32_t)((fx) & 0x0000ffff)) #define FX_CEILI(fx) ((int)(((fx) + FX_ONEW) >> 16)) #define FX_MUL(v,m) ((int32_t)(((int64_t)(v) * (int64_t)(m)) >> 16)) #define FX_MUL32(v,m) ((int32_t)(((int32_t)(v) * (int32_t)(m)) >> 16)) #define FX_DIV(n,d) ((int32_t)(((int64_t)(n) << 16) / ((int64_t)(d)))) static inline uint16_t rgb_pack(int *rgb) { uint16_t col; col = (rgb[0] & 0xf8) << 8; col |= (rgb[1] & 0xfc) << 3; col |= (rgb[2] & 0xf8) >> 3; return col; } static inline void rgb_unpack(uint16_t col, int *rgb) { rgb[0] = (col & 0xf800) >> 8; rgb[1] = (col & 0x07e0) >> 3; rgb[2] = (col & 0x001f) << 3; } static inline void rgb_zero(int *dst) { dst[0] = 0; dst[1] = 0; dst[2] = 0; } static inline void rgb_unpack_add_w(uint16_t col, int *rgb, int32_t w) { rgb[0] += FX_MUL32((col & 0xf800) >> 8, w); rgb[1] += FX_MUL32((col & 0x07e0) >> 3, w); rgb[2] += FX_MUL32((col & 0x001f) << 3, w); } static void fb_calc_weights_for_pixel(struct scale *sc, int x, int y) { int32_t us, vs; int32_t ue, ve; int32_t ps, qs; int32_t pe, qe; int32_t iw, jw, fw; int32_t wsum, wtmp; int dx, dy; int i, j; int ilim, jlim; union weight *wbeg; us = FX_MUL( FX_DIV( FX_ILD(sc->src_width), FX_ILD(sc->dst_width)), FX_ILD(x)); vs = FX_MUL( FX_DIV( FX_ILD(sc->src_height), FX_ILD(sc->dst_height)), FX_ILD(y)); ue = FX_MUL( FX_DIV( FX_ILD(sc->src_width), FX_ILD(sc->dst_width)), FX_ILD(x + 1)); ve = FX_MUL( FX_DIV( FX_ILD(sc->src_height), FX_ILD(sc->dst_height)), FX_ILD(y + 1)); i = FX_STI(us); j = FX_STI(vs); ilim = i + sc->scan_w; jlim = j + sc->scan_h; wsum = 0; wbeg = sc->wp; for (; j < jlim; ++j) for (i = FX_STI(us); i < ilim; ++i) { ps = FX_ILD(i); qs = FX_ILD(j); pe = FX_ILD(i + 1); qe = FX_ILD(j + 1); /* Intersection pixels on axis X * */ if (ps > ue) iw = FX_ZERO; else if (ps < us) iw = FX_ONE - (us - ps); else if (ue < pe) iw = FX_ONE - (pe - ue); else iw = FX_ONEW; /* Intersection pixels on axis Y * */ if (qs > ve) jw = FX_ZERO; else if (qs < vs) jw = FX_ONE - (vs - qs); else if (ve < qe) jw = FX_ONE - (qe - ve); else jw = FX_ONEW; /* This case give more blured result * */ //fw = (iw + jw) / 2; /* Calculate weight as square * */ fw = FX_MUL(iw, jw); /* Add if it have influence only * */ if (fw > FX_ZERO) { wsum += fw; dx = i - sc->pt_x; dy = j - sc->pt_y; sc->wp->val.diff = sc->src_width * dy + dx; sc->pt_x = i; sc->pt_y = j; sc->wp->val.fract = FX_STF(fw); sc->wp++; } } /* Add end-pixel marker * */ sc->wp->raw = 0; sc->wp++; /* Normalize weights * */ for (; wbeg->raw; ++wbeg) { wtmp = FX_DIV( FX_FLD(wbeg->val.fract), wsum); if (wtmp < FX_ONE) wbeg->val.fract = FX_STF(wtmp); else wbeg->val.fract = FX_ONEW; } } static void fb_scale_open(struct scale *sc) { int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101 }; int x, y, i; int mdw, mdh; int bsz; int yet; /* Calculate scan area size * */ sc->scan_w = FX_CEILI(FX_DIV( FX_ILD(sc->src_width), FX_ILD(sc->dst_width))) + 1; sc->scan_h = FX_CEILI(FX_DIV( FX_ILD(sc->src_height), FX_ILD(sc->dst_height))) + 1; /* Block fraction * */ mdw = 1; mdh = 1; sc->src_blk_w = sc->src_width / mdw; sc->src_blk_h = sc->src_height / mdh; sc->dst_blk_w = sc->dst_width / mdw; sc->dst_blk_h = sc->dst_height / mdh; /* Minimize block size on width * */ do { yet = 0; for (i = 0; i < 26; ++i) { if ( !(sc->src_blk_w % prime[i]) && !(sc->dst_blk_w % prime[i])) { mdw *= prime[i]; sc->src_blk_w = sc->src_width / mdw; sc->dst_blk_w = sc->dst_width / mdw; yet = 1; break; } } } while (yet); /* Minimize block size on height * */ do { yet = 0; for (i = 0; i < 26; ++i) { if ( !(sc->src_blk_h % prime[i]) && !(sc->dst_blk_h % prime[i])) { mdh *= prime[i]; sc->src_blk_h = sc->src_height / mdh; sc->dst_blk_h = sc->dst_height / mdh; yet = 1; break; } } } while (yet); /* Near boundary for block size * */ if (sc->dst_blksz_nb) { bsz = sc->dst_blk_w * sc->dst_blk_h; while (sc->dst_blksz_nb < bsz) { if (sc->dst_blk_w < sc->dst_blk_h) sc->dst_blk_w *= 2; else sc->dst_blk_h *= 2; bsz = sc->dst_blk_w * sc->dst_blk_h; } } /* Weights allocation * */ sc->weights = malloc( sc->dst_blk_h * sc->dst_blk_w * sizeof(union weight) * (sc->scan_w * sc->scan_h + 1)); /* Calculate weights * */ sc->pt_x = 0; sc->pt_y = 0; sc->wp = sc->weights; for (y = 0; y < sc->dst_blk_h; ++y) { for (x = 0; x < sc->dst_blk_w; ++x) fb_calc_weights_for_pixel(sc, x, y); } } static void fb_scale_close(struct scale *sc) { free(sc->weights); } static void fb_scale_block_r5g6b5( struct scale *sc, const uint16_t *src, uint16_t *dst) { uint16_t *fin; int c16[3]; int y, dw, adw, dh; union weight *wp, w; dw = sc->dst_blk_w; dh = sc->dst_blk_h; wp = sc->weights; adw = sc->dst_width - dw; /* For all lines in this block * */ for (y = 0; y < dh; ++y) { fin = dst + dw; /* For all pixels on line * */ do { /* c = 0 * */ rgb_zero(c16); /* Calculate color, c = c1*w1 + c2*w2 + ... + cn*wn * */ do { /* If is not end-pixel marker * */ if ((w = *wp++).raw) { /* Go to new position in source * */ src += w.val.diff; /* Read color, c = c + ci*wi * */ rgb_unpack_add_w(*src, c16, FX_FLD(w.val.fract)); } else break; } while (1); /* Write result * */ *dst++ = rgb_pack(c16); } while (dst != fin); /* Go to next line * */ dst += adw; } } static void fb_scale_r5g6b5(struct scale *sc) { int y, lines; int inc_d, inc_s; int dw, bdw_d, bdw_s; uint16_t *src; uint16_t *dst, *fin; dw = sc->dst_width; bdw_s = sc->src_blk_w; bdw_d = sc->dst_blk_w; inc_s = sc->src_width * (sc->src_blk_h - 1); inc_d = sc->dst_width * (sc->dst_blk_h - 1); lines = sc->dst_height / sc->dst_blk_h; src = sc->src; dst = sc->dst; /* For all lines of blocks * */ for (y = 0; y < lines; ++y) { fin = dst + dw; /* For all block on line * */ while (dst != fin) { /* Scale block * */ fb_scale_block_r5g6b5(sc, src, dst); /* Go to next block in this line * */ src += bdw_s; dst += bdw_d; } src += inc_s; dst += inc_d; } } -
поворот изображения
amaora ответил ecs тема в В помощь начинающему
for (i = 0; i < height; ++i) for (j = 0; j < width; ++j) { u = i*C00 + j*C01 + C02; v = i*C10 + j*C11 + C12; dst[i][j] = lookup(src, u, v); } C - матрица поворота, обратная -
Мой вариант для 4.4.1 (с uClibc) http://paravozeg.narod.ru/tcmakev3.gz Правка: перед запуском скрипта, # cd /usr/local # ln -s /path_to_script_dir/sysroot/usr/local/arm arm ну и PATH надо заранее поправить, это как всегда. alx2 Странно, только сейчас узнал, что newlib не есть часть gcc, конфигурил с --with-newlib а newlib не добавлял, собиралось и работало.
-
Софт для трассировки
amaora опубликовал тема в В помощь начинающему
Есть ли что нибудь такое? тоесть, меня не интересует рисование дорожек вручную, и не инетересует кнопка auto_route и пара параметров к ней. Интересует что то такое, board {type=rect, size=free, holes={0.5,0.3}, paths=0.2, gap=0.2} uselib ARM, SRAM place {ARM_SoC, id=soc, pos={324,123}} place {SRAM, id=s1, pos=free} group {s1_addr, s1.0, s1.2, ... } group {soc_addr, soc.23, soc.24, ...} place {resistor, id=resb, count=16, pos=free} link {s1_addr, soc_addr} via {resb} result {path_addr} optimize {path_addr, length=min, length=align} constraint {legth_between {soc,resb} < 10} Грязновато, но смысл думаю понятен. Пишутся ограничения и параметры которые надо оптимизировать (связи можно указывать сдесь же или брать из схемы, не особо важно), на декларативном языке, отдаются трассировщику, на выходе готовая геометрия дорожек и отверстий. Извиняюсь, что начал не сначала, и спасибо что дочитали. -
Возможно это связвно с вот этими изменениями в binutils http://www.nabble.com/Update-ARM-mapping-s...td24760784.html Как и куда отправлять багрепорт написано в binutils/README Проблема в thumb, без multilib должно собраться.
-
linux собрать
amaora ответил SergeyVas тема в GNU/OpenSource средства разработки
Вот вполне книга, http://www.linuxfromscratch.org/ Коротко, как происходит загрузка, Загрузчик копирует образ ядра по некоторому адресу, делает возможно ещё какие то действия (передача параметров, например диапазон адресов RAM) это платформо-специфично, подробности должны быть в документации вместе с исходниками ядра. Загрузчик передает упрвленияе ядру, ядро инициализируется, после чего важный этап это монтирование корневой файловой системы, нужно либо иметь драйвер устройства на котором будет фс, либо сделать initrd, это корневая фс которая хранится в RAM, загрузка образа initrd производится загрузчиком. В корне ищется бинарник init (обычно /sbin/init) и запускается. Далее init производит инициализацию user space, обычно это предствалено шелл скриптом и туда можно вписать все что нужно. Все дальнейшие действия сильно зависят от того что вам надо и легко перенастраиваются, обычно дальше идет запуск login (getty) процессов для терминалов. Образы программ в формате ELF представлены файлами на фс, и могут быть запущены (т.е. создан соответствующий им процесс) с помощью системных вызовов из уже работающих процессов. Как конкретно производится системный вызов и передача/возврат параметров отностися к ABI. Драверы либо вкомпиливаются в ядро, либо создается модуль который можно загрузить и выгрузить в любой момент в работающей системе. Выбрать это все можно при конфигурировании ядра. Для кнопок и меню, да нужен софт это реализующий. -
RTOS, кратко: вытесняющая многозадачность, простой API ядра, отдельный стек для прерываний, язык С, компилятор GCC. В архиве весь проект в котором ОС и используется. http://paravozeg.narod.ru/avr_os-090825.tar.gz
-
Обычно использую бинарный протокол для отладки, но если надо текстовую консоль, скопировал бы схему работы с юниксовых шелл+терминал, что то лучше придумать сложно. u8 uart_read(); void uart_write(u8 val); //... do { c = uart_read(); buff[i++]; if (c == CR) { uart_write('\n'); parse_line(buff); i = 0; continue; } if (c == BACKSPACE) { uart_write('\b'); --i; continue; } uart_write(c); } while(1); Конечно тут мало проверок, и можно удалять только последний символ, это упрощенный пример.
-
Резервный источник питания
amaora ответил amaora тема в Схемотехника
Переключил питание МК на 5в (к истоку транзистора), так транзистор стал нормально закрываться (хотя где то проходят ~8мА). Добавил резистор от CTL1 на землю как писали выше. Програмно реализованный источник тока показал свои недостатки, ШИМ создает столько шума, что измерять напряжение на батарее не возможно (+-0.1в), повышение частоты (до ~23кГц) не помогает. Какой критерий останова заряда теперь использовать не понятно, я расчитывал на измерение спада напряжения в несколько десятков милливольт (хотя, это только для быстрого заряда? мне же надо что то среднее 0.2C-0.4C). Можно ещё останавливать ШИМ на время измерения, но тогда можно пропустить максимум. Остаеться 0.1С и 10-16 часов. Может я что то не учел? и есть варианты получше? -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Проверил макрос, он имеет неожиданный эффект, #define surely(var) (*(volatile __typeof__ (var) *) &(var)) if (likely(*th_head)) { interrupts_disable(); surely(*th_head) = (*th_head)->next; surely(th_self) = *th_head; thread_restore_helper(); } 6fe: ed 01 movw r28, r26 700: 89 a5 ldd r24, Y+41; 0x29 702: 9a a5 ldd r25, Y+42; 0x2a 704: 91 83 std Z+1, r25; 0x01 706: 80 83 st Z, r24 /* !!! */ 708: 80 81 ld r24, Z 70a: 91 81 ldd r25, Z+1; 0x01 /* !!! */ 70c: 90 93 ea 00 sts 0x00EA, r25 710: 80 93 e9 00 sts 0x00E9, r24 714: e0 91 e9 00 lds r30, 0x00E9 718: f0 91 ea 00 lds r31, 0x00EA 71c: 00 a1 ldd r16, Z+32; 0x20 -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Сейчас вернул код в исходное состояние, в то, что я показал здесь, присвоение th_self заработало в обоих местах, странно, видимо как то повлияли другие изменения. Но вот что более инетересно, пробую вот такое изменение, thread_restore_helper() { - thread_regs_restore(); + //thread_regs_restore(); for (;;); } Второе присваивание, то что перед вызовом этой безвозвратной функции исчезло, значит компилятор все таки учитывает содержимое асм-вставки. -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
>#define volatile_var(x) (*(volatile typeof(x) *)&x) Действительно, а я все только усложнил. Спасибо, с этим ясно. th_self используется в следующем коде, и далее другим кодом в том контексте который востановил этот код, th_self это указатель на структуру задачи которая выполняется в данный момент. #define thread_regs_restore() \ __asm__ __volatile__ ( \ "lds r30, th_self \n\t" \ "lds r31, th_self+1 \n\t" \ "ldd r16, Z+32 \n\t" \ "out __SREG__, r16 \n\t" \ "ldd r16, Z+33 \n\t" \ "ldd r17, Z+34 \n\t" \ "out __SP_L__, r16 \n\t" \ "out __SP_H__, r17 \n\t" \ "ldd r16, Z+30 \n\t" \ "ldd r17, Z+31 \n\t" \ "sts (%0-1), r16 \n\t" \ "sts (%0-0), r17 \n\t" \ "ld r0, Z+ \n\t" \ "ld r1, Z+ \n\t" \ "ld r2, Z+ \n\t" \ "ld r3, Z+ \n\t" \ "ld r4, Z+ \n\t" \ "ld r5, Z+ \n\t" \ "ld r6, Z+ \n\t" \ "ld r7, Z+ \n\t" \ "ld r8, Z+ \n\t" \ "ld r9, Z+ \n\t" \ "ld r10, Z+ \n\t" \ "ld r11, Z+ \n\t" \ "ld r12, Z+ \n\t" \ "ld r13, Z+ \n\t" \ "ld r14, Z+ \n\t" \ "ld r15, Z+ \n\t" \ "ld r16, Z+ \n\t" \ "ld r17, Z+ \n\t" \ "ld r18, Z+ \n\t" \ "ld r19, Z+ \n\t" \ "ld r20, Z+ \n\t" \ "ld r21, Z+ \n\t" \ "ld r22, Z+ \n\t" \ "ld r23, Z+ \n\t" \ "ld r24, Z+ \n\t" \ "ld r25, Z+ \n\t" \ "ld r26, Z+ \n\t" \ "ld r27, Z+ \n\t" \ "ld r28, Z+ \n\t" \ "ld r29, Z+ \n\t" \ "lds r30, (%0-1) \n\t" \ "lds r31, (%0-0) \n\t" \ "reti \n\t" \ : : "X" (THREAD_TEMP_ADDR) \ ) -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Про присваивание *th_head ошибся, но я уже писал об этом. >В теле thread_restore_helper() th_self не используется, управление вызывающей > функции она не возвращает - видимо поэтому компилятор разумно посчитал, что > присваивание th_self не имеет эффекта. Слишком сильное предположение, так и предыдущее присваивание можно отбросить. Да и вот ещё раз повторю, >Сейчас проверил, если убрать первое присвоение th_self = NULL; то второе не > выбрасывается. почему? >То есть это что-то типа пайпа между двумя равноправными тредами? Мне такого > делать не приходилось, но думаю, тут помогут автоматические переменные, типа > вот: Я так и делаю, но это работа которую хочется преложить на компилтор, uint8_t read() { while (rd == volatile_read(wr)); uint8_t val = buff[rd]; rd = (rd + 1) & 15; return val; } Это похоже можно сделать вот так, #define volatile_read(op) \ ({ volatile typeof (op) *__op = &(op); *__op; }) Как сделать volatile_write не знаю, ни когда с такой ({}) конструкцией не связывался. Правка: ну конечно можно параметром передать это очевидно. -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Вот от компилятора, но тут есть ещё изменения, cli/sei убраны, .global thread_global_shedule .type thread_global_shedule, @function thread_global_shedule: /* prologue: naked */ /* frame size = 0 */ sts (th_self)+1,__zero_reg__ sts th_self,__zero_reg__ ldi r17,lo8(64) .L73: in r18,82-0x20 out 82-0x20,__zero_reg__ out 92-0x20,r17 lds r28,th_sleep lds r29,(th_sleep)+1 sbiw r28,0 breq .L65 lds r24,tov lds r25,(tov)+1 add r24,r18 adc r25,__zero_reg__ sts (tov)+1,__zero_reg__ sts tov,__zero_reg__ ldd r18,Y+35 ldd r19,Y+36 cp r24,r18 cpc r25,r19 brlo .+2 rjmp .L66 sub r18,r24 sbc r19,r25 std Y+36,r19 std Y+35,r18 .L65: ldi r24,lo8(1) ldi r25,hi8(1) .L72: movw r30,r24 lsl r30 rol r31 subi r30,lo8(-(th_run)) sbci r31,hi8(-(th_run)) ld r26,Z ldd r27,Z+1 sbiw r26,0 brne .+2 rjmp .L69 movw r28,r26 ldd r24,Y+41 ldd r25,Y+42 std Z+1,r25 st Z,r24 /* вот это здесь должно быть но его нет */ sts (th_self)+1,r25 sts th_self,r24 /* конец */ /* #APP */ ; 32 "thread.c" 1 lds r30, th_self lds r31, th_self+1 ldd r16, Z+32 out __SREG__, r16 ldd r16, Z+33 ldd r17, Z+34 out __SP_L__, r16 out __SP_H__, r17 ldd r16, Z+30 ldd r17, Z+31 sts 0x045E, r16 sts 0x045F, r17 ld r0, Z+ ld r1, Z+ ld r2, Z+ ld r3, Z+ ld r4, Z+ ld r5, Z+ ld r6, Z+ ld r7, Z+ ld r8, Z+ ld r9, Z+ ld r10, Z+ ld r11, Z+ ld r12, Z+ ld r13, Z+ ld r14, Z+ ld r15, Z+ ld r16, Z+ ld r17, Z+ ld r18, Z+ ld r19, Z+ ld r20, Z+ ld r21, Z+ ld r22, Z+ ld r23, Z+ ld r24, Z+ ld r25, Z+ ld r26, Z+ ld r27, Z+ ld r28, Z+ ld r29, Z+ lds r30, 0x045E lds r31, 0x045F reti ; 0 "" 2 /* #NOAPP */ .L70: rjmp .L70 .L69: sbiw r24,1 brne .L71 ldi r24,lo8(0) ldi r25,hi8(0) rjmp .L72 .L66: sub r24,r18 sbc r25,r19 sts (tov)+1,r25 sts tov,r24 ldd r18,Y+41 ldd r19,Y+42 ldd r24,Y+38 mov r26,r24 ldi r27,lo8(0) lsl r26 rol r27 subi r26,lo8(-(th_run)) sbci r27,hi8(-(th_run)) ld r30,X+ ld r31,X sbiw r26,1 sbiw r30,0 breq .L67 ldd r24,Z+41 ldd r25,Z+42 std Y+42,r25 std Y+41,r24 ld r30,X+ ld r31,X sbiw r26,1 ldd __tmp_reg__,Z+41 ldd r31,Z+42 mov r30,__tmp_reg__ std Z+40,r29 std Z+39,r28 ld r24,X+ ld r25,X sbiw r26,1 std Y+40,r25 std Y+39,r24 ld r30,X+ ld r31,X std Z+42,r29 std Z+41,r28 .L68: sts (th_sleep)+1,r19 sts th_sleep,r18 rjmp .L65 .L71: call idle_go rjmp .L73 .L67: adiw r26,1 st X,r29 st -X,r28 std Y+40,r29 std Y+39,r28 ld r30,X+ ld r31,X std Z+42,r31 std Z+41,r30 rjmp .L68 .size thread_global_shedule, .-thread_global_shedule Сейчас проверил, если убрать первое присвоение th_self = NULL; то второе не выбрасывается. По поводу моего примера с read, там предполагается так же и write, в которой наоборот rd будет volatile а wr нет. Если сделать вот так, th_head = th_run + (i--); + th_self = *th_head; if (likely(*th_head)) { то, тоже код генерируется нормально, для этого присвоения. -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Копилятор GCC, были проблемы с тем, что компилятор видимо расчитывал на возрат из thread_regs_restore() при -O2 оптмизации, поэтому обернул в функцию с атрибутом noreturn. Вот код полностью, struct thread *th_self; /* running thread */ struct thread *th_run[CONFIG_PRIORITIES_NUMBER]; static struct thread *th_sleep; static uint16_t tov; static void thread_relax() { idle_go(); } static void thread_restore_helper() __attribute__ ((__noreturn__, __naked__)); static void thread_restore_helper() { thread_regs_restore(); for (;;); } void thread_global_shedule() { struct thread * th_temp; struct thread ** th_head; struct thread * volatile * th_self_v = &th_self; uint8_t tqu; uint16_t tdelta; int i; th_self = NULL; tqu = CONFIG_SHEDULE_TQUANT; do { tdelta = (uint16_t) timer_read(); timer_setup(tqu); interrupts_enable(); if (likely(th_sleep)) { tdelta += tov; tov = 0; if (th_sleep->th_tval > tdelta) { th_sleep->th_tval -= tdelta; } else { tov = tdelta - th_sleep->th_tval; th_temp = th_sleep->next; interrupts_disable(); TH_INSERT(th_sleep); interrupts_enable(); th_sleep = th_temp; } } i = (CONFIG_PRIORITIES_NUMBER - 1); do { th_head = th_run + (i--); if (likely(*th_head)) { interrupts_disable(); *th_head = (*th_head)->next; th_self = *th_head; thread_restore_helper(); } } while (i >= 0); dbg_write(0xff); thread_relax(); } while (1); } дизасм, 00000576 <thread_global_shedule>: 576: 10 92 ea 00 sts 0x00EA, r1 57a: 10 92 e9 00 sts 0x00E9, r1 57e: 10 e4 ldi r17, 0x40 ; 64 580: 22 b7 in r18, 0x32 ; 50 582: 12 be out 0x32, r1 ; 50 584: 1c bf out 0x3c, r17 ; 60 586: 78 94 sei 588: c0 91 60 00 lds r28, 0x0060 58c: d0 91 61 00 lds r29, 0x0061 590: 20 97 sbiw r28, 0x00 ; 0 592: a1 f0 breq .+40 ; 0x5bc <thread_global_shedule+0x46> 594: 80 91 62 00 lds r24, 0x0062 598: 90 91 63 00 lds r25, 0x0063 59c: 82 0f add r24, r18 59e: 91 1d adc r25, r1 5a0: 10 92 63 00 sts 0x0063, r1 5a4: 10 92 62 00 sts 0x0062, r1 5a8: 2b a1 ldd r18, Y+35 ; 0x23 5aa: 3c a1 ldd r19, Y+36 ; 0x24 5ac: 82 17 cp r24, r18 5ae: 93 07 cpc r25, r19 5b0: 08 f0 brcs .+2 ; 0x5b4 <thread_global_shedule+0x3e> 5b2: 4f c0 rjmp .+158 ; 0x652 <thread_global_shedule+0xdc> 5b4: 28 1b sub r18, r24 5b6: 39 0b sbc r19, r25 5b8: 3c a3 std Y+36, r19 ; 0x24 5ba: 2b a3 std Y+35, r18 ; 0x23 5bc: 81 e0 ldi r24, 0x01 ; 1 5be: 90 e0 ldi r25, 0x00 ; 0 5c0: fc 01 movw r30, r24 5c2: ee 0f add r30, r30 5c4: ff 1f adc r31, r31 5c6: eb 51 subi r30, 0x1B ; 27 5c8: ff 4f sbci r31, 0xFF ; 255 5ca: a0 81 ld r26, Z 5cc: b1 81 ldd r27, Z+1 ; 0x01 5ce: 10 97 sbiw r26, 0x00 ; 0 5d0: 09 f4 brne .+2 ; 0x5d4 <thread_global_shedule+0x5e> 5d2: 3a c0 rjmp .+116 ; 0x648 <thread_global_shedule+0xd2> 5d4: f8 94 cli 5d6: ed 01 movw r28, r26 5d8: 89 a5 ldd r24, Y+41 ; 0x29 5da: 9a a5 ldd r25, Y+42 ; 0x2a 5dc: 91 83 std Z+1, r25 ; 0x01 5de: 80 83 st Z, r24 5e0: e0 91 e9 00 lds r30, 0x00E9 5e4: f0 91 ea 00 lds r31, 0x00EA 5e8: 00 a1 ldd r16, Z+32 ; 0x20 5ea: 0f bf out 0x3f, r16 ; 63 5ec: 01 a1 ldd r16, Z+33 ; 0x21 5ee: 12 a1 ldd r17, Z+34 ; 0x22 5f0: 0d bf out 0x3d, r16 ; 61 5f2: 1e bf out 0x3e, r17 ; 62 5f4: 06 8d ldd r16, Z+30 ; 0x1e 5f6: 17 8d ldd r17, Z+31 ; 0x1f 5f8: 00 93 5e 04 sts 0x045E, r16 5fc: 10 93 5f 04 sts 0x045F, r17 600: 01 90 ld r0, Z+ 602: 11 90 ld r1, Z+ 604: 21 90 ld r2, Z+ 606: 31 90 ld r3, Z+ 608: 41 90 ld r4, Z+ 60a: 51 90 ld r5, Z+ 60c: 61 90 ld r6, Z+ 60e: 71 90 ld r7, Z+ 610: 81 90 ld r8, Z+ 612: 91 90 ld r9, Z+ 614: a1 90 ld r10, Z+ 616: b1 90 ld r11, Z+ 618: c1 90 ld r12, Z+ 61a: d1 90 ld r13, Z+ 61c: e1 90 ld r14, Z+ 61e: f1 90 ld r15, Z+ 620: 01 91 ld r16, Z+ 622: 11 91 ld r17, Z+ 624: 21 91 ld r18, Z+ 626: 31 91 ld r19, Z+ 628: 41 91 ld r20, Z+ 62a: 51 91 ld r21, Z+ 62c: 61 91 ld r22, Z+ 62e: 71 91 ld r23, Z+ 630: 81 91 ld r24, Z+ 632: 91 91 ld r25, Z+ 634: a1 91 ld r26, Z+ 636: b1 91 ld r27, Z+ 638: c1 91 ld r28, Z+ 63a: d1 91 ld r29, Z+ 63c: e0 91 5e 04 lds r30, 0x045E 640: f0 91 5f 04 lds r31, 0x045F 644: 18 95 reti 646: ff cf rjmp .-2 ; 0x646 <thread_global_shedule+0xd0> 648: 01 97 sbiw r24, 0x01 ; 1 64a: 99 f5 brne .+102 ; 0x6b2 <thread_global_shedule+0x13c> 64c: 80 e0 ldi r24, 0x00 ; 0 64e: 90 e0 ldi r25, 0x00 ; 0 650: b7 cf rjmp .-146 ; 0x5c0 <thread_global_shedule+0x4a> 652: 82 1b sub r24, r18 654: 93 0b sbc r25, r19 656: 90 93 63 00 sts 0x0063, r25 65a: 80 93 62 00 sts 0x0062, r24 65e: 29 a5 ldd r18, Y+41 ; 0x29 660: 3a a5 ldd r19, Y+42 ; 0x2a 662: f8 94 cli 664: 8e a1 ldd r24, Y+38 ; 0x26 666: a8 2f mov r26, r24 668: b0 e0 ldi r27, 0x00 ; 0 66a: aa 0f add r26, r26 66c: bb 1f adc r27, r27 66e: ab 51 subi r26, 0x1B ; 27 670: bf 4f sbci r27, 0xFF ; 255 672: ed 91 ld r30, X+ 674: fc 91 ld r31, X 676: 11 97 sbiw r26, 0x01 ; 1 678: 30 97 sbiw r30, 0x00 ; 0 67a: 09 f1 breq .+66 ; 0x6be <thread_global_shedule+0x148> 67c: 81 a5 ldd r24, Z+41 ; 0x29 67e: 92 a5 ldd r25, Z+42 ; 0x2a 680: 9a a7 std Y+42, r25 ; 0x2a 682: 89 a7 std Y+41, r24 ; 0x29 684: ed 91 ld r30, X+ 686: fc 91 ld r31, X 688: 11 97 sbiw r26, 0x01 ; 1 68a: 01 a4 ldd r0, Z+41 ; 0x29 68c: f2 a5 ldd r31, Z+42 ; 0x2a 68e: e0 2d mov r30, r0 690: d0 a7 std Z+40, r29 ; 0x28 692: c7 a3 std Z+39, r28 ; 0x27 694: 8d 91 ld r24, X+ 696: 9c 91 ld r25, X 698: 11 97 sbiw r26, 0x01 ; 1 69a: 98 a7 std Y+40, r25 ; 0x28 69c: 8f a3 std Y+39, r24 ; 0x27 69e: ed 91 ld r30, X+ 6a0: fc 91 ld r31, X 6a2: d2 a7 std Z+42, r29 ; 0x2a 6a4: c1 a7 std Z+41, r28 ; 0x29 6a6: 78 94 sei 6a8: 30 93 61 00 sts 0x0061, r19 6ac: 20 93 60 00 sts 0x0060, r18 6b0: 85 cf rjmp .-246 ; 0x5bc <thread_global_shedule+0x46> 6b2: 8f ef ldi r24, 0xFF ; 255 6b4: 0e 94 d6 04 call 0x9ac ; 0x9ac <dbg_write> 6b8: 0e 94 ab 03 call 0x756 ; 0x756 <idle_go> 6bc: 61 cf rjmp .-318 ; 0x580 <thread_global_shedule+0xa> 6be: 11 96 adiw r26, 0x01 ; 1 6c0: dc 93 st X, r29 6c2: ce 93 st -X, r28 6c4: d8 a7 std Y+40, r29 ; 0x28 6c6: cf a3 std Y+39, r28 ; 0x27 6c8: ed 91 ld r30, X+ 6ca: fc 91 ld r31, X 6cc: f2 a7 std Z+42, r31 ; 0x2a 6ce: e1 a7 std Z+41, r30 ; 0x29 6d0: ea cf rjmp .-44 ; 0x6a6 <thread_global_shedule+0x130> теперь запись производиться в *th_self_v diff --git a/thread.c.cp b/thread.c index 9e9d22b..6a0f9f5 100644 --- a/thread.c.cp +++ b/thread.c @@ -42,7 +42,7 @@ void thread_global_shedule() uint16_t tdelta; int i; - th_self = NULL; + *th_self_v = NULL; tqu = CONFIG_SHEDULE_TQUANT; do { @@ -77,7 +77,7 @@ void thread_global_shedule() if (likely(*th_head)) { interrupts_disable(); *th_head = (*th_head)->next; - th_self = *th_head; + *th_self_v = *th_head; thread_restore_helper(); } } дизасм, 00000576 <thread_global_shedule>: 576: 10 92 ea 00 sts 0x00EA, r1 57a: 10 92 e9 00 sts 0x00E9, r1 57e: 10 e4 ldi r17, 0x40 ; 64 580: 22 b7 in r18, 0x32 ; 50 582: 12 be out 0x32, r1 ; 50 584: 1c bf out 0x3c, r17 ; 60 586: 78 94 sei 588: c0 91 60 00 lds r28, 0x0060 58c: d0 91 61 00 lds r29, 0x0061 590: 20 97 sbiw r28, 0x00 ; 0 592: a1 f0 breq .+40 ; 0x5bc <thread_global_shedule+0x46> 594: 80 91 62 00 lds r24, 0x0062 598: 90 91 63 00 lds r25, 0x0063 59c: 82 0f add r24, r18 59e: 91 1d adc r25, r1 5a0: 10 92 63 00 sts 0x0063, r1 5a4: 10 92 62 00 sts 0x0062, r1 5a8: 2b a1 ldd r18, Y+35 ; 0x23 5aa: 3c a1 ldd r19, Y+36 ; 0x24 5ac: 82 17 cp r24, r18 5ae: 93 07 cpc r25, r19 5b0: 08 f0 brcs .+2 ; 0x5b4 <thread_global_shedule+0x3e> 5b2: 53 c0 rjmp .+166 ; 0x65a <thread_global_shedule+0xe4> 5b4: 28 1b sub r18, r24 5b6: 39 0b sbc r19, r25 5b8: 3c a3 std Y+36, r19 ; 0x24 5ba: 2b a3 std Y+35, r18 ; 0x23 5bc: 81 e0 ldi r24, 0x01 ; 1 5be: 90 e0 ldi r25, 0x00 ; 0 5c0: fc 01 movw r30, r24 5c2: ee 0f add r30, r30 5c4: ff 1f adc r31, r31 5c6: eb 51 subi r30, 0x1B ; 27 5c8: ff 4f sbci r31, 0xFF ; 255 5ca: a0 81 ld r26, Z 5cc: b1 81 ldd r27, Z+1 ; 0x01 5ce: 10 97 sbiw r26, 0x00 ; 0 5d0: 09 f4 brne .+2 ; 0x5d4 <thread_global_shedule+0x5e> 5d2: 3e c0 rjmp .+124 ; 0x650 <thread_global_shedule+0xda> 5d4: f8 94 cli 5d6: ed 01 movw r28, r26 5d8: 89 a5 ldd r24, Y+41 ; 0x29 5da: 9a a5 ldd r25, Y+42 ; 0x2a 5dc: 91 83 std Z+1, r25 ; 0x01 5de: 80 83 st Z, r24 5e0: 90 93 ea 00 sts 0x00EA, r25 5e4: 80 93 e9 00 sts 0x00E9, r24 5e8: e0 91 e9 00 lds r30, 0x00E9 5ec: f0 91 ea 00 lds r31, 0x00EA 5f0: 00 a1 ldd r16, Z+32 ; 0x20 5f2: 0f bf out 0x3f, r16 ; 63 5f4: 01 a1 ldd r16, Z+33 ; 0x21 5f6: 12 a1 ldd r17, Z+34 ; 0x22 5f8: 0d bf out 0x3d, r16 ; 61 5fa: 1e bf out 0x3e, r17 ; 62 5fc: 06 8d ldd r16, Z+30 ; 0x1e 5fe: 17 8d ldd r17, Z+31 ; 0x1f 600: 00 93 5e 04 sts 0x045E, r16 604: 10 93 5f 04 sts 0x045F, r17 608: 01 90 ld r0, Z+ 60a: 11 90 ld r1, Z+ 60c: 21 90 ld r2, Z+ 60e: 31 90 ld r3, Z+ 610: 41 90 ld r4, Z+ 612: 51 90 ld r5, Z+ 614: 61 90 ld r6, Z+ 616: 71 90 ld r7, Z+ 618: 81 90 ld r8, Z+ 61a: 91 90 ld r9, Z+ 61c: a1 90 ld r10, Z+ 61e: b1 90 ld r11, Z+ 620: c1 90 ld r12, Z+ 622: d1 90 ld r13, Z+ 624: e1 90 ld r14, Z+ 626: f1 90 ld r15, Z+ 628: 01 91 ld r16, Z+ 62a: 11 91 ld r17, Z+ 62c: 21 91 ld r18, Z+ 62e: 31 91 ld r19, Z+ 630: 41 91 ld r20, Z+ 632: 51 91 ld r21, Z+ 634: 61 91 ld r22, Z+ 636: 71 91 ld r23, Z+ 638: 81 91 ld r24, Z+ 63a: 91 91 ld r25, Z+ 63c: a1 91 ld r26, Z+ 63e: b1 91 ld r27, Z+ 640: c1 91 ld r28, Z+ 642: d1 91 ld r29, Z+ 644: e0 91 5e 04 lds r30, 0x045E 648: f0 91 5f 04 lds r31, 0x045F 64c: 18 95 reti 64e: ff cf rjmp .-2 ; 0x64e <thread_global_shedule+0xd8> 650: 01 97 sbiw r24, 0x01 ; 1 652: 99 f5 brne .+102 ; 0x6ba <thread_global_shedule+0x144> 654: 80 e0 ldi r24, 0x00 ; 0 656: 90 e0 ldi r25, 0x00 ; 0 658: b3 cf rjmp .-154 ; 0x5c0 <thread_global_shedule+0x4a> 65a: 82 1b sub r24, r18 65c: 93 0b sbc r25, r19 65e: 90 93 63 00 sts 0x0063, r25 662: 80 93 62 00 sts 0x0062, r24 666: 29 a5 ldd r18, Y+41 ; 0x29 668: 3a a5 ldd r19, Y+42 ; 0x2a 66a: f8 94 cli 66c: 8e a1 ldd r24, Y+38 ; 0x26 66e: a8 2f mov r26, r24 670: b0 e0 ldi r27, 0x00 ; 0 672: aa 0f add r26, r26 674: bb 1f adc r27, r27 676: ab 51 subi r26, 0x1B ; 27 678: bf 4f sbci r27, 0xFF ; 255 67a: ed 91 ld r30, X+ 67c: fc 91 ld r31, X 67e: 11 97 sbiw r26, 0x01 ; 1 680: 30 97 sbiw r30, 0x00 ; 0 682: 09 f1 breq .+66 ; 0x6c6 <thread_global_shedule+0x150> 684: 81 a5 ldd r24, Z+41 ; 0x29 686: 92 a5 ldd r25, Z+42 ; 0x2a 688: 9a a7 std Y+42, r25 ; 0x2a 68a: 89 a7 std Y+41, r24 ; 0x29 68c: ed 91 ld r30, X+ 68e: fc 91 ld r31, X 690: 11 97 sbiw r26, 0x01 ; 1 692: 01 a4 ldd r0, Z+41 ; 0x29 694: f2 a5 ldd r31, Z+42 ; 0x2a 696: e0 2d mov r30, r0 698: d0 a7 std Z+40, r29 ; 0x28 69a: c7 a3 std Z+39, r28 ; 0x27 69c: 8d 91 ld r24, X+ 69e: 9c 91 ld r25, X 6a0: 11 97 sbiw r26, 0x01 ; 1 6a2: 98 a7 std Y+40, r25 ; 0x28 6a4: 8f a3 std Y+39, r24 ; 0x27 6a6: ed 91 ld r30, X+ 6a8: fc 91 ld r31, X 6aa: d2 a7 std Z+42, r29 ; 0x2a 6ac: c1 a7 std Z+41, r28 ; 0x29 6ae: 78 94 sei 6b0: 30 93 61 00 sts 0x0061, r19 6b4: 20 93 60 00 sts 0x0060, r18 6b8: 81 cf rjmp .-254 ; 0x5bc <thread_global_shedule+0x46> 6ba: 8f ef ldi r24, 0xFF ; 255 6bc: 0e 94 da 04 call 0x9b4 ; 0x9b4 <dbg_write> 6c0: 0e 94 af 03 call 0x75e ; 0x75e <idle_go> 6c4: 5d cf rjmp .-326 ; 0x580 <thread_global_shedule+0xa> 6c6: 11 96 adiw r26, 0x01 ; 1 6c8: dc 93 st X, r29 6ca: ce 93 st -X, r28 6cc: d8 a7 std Y+40, r29 ; 0x28 6ce: cf a3 std Y+39, r28 ; 0x27 6d0: ed 91 ld r30, X+ 6d2: fc 91 ld r31, X 6d4: f2 a7 std Z+42, r31 ; 0x2a 6d6: e1 a7 std Z+41, r30 ; 0x29 6d8: ea cf rjmp .-44 ; 0x6ae <thread_global_shedule+0x138> не понимаю почему это происходит. Исходный вопрос был о том как попроще писать следующий код, так чтобы он работал и не было лишних перечитываний, uint8_t buff[16]; volatile uint8_t rd, wr; uint8_t read() { uint8_t val; while (rd == wr); // не плохо было бы только здесь указать, что есть volatile чтение, а с переменных квалификатор снять val = buff[rd]; rd = (rd + 1) & 0x0f; return val; } -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Причем здесь атомарный доступ? запись в th_self не производится, не понятно почему. А сохранять действительно нужно, далее значение используется, и не только в следующих двух инструкциях. -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
А не volatile глобальные переменные сохранять не надо? -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Насчет одной из строк ошибся, она не выбрасывается, но вот это все таки вот так, th_self = *th_head; 5a6: ed 01 movw r28, r26 5a8: 89 a5 ldd r24, Y+41; 0x29 5aa: 9a a5 ldd r25, Y+42; 0x2a 5ac: 91 83 std Z+1, r25; 0x01 5ae: 80 83 st Z, r24 5b0: e0 91 e9 00 lds r30, 0x00E9 5b4: f0 91 ea 00 lds r31, 0x00EA *th_self_v = *th_head; movw r28, r26 5a8: 89 a5 ldd r24, Y+41; 0x29 5aa: 9a a5 ldd r25, Y+42; 0x2a 5ac: 91 83 std Z+1, r25; 0x01 5ae: 80 83 st Z, r24 5b0: 90 93 ea 00 sts 0x00EA, r25 5b4: 80 93 e9 00 sts 0x00E9, r24 5b8: e0 91 e9 00 lds r30, 0x00E9 5bc: f0 91 ea 00 lds r31, 0x00EA -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Вот тот код, static void thread_restore_helper() __attribute__ ((__noreturn__, __naked__)); struct thread **th_head; struct thread * volatile * th_self_v = &th_self; if (likely(*th_head)) { interrupts_disable(); *th_head = (*th_head)->next; // это было вырезано компилятором *th_self_v = *th_head; // это тоже было, теперь нет thread_restore_helper(); } th_head надо записать, но при этом его не надо три раза читать. Тоесть ещё один указатель на volatile, это все делает код менее понятным, сначала там и th_self_v не было. -
Борьба с компилятором
amaora ответил amaora тема в В помощь начинающему
Узнать как другие решают такие проблемы, смысл. Как проще сделать перечитавание и перезапись значения из RAM только в нужных местах.