Создадим минимальный работоспособный код для заливки в LPC2106. Наше первое embedded приложение будет уметь мигать светодиодом.
Скачайте архив с проектом 02-skel.tar.gz и распакуйте где вам удобно.
tar xzvf 02-skel.tar.gz cd 02-skel
Так же доступ к исходному коду проекта вы можете получить через mercurial репозиторий: http://freehg.org/u/iar/lpc210x-tutorial/rev/ba4b8bd9bdf0
Проект содержит следующие файлы:
lpc210x.h - заголовочный файл с символическими именами для преферии процессора.crt.s - код инициализации. Этот ассемблерный код инициирует стек, вектора прервываний, некоторую преферию процессора и передаёт управление C-функции main().main.c - собственно код приложения. Здесь проходит окончательная инициализация процессора (функция void Initialize(void)) и преферии. Запускается бесконечный цикл мерцания красным светодиодом. Дополнительно проверяются кнопки на борде и в зависимости от их состояния включаются зелёный или синий светодиоды. lpc2106_flash.cmd - карта памяти для линковщика. Карта описывает расположение приложения в области FLASH памяти.Makefile - файл автоматизации для команды make. Он инкапсулирует в себе операции по компиляции, сборке и прошивки кода для процессра.
Небольшой участок кода main.c с подробными комментариями:
main.c
// Задаём маску для доступа к красному компоненту трёхцветного светодиода #define LEDR (1<<19) // Задаём маску для доступа к синему компоненту трёхцветного светодиода #define LEDB (1<<20) // Задаём маску для доступа к зелёному компоненту трёхцветного светодиода #define LEDG (1<<21) // Общая маска для доступа к трёхцветному светодиоду #define USEPINS LEDR | LEDB | LEDG // Маска для доступа к кнопке Volume #define BUTTON1 (1<<22) // Маска для доступа к кнопку Program #define BUTTON2 (1<<23) /********************************************************** MAIN **********************************************************/ int main (void) { int j; // loop counter (stack variable) // Вызов функции инициализации ядра процессора Initialize(); // Инициализация преферии. В нашем случае это только порты ввода-вывода IODIR |= USEPINS; // Настраиваем порты к которым подключён светодиод на вывод IOSET = USEPINS; // Включаем светодиод IOCLR = USEPINS; // Выключаем светодиод // Бесконечный цикл в котором светодиод мерцает красным и // в зависимости от состояния кнопок зажигается синяя или зелёная компонента светодиода while (1) { // Проверяем состояние кнопок и в зависимости от результата зажигаем или гасим светодиод if (!(IOPIN & BUTTON1)) IOSET = LEDB; else IOCLR = LEDB; if (!(IOPIN & BUTTON2)) IOSET = LEDG; else IOCLR = LEDG; IOSET = LEDR; // Зажигаем светодиод for (j = 0; j < 100000; j++ ); // Небольшая задержка сделанная глупым циклом IOCLR = LEDR; // Гасим светодиод for (j = 0; j < 2000000; j++ ); } }
Обратите внимание на следующие моменты:
IOSET мы устанавливаем состояние соответствующего вывода порта в единицу. Записью единиц в разряды регистра IOCLR мы сбрасываем состояние соответствующего вывода порта в ноль.-O0 при вызове копилятора arm-elf-gcc). Любая оптимизация выкинет цикл задержки, как ничего не делающий.
Makefile
NAME = tutorial_project # Команды компиляции и сборки специфичные для архитектуры CC = arm-elf-gcc LD = arm-elf-ld -v AR = arm-elf-ar AS = arm-elf-as CP = arm-elf-objcopy OD = arm-elf-objdump # Карта памяти для сборщика (arm-elf-ld) LDCMD=lpc2106_flash.cmd # Флаги компиляции # -O0 - без оптимизации # -Wa,-ahlms=$(<:.c=.lst) - транслировать откомпилированный код в мнемоники CFLAGS = -I./ -c -fno-common -O0 -g -Wa,-ahlms=$(<:.c=.lst) # Флаги ассемблирования AFLAGS = -ahls -mapcs-32 -o crt.o # Флаги сборки LFLAGS = -Map main.map -T$(LDCMD) # флаги копирования CPFLAGS = # Флаги дампа ODFLAGS = -x --syms # Команда загрузчика LPCFLASH=lpcflash -v # Флаги загрузчика LPCFLAGS=-i /dev/ttyUSB0 -b 115200 -f 14746 all: test clean: -rm -rf crt.lst main.lst crt.o main.o main.out main.hex main.map main.dmp main.bin # Из полученного бинарного файла извлекаем собственно код в бинарном формате и в intel hex формате test: main.out @echo "...copying" $(CP) $(CPFLAGS) -O binary main.out main.bin $(CP) $(CPFLAGS) -O ihex main.out main.hex $(OD) $(ODFLAGS) main.out > main.dmp main.out: crt.o main.o $(LDCMD) @echo "..linking" $(LD) $(LFLAGS) -o main.out crt.o main.o crt.o: crt.s @echo ".assembling" $(AS) $(AFLAGS) crt.s > crt.lst main.o: main.c @echo ".compiling" $(CC) $(CFLAGS) main.c # Очищаем первые две страницы памяти встроенного в процессор FLASH и прошиваем туда программу load: test @echo ".upload to crystal" $(LPCFLASH) $(LPCFLAGS) -e 0:2 $(LPCFLASH) $(LPCFLAGS) -p 0x00 -l main.bin -g 0x00:A
Для того что бы собрать приложение, нам достаточно выполнить команду make в каталоге проекта.
Команда make load загрузит полученную прошивку в процессор подключённой демо-платы.