Старт ARM. GPIO SAM3N. Atmel Studio 6.

Всем привет! Сегодня речь пойдет про Atmel Studio.

  1. Устанавливаем Atmel Studio, для этого необходимо зарегистрироваться на atmel.com и скачать программу Atmel Studio 6 (6.1 или 6.2).
  2. После установки AtmelStudio 6.1, запускаем среду для программирования микроконтроллеров (ARM и AVR), нас сразу приветствует стартовое окно «Начальная страница». В центре экрана присутствует окно с вкладками, в этих вкладках мы можем просматривать последнюю новостную информации от компании Atmel, получить необходимую информацию по отладочным платам и другие информационные вещи, касающиеся программирования в среде.
  3. В верхней части находится основное меню и палитра различных инструментов для комфортной работы в AtmelStudio 6.1.
  4. С правой стороны расположено окно «Обозреватель решений», в окне располагаться дерево проекта, дерево проекта включают заголовочные файлы и исходный файлы проекта. Конфигурировать проект и формировать будущую структуру проекта можно с помощью ASFWizard. ASFWizard используется для включения библиотечных файлов в зависимости от поставленной задачи, целей проекта и схемотехнической составляющей.
  5. С правой стороны помещена информация о недавних рабочих проектах, там же расположены элементы создания нового проекта и открытия старых проектов.


Начальная страница AtmelStudio 6.1

Осваивать работу в среде будем с помощью отладочной платы ATSAM3N-EK. На борту отладочной платы стоит микроконтроллер SAM3N4C, четыре светодиода, три кнопки (одна из них сбросовая), MicroSD порт, ZIGBEE – порт,QTouch –slider и пару кнопок, TFT – дисплей TM020GDZ18 и драйвер ILI9225B, Flash память AT25DF321 и другие полезные устройства. Запрограммировать микроконтроллер можно с помощь RS-232 и JTAG программатора. Микроконтроллер SAN3N4C имеет технологию ARM Cortex M3, которая объединяет в себе высокопроизводительную архитектуру, множество периферийных устройств и технологию энергосбережения и обеспечивает максимальную эффективность.

Создадим проект. Для этого нужно выбрать Файл -> Создать -> Проект(Ctrl+Shift+N), затем необходимо вести «Имя» проекта, «Расположение» проекта и «Имя расширения», далее из списка отладочных плат (Atmel – Boards) выбираем SAM3N-EK – ATSAM3N4C  и создаем проект.


Окно создание нового проекта.


Созданный пустой проект в AtmelStudio 6.1.

Любое программирование начинается с какого либо примера, для нас это будет «gpio_1», у типичных программистов это сочетание слов выведенное на консоль вышей операционной системы, а для программистов микроконтроллеров это программа зажигания светодиода. Светодиоды уже присутствую на отладочной плате, следовательно для нашей первой программы уже всё необходимое присутствует. Перед тем как написать пример, изучим схемотехническую часть отладочной платы со светодиодами.


Принципиальная электрическая подключения светодиода на отладочной плате.

На отладочной плате присутствую четыре светодиода: D1 – синий, D2 – зеленый, D3 – желтый, D4 – красный, которые управляются с помощью стандартных дискретных функций. Ножка (PIN) может быть, как входом, так и выходом GPIO (General purpose input/output – вход/выходы общего назначения) в зависимости от программной конфигурации железа. Красный светодиод D4 контролирую наличие питания на отладочной плате, единственно отличие от других светодиодов наличие MOP – транзистора. По умолчанию линия отключена. Для зажигания светодиода необходимо подтянуть резистор к PIN-у и подать напряжение на этот PIN (тем самым светодиод заработает, при наличии питания на плате). Светодиоды подключены через резисторы, которые ограничиваю ток идущий через них, предохраняя их от выгорания.

В пустом проекте присутствует заголовочный файл <asf.h>. C помощью ASF программных библиотек мы сможем подключить те или иные функции для непосредственного управления микроконтроллером. В подключенной библиотеки #include<asf.h> уже существует набор тоже подключаемых заголовочный файлов, которые включают в себя библиотеки инициализации и конфигурации железа, работа с интерфейсами, временными задержками и другие вещи необходимые от поставленной задачи для проекта.

Как добавить и узнать, какие нам нужны библиотеки для построения проекта? Для этого зайдите в ASF Wizard, в главном меню программы выберите Проект -> ASF Wizard, затем происходит загрузка стандартных библиотек наших отладочных функций. Появилось окно со всеми библиотеки для работы с нашей отладочной платой SAM3N – EK. ASF Wizard содержит название микроконтроллера ATSAM3N4C и название проекта “gpio_1”. Здесь присутствую, библиотеки для работы с дисплеем TM020GDZ18 и драйвером ILI9225B, библиотека операционной системы реального времени – FreeRTOS, различные интерфейсы: UART (USART), SPI, TWI (I2C) и т.д.


ASFWizard

Добавление библиотеки происходит выбором ее из левой части окно, затем необходимо нажать кнопку «Add» и затем нажать кнопку «Apply». Добавленная библиотека появиться с правой стороны, после чего ее можно будет использовать в проекте.

Напишем программу зажигания светодиода D1, наш “gpio_1” – первый шаг в мире программирования ARM микроконтроллеров, для этого перейдите вовкладуASFWizard и выберите из левого окна строку с названием IOPORT. IOPORT – библиотека для инициализации и конфигурации входов/выходов микроконтроллера.

//Подличаем необходимые библиотеки asf и led, для //работы со светодиодами.

#include <asf.h>
#include <led.h>
int main(void)
{
    //Делаем инициализацию нашей отладочной платы,
    //микроконтроллера.
    board_init();
    //Инициализация входов/выходов микроконтроллера.
    ioport_init();
    //Объявляем PIN микроконтроллера, как выход.
    ioport_set_pin_dir(LED0_GPIO,1);
    while(true) {
        //Подаем положительный импульс на выход для
        //зажигания светодиода.
        LED_On(LED0_GPIO);
    }
    return 0;
}

Дела остается за малым, нажимаем F7 для построения проекта или F5 для непосредственно загрузки проекта (hex – файл) в микроконтроллер и его отладки, при необходимости.


Построение проекта и его загрузка в микроконтроллер, с помощью JTAG программатора.

Atmel просит наличие программатора ICE, цена конечно кусается, но зато эффект сразу на лицу, для учебных целей можно воспользоваться стационарным компьютером с COM – портом на борту у ПК или неродным J-Link, у меня китайскиййJ-Link (у которого иного появляться неполадки, может слететь прошивка) программатор который можно приобрести на aliexpress.com, dx.com или аналогичных китайских интернет магазинах. Так же это же пример можно реализовать не через функции среды, а непосредственно обращаясь  к регистрам микроконтроллера SAM3N4C.

#include <asf.h>
#include <led.h>
#include <delay.h>
int main(void)
{
    sysclk_init();
    ioport_init();
    board_init();
    /* Configure the pins as outputs */
    PIOA->PIO_OER=PIO_PA23;           //PIO Output Enable Register
    /* Enable PIOC control on the pins */
    PIOA->PIO_PER=PIO_PA23;           //PIO Enable Register
    /* Disable pull-ups */
    PIOA->PIO_PUDR=PIO_PA23;          //PIO Pull Up Disable Register
    /* Turn LED off */
    PIOA->PIO_SODR=PIO_PA23;          // PIO Set Output Data Register
    /* Turn LED on */
    PIOA->PIO_CODR=PIO_PA23;          //PIO Clear Output Data Register
    while(1);
    return 0;
}

Немного усложним первоначальный проект, вместо одного светодиода зажжем еще оставшихся два светодиода: D2 и D3. Делаем аналогично предыдущему примеру, добавляем функцию конфигурации порта – ioport_set_pin_dir(ioport_pin_tpin,enumioport_directiondir), где pin – номер ножки микроконтроллера (подробное описание железа для отладочной платы можно посмотреть в заголовочном файле «sam3n_ek.h»), dir – это аргумент, говорит о том, как должен быть сконфигурирован выход микроконтроллера (1 – выход, 0 – вход). Например, название LED0_GPIO соответствует PIO_PA23_IDX (PA23), а LED1_GPIO соответствует PIO_PB14_IDX (PB14). Все ножки микроконтроллера выведены через двухрядные штыри (с шагом 2.54 мм) и имеют надписи – соответствия на отладочной плате.

Ѻ Пример 2.

#include <asf.h>
#include <led.h>
int main(void) {
    //Инициализацию отладочной платы.
    board_init();
    //Инициализация входов/выходов микроконтроллера.
    ioport_init();
    //Объявление PIN-ов микроконтроллера, как выходы.
    ioport_set_pin_dir(LED0_GPIO,1);
    ioport_set_pin_dir(LED1_GPIO,1);
    ioport_set_pin_dir(LED2_GPIO,1);
    while(true){
        //Подаем положительные импульсы на выходы для
        //зажиганиясветодиодов.
        LED_On(LED0_GPIO);
        LED_On(LED1_GPIO);
        LED_On(LED2_GPIO);
    }
    return 0;
}
#include <asf.h>
#include <led.h>
#include <delay.h>
int main(void)
{
    sysclk_init();
    ioport_init();
    board_init();
    /* Configure the pins as outputs */
    PIOA->PIO_OER=(PIO_PA23|PIO_PA25);
    PIOB->PIO_OER=PIO_PB14;
    /* Enable PIOC control on the pins */
    PIOA->PIO_PER=(PIO_PA23|PIO_PA25);
    PIOB->PIO_PER=PIO_PB14;
    /* Disable pull-ups */
    PIOA->PIO_PUDR=(PIO_PA23|PIO_PA25);
    PIOB->PIO_PUDR=PIO_PB14;
    /* Turn LED off */
    PIOA->PIO_SODR=(PIO_PA23|PIO_PA25);
    PIOB->PIO_SODR=PIO_PB14;
    /* Turn LED on */
    PIOA->PIO_CODR=(PIO_PA23|PIO_PA25);
    PIOB->PIO_CODR=PIO_PB14;
    while(1);
    return 0;
}
#include <asf.h>
#include <led.h>
#include <delay.h>
int main(void)
{
    sysclk_init();
    ioport_init();
    board_init();
    /* Configure the pins as ouputs */
    //PIO_PA23_IDX - LED0_GPIO //0x400E0E00U - PI0A //0x0010 - PIO_OER
    PIOA->PIO_OER=PIO_PA23;    //PIO Output Enable Register
    PIOA->PIO_IER=PIO_PA15;
    /* Enable PIOC control on the pins */
    PIOA->PIO_PER=(PIO_PA23|PIO_PA15);//LED1_GPIO;  //PIO Enable Registe //(LED0_GPIO | LED1_GPIO);       //(LED_A | LED_B);
    /* Disable pull-ups */
    //PIOA->PIO_PUER = PIO_PA23;
    PIOA->PIO_IFER=PIO_PA15;
    PIOA->PIO_ODR=PIO_PA15;
    PIOA->PIO_PUDR=PIO_PA23;   //PIO Pull Up Disable Register
    while(1) {
        /* Turn LED off */
        //return arch_ioport_pin_to_base(pin)->;PIO_PDSR &amp; arch_ioport_pin_to_mask(pin);
        //return arch_ioport_port_to_base(arch_ioport_pin_to_port_id(pin));
        //1U << (pin & 0x1F);
        //     return (Pio *)((uintptr_t)IOPORT_BASE_ADDRESS +
        //(IOPORT_PIO_OFFSET * port));
        if(PIOA->PIO_PDSR & PIO_PA15)
            PIOA->PIO_SODR=PIO_PA23;   // PIO Set Output Data Register
        //delay_ms(1000);
        /* Turn LED on */
        else
            PIOA->PIO_CODR=PIO_PA23;   //PIO Clear Output Data Register
        //delay_ms(1000);
    }
    return 0;
}

Чтобы наша программа стала по настоящему полноценной необходимо вести временные задержки, поэтому воспользуемся функцией delay_ms из библиотеки «delay.h». Для этого сначала перейдите ASFWizard, в левой части окна найдите Delay routines (service) и добавьте их в SelectedModules, нажмите кнопку «Add» и затем кнопку «Apply», чтобы среда разработка поняла, что вы хотите добавить их в своей проект. Затем возвращаемся снова на си файл проекта, в заголовочных файлах добавляем #include<delay.h>, теперь мы можем воспользоваться функцией delay_ms(delay), где delay – число, целый тип данных, которое соответствует интервалу задержки в миллисекундах.

Ѻ Пример 3.

#include <asf.h>
#include <led.h>
#include <delay.h>
int main(void)
{
    board_init();
    //Инициализация входов/выходов микроконтроллера.
    ioport_init();
    //Объявляем PIN микроконтроллера, как выход.
    ioport_set_pin_dir(LED0_GPIO,1);
    while(true) {
        //Включаем светодиод
        LED_On(LED0_GPIO);
        //Временная задержка на 2с.
        delay_ms(2000);
        //Выключаем светодиод
        LED_Off(LED0_GPIO);
        //Временная задержка на 2с.
        delay_ms(2000);
    }
    return 0;
}

Снова усложним проект, будим делать светомузыку! Светомузыка – это так называемая смена/переключение светодиодов, когда световое изменение светодиодов соответствует музыкальному ритму музыки. У нас кончено музыки не будет, а будет просто матрица все возможных состояний светодиодов, проект будет напоминать новогоднюю иллюминацию елочных гирлянд. Что нам понадобиться? Создать множество функций отвечающий за разную смену/переключение светодиода, с различными временными задержками. Предлагаю реализовать пять различных функций мигания светодиодами:

  1. Быстрое ускорение – мигания светодиодами.
  2. Возрастающая лестница переключения светодиодов.
  3. Рассогласованность мигания светодиодов.
  4. Убывающая лестница мигания светодиодов.
  5. Простое мигание, через равный промежуток времени.

Ѻ Пример 4.

#include <asf .h>
#include <led .h>
#include <delay .h>
//Быстрое ускорение – мигания светодиодами
static void funLed1(void)
{
    for(int i=2000; i&gt; =200; i-=200) {
        LED_On(LED0_GPIO);
        LED_On(LED1_GPIO);
        LED_On(LED2_GPIO);
        delay_ms(i);
        LED_Off(LED0_GPIO);
        LED_Off(LED1_GPIO);
        LED_Off(LED2_GPIO);
        delay_ms(i);
    }
    return;
}
//Возрастающая лестница переключения светодиодов
static void funLed2(void)
{
    LED_On(LED0_GPIO);
    delay_ms(500);
    LED_Off(LED0_GPIO);
    delay_ms(500);
    LED_On(LED1_GPIO);
    delay_ms(500);
    LED_Off(LED1_GPIO);
    delay_ms(500);
    LED_On(LED2_GPIO);
    delay_ms(500);
    LED_Off(LED2_GPIO);
    delay_ms(500);
    return;
}
//Рассогласованность мигания светодиодов
static void funLed3(void)
{
    LED_On(LED0_GPIO);
    LED_Off(LED1_GPIO);
    LED_On(LED2_GPIO);
    delay_ms(500);
    LED_Off(LED0_GPIO);
    LED_On(LED1_GPIO);
    LED_Off(LED2_GPIO);
    delay_ms(500);
    return;
}
//Убывающая лестница мигания светодиодов
static void funLed4(void)
{
    LED_On(LED2_GPIO);
    delay_ms(500);
    LED_Off(LED2_GPIO);
    delay_ms(500);
    LED_On(LED1_GPIO);
    delay_ms(500);
    LED_Off(LED1_GPIO);
    delay_ms(500);
    LED_On(LED0_GPIO);
    delay_ms(500);
    LED_Off(LED0_GPIO);
    delay_ms(500);
    return;
}
//Простое мигание, через равный промежуток времени
static void funLed5(void)
{
    LED_On(LED0_GPIO);
    LED_On(LED1_GPIO);
    LED_On(LED2_GPIO);
    delay_ms(500);
    LED_Off(LED0_GPIO);
    LED_Off(LED1_GPIO);
    LED_Off(LED2_GPIO);
    delay_ms(500);
    return;
}
int main(void)
{
    board_init();
    ioport_init();
    ioport_set_pin_dir(LED0_GPIO,1);
    ioport_set_pin_dir(LED1_GPIO,1);
    ioport_set_pin_dir(LED2_GPIO,1);
    while(true) {
        //Реализации светомузыки с помощью созданными нами
        //функциями
        funLed1();
        funLed2();
        funLed3();
        funLed4();
        funLed5();
    }
    return 0;
}

Кончено идеальным вариантом было бы накупить множество различных светодиодов различной цветовой гаммы и сделать например LED – куб или оригинальную подсветку для компьютера или интерьера, иначе произвести модинг ПК. Думаю что это будет хорошей задачей для Вас на досуге, при наличие большого желания и времени.

До этого мы вели речь только о том как воздействовать на светодиод, изучали как подать на выход микроконтроллера сигнал, теперь пришло время поговорить о том как и каким образом можно прочитать входной сигнал на ножке микроконтроллера, скажем после того как нажали кнопку на отладочной плате.

Для начала необходимо познакомиться с принципиальной электрической схемой подключения кнопок на отладочной плате ATMELSAM3N-EK. На отладочной плате присутствуют 3 кнопки: BP1 – кнопка сброса (reset) системы, PB2 и PB3 – обычные пользовательские кнопки.


Принципиальная электрическая подключения кнопок на отладочной плате

Приведем имена соответствия для кнопок на отладочной плате и в программе:

  • GPIO_PUSH_BUTTON_1/(PIO_PA15_IDX) – правая кнопка на отладочной плате.
  • GPIO_PUSH_BUTTON_2/(PIO_PA16_IDX) – левая кнопка на отладочной плате.

Пришло время написать программу управления светодиодами с помощью кнопок. Предлагаю по нажатию на правую кнопку зажигать светодиоды, а при нажатие на левую кнопку гасить светодиоды.

Ѻ Пример 5.

#include <asf.h>
int main(void)
{
    sysclk_init();
    board_init();
    ioport_init();
    ioport_set_pin_dir(LED2_GPIO,1);
    ioport_set_pin_dir(LED0_GPIO,1);
    //Конфигурацияпорта, каквход.
    ioport_set_pin_dir(GPIO_PUSH_BUTTON_1,0);
    ioport_set_pin_mode(GPIO_PUSH_BUTTON_1,1&lt; &lt; 3);
    //Конфигурацияпорта, каквход.
    ioport_set_pin_dir(LED1_GPIO,1);
    ioport_set_pin_dir(GPIO_PUSH_BUTTON_2,0);
    ioport_set_pin_mode(GPIO_PUSH_BUTTON_2,1&lt; &lt; 3);
    while(true) {
        //Проверяем уровень сигнала на входе ARM-а.
        if(!ioport_get_pin_level(GPIO_PUSH_BUTTON_1)) {
            LED_On(LED0_GPIO);
            LED_On(LED1_GPIO);
            LED_On(LED2_GPIO);
        }
        //Проверяем уровень сигнала на входе ARM-а.
        if(!ioport_get_pin_level(GPIO_PUSH_BUTTON_2)) {
            LED_Off(LED0_GPIO);
            LED_Off(LED1_GPIO);
            LED_Off(LED2_GPIO);
        }
    }
    return 0;
}

Продолжим изучать работу с битовыми входными сигналами, еще одним стандартным примерам при программирование микроконтроллеров является написание программы работы светофора. Что будет представлять из себя программа:

  1. Подходит человек к регулированому пешеходному переходу нажимает кнопку.
  2. Далее следует светосигнал.
  3. Светофор циклично работает.
#include <board.h>
#include <delay.h>
#include <gpio.h>
static led_function_1(void)
{
    LED_On(LED0_GPIO);
    LED_On(LED1_GPIO);
    LED_On(LED2_GPIO);
    delay_ms(100);
    LED_Off(LED0_GPIO);
    LED_Off(LED1_GPIO);
    LED_Off(LED2_GPIO);
    delay_ms(500);
    LED_On(LED0_GPIO);
    LED_On(LED1_GPIO);
    LED_On(LED2_GPIO);
    delay_ms(1000);
    LED_Off(LED0_GPIO);
    LED_Off(LED1_GPIO);
    LED_Off(LED2_GPIO);
    delay_ms(1500);
    return;
}

static led_function_2(void)
{
    LED_On(LED0_GPIO);
    LED_Off(LED1_GPIO);
    LED_Off(LED2_GPIO);
    delay_ms(1000);
    LED_Off(LED0_GPIO);
    LED_On(LED1_GPIO);
    LED_Off(LED2_GPIO);
    delay_ms(1000);
    LED_Off(LED0_GPIO);
    LED_Off(LED1_GPIO);
    LED_On(LED2_GPIO);
    delay_ms(1000);
}
int main(void)
{
    sysclk_init();
    board_init();
    gpio_configure_pin(LED0_GPIO,PIO_OUTPUT_1);
    gpio_configure_pin(LED1_GPIO,PIO_OUTPUT_1);
    gpio_configure_pin(LED2_GPIO,PIO_OUTPUT_1);
    gpio_configure_group(GPIO_PUSH_BUTTON_1,PIN_PUSHBUTTON_1_MASK,PIO_INPUT);
    gpio_configure_pin(GPIO_PUSH_BUTTON_1,PIO_PULLUP);
    while(true) {
        if(gpio_pin_is_high(GPIO_PUSH_BUTTON_1)) {
            led_function_1();
        }
        if(gpio_pin_is_high(GPIO_PUSH_BUTTON_2)) {
            led_function_2();
        }
    }
    return 0;
}

На этом все, продолжим во 2-ой части.