- PVSM.RU - https://www.pvsm.ru -
Признайтесь, как часто вы думали о том, чтоб освоить азы программирования микроконтроллеров? Наверняка у вас есть в голове несколько идей потенциальных проектов, но воплощать их в жизнь вы так и не взялись. Так вот: лучше времени для старта, чем сейчас просто не найти.
Почему я решил, что этот вопрос интересен аудитории Хабра? Достаточно проанализировать количество добавления в избранное некоторых постов и выводы напрашиваются сами собой.
С другой стороны, в моём текущем окружении очень много программистов, но почти нет имбедеров. Когда я разговариваю с ними на тему микроконтроллеров, у меня создаётся впечатление, что мнение о них у многих осталось на уровне 10-летней давности.
Не смотря на то, что писать на asm’е для микроконтроллеров проще, чем под x86 архитектуру, многие его боятся и это служит для них преградой на пути к встраиваемым системам. Друзья, для того, чтоб сейчас запустить микроконтроллер, не обязательно, даже, досконально читать даташиты, не говоря уже о том, чтоб знать его инструкции. Конечно, если это – ваша профессия, то тут уровень погружения гораздо выше, но, скажите мне, как часто вы, вне зависимости от того, профессионалом в каком деле вы являетесь, при создании продуктов стараетесь не нарушать принципа инкапсуляции до последнего и нет нет да и заглядываете в исходники используемых библиотек? Сейчас вы поймёте, что я имею в виду.
Я смутно помню те времена, когда я не программировал микроконтроллеры. Я начинал писать на asm’е, не только потому, что это делали все, но и потому, что нормальных инструментов практически не было. Популярность 8-битных контроллеров от AVR я объясняю тем, что для них создавались очень простые в использовании библиотеки, позволяющие создать новый проект, написать десяток строчек кода и получить вполне себе рабочую программу (адреса регистров периферийных устройств и векторы прерываний любезно заполнены создателями библиотек). Я не проводил исследования, это из моих личных воспоминаний — я уверен, что более толковые библиотеки для других контроллеров существовали ещё раньше, но тогда мы об этом не знали.
Первый действительно массовый 32-битный микроконтроллер создала французская контора STM. Именно в тот момент многие любители познакомились с архитектурой Cortex-M3 и начали её широко использовать. Помню, мне одновременно в руки попало 2 контроллера – STM32F103 [1]и LPC1768. Мне надо было как можно быстрее сделать прототип устройства на одном из них. Естественно, мой выбор пал на первый: французы выпустили библиотеку для периферии под названием Standard Peripherals Library [2] и всё, что мне оставалось сделать – это запустить FreeRTOS [3], подключить необходимую периферию и на основе созданного скелета собирать проект уже на следующем уровне абстракции, не отвлекаясь больше на работу с регистрами. Скелет я использовал и в дальнейшем, часто перегибая и засовывая 32-х битный Cortex туда, где хватило бы и самой маленькой ATtiny, но чаще всего цена позволяла (а там, где не позволяла, либо нужно было пониженное энергопотребление, можно было использовать дешёвые MSP430 и STM8, но случалось это редко).
Конечно, я слукавлю, если скажу, что мне так и не пришлось выучить полностью архитектуру Cortex-M3 и скурить даташит F103 – конечно же, пришлось и тут моё увлечение библиотекой CMSIS [4] и StdPeriph_Lib мне скорее помешало, чем помогло, но скорость вхождения в новое для меня семейство поразила и уже тогда я понял, что мир контроллеров меняется и становится одновременно и проще и сложнее.
И вот мы плавно подобрались к тому, о чём я и хотел вам рассказать. Дело в том, что популярность всяких Arduino сборок долго не давала покоя ребятам из Texas Instruments. Они выпускали лаунчпады на основе MSP430 [5] и продавали их дешевле себестоимости и бесплатной доставкой, они запускали сообщество, в котором можно было выкладывать свои проекты, они создавали Energia [6]– форк Arduino, они выпускали лаунчпады Stellaris, а затем переименовывали их в Tiva C (хотя тут речь идёт о более глобальном ребрендинге и добавлении некоторых новых функций, суть не поменялась). О последнем я и хочу поговорить.
Купить лаунчпад EK-TM4C123GXL [7] можно за 12.99$ вместе с доставкой FedEx (то есть получите вы его достаточно скоро). Плата не изобилует различной электроникой, как, например, Discovery F4 (на борту которой находятся акселерометр, звуковой сенсор, ЦАП, куча светодиодов) – всё, что вы найдёте на Tiva C Launchpad – это RGB диод и 2 кнопки, но его сила заключается не в дополнительных устройствах на плате.
Сила EK-TM4C123GXL в библиотеках, доступных для скачивания с сайта TI под названием TivaWare. Дело в том, что библиотеки для своих контроллеров сейчас пишут все, но многие из них, к сожалению, качеством не особо отличаются и являются скорее традиционными примерами, чем полноценными библиотеками, которые не стыдно использовать в своих проектах (для упомянутого чуть выше LPC1768, NXP написали свою библиотеку почти одновременно с STM, но качеством она тогда не особо отличалась). Библиотека для Tiva C удивляет своей стандартизированностью, документированностью и многообразием.
Чуть позже я предложу вам скачать TivaWare [8] и, если вам не будет лень, то после установки вы сможете наблюдать следующие каталоги:
Для того, чтоб запустить любой пример на вашем лаунчпаде, достаточно открыть проект из папки examples/boards/ ek-tm4c123gxl в вашей любимой IDE – там всё уже готово (я использую IAR, по этому я открыл ek-tm4c123gxl.eww и он мне загрузил уже настроенный workspace ). Но, знаете, такие настроенные примеры есть сейчас почти у каждого микроконтроллера, а настоящие трудности начинаются, когда мы пытаемся создать что-то своё.
Ок, давайте откажемся не только от примеров но и от настроенного скелета проекта – запустим всё с нуля (естественно с использованием файл из библиотек). Сразу дисклеймер: работать с лаунчпадом я начал только сегодня, так что я пока не знаю почти ничего ни о нём, ни об исходниках с которыми я буду работать. Это и есть основной лейтмотив всей статьи – человек видит Tiva C первый раз и сразу пытается работать с ней.
Я хотел написать сразу какое-нибудь сложное и интересное приложение, но потом понял, что это займёт некоторое время, а публиковать статью надо срочно и, поэтому я решил сделать простенький пример, а потом, если будут желающие, мы сделаем что-нибудь поинтереснее.
Итак, первое, что нам нужно — это скачать и установить библиотеку (если вы не сделали этого до сих пор). Кроме этого, вам необходимо установить IDE и флэшер.
В качестве IDE я буду использовать IAR (следовательно и примеры будут с ним), однако вы можете использовать любую из поддерживаемых.
Кто не знает, у IAR есть 2 варианта бесплатного использования — с ограничением по времени и с ограничением по размеру кода. И, естественно, есть другие варианты, если вам не подходят эти 2 (сами знаете какие). Описывать процедуру установки и регистрации IAR я не буду — там всё просто, но, если у вас возникнут трудности — не стесняйтесь задавать вопросы в комментариях.
Итак, первым делом создадим новый проект. В свойствах проекта изменим некоторые настройки.
В C/C++ Compiler, на вкладке Preprocessor укажем путь к папке TivaWare. На этой же вкладке чуть позже мы добавим некоторые константы.
В Debugger выберем TI Stellaris.
Более детальные настройки (если нужно), можно посомотреть в примерах (например там используется другой файл конфигурации линковщика, не тот, что предложен IAR'ом).
Теперь нам необходимо настроить структуру проекта. Я предлагаю придерживаться структуры, предложенной TI (как в примерах), но с некоторыми отличиями.
В папке (на самом деле «в группе», но папки — както привычнее) Src у нас располагаются наши исходники. В примерах туда добавляют и исходники библиотечных файлов, но я считаю, что это только запутает проект.
В папке Library хранятся файлы из DriverLib. TI добавляют туда уже скомпилированный файл (в случае с IAR это файл driverlib/ewarm/Exe/driverlib.a), вы можете сделать так же, но я бы предложил добавлять вместо этого исходники, причём только в случае необходимости — так проще запомнить где что находится, да и смотреть исходный код полезно. Если вы планируете добавлять в эту же папку файлы из других библиотек (Utils, например), то лучше создать ещё один уровень иерархии.
В примерах упущено, и я тоже этого не делал, но, если вы будете писать свои заголовочные файлы, то создайте папку Inc.
Главное не забывать, что вот эти папки — это только для удобства пользователя, они ничего общего с размещением файлов на диске не имеют и никак не влияют на компиляцию.
Итак, в папке Src создадим файл main.c
В папку Library добавим startup_ewarm.c — он нужен для правильной инициализации вектора прерываний. Взять можете его из project_0 (это в examples) проекта, например.
Начнём нашу программу с функции main. Так как к порту F нашего лаунчпада подключен RGB светодиод, то им мы и поморгаем.
void main(void)
{
volatile uint32_t ui32Counter;
//Инициализация периферии
while(1)
{
//Тут код для переключения пинов
for(ui32Counter = 0; ui32Counter < 1000000; ui32Counter++)
{
}
//Тут код для переключения пинов
for(ui32Counter = 0; ui32Counter < 1000000; ui32Counter++)
{
}
}
}
Думаю всё понятно: использовать типы вроде uint32_t — хорошая привычка, это помогает решить неоднозначность с размерами переменных на различных контроллерах (кроме того, это соответствует стандартам MISRA-C); volatile — сообщает компилятору, что эту переменную не стоит оптимизировать (потому-что мы её будем использовать для, в общем-то, бесполезной операции). Дальше — беконечный цикл (как учат студентов — программа на микроконтроллерах не должна никогда кончаться) и 2 счётчика для задержек.
Чтоб этот код компилировался, добавим в начало файла.
#include <stdint.h>
Теперь мы приступим непосредственно к миганию светодиодами.
Скачиваем со стрницы лаунчпада [7] файл Tiva C Series TM4C123G LaunchPad Evaluation Kit User's Manual и читаем в разделе User Switches and RGB User LED о том, что диод подключен к пинам PF1 (red), PF2 (blue) и PF3 (green).
Теперь открываем SW-TM4C-DRL-UG (в папке docs TivaWare) и просматриваем раздел GPIO. Из введения мы понимаем, что сперва пины должны быть сконфигурированны (конфигураций, естественно, множество) на выход. Тут же читаем, что одни из самых полезный функций — GPIOPinRead() и GPIOPinWrite(). Что они делают — понятно, осталось глянуть в их описание для уточнения списка параметров. Тут же находим, что для регистрации пинов на вывод используется функция GPIOPinTypeGPIOOutput(). Итак, меняем комментарии, в нашем коде на:
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2); //для инициализации
//и
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0xFF);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
//и
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0xFF);
Для включения и выключения диодов.
Естественно, не забываем добавить файл driverlib/gpio.c в папку Library, а так же
#include "driverlib/gpio.h"
в заголовки.
Кроме того, уже в процессе компиляци замечаем, что необходимо добавить ещё 2 заголовочных файла:
#include <stdbool.h> // Для поддержки типа bool, который используется в gpio
#include "inc/hw_memmap.h" //Для поддержки деклараций пинов.
Теперь наша программа выглядит вот так:
#include <stdint.h>
#include <stdbool.h>
#include "driverlib/gpio.h"
#include "inc/hw_memmap.h"
void main(void)
{
volatile uint32_t ui32Counter;
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
while(1)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0xFF);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
for(ui32Counter = 0; ui32Counter < 2000000; ui32Counter++)
{
}
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0xFF);
for(ui32Counter = 0; ui32Counter < 2000000; ui32Counter++)
{
}
}
}
И, если вы её скомпилируете и запустите — сможете наблюдать поочерёдную смену цвета диода.
Но моргание светодиодом — слишком просто для нас. Давайте пойдём чуть дальше и добавим поддержку порта ввода-вывода.
Действия — все те же. Находим к каким портам подключен UART, читаем про конфигурацию модуля в UserGuide, конфигурируем, используем функции для записи в и чтения из uart.
Моя функция инициализации uart получилась похожа на функцию из примера, но с одним интересным отличием. Вот так выглядит инициализация из примера:
void ConfigureUART(void)
{
//
// Enable the GPIO Peripheral used by the UART.
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//
// Enable UART0
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
//
// Configure GPIO Pins for UART mode.
//
ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//
// Use the internal 16MHz oscillator as the UART clock source.
//
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
//
// Initialize the UART for console I/O.
//
UARTStdioConfig(0, 115200, 16000000);
}
Как видите, тут используются странные функции с префиксом ROM_ — это специальные функции, которые уже сохранены в ROM'е микроконтроллера лаунчпада. Прочитать о них можно в всё том же UserGuide для DRL. Созданны они для того, чтоб уменьшить размер кода в Flash памяти. Нужно оно вам или нет — решать вам, мне идея понравилась (раз уж я всё-равно использую Peripheral Driver Library). Кстати, если вы не знаете, будет код использвоаться на устройстве с кусками библиотеки в ROM или нет — вы можете использовать Mapped ROM Calls. Тогда будет использоваться код из ROM, если он есть и компилироваться, если его нет.
Для работы с ROM необходимо настроить несколько констант: в опциях проекта, в C/C++ Compiler, на вкладке Preprocessor добавить константу TARGET_IS_BLIZZARD_RB1 в поле Defined Symbols. Туда же сразу добавьте PART_TM4C123GH6PM и ewarm — они нужны для успешной компиляции фалов библиотеки.
Кроме того, необходимо добавить в дерево проекта недостающие файлы:
Итак, всё, что нам осталось, это вывести что-то в порт (можете использовать для чтения любой эмулатор терминала. Например, для Windows я использовал Real Term). Затем, я предлагаю считать букву из порта, проверить, принадлежит ли она к одному из цветов (r, g, b) и поменять состояние соответствующего пина.
Функция для инициализации UART у вас уже есть. Изменяем инициализацию портов, чтоб добавить третий пин (раньше мы настроили только 2 на выход). Вывести строку в терминал можно с помощью функции UARTprintf(); из библиотеки utils/uartstdio.c (естественно, этот необходимо добавить к проекту и подключить заголовчный файл).
Считываем символ функцией UARTCharGet(). Она входит в цикл до тех пор, пока в уарт не придёт символ. После этого совершаем действия над пинами и возвращаемся в начало цикла.
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/pin_map.h"
#include "utils/uartstdio.h"
void ConfigureUART(void)
{
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
UARTStdioConfig(0, 115200, 16000000);
}
void main(void)
{
volatile uint32_t ui32Loop;
uint32_t ui32Color;
uint8_t ui8Red = 0xFF;
uint8_t ui8Green = 0xFF;
uint8_t ui8Blue = 0xFF;
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
ConfigureUART();
UARTprintf("Hello HabraHabr!n");
while (1)
{
UARTprintf("Please, enter color(r,g,b) n");
ui32Color = 'g';
switch (ui32Color)
{
case 'r':
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, ui8Red);
ui8Red = ~ui8Red;
break;
case 'b':
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, ui8Blue);
ui8Blue = ~ui8Blue;
break;
case 'g':
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, ui8Green);
ui8Green = ~ui8Green;
break;
default:
UARTprintf("Incorrect color! n");
break;
}
}
}
В TivaWare я нашёл интересную либу – utils/cmdline. Она позволяет создавать и обрабатывать команды введённые из командной строки. Я хотел сделать интересный проект с использованием её и ещё нескольких интересных библиотек, но время поджимает, так что я могу написать об этом позже, если будет интерес (а так же о прерываниях, которые тут даже не упомянуты и о FreeRTOS).
Ну, а теперь о том, почему я несколько раз написал о том, что время поджимает и почему из всех благоприятных времён для начала изучений контроллеров сейчас самое благоприятное: 22 января на edX стартуют курсы Embedded Systems — Shape The World [10].
Регистрация бесплатная, но, если вы хотите получить сретификат, то необходимо заплатить взнос (минимум 50$). Лично я заплатил 50$ — не из-за сертификата, а просто из любви к подобным курсам и в их поддержку.
Для участия вам надо купить Tiva C лаунчпад и различную рассыпуху. Последнюю вы можете купить на любом радиорынке, а вот с лаунчпадом придётся поторопиться: TI обычно отправляют через FedEx, но это может занять до 10 дней, в то время, как до начала курса осталась неделя.
Но переживать не стоит: не думаю, что на первом уроке вам сразу понадобится работать с железом, возможно вы сможете просимулировать вашу программу.
Итак, немного выводов. Использование подобных библиотек – палка о двух концах. С одной стороны она упрощает разработку, понижает порог входа, с другой стороны создаёт уровень абстракции, который усложняет понимание основ (во всей статье нет ни одной отсылки к даташиту, и это – неправильно: даташит надо смотреть всегда и это является обязательным условием певращения из любителя в профессионала). Но у подобных библиотек в отличии от ардуино (кстати, Energia поддерживает описанный лаунчпад), есть одно преимущество: они не создают у вас ложного понимания реальности. Если вы используете библиотеку, вы понимаете, что за абстракцией кроется вполне реальное устройство и параллели между функциями и реальными регистрами проследить совсем не сложно.
Я надесюь, что данный материал подтолкнёт вас к покупке и изучению (пусть и столь поверхностному) этого замечательного устройства. Если у вас есть идеи проектов, которые вы могли бы реализовать на TM4C123G, но возникли сложности в реализации – не стесняйтесь писать об этом в комментариях: будем разбираться вместе.
Автор: aronsky
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/texas-instruments/52888
Ссылки в тексте:
[1] STM32F103 : http://www.st.com/web/en/catalog/mmc/FM141/FM141/SC1169/SS1031/LN1565
[2] Standard Peripherals Library: http://ru.wikipedia.org/wiki/STM32F10x_Standard_Peripherals_Library
[3] FreeRTOS: http://ru.wikipedia.org/wiki/FreeRTOS
[4] CMSIS: http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.php
[5] лаунчпады на основе MSP430: http://www.ti.com/ww/en/launchpad/launchpads.html
[6] Energia : http://www.energia.nu/
[7] EK-TM4C123GXL: http://www.ti.com/tool/ek-tm4c123gxl
[8] TivaWare: http://www.ti.com/tool/sw-tm4c
[9] этой ссылке: http://software-dl.ti.com/tiva-c/SW-TM4C/latest/index_FDS.html
[10] Embedded Systems — Shape The World: https://www.edx.org/course/utaustinx/utaustinx-ut-6-01x-embedded-systems-1172
[11] Источник: http://habrahabr.ru/post/209218/
Нажмите здесь для печати.