Не так страшен makefile

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

Итак, makefile — сценарий сборки для процедуры GNU make, являющейся неотъемлемой частью любого GCC-тулчейна.

Я мог бы цитировать главы из документации по GNU make или пересказать своими словами замечательную статью Владимира Игнатова, однако не хочу да и не вижу особого смысла, ибо все это любой заинтересованный читатель может изучить самостоятельно. Вместо этого я по пунктам разберу мой рабочий makefile, который с небольшими вариациями служит мне верой и правдой около 5 лет во многих проектах.

Поехали.


Для начала, необходимо уяснить, как происходит процесс сборки, т.к без четкого понимания необходимой последовательности действий мы не можем описать её в скрипте makefile.
Как известно, процесс сборки традиционно разбивается на несколько этапов. Первый — это компиляция. На данном этапе происходит последовательный прогон файлов исходного кода через компилятор с заданными параметрами.

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

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

После небольшого вводного слова мы вплотную подошли непосредственно к скрипту makefile.
Очевидно, что он должен пошагово описывать процедуру сборки. Однако, на самом деле makefile не является программой, исполняемой последовательно сверху вниз. Вместо этого он предоставляет набор правил сборки (rules) для одной или нескольких целей (targets). Целью может быть как конкретный файл (набор файлов), так и абстрактное действие, такое как очистка рабочих директорий или прошивка в кристалл, или автоматический коммит в репозиторий.

#***************************************************************************
#
#	ProjectX FirmWare - Copyright (C) MrYuran.
#
#***************************************************************************

Себя не похвалишь — весь день как оплеванный :)


# Имя:

PROJECT = ProjectX
HARDWARE = 01
RELEASE = 00

NAME = $(PROJECT)_430_$(HARDWARE)_$(RELEASE)

Хороший тон — использовать мнемонические обозначения. И писанины меньше, и править проще.
Поскольку речь далее пойдет о конкретном тулчейне mspgcc для славных техасских MSP430, определяем команды для вызова процедур:
# Префикс: MSP430
ifndef CROSS
  CROSS = msp430
endif

# Компилятор: MSPGCC.
# Корень MSPGCC:
MSPGCC_ROOT = C:\mspgcc-20120406-p20120502

BIN = $(MSPGCC_ROOT)\bin
CC = $(BIN)\$(CROSS)-gcc

# Ассемблер.
AS = $(BIN)\$(CROSS)-gcc

#
SIZE = $(BIN)\$(CROSS)-size

# Обработка двоичных файлов: msp430-objcopy.
OBJCOPY = $(BIN)\$(CROSS)-objcopy

# Обработка двоичных файлов: msp430-objdump.
OBJDUMP = $(BIN)\$(CROSS)-objdump

# Очистка (del - команда DOS !!!!).
RM = del

# ihex -> TI text
MAKETXT = $(BIN)\ihex2titext

# Показывает размеры файла
ELFSIZE = $(SIZE) -B $(TARGET).elf

Нетрудно заметить, что смена одного тулчейна на другой (например, более старый или более новый или вообще ARM или AVR) делается легким движением руки в соответствующей строке (CROSS/ROOT/BIN). Также, версию можно легко исправить в одной строке, не перебивая вручную имена многих файлов.
В комментариях развернулась небольшая дискуссия относительно абсолютного пути к тулчейну, но я все-таки предпочитаю данный вариант. Все-таки, иногда нужно бывает точно знать, каким конкретно тулчейном (версией) была осуществлена сборка. И в мэйкфайле эта информация останется.
Хотя у нас вроде все идет в хронологическом порядке, на самом деле это сделано просто для удобства восприятия. Можно тасовать правила в любом порядке, это чем-то сродни директивам #define. Например, в последней строке используется переменная TARGET, которая пока не была определена. Не беда, опишем ниже.
# Микроконтроллер: MSP430F149.
MCU = msp430f149

# Уровень оптимизации:
OPT = -Os

# Корень проекта:
PROJECT_ROOT = .

# Папка для сохранения объектных файлов UNIX type.
OBJDIR = $(PROJECT_ROOT)/Obj

# Папка для сохранения объектных файлов WINDOWS type.
obj_path = $(subst /,\,$(OBJDIR))

# Папка для созранения листингов UNIX type.
LSTDIR = $(PROJECT_ROOT)/Lst

# Папка для сохранения листингов WINDOWS type.
lst_path = $(subst /,\,$(LSTDIR))

# Папка для выходных файлов прошивки
OUTDIR = $(PROJECT_ROOT)/bin/Debug

out_path = $(subst /,\,$(OUTDIR))

TARGET = $(out_path)\$(NAME)

Тут вроде все понятно без лишних слов. Задаем рабочие пути, причем в двух вариантах — Win/Lin style. Хотя можно было бы сразу в нужном, если априори известно, что выполняться будет только на платформе Win (или Lin).
Вот и таргет объявился :) (сразу в нужном склонении слеша)

Теперь пару слов о структуре проекта. У меня любой проект состоит из модулей, разложенных по одноименным папкам в корне проекта. То есть имеются папки Main, Flash, UART, Timers и т.д., включая драйверы внешней периферии и сторонние проекты типа FreeMODBUS. Я исхожу из предпосылки, что все исходные файлы, содержащиеся в папке модуля, должны быть откомпилированы. В этом случае мне достаточно перечислить имена папок, а внутри реализовать автоматический поиск по шаблонам исходных файлов.
# ---------------------------------------------------------------------------------------
#   Модули
# ---------------------------------------------------------------------------------------
MODULES = main
MODULES += AD7708
MODULES += Flash
MODULES += UART
MODULES += measure
MODULES += timerb
MODULES += gen
MODULES += utils
MODULES += CRC16

SRCDIRS = $(addprefix $(PROJECT_ROOT)/,$(MODULES))

INCLUDES  = $(addprefix -I$(PROJECT_ROOT)/,$(MODULES))

CSRC    = $(wildcard $(addsuffix /*.c,$(SRCDIRS)))
CPPSRC  = $(wildcard $(addsuffix /*.cpp,$(SRCDIRS)))
ASRC    = $(wildcard $(addsuffix /*.s,$(SRCDIRS)))

Здесь ненадолго остановимся.
Сначала перечисляем модули исходного кода. Оператор += добавляет к общему результату строку через пробел.
В результате переменная MODULES будет содержать строку с перечисленными через пробел именами папок/блоков.

SRCDIRS образуется путем добавления префикса — пути к корню проекта и таким образом будет содержать список полных путей до папок с исходниками.
INCLUDES — те же пути, но с префиксом -I. Это будут ключи путей поиска для компилятора.

CSRC, CPPSRC и ASRC — это соответственно найденные по шаблону исходные файлы С, С++ и ассемблера.
Альтернатива данному подходу — долго и муторно перечислять пофайлово вручную. Возможен, правда, компромиссный вариант, когда сочетаются оба метода. Тогда к переменным CSRC, CPPSRC и ASRC нужно добавить (+=) отдельные исходные файлы.

Добавим несколько штрихов…
# Search path for common sources and headers
vpath
vpath %.c $(SRCDIRS)
vpath %.cpp $(SRCDIRS)
vpath %.h $(SRCDIRS)
vpath %.s $(SRCDIRS)

… и начнем уже описывать правила и зависимости.
# Objects that must be built in order to link (Объявляем объектные файлы).
OBJ = $(addprefix $(OBJDIR)/,$(notdir $(CSRC:.c=.o)
OBJ += $(CPPSRC:.cpp=.o)
OBJ +=$(ASRC:.s=.o) ))

Эти три строчки нужно рассматривать как одну длинную. Что мы имеем? Какие-то загадочные формулы…
На самом деле все довольно прозрачно. Эта строка берет путь OBJDIR и добавляет его к списку исходных файлов, попутно отрывая от них префиксы путей (notdir) и заменяя суффиксы каждого вида исходников на .o
Итого, получаем список нужных нам объектных файлов, расположенных в папке OBJDIR.
# Компиляция: создать объектные файлы из исходников Си.
$(OBJDIR)/%.o : %.c
	@echo Start compile file: $<
	@$(CC) -c $(CFLAGS) $< -o $@
	@echo Compile file: $< - OK.

Попробуем угадать, что здесь происходит.
Первая строка — это зависимость. Файлы .o зависят от одноименных файлов .c
При изменении исходных файлов соответствующие им объектные файлы будут перекомпилированы.
Далее задается правило преобразования. ВАЖНО! что отступы — обязательно символы TAB. Не пробелы. Если об этом забыть, то можно огрести граблей.
@echo — надеюсь, не нужно объяснять. Выводится сообщение, а на конце какие-то закорючки.
$< — обозначает автоматическую переменную «имя первой зависимости правила», то есть имя входного сишного исходника.
$@ — имя цели, то есть в данном случае объектного файла.
Итого, запускается компилятор (макрос СС) со списком ключей и парой исходник-объектник.
Да, список ключей тоже надо описать.

# Предупреждения:
WARNINGS  = -Wall
WARNINGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-align -Wsign-compare
WARNINGS += -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wunused
# WARNINGS += -Werror

CFLAGS = -mmcu=$(MCU)
CFLAGS += $(OPT)
CFLAGS += -DGCC_MSP430
CFLAGS += $(WARNINGS)
CFLAGS += -std=gnu99
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += $(INCLUDES)

На ключах подробно останавливаться не буду, т.к. это несколько из другой оперы
Теперь мы можем компилировать отдельные файлы и складывать их в объектную папочку.
Двигаем дальше.
# Linking.
$(TARGET).elf : $(OBJ) makefile
	@echo Start linking file: $<.
	$(CC) $(OBJ) $(LDFLAGS) -o $@ $(LIBS)
	@echo Linking file: $< - OK.

Целевой бинарник .elf образуется из списка объектников OBJ путем нехитрых преобразований.
Вместо $(OBJ) в правиле можно было использовать автопеременную $^, которая обозначает список всех зависимостей, то есть тот самый $(OBJ) из первой строки.

LDFLAGS  = -mmcu=$(MCU)
LDFLAGS += -Wl,-gc-sections
LDFLAGS += -Wl,-Map=$(NAME).map,--cref
LDFLAGS += -L$(MSPGCC_ROOT)"\bin\lib"

LIBS = -lc -lm

Здесь следует внести небольшое уточнение, по справедливому замечанию amx. Дело в том, что последняя строчка подключает библиотеки libc.a и libm.a, и подключение это во избежание ошибок должно стоять в самом конце командной строки линкера. Что, собственно, я и поправил. Отцепил библиотеки от LDFLAGS и перенес в LIBS.
Теперь мы умеем и компилировать, и линковать. Осталось немного автоматизировать процесс.
Создание IHEX прошивки из ELF:
$(TARGET).a43 : $(TARGET).elf
	@$(OBJCOPY) -O ihex $< $@

Создание TI-text из IHEX:

$(TARGET).txt : $(TARGET).elf
	@echo Make $@ from $<
	@$(MAKETXT) $< -o $@
	lin2win.bat $@ $(TARGET).win.txt

lin2win.bat содержит sed-скрипт, который дополняет символы возврата каретки к переводу строки. Есть такая заморочка в винде… По умолчанию кодировка выходных файлов линуксовая.

# Main listing.
$(lst_path)\$(NAME).lst : $(TARGET).elf
	@echo Start create listing file from: $<.
	$(OBJDUMP) -dStl $< > $@
	@echo Create listing file from: $< - OK.

Последнее правило формирует общий листинг.

Ну и финишный аккорд: корневые цели.
clean :
	- $(RM) $(obj_path)\*.o
	- $(RM) $(lst_path)\*.lst

rebuild :
	$(MAKE) clean
	$(MAKE) all

all : $(TARGET).elf $(TARGET).a43 $(TARGET).txt $(lst_path)\$(NAME).lst
	@echo Build project $(NAME) - OK.
	@$(ELFSIZE)
	@$(CC) --version

program: $(TARGET).elf
	load.bat $< 


Теперь достаточно зайти в консоль, переместиться в корень проекта и вбить make all, чтобы пошел процесс.
Затем make program загружает свежесобранную прошивку в контроллер через BSL.

В качестве бонуса скрипт lin2win
sed 's/$/\r/' %1 >%2


load.bat будет интересен тем, кто собирается заливать прошивку через BSL и COM-порт:
echo Device flash programming: %1
msp430-bsl -c1 -m5 -S38400 -1 --invert-test -eprw %1


В первом приближении, как-то так.

Домашнее задание:
  1. написать правила для компиляции .cpp и .s
  2. почитать про зависимости и добавить автогенерацию зависимостей
  3. подумать, как компилировать все файлы блока в один объектник с именем блока. В принципе, если там всего один исходник и его имя совпадает с именем папки, то и так все получится. Но речь идет о более общем случае.

Ответы:
  1. Мне пока не надо, так что думайте сами :)
  2. Добавить две строчки:
    CFLAGS += -MD
    include $(wildcard *.d)

    Проверил, в папке OBJ нашел много интересного :)
  3. Пожалуй, без серьезной правки никак. Подумаю ещё.

Ещё немного добавлю.
Прозвучал вопрос от ig_z, как вывести список исходников с зависимостями.
Можно как-то вот так:

# Список исходников Си.
list: list.txt

list.txt: $(CSRC)
	@$(CC) -c -M $^ > $@

Выводятся все зависимости проекта в последовательности *.o — *.c — *.h с полными путями и записываются в файл

Надеюсь, не зря потратил свое и ваше время.
  • +11
  • 19 февраля 2014, 16:39
  • MrYuran

Комментарии (37)

RSS свернуть / развернуть
Не зря потратил. Спасибо! Да, вродь, и не слишком сложно, при беглом просмотре. Пока не ясно, как это прикрутить к Кодблокс, но это уже вопрос практического освоения твоего материала. А пока — премного благодарен. Утащу сразу в комп, мало ли там с Инетом что будет.
0
Прикрутить очень просто.
Вот так
0
Плюсанул.
Немного не понятно почему в блоге MSP430 — мейкфайлы же применимы практически к любым платформам и языкам.
0
Да это я приставал, все расскажи да расскажи… На форуме была тема как раз по мсп430.
0
эх, кармы не хватает проголосовать…
у меня вопрос по этой строчке:
MSPGCC_ROOT = C:\mspgcc-20120406-p20120502
разве такие вещи не должны быть в PATH? я просто недавно ковырял мэйк от ядра линуксового с кошерным скриптом, который сам подсасывает компилятор, сам патчит итд итп — там качали сборку гцц, распаковывали в папку, запихивалу папку в path и потом просто export ${CC}=arm-non-eabi- и где надо вызывали уже просто ${CC}-gcc, ${CC}-ld итд итп. удобнож, имхо
0
Если я вам покажу свой C:\ и Path…
Там одних версий mspgcc штук пять, начиная с 2008 года
Нет, именно фулл контрол, никаких соплей.
0
Итак, makefile — сценарий сборки для процедуры GNU make
Ну, вообще говоря, та или иная разновидность make входит практически в каждый компилятор (даже в Delphi).
Модуль в С/С++ — это единичный исходный файл, так называемая единица компиляции
Я бы не стал называть это модулем. Модуль — понятие из модульного программирования, которое в С и С++ не поддерживается. «Единица трансляции» — корректней.
MSPGCC_ROOT = C:\mspgcc-20120406-p20120502
Абсолютные пути в скриптах сборки — зло. Если уж у тебя куча однотипных тулчейнов — то лучше уж хотя бы подтягивать пути из переменных среды. Тогда кто угодно может просто выполнить перед сборкой
set MSPGCC_verXX_ROOT= C:\mspgcc-20120406-p20120502

подставив свои пути.
Эта строка берет путь OBJDIR и добавляет его к списку исходных файлов, попутно отрывая от них префиксы путей (notdir)
А что будет, если в разных папках окажутся одноименные файлы?
ВАЖНО! что отступы — обязательно символы. Не пробелы.
По видимому, ты написал «tab» в угловых скобках и его съело. Поправь.
В качестве бонуса скрипт lin2win
load.bat еще забыл. Ну и можно мейкфайл-заготовку приаттачить.
0
  • avatar
  • Vga
  • 19 февраля 2014, 20:50
Без замечаний от Vga и статья не статья )))
+2
Замечания как то проще писать, чем статьи :)))
0
Спасибо за замечания.
Как появится немного времени, поправлю/добавлю.
Таб да, съелся :(
0
Я еще вопрос задавал:
Эта строка берет путь OBJDIR и добавляет его к списку исходных файлов, попутно отрывая от них префиксы путей (notdir)
А что будет, если в разных папках окажутся одноименные файлы?

Алсо, почему бы не приаттачить к статье весь мейкфайл с сборе?
0
Да, я уже думал.
Скорее всего, будет не очень.
Два одинаковых объектника в одной папке, в которые компилятся разные исходники.
Надо попробовать :)
0
это все пережитки командной строки. в 1000 раз проще использовать IDE для генерации. Хотя всегда есть люди, привыкшие к ручным методам. особенно если много свободного времени.
0
  • avatar
  • x893
  • 20 февраля 2014, 02:09
Утверждение весьма спорное, поэтому спорить не буду.
К тому же, попробуйте в Visual Studio настроить сборку mspgcc :)
0
Более того, если вы посмотрите более сложные проекты, типа операционок FreeRTOS, scmRTOS, то они собираются исключительно собственным makefile-ом и никак иначе.
Это не «пережиток», а полный контроль за процессом плюс возможность тонкой настройки.
Насчет времени тоже не соглашусь.
Гораздо быстрее поправить нужную строчку в мэйкфайле, чем искать нужную галочку по кучам вкладок
0
то они собираются исключительно собственным makefile-ом и никак иначе.
В основном потому, что это стандартное и имеющееся везде средство. Не предоставлять же проекты для всех возможных среди компиляторов.
0
то они собираются исключительно собственным makefile-ом и никак иначе.
Вовсе нет — завит от порта, то есть от того как автору показалось удобнее. Порты для AVR и STM32 для IAR-а makefile не содержат.
0
завит
зависит
0
C ИАРом все понятно.
Это, кстати, его слабое место, что невозможно работать по-человечески.
Например, поменять убогую серую среду на что-нибудь поцветастее. Вроде были слухи про плагин к Eclipse, но опять же это зависит от милости IAR Systems.
Вариант с мэйкфайлом выгодно отличается тем, что он самодостаточный и инвариантный относительно внешней шелухи.
0
его слабое место, что невозможно работать по-человечески
Makefile вроде было можно прикрутить. А вот в Эклипсе разбор исходников сделать — проблема.
Вроде были слухи про плагин к Eclipse
Почему слухи? Есть такой плугин. Правда только для АРМа — увы. Не получается поцветастее для всего чего захочешь (для АВР например).
0
А вот в Эклипсе разбор исходников сделать — проблема.
Почему?
0
Почему?
Эээ… Действительно — почему? Ну может быть я просто не знаю как это сделать?
По-вашему получается к Эклипсу можно любой компилер прикрутить?
Поделитесь рецептом тогда…
0
Наверняка можно. Но речь не об этом. Вы сказали, что проблема в том, что бы сделать разбор исходников. Мне интересно в чем это выражается.
0
Вы сказали, что проблема в том, что бы сделать разбор исходников.
Возможно я не правильно назвал цель («разбор исходников»).
Попробую описать её «контуры».
Хотелось бы:
1) Поддержку периферии МК — то есть если набрать что-нибудь вроде USART->, то хотелось бы получить список возможных регистров модуля USART (или любого другого).
2) Возможность навигации по хидерам нужного типа МК — то есть кликнув ПКМ на каком-нибудь ADC_RESOLUTION_12BIT_gc и выбрав в меню Open declaration, хотелось бы добраться до чего-то навроде:

/* Conversion result resolution */
typedef enum ADC_RESOLUTION_enum
{
    ADC_RESOLUTION_12BIT_gc = (0x00<<1),  /* 12-bit right-adjusted result */
    ADC_RESOLUTION_8BIT_gc = (0x02<<1),  /* 8-bit right-adjusted result */
    ADC_RESOLUTION_LEFT12BIT_gc = (0x03<<1),  /* 12-bit left-adjusted result */
} ADC_RESOLUTION_t;

3) получать автодополнение по встроенным функциям тулчайна — например __disable_interrupts() чтобы подсказало по ходу набора имени функции
4) Привязка варнингов и ерроров к строкам исходника
5) Не заниматься выставлением галочек в настройках проекта — чтобы делалось всё через makefile
6) Компилятор чтобы для любого МК так можно было привязать.

Вообщем иметь всё то что есть для связки AVR/ARM GCC + Eclipse. Вот как бы это сделать для того же иара или кайла…
0
Вот как бы это сделать для того же иара или кайла…
Допилить ARM GCC Plugin, полагаю.
0
Думаете это так просто? Где оно лежит и на чём написано?
ARM GCC Plugin
К тому же причём тут этот плугин? Одна из его фич:
simplify project management (no need to create makefiles)
Этот плугин обеспечивает те самые галочки в настройках проекта.
Для тех пунктов что я описывал в своём предыдущем посте он не нужен — я не ставлю ни AVR, ни ARM plugin в Эклипсу.
, полагаю.
Что-то вы не то полагаете… имхо.
0
Думаете это так просто?
Думаю да.
Где оно лежит и на чём написано?
sourceforge.net/projects/gnuarmeclipse/, Java, естественно.
Что-то вы не то полагаете… имхо.
Возможно. Скажем, может потребоваться доделка CDT. Но и эта часть есть в сорсах.
0
может потребоваться доделка CDT
Всего-то CDT переделать? Делов-то на пару выходных… Или больше?
0
Всего-то CDT переделать?
Не переделать, а доделать. Возможно придется добавить поддержку нового компилятора.
Делов-то на пару выходных… Или больше?
На вскидку не скажу. Может и меньше.
0
это все пережитки командной строки.
Командная строка никуда не делась, так что в пережитки ее записывать рано.
в 1000 раз проще использовать IDE для генерации.
Если уж генерировать, то куда как проще использовать соответствующие инструменты, типа configure. Да, кстати, это тоже командная строка.
Хотя всегда есть люди, привыкшие к ручным методам. особенно если много свободного времени.
Вы не поверите, но IDE как раз из категории «ручных методов».

P.S. хотя, как по мне, сама идея make/makefile неудобна и ее не спасает ни IDE, ни configure.
0
Когда работает один человек над небольшим проектом — генерации из IDE действительно хватает.
Но когда появляется комманда (разрабочики, тестировщики, билд сервера, тестовые сервера, и т.д.), в проекте куча контрибов (своих и сторонних), юнит тесты, сборка дистрибутивов, требование поддержки разных платформ, окружений, конфигураций стороннего ПО и т.п. — без ручного создания скриптов сборки (или как минимум допилки автоматически сгенерированных) никак не обойтись.
А поэтому желательно все же знать как это устроено и уметь делать скрипты вручную под свои условия.

Правда все вышеизложенное относится к разработке ПО для больших машин. В эмбеде размеры проектов и команд наверное поменьше.
0
# Linking.
$(TARGET).elf : $(OBJ) makefile
Правильно ли я понимаю, что добавлена зависимость от makefile для того, что бы при его изменении, но неизменных исходниках, происходила пересборка проекта?
0
Действительно, а я-то думал, нафига там makefile… Хотел даже убрать.
0
Было бы уместно добавить такой же трюк и для цели
$(OBJDIR)/%.o : %.c
0
А как можно получить список всех файлов проекта? Т.е. добавить цель «сгенерировать список файлов проекта». С полными путями и со всеми инклюдами, как своими так и системными. Скорее всего нужно дополнительно парсить выхлоп компилятора, чтобы иметь полный список файлов проекта. И второй вопрос на эту же тему: как получить список.с файлов и список директорий с .h файлами, которые использовались в проекте?
0
  • avatar
  • ig_z
  • 20 февраля 2014, 19:45
Добавил в конце.
Ну и немного подправил замеченные замечания :)
0
У меня вопрос следующего плана. Студия CCS может в качестве выходного файла выплевывать hex. Далее требуется постобработка: вычисление контрольной суммы и запись в определенное место. После этого требуется как-то все это прошить. Вопрос следующий: Как его можно прошить на TMS320f28032? UniFlash вроде как должен поддреживать hex, но ума не приложу, как его туда вставить
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.