STM32 новичку в ARM что к чему

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

С чего вы взяли, что последние должны быть чисто красные? Это первые красные, а последние еще чуть-чуть сиреневые. Цветовой круг замкнут, все верно.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

ARV писал(а):С чего вы взяли, что последние должны быть чисто красные?
Так онлайн-конвертеры говорят и ваша программа.
Вот для анализа:
Вариант_1
Спойлер

Код: Выделить всё

mData mHSVfast(uint8_t h, uint8_t s, uint8_t v) {	
	// быстрый HSV
	uint8_t r, g, b;
	uint8_t value = ((24 * h / 17) / 60) % 6;
	uint8_t vmin = (long)v - v * s / 255;
	uint8_t a = (long)v * s / 255 * (h * 24 / 17 % 60) / 60;
	uint8_t vinc = vmin + a;
	uint8_t vdec = v - a;
	switch (value) {
	case 0: r = v; g = vinc; b = vmin; break;
	case 1: r = vdec; g = v; b = vmin; break;
	case 2: r = vmin; g = v; b = vinc; break;
	case 3: r = vmin; g = vdec; b = v; break;
	case 4: r = vinc; g = vmin; b = v; break;
	case 5: r = v; g = vmin; b = vdec; break;
	}

    rgb_temp2.R = r;
    rgb_temp2.G = g;
    rgb_temp2.B = b;

	return 0;
}
Вариант_2
Спойлер

Код: Выделить всё

mData mHSV(uint8_t h, uint8_t s, uint8_t v) {	
	// обычный HSV
	float r, g, b;
	
	float H = h / 255.0;
	float S = s / 255.0;
	float V = v / 255.0;
	
	int16_t i = (int16_t)(H * 6);
	float f = H * 6 - i;
	float p = V * (1 - S);
	float q = V * (1 - f * S);
	float t = V * (1 - (1 - f) * S);
	
	switch (i % 6) {
	case 0: r = V, g = t, b = p; break;
	case 1: r = q, g = V, b = p; break;
	case 2: r = p, g = V, b = t; break;
	case 3: r = p, g = q, b = V; break;
	case 4: r = t, g = p, b = V; break;
	case 5: r = V, g = p, b = q; break;	
	}
	r *= 255.0;
	g *= 255.0;
	b *= 255.0;

    rgb_temp2.R = (uint8_t)r;
    rgb_temp2.G = (uint8_t)g;
    rgb_temp2.B = (uint8_t)b;

	return 0;
}
Вариант_3 (функция из проекта ARV)
Спойлер

Код: Выделить всё

void hsv_to_rgb(uint8_t h, uint8_t s, uint8_t v){
    unsigned char region, remainder, p, q, t;

    if (s == 0){
        rgb_temp2.R = v;
        rgb_temp2.G = v;
        rgb_temp2.B = v;
        return;
    }


    region = h / 43;
    remainder = (h - (region * 43)) * 6;

    p = (v * (256 - s)) >> 8;
    q = (v * (256 - ((s * remainder) >> 8))) >> 8;
    t = (v * (256 - ((s * (256L - remainder)) >> 8))) >> 8;

    switch (region){
	case 0:
		rgb_temp2.R = v; rgb_temp2.G = t; rgb_temp2.B = p;
		break;
	case 1:
		rgb_temp2.R = q; rgb_temp2.G = v; rgb_temp2.B = p;
		break;
	case 2:
		rgb_temp2.R = p; rgb_temp2.G = v; rgb_temp2.B = t;
		break;
	case 3:
		rgb_temp2.R = p; rgb_temp2.G = q; rgb_temp2.B = v;
		break;
	case 4:
		rgb_temp2.R = t; rgb_temp2.G = p; rgb_temp2.B = v;
		break;
	default:
		rgb_temp2.R = v; rgb_temp2.G = p; rgb_temp2.B = q;
		break;
    }
}
Все коды приукрасить можно, но в данном случае не важно.
Сравнительный анализ, таблица
СпойлерИзображение
У кого что есть еще, так сказать потестить?
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

сравните в своей таблице последнюю строку с первой - поскольку между строками таблицы должен быть примерно одинаковый шаг изменения цвета, вы можете видеть, что последня строка минус этот самый шаг будет равна первой, что и есть правильно. если у вас будут одинаковыми первая и последняя строки, значит, алгоритм работает с ошибкой: двум разным (а 00 и FF - это разные цвета) цветам в HSV-модели должны соответствовать РАЗНЫЕ RGB-цвета. так что мой алгоритм работает правильно (с учетом погрешности 8-битной арифметики), а что там показывают другие алгоритмы или конвертеры - мне неведомо.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 960
Зарегистрирован: Вс дек 02, 2012 16:58:33
Откуда: от туда

Сообщение GARMIN »

Проверьте работу алгоритмов с ненасыщенными цветами, то есть S < 255, например 128 или вообще 16. В моём случае была проблема именно с этим.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

ARV писал(а):сравните в своей таблице последнюю строку с первой
Точно, 255 это примерно 358 градусов.
GARMIN, вот таблица
СпойлерИзображение
В первых двух вариантах кода фигурирует в арифметике число 255, в варианте ARV число 256.
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3921440#p3921440"]

Код: Выделить всё

   // быстрый HSV
   uint8_t r, g, b;
   uint8_t value = ((24 * h / 17) / 60) % 6;
[/uquote]
Это, кстати, неплохой подход, только на ARM так лучше не делать. Вместо h = 24 * h / 17 лучше написать:

Код: Выделить всё

h = h * uint32_t(65536 * (360.0f / 256) + 0.5f) >> 16;
Будет быстрее, т.к. нет деления, и точнее тоже. А делают так потому что 256/6 не делится нацело и накапливает погрешность, у меня максимум получалось 12 для одного из цветов. Перейдя к диапазону [0..360) можно делить и брать остаток от деления на ровно 60.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

На АРМ можно себе позволить и float... А в моем плейере концептуально 256 эквивалентно 360 градусам, и далее соответственно пересчет. Погрешность есть, но для автомата светоэффектов она роли не играет.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Где вы там флоат увидели? :)
Друг Кота
Аватара пользователя
Сообщения: 3386
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

Reflector писал(а):Будет быстрее
Даже на МК не аппаратно поддерживающих float?
Проверил, компиль "сильно умный". :))) :)

Код: Выделить всё

;  h = h * (uint32_t) (65536 * (360.0f / 256) + 0.5f) >> 16;
20000314	ldr	r3, [r7, #4]
20000316	mov.w	r2, #92160	; 0x16800
2000031A	mul.w	r3, r2, r3
2000031E	lsrs	r3, r3, #16
20000320	str	r3, [r7, #4]
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Да причём тут компилятор? Вы код то читать умеете? Где вы там float в рантайме увидели???
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

А кто, если не компилятор, делает эти вычисления и подставляет в бинарник сразу готовое число 92160?
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

На самом деле можно даже так:

Код: Выделить всё

h = uint32_t(h * Fixed<16>(360.0f / 256));

// str r3, [sp, #0] 
// movs r3, #180
// lsls r3, r3, #9 
// muls r3, r7 
// asrs r3, r3, #16 
// str r3, [sp, #12] 
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Reflector, прекрати насиловать неокрепшие мозги. Всё гораздо проще

Код: Выделить всё

h = h*92160 >> 16; 
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="WiseLord",url="/forum/viewtopic.php?p=3921711#p3921711"]А кто, если не компилятор, делает эти вычисления и подставляет в бинарник сразу готовое число 92160?[/uquote]Это сделал программист, записавший целочисленную константу в таком виде. У компилятора не было никакого выбора, даже у самого тупого.

И что-то мне подсказывает, что это

Код: Выделить всё

h = (uint32_t)h*360 >> 8; 
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

Float константы удобно цепными дробями задавать. На F072 я так и делаю обычно (особенно если нужно построить таблицу для кусочно-линейной аппроксимации показаний термисторов). Завожу вместо одного массива флоатов два массива uint_16t: числитель и знаменатель. Их по заданной точности считаю в октаве (функция rat).
Вот, например: отградуировал NTC в нужном мне диапазоне (8…90℃), потом несложной функцией в октаве аппроксимировал эту кривую полиномом (с погрешностью не хуже 0.05℃), далее автоматом разбил этот диапазон на N узлов (в данном случае получилось 14) так, чтобы кусочно-линейная аппроксимация между узлами давала точность не хуже 0.1℃ (фактически же можно было меньше узлов делать: сами понимаете, что NTC лучше ±2℃ дать не способны, обычно их заявленная точность вообще 1%, т.е. ±3℃ в диапазоне комнатных температур). На каждом интервале температура вычисляется так: T=T₀+k(ADU-ADU₀), T₀ и ADU₀ затабулированы, а вот для k я посчитал числители и знаменатели при помощи rat(k*10). По умолчанию точность 1e-6, но в данном случае можно было бы даже немного уменьшить числа, установив точность 1e-4 (я этого не делал, т.к. все равно все отлично влезло в int16_t).
И все: если нужно посчитать температуру, дихотомией ищем соответствующий интервал и на нем элементарно считаем температуру. Никаких флоатов не нужно. А вот от деления, к сожалению, избавиться невозможно: точность намного хуже будет, если подбирать числитель под знаменатель, равный определенной степени двойки (да и в этом случае вполне возможна ситуация, когда число перед сдвигом вылезет за пределы int32_t).
P.S. Когда калибровал NTC, оказалось, что в моем диапазоне погрешность была всего-то ±0.5%! Кстати, это совпадает с разбросом показаний домашних китайских "термометров", основанных на тех же 10-килоомных термисторах. Они тоже где-то на полтора градуса врут. Зато для терморегулирования этого с лихвой хватает: что я в +45℃ вентилятор включу, что в +47℃ — охлаждаемой цепи от этого хуже не будет.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3921931#p3921931"]И что-то мне подсказывает, что это

Код: Выделить всё

h = (uint32_t)h*360 >> 8; 
[/uquote]
Да, результат одинаковый поскольку младший байт нулевой, но и инструкций получится столько-же, просто 360 компилятор получает сдвигая 180 на 1, а для 92160 он сдвигает 180 на 9 :) Там еще вместо деления на 60 используется умножение на 65536.0f / 60 + 0.5f, в обоих случаях под дробную часть выделено 16 бит, так проще.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Cortex-M4

Код: Выделить всё

h = (uint32_t)h*360/256;
        MOV      R0,#+360
        LDRB     R2,[R1, #+2]
        SMULBB   R2,R0,R2
        LSRS     R2,R2,#+8
        STRB     R2,[R1, #+2]
Cortex-M0+

Код: Выделить всё

h = (uint32_t)h*360/256;
        LDRB     R1,[R0, #+2]
        MOVS     R2,#+180
        LSLS     R2,R2,#+1
        MULS     R1,R2,R1
        LSRS     R1,R1,#+8
        STRB     R1,[R0, #+2]
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=3921946#p3921946"]а вот для k я посчитал числители и знаменатели при помощи rat(k*10).[/uquote]
Eddy, ну какие числители и знаменатели в 21 веке... Беру у тебя в коде коэффициент 0.028261, умноженный на 10 он получается делением 13 / 46 = 0.282609, что очень близко, но будет тяжелое для M0 деление и коэффициенты приходится рассчитывать самому. В то же время даже мои классы все делают быстрее и автоматически:

Код: Выделить всё

Fixed<12> k(0.028261f);
rtt.printf<"{}, {}, {}\n">(k.rawValue(), (k*10).toStr(), (float)k);		// 29634, 0.2826, 2.82611847e-2
Тут я задал 12 бит для целой части, соответственно 20 осталось для дробной, а могло быть 18 или 25...
29634 - это (1 << 20) * 0.028261 + 0.5, если умножить это число на 10000 и сдвинуть на 20 бит вправо, то получим 282.
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

Reflector, хватит уже со своими крестами! Я в эту [censored] лезть не собираюсь!
А вообще, когда я впервые увидел, как абдуринщики флоатами пользуются на 8-битной фигнюшке, так охренел, что даже не знаю… Меня теперь, наверное, даже даблы на cortex-M0 не удивят ☺
Жаль, что там аппаратного деления нет.
Последний раз редактировалось Eddy_Em Вт ноя 10, 2020 12:10:39, всего редактировалось 1 раз.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Reflector выдаёт знания в чистом виде! Вам бы на ус мотать, а вы плюётесь.
Ответить

Вернуться в «ARM»