Прошивка TI TIVA-C с помощью USB DFU

Технологии
Есть множество способов поместить прошивку в микроконтроллер после того, как она будет готова. Однако, когда речь идет об устройстве, которое в обычном состоянии использует USB порт для связи с компьютером, неплохо бы иметь возможность загружать прошивку именно через него.
У контроллеров TIVA-C TM4C есть возможность воспользоваться режимом USB Device Firmware Update.

Все подробности генерации бинарников и их заливки под катом

Подготовка проекта:

В Code Composer Studio Создадим пустой проект:

Здесь необходимо отметить, что в микроконтроллеры TM4C встроено множество функций библиотеки TivaWare, на чем можно сэкономить в программном коде просто вызывая функции из ROM контроллера. Все эти функции начинаются с соответствующего префикса «ROM_»
В настройках проекта добавим путь до библиотек TivaWare:
"${COM_TI_RTSC_TIRTOSTIVAC_INSTALL_DIR}/products/TivaWare_C_Series-2.1.0.12573c"

Теперь, в нужное место (у меня это торчит в обработчике консольной команды команды «ATU») добавляем следующий код:
Его задача, перезапустить USB контроллер в новом режиме, попутно перенастроив все прерывания, чтобы ничего более не мешало.
Спойлер

#include <stdint.h>
#include <stdbool.h>

//алиасы
#include <inc/hw_memmap.h>
#include <inc/hw_types.h>
#include <inc/hw_ints.h>
#include <inc/hw_nvic.h>
#include <inc/hw_gpio.h>

//драйвера - ROM, выходы и системный клок
#define TARGET_IS_BLIZZARD_RB1
#include <driverlib/rom.h>
#include <driverlib/gpio.h>
#include <driverlib/sysctl.h>

int main(Void)
{	//Отключаем все прерывания, перезапускаем тактирование
	ROM_IntMasterDisable();
	ROM_SysTickIntDisable();
	ROM_SysTickDisable();
	uint32_t ui32SysClock;
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
	SYSCTL_XTAL_16MHZ);
	ui32SysClock = ROM_SysCtlClockGet();
	//активируем аналоговые цепи USB
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	ROM_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);
	ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / 100);//ожидаем запуска
	//сбрасываем все прерывания
	HWREG(NVIC_DIS0) = 0xffffffff;
	HWREG(NVIC_DIS1) = 0xffffffff;
	HWREG(NVIC_DIS2) = 0xffffffff;
	HWREG(NVIC_DIS3) = 0xffffffff;
	HWREG(NVIC_DIS4) = 0xffffffff;
	int ui32Addr;
	for(ui32Addr = NVIC_PRI0; ui32Addr <= NVIC_PRI34; ui32Addr+=4)
	{
	  HWREG(ui32Addr) = 0;
	}
	HWREG(NVIC_SYS_PRI1) = 0;
	HWREG(NVIC_SYS_PRI2) = 0;
	HWREG(NVIC_SYS_PRI3) = 0;
	//перезапускаем тактирование USB
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
	ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
	ROM_SysCtlUSBPLLEnable();
	ROM_SysCtlDelay(ui32SysClock*2 / 3);
	//Активируем прерывание и запускаем DFU
	ROM_IntMasterEnable();
	ROM_UpdateUSB(0);
	while(1)
	   {
	   }
	return 0;
}


Запускаем на компиляцию.

Генерация .bin файла

Теперь начинается самое интересное.
Посмотрим, что из себя представляет наш .out файл прошивки:
C:\home\...\Debug>objdump -h usb_dfu_test.out
Спойлер


usb_dfu_test.out:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .isr_vector   0000026c  00000000  00000000  00008000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text         0000087c  0000026c  0000026c  0000826c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .rodata       00000008  00000ae8  00000ae8  00008ae8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .eh_frame     00000004  00000af0  00000af0  00008af0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .data         00000434  20000000  00000af4  00010000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  5 .jcr          00000004  20000434  00000f28  00010434  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  6 .ARM.exidx    00000008  00000f2c  00000f2c  00010f2c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .bss          0000021c  20000438  20000438  00018438  2**2
                  ALLOC
  8 .ARM.attributes 00000035  00000000  00000000  00010f34  2**0
                  CONTENTS, READONLY
  9 .comment      00000070  00000000  00000000  00010f69  2**0
                  CONTENTS, READONLY
 10 .debug_info   0000022a  00000000  00000000  00010fd9  2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .debug_abbrev 00000134  00000000  00000000  00011203  2**0
                  CONTENTS, READONLY, DEBUGGING
 12 .debug_aranges 00000058  00000000  00000000  00011337  2**0
                  CONTENTS, READONLY, DEBUGGING
 13 .debug_ranges 00000038  00000000  00000000  0001138f  2**0
                  CONTENTS, READONLY, DEBUGGING
 14 .debug_line   0000023a  00000000  00000000  000113c7  2**0
                  CONTENTS, READONLY, DEBUGGING
 15 .debug_str    00000213  00000000  00000000  00011601  2**0
                  CONTENTS, READONLY, DEBUGGING
 16 .debug_frame  0000021c  00000000  00000000  00011814  2**2
                  CONTENTS, READONLY, DEBUGGING


Мы видим секции, из которых состоит прошивка. Столбец LMA показывает, по какому адресу будут находиться данные, а столбец VMA показывает, по какому адресу программа будет эти данные искать. Как мы видим, секция data находится в области прошивки, но при запуске данные загрузятся в область ОЗУ.
Секция .bss по обеим колонкам находятся по адресу 512Мбайт и выше. Если мы просто сгенерируем bin файл, он получится весом более 0.5Гбйат. И это не баг, это фича
Поэтому генерируем бинарник без соответствующих секций, с помощью ключа -R секция
В Code Composer Studio для этого есть соответствующий пункт в настройках GNU objcopy Utility — воспользуемся им:

Пересобираем проект и наблюдаем в консоли результат:
'Invoking: GNU Objcopy Utility'
«C:/bin/energia/hardware/tools/lm4f/bin/arm-none-eabi-objcopy.exe» -I elf32-littlearm -O binary --remove-section .bss «usb_dfu_test.out» «usb_dfu_test.bin»
'Finished building: usb_dfu_test.bin'

Объем нашего файла составил 4 кбайт.
Здесь мы можем загрузить прошивку каким-нибудь программатором — увы, но первый раз это потребуется.

Настройка системы

Допустим, мы уже запустили прошивку с помощью программатора или отладчика и в системе определилось устройство как на КДПВ.
Запускаем LM Flash Programmer. У меня версия 1613. В качестве интерфейса выбираем USB DFU и видим в списке наше устройство.

не видим? Да, есть такая проблема — в системе наше устройство определяется, но программа его не видит. В этом случае смотрим версии драйверов устройств и пробуем их либо просто переустановить, либо поставить более старые. Я бы однозначно ответил на этот вопрос, да накануне все заработало только со старым драйвером, а сейчас смотрю — определяется под новым. на TI E2E много соответствующих тем, но где косяк — никто не знает :)
Выбираем наш файл прошивки и зашиваем — тыдынь — устройство вновь определяется. Так как мы залили тоже самое — можем вновь попробовать залить что-то более полезное.


Готово!

немного ссылок напоследок:
TI-RTOS USB DFU mode problem — исходный код
TIVA-C TM4C123 ROM User's Guide
LM Flash Programmer

2 комментария

avatar
В LM Flash Programmer есть опция red probe.
austinblackstoneengineering.com/jtag-and-the-stellaris-launchpad/
Возможно ли превратить TM4C в программатор jtag для msp430?
avatar
Специалисты TI говорят что нет, да и я с такой возможностью первый раз слышусь.
В принципе, ежель написать соответствющую прошивку, то это будет возможно.

например в tiva-c launchpad на один из контроллеров как раз приходится JTAG-отладчик.
Впрочем, проще воспользоваться решением на FTDI.

У меня такой задачи не возникало, ибо имеетс MSP430-JTAG адаптер. Но успешно SWD-шил я как то девайсину, используя msp430g2553 launchpad.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.