Перейти к содержанию

    

Оверлеи - посоветуйте или раскритикуйте

Коллеги! Обращаюсь к знатокам за советом.

Появилась идея сделать нечто, функционально напоминающее динамическую линковку для программ AVR. Раньше, когда DLL еще не изобрели, такое называлось "оверлейными модулями"...

Известно, что основная беда всех программ для МК AVR - это высокая трудоемкость модификации прошивки. И вот предлагаемая идея призвана значительно улучшить эту ситуацию.

Идея такая:

1. Основную программу собираем, как обычно. В ней есть интерфейс к SD-карте, и определена раз и навсегда область памяти, где будут оверлеи. Ну и выделен блок ОЗУ для данных оверлея.

2. Адреса начала кода оверлея и буфера данных фиксированы, и на этапе разработки оверлея известны.

3. Оверлей - это единственная функция, либо (предпочтительнее) несколько функций, адреса которых определены в структуре, которая как раз и размещается с адреса flash, выделенного для оверлея - ну типа таблицы векторов или вызовов. В общем, не суть важно, как.

4. Когда мы хотим наделить наше устройство другим функционалом, мы записываем на SD-карту скомпилированный оверлей, стартуем девайс, который обнаруживает соответствующий файл на карте, и прошивает его содержимое в заданную область, после чего обращается через таблицу вызовов к функциям оверлея.

 

Лично я хочу попробовать задействовать этот функционал для модификаци своего проекта "цифровой цветомузыки": сейчас в коде намертво прошито несколько эффектов, сменить которые для рядового пользователя достаточно сложно, как и избавиться от не нужных. Планирую каждый эффект сделать в виде оверлея, чтобы каждый желающий выбрал себе нужные и использовал без геморроя с перекомпиляцией прошивки.

 

Как оцените идею?

 

Это не совсем ситуация с самопрошивкой через бут-область AVR, т.к. объем прошиваемой области предполагается не с нулевого адреса, а скорее с середины flash, и при этом с перезатиранием области бута, которая в конце, как правило. Очень похоже, но чуточку отличается... в связи с чем и вопросы:

 

- как компилировать оверлей? То есть как получить hex-файл для набора функций?

- как задать секцию (т.е. конкретный адрес начала функции) для функции я знаю, но как сделать это для целого модуля? тем более для модуля, содержащего как функции, так и данне во flash?

 

я сильно-сильно плаваю в скриптах линковщика (а точнее - вообще тону), и хитрости makefile меня тоже скорее пугают, чем помогают... Мне бы как-то попроще, если это возможно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
4. Когда мы хотим наделить наше устройство другим функционалом, мы записываем на SD-карту скомпилированный оверлей, стартуем девайс, который обнаруживает соответствующий файл на карте, и прошивает его содержимое в заданную область, после чего обращается через таблицу вызовов к функциям оверлея.

....Вот так и родились когда-то вирусы на PC :biggrin:

 

PS: Вообще-то описанное - это не оверлей, если уж говорить строго.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы хотите сфой формат этих библиотек использовать? Есть же готовые готовые, описанные. Например у uClinux можно посмотреть BFLT, у NuttX есть свой NXFLAT, ну и про ELF формат почитать ещё можно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
я сильно-сильно плаваю в скриптах линковщика (а точнее - вообще тону), и хитрости makefile меня тоже скорее пугают, чем помогают... Мне бы как-то попроще, если это возможно...

 

Тогда Вам нужно знать хитрости линковщика чтобы во время перезаписи созданной отдельной библиотеки для каждого выбранного эффекта, производить корректную модификацию кода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

как бородатый вариант, допаять линейку памяти, таки да, СД -шку, запустить на (лучше 20Мгц) Мег виртуалку, и поднять Линуху))))

https://habr.com/post/177425/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Какие-то советы не совсем по теме вы даёте, коллеги :)

Основной код модифицировать не нужно, он знает только номера функций в таблице оверлея и адрес этой таблицы, и обращается по ним. А все варианты оверлеев содержат в самом своём начале эту самую таблицу, ссылающуюся на собственные функции. Поэтому в одном оверлее условно 5-я функция цветомузыки может быть "красный на максимум", а в другом - "синий на минимум".

 

И как бы настоящую линковку мне не надо повторять, и разбираться с ней особенно не стоит, как и с форматом elf-файла - не влезет его разбор в AVR, да и ни к чему... Мне бы просто понять, как при помощи AVR-GCC собрать модуль с функциями и таблицей, и как из него получить HEX для записи...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Какие-то советы не совсем по теме вы даёте, коллеги :)

Перефразирую:

- есть код и данные (константы и переменные);

- нужно уметь запускать этот код и размещать данные по указанным доступным адресам/смещениям;

- допускается иметь таблицу смещений функции, данных и использовать ее при загрузке модуля;

- модуль может пользоваться функциями/данными основного приложения, вызывая их по конкретным адресам

или по таблице указателей.

 

На каком-нить Cortex-M - без проблем. А на AVR... ну, только если путем переписывания flash и динамического распределения ОЗУ.

Задачка неактуальная, но интересная.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Задачка неактуальная, но интересная.

интересно, когда придется работать с трехбайтовыми адресами, в мегах выше 64-й, из-за 16-ой флеш адресации, и побайтовой Озу,

при описании движения констант меж ними потребуют работу с модификаторами generic (IAR) ,куча мата от линкера, и прочая..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Именно переписыванием flash.

Но вопрос в том, как скомпилировать модуль!

Для бутлоадера есть заготовки, известны ограничения и т.п. У меня цель немного отличается от бутлоадера, и поэтому я спрашиваю: как скомпилировать? просто модуль компилируется в файл с расширением .a - объектный файл. как указать компилятору (или чему?), что адрес таблицы функций должен быть строго таким-то? все функции тоже должны быть строго в определенной области адресов? как потом получить hex-?

 

avr-gcc, никакого IAR, и предполагается не вылезать за пределы 64К flash

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
как указать компилятору (или чему?), что адрес таблицы функций должен быть строго таким-то? все функции тоже должны быть строго в определенной области адресов? как потом получить hex-?

Дык, это легко указать в скрипте линкера, но на этапе компиляции.

Гораздо сложнее получить некий объектный код и запускать его с произвольного адреса.

Например, создать 3 файла obj1, obj2, obj3, которые в произвольном порядке

закинуть на карту, а МК потом их по очереди вычитает и загрузит по первым доступным адресам.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Этого (загрузки по произвольным адресам) не требуется (пока).

Я в скриптах, как уже писал, не силен, и ответов на заданные вопросы не знаю... надеюсь на помощь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
...как скомпилировать? ....адрес таблицы функций должен быть строго таким-то? все функции тоже должны быть строго в определенной области адресов? как потом получить hex-?...

 

делал подобное в меге128. на лопапалам её флэш делил. компилял как обычно. но делал софтинку для потрошения hex формата (подправлял адресацию). Менял и вектора так-же...прошивал половинку меги + таблицу векторов.

 

у Вас без таблицы векторов, насколько я понимаешь.

Общая засада при таких хотелках = проследить чтоб везде была относительная адресация.

имхо: компилять обычно как программу. обязательно везде относительная адресация. дать линкеру честно сформировать таблицу нужных вентилей вызовов (таблица векторов ли или некая своя структура адресов функций - не суть). далее корректируем эту таблицу - до загрузки, если адреса загрузки фиксированы. - в момент загрузки, если адрес загрузки не известен. адрес естественно выровнен на нужное смещение.

 

 

как то так

(круглый)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Этого (загрузки по произвольным адресам) не требуется (пока).

Я в скриптах, как уже писал, не силен, и ответов на заданные вопросы не знаю... надеюсь на помощь.

Нужно определить секцию под оверлеи.

Все данные и функции размещать в этой секции.

Попробую набросать код в AVR-студии, но ничего не обещаю, т.к. ни разу с AVR этого не делал.

 

Сделал таблицу экспорта

test_ovl.c

#include "test_ovl.h"

const uint16_t	ovl_const_1 = 1;
const uint16_t	ovl_const_2 = 2;

volatile const sOVL_EXPORT ovl_export_func __attribute__((section(".ovl_export"))) =
{
0,							// ovl_data_ram_pointer
sizeof(sOVL_DATA),			// ovl_data_ram_size
&ovl_func_1,				// func_1
&ovl_func_2,				// func_2
&ovl_const_1,				// const_1
&ovl_const_2,				// const_2
};

void ovl_entry(void){}

uint16_t ovl_func_1(const uint16_t param)
{
return param + ovl_const_2 + ovl_export_func.ovl_data->data_1;
}

uint16_t ovl_func_2(const uint16_t param)
{
return param / ovl_export_func.ovl_data->data_2 + ovl_const_2;
}

 

test_ovl.h

#ifndef __TEST_OVL_H__
#define __TEST_OVL_H__

#include <stdint.h>

typedef uint16_t t_ovl_func(const uint16_t param);

typedef struct sOVL_DATA
{
uint16_t			data_1;
uint16_t			data_2;
} sOVL_DATA;

typedef struct sOVL_EXPORT
{
sOVL_DATA			*ovl_data;
const uintptr_t		ovl_data_size;
t_ovl_func			*func_1;
t_ovl_func			*func_2;
const uint16_t		*const_1;
const uint16_t		*const_2;
} sOVL_EXPORT;

uint16_t	ovl_func_1(const uint16_t param);
uint16_t	ovl_func_2(const uint16_t param);

#endif // __TEST_OVL_H__

test_ovl.ld

MEMORY
{
OVL_EXPORT(r!x)	: ORIGIN = 0xE000, LENGTH = 16
OVL(rx)			: ORIGIN = 0xE010, LENGTH = 8k - 16
}

SECTIONS
{
.ovl_export :
{
	KEEP(*(.ovl_export))
} >OVL_EXPORT

.text :
{
	*(.text)
	*(.text.*)
	*(.data)
	*(.data.*)
} >OVL
}

 

test_ovl.bat

del test_ovl.s test_ovl.d test_ovl.map
avr-gcc -mmcu=atmega88 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT test_ovl.o -c test_ovl.c
avr-gcc -mmcu=atmega88 -Wl,--gc-sections,-Map=test_ovl.map,-cref,-u,ovl_entry test_ovl.o -T test_ovl.ld -o test_ovl.elf
avr-objcopy -O binary test_ovl.elf test_ovl.bin
avr-objdump -D -bbinary -mavr --start-address=16 test_ovl.bin > test_ovl.s
del test_ovl.o test_ovl.d test_ovl.elf

 

test_ovl.s (test_ovl.bin с 16 смещения)

 
00:   00 00 04 00 09 70 15 70 68 E0 6A E0 00 00 00 00
0000e010 <ovl_entry>:
&ovl_func_2,				// func_2
&ovl_const_1,				// const_1
&ovl_const_2,				// const_2
};

void ovl_entry(void){}
   e010:	08 95       	ret

0000e012 <ovl_func_1>:

uint16_t ovl_func_1(const uint16_t param)
{
return param + ovl_const_2 + ovl_export_func.ovl_data->data_1;
   e012:	e0 91 00 e0 	lds	r30, 0xE000
   e016:	f0 91 01 e0 	lds	r31, 0xE001
   e01a:	20 81       	ld	r18, Z
   e01c:	31 81       	ldd	r19, Z+1	; 0x01
   e01e:	2e 5f       	subi	r18, 0xFE	; 254
   e020:	3f 4f       	sbci	r19, 0xFF	; 255
   e022:	28 0f       	add	r18, r24
   e024:	39 1f       	adc	r19, r25
}
   e026:	c9 01       	movw	r24, r18
   e028:	08 95       	ret

0000e02a <ovl_func_2>:

uint16_t ovl_func_2(const uint16_t param)
{
return param / ovl_export_func.ovl_data->data_2 + ovl_const_2;
   e02a:	e0 91 00 e0 	lds	r30, 0xE000
   e02e:	f0 91 01 e0 	lds	r31, 0xE001
   e032:	62 81       	ldd	r22, Z+2	; 0x02
   e034:	73 81       	ldd	r23, Z+3	; 0x03
   e036:	04 d0       	rcall	.+8      	; 0xe040 <__udivmodhi4>
   e038:	6e 5f       	subi	r22, 0xFE	; 254
   e03a:	7f 4f       	sbci	r23, 0xFF	; 255
}
   e03c:	cb 01       	movw	r24, r22
   e03e:	08 95       	ret

0000e040 <__udivmodhi4>:
   e040:	aa 1b       	sub	r26, r26
   e042:	bb 1b       	sub	r27, r27
   e044:	51 e1       	ldi	r21, 0x11	; 17
   e046:	07 c0       	rjmp	.+14     	; 0xe056 <__udivmodhi4_ep>

0000e048 <__udivmodhi4_loop>:
   e048:	aa 1f       	adc	r26, r26
   e04a:	bb 1f       	adc	r27, r27
   e04c:	a6 17       	cp	r26, r22
   e04e:	b7 07       	cpc	r27, r23
   e050:	10 f0       	brcs	.+4      	; 0xe056 <__udivmodhi4_ep>
   e052:	a6 1b       	sub	r26, r22
   e054:	b7 0b       	sbc	r27, r23

0000e056 <__udivmodhi4_ep>:
   e056:	88 1f       	adc	r24, r24
   e058:	99 1f       	adc	r25, r25
   e05a:	5a 95       	dec	r21
   e05c:	a9 f7       	brne	.-22     	; 0xe048 <__udivmodhi4_loop>
   e05e:	80 95       	com	r24
   e060:	90 95       	com	r25
   e062:	bc 01       	movw	r22, r24
   e064:	cd 01       	movw	r24, r26
   e066:	08 95       	ret

0000e068 <ovl_const_1>:
   e068:	01 00                                               ..

0000e06a <ovl_const_2>:
   e06a:	02 00                                               ..

 

Все переменные нужно задать в sOVL_DATA и обращаться к ним так ovl_export_func.ovl_data->data_1.

При загрузке модуля в первых 16 битах нужно записать адрес, выделяемого блока в ОЗУ для данного модуля,

а размер можно узнать из следующих 16 бит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В AVR-студии добавил пару строчек в опциях линкера:

-T../test_ovl.ld

-Wl,--gc-sections,-Map=test_ovl.map,-cref,-u,ovl_entry

 

см. картинку

post-27702-1530727173_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Поэтому в одном оверлее условно 5-я функция цветомузыки может быть "красный на максимум", а в другом - "синий на минимум".

С другой стороны эти 5-е функции из разных оверлеев по сути представляют одну функцию с двумя параметрами: цвет и яркость.

И реализовать такой функционал гораздо проще через табличную организацию параметров в EEPROM.

 

 

И как бы настоящую линковку мне не надо повторять, и разбираться с ней особенно не стоит, как и с форматом elf-файла - не влезет его разбор в AVR, да и ни к чему... Мне бы просто понять, как при помощи AVR-GCC собрать модуль с функциями и таблицей, и как из него получить HEX для записи...

 

Т.е. Вы планируете не все возможные варианты функций-эффкектов собрать в один файл, а на каждую допустимую комбинацию свой файл транслировать?

Изменено пользователем aiwa

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация