Стаття про мікроконтролер EFM32ZG110F32

Так вже вийшло, що у нас на складі виявилося досить багато мікроконтролерів EFM32ZG110F32, це серія Zero Gecko від компанії SiLabs. Контролери класні, але поки не особливо популярні, тому я і пишу цю статтю.


На правах реклами ми пропонуємо ось такий набір: ARM Cortex-M0+, 32 Кбайт Flash, 4 Кбайт ОЗУ, DMA, I2C, UART, USART, 12-розрядний АЦП, струмовий ЦАП, компаратор, апаратний лічильник імпульсів, годинник реального часу і різні штуки для зниження енергоспоживання в корпусі QFN-24за $0.96.

Під катом довгий пост з докладним оглядом кристала і налагоджувальної плати, описом доступних засобів програмування і налагодження. Наведено приклади роботи з різними периферійними блоками кристала, використовуються фірмові засоби розробки і платформа mbed від ARM.

Огляд апаратної частини



EFM32 — це 32-розрядні маолопотребляющие мікроконтролери на базі процесорних ядер ARM Cortex-M. Їх головною особливістю є підтримка різноманітних програмних і апаратних технологій для оптимізації енергоспоживання, але разом з цим надається і стандартний набір периферійних пристроїв.

Герой цієї статті — мікроконтролер EFM32ZG110F32 — належить до самої молодшої серії сімейства EFM32, вона називається EFM32 Zero Gecko. Це найпростіші і найдешевші контролери під брендом EFM32, вони побудовані на базі ядра Cortex-M0+ і різняться між собою за набором підтримуваних периферійних пристроїв і корпусам. Про те, що являє собою EFM32ZG110F32, найпростіше судити за ось такою схемою.



Кольором для кожного блоку позначений режим енергоспоживання, аж до якого блок може використовуватися:
  • EM0 — активний режим, заявлений виробником енергоспоживання — 114 мкА / МГц
  • EM1 — режим з відключеним процесорним ядром, заявлене енергоспоживання — 48 мкА / МГц
    Сучасні малопотребляющие мікроконтролери як правило, підтримують технології автономної роботи периферії. Кожен виробник називає їх по-своєму, для EFM32 технологія взаємодії периферії без участі процесорного ядра називається Peripheral Reflex System (PRS). З використанням PRS і DMA можна організувати досить складні сценарії роботи кристала. Наприклад, такий: по переповненню таймера виконується перетворення на АЦП, результати перетворення через DMA записуються в ОЗП; ці дії повторюються двадцять разів і тільки після збереження двадцяти результатів генерується переривання, по якому прокидається процесорне ядро і починається обробка отриманого масиву даних.
  • EM2 — це режим, в якому відключаються високочастотні тактові генератори і доступними залишаються тільки низькочастотні і асинхронні периферійні модулі. Заявлене виробником енергоспоживання — 0.9 мкА
    Найчастіше саме EM2 використовується в якості режиму «сну». На відміну від EM1, цей режим дозволяє забезпечити тривале живлення від батарейки, але із збереженням підтримки DMA, послідовного інтерфейсу, I2C, лічильника імпульсів, компаратора і інших блоків, що дозволяють детектувати події і обмінюватися даними з іншими пристроями.
  • EM3 — режим, у якому відключаються не тільки високочастотні, але і низькочастотні тактові генератори. Відповідно, стають недоступні LEUART, годинник реального часу і DMA. Заявлене виробником енергоспоживання режиму EM3 — 0.5 мкА.
  • В режимі EM4 мікроконтролер фактично виключений і споживає близько 20. Вийти з такої «глибокої сплячки» можна тільки за reset, який, втім, може генеруватися не тільки по лінії скидання, але і від іншої лінії вводу/виводу, попередньо налаштованої відповідним чином.


Щоб оцінити описаний мікроконтролер, зручніше всього використовувати налагоджувальну плату і в цій статті можливості кристала будуть демонстироваться саме з її допомогою. Кіт для мікроконтролерів серії EFM32 Zero Gecko називається EFM32ZG-STK3200 і купується за 42 долара, звертайтеся. Набір складається з USB-кабелю, батарейки і ось такої плати.



Тут важливо зауважити ось що: стаття присвячена мікросхемі EFM32ZG110F32, а на налагоджувальної платі знаходиться більш «старший» мікроконтролер тієї ж серії — EFM32ZG222F32. Перший контролер виконаний в корпусі QFN-24, другий — у QPF-48. Як наслідок, на EFM32ZG110F32 доступно тільки 17 ліній вводу/виводу, з яких до п'яти можна використовувати як канали АЦП, а на EFM32ZG222F32 вже 37 ліній, з яких тільки два потенційних каналу для АЦП. В іншому кристали повністю ідентичні, тому розглянуті нижче приклади можна сміливо відносити до EFM32ZG222F32, так і до EFM32ZG110F32.

Тепер повернемося до налагоджувальної платі і розглянемо доступні на ній модулі:
  • J-Link — повноцінний текстовий інтерфейс для програмування і налагодження встановленого на платі мікроконтролера. Плата EFM32ZG-STK3200 може також використовуватися в якості програматора для сторонньої плати, для цього потрібно конфігурувати EFM32ZG-STK3200 як відладчика і підключитися до сторонньої платі певним чином. Про це розповім про це нижче.
  • Перемикач живлення дозволяє вибрати в якості джерела або налагоджувальний USB-інтерфейс, або трехвольтовую батарейку, відповідно перемикача два положення — DBG та BAT. В першому випадку забезпечується не тільки живлення контролера і налагоджувальний інтерфейсу. При підключення до комп'ютера через USB-кабель можлива робота з блоком Advanced Energy Monitor. Це вимірювальний модуль, який встановлений на платі для вимірювання енергоспоживання кристала. Дані, які можна одержати з Advanced Energy Monitor, використовуються програмою профілювання енергоспоживання, про яку також буде розказано трохи пізніше.
  • Основний пристрій виведення, встановлене на платі — це так званий memory LCD, підключений до контролера через інтерфейс SPI. Memory LCD — це монохромний дисплей, имеюий власну пам'ять, в якій зберігається який відображається зображення. При зміні оновлення зображення перерисовываются тільки змінилися пікселі, таким чином забезпечується низьке енергоспоживання і порівняно висока швидкодія дисплея. Memory LCD дисплей, встановлений на EFM32ZG-STK3200 настільки хороший, що одну плату у нас купили тільки заради дисплея. Було дивно.
  • За світлодіодами і механічних кнопок жодних пояснень, думаю, не потрібно. Але вони є, по дві штуки.
  • Сенсорні кнопки являють собою ємнісні сенсори і побудовані на популярною схемою, що використовує RC-ланцюжок і інтегровані в мікроконтроллер аналоговий компаратор і таймер. Якщо коротко, то на RC-ланцюжком і компараторі будується генератор частоти, частота якого залежить від ємності, яка в свою чергу збільшується при дотику пальця до контактної майданчику. Дотик детектується при через вимірювання частоти, що виконується, як правило, на таймерах.
  • Контактні майданчики, на яких доступні всі лінії вводу/виводу, розташовані у два ряди по верхньому і нижньому краю плати і на 20-вивідному роз'ємі по правому краю.


Якщо ваш додаток розраховане на задачу, в якій важливо енергоспоживання, то EFM32ZG-STK3200 стовідсотково вам стане в нагоді (в першу чергу з-за цього вимірювального модуля Advanced Energy Monitor). Якщо ж EFM32 буде використовуватися в пристрої не з батарейним живленням, і вам чомусь зовсім не хочеться використовувати цю плату, то все одно тримайте посилання Zero Gecko Starter Kit Schematics. Цілком може стати в нагоді при проектуванні.

Від огляду мікроконтролера і налагоджувальної плати перейдемо до огляду доступних програмних засобів розробки.

Огляд програмного забезпечення



Для розробки можна використовувати як програмне забезпечення від Silicon Labs, так і загальновживані gcc або Keil, IAR та ін

Платформа від Silicon Labs називається Simplicity Studio. Вона включає в себе IDE на базі eclipse, кілька утиліт для розробки та налагодження проекту, приклади програм, всю документацію та інші компоненти. Має сенс використовувати тільки Simplicity Studio, або звичну вам середовище розробки (Keil, IAR, Atollic, Rowley або Sourcery) або gcc разом з утилітами з Simplicity Studio.

Чому варто завантажити Simplicity Studio незалежно від бажаного компілятора і IDE?
По-перше, це нічого не варто. Як і будь-яке інше від виробників мікроконтролерів, Simplicity Studio — безкоштовна середовище. По-друге, дистрибутиви доступні для Mac і Ubuntu. По-третє, при встановленні Simplicity Studio для вибраного сімейства мікроконтролерів (в нашому випадку для 32-розрядних EFM32) ви одразу отримаєте повний комплект засобів розробки, документації і корисних посилань, які будуть автоматично оновлюватися. Це зручно.

Отже, після установки Simplicity Studio і підключення налагоджувальної плати (на якій повинно бути вибрано живлення від USB), з'явиться головне меню програми.



Все відобразилися інструменти активні саме для підключеного мікроконтролера. Якби був обраний, наприклад, Zigbee-модуль, то вийшов би зовсім інший набір іконок. Для налагодження програми на EFM32ZGxxx доступні наступні опції:
  • Середовище розробки. За замовчуванням це Simplicity IDE, однак в якості бажаної IDE може бути обрана й інша середовище, в цьому випадку іконка «Simplicity IDE» буде замінена.
  • Профілювання енергоспоживання — це утиліта, яка працює з встановленим на налагоджувальної платі вимірювальним модулем Advanced Energy Monitor і будує гарний графік Current / Time, який оновлюється по ходу виконання програми.
  • Конфігуратор — це графічний інтерфейс для налаштування ліній вводу/виводу і периферійних пристроїв, що дозволяє згенерувати проект програми з відповідними функціями ініціалізації.
  • З демо-прикладами і утилітою для програмування кристала, думаю, все зрозуміло.
  • У налаштуваннях налагоджувальної плати можна вибрати режим налагодження. Доступно три режими:
    1. Налагодження МК, розташованого на платі, через J-Link, розташований на платі
    2. Налагодження МК, розташованого на платі, через зовнішній відладчик
    3. Використання плати як відладчик для підключеного плати.
    У цьому ж розділі можна оновити прошивку плати, докладніше про це див. у прикладі #5 .
  • Як SWO-термінал потрапив в меню для контролера EFM32 Zero Gecko я не знаю — лінія SWO не передбачена на мікроконтролерах на базі ядра Cortex-M0+. Будемо вважати це випадковістю.
  • Емуляція роботи пристрою від батареї — це утиліта, якій на вхід задаються серія мікроконтролера, його стани (режими енергоспоживання і активні периферійні блоки), кількість і тип батарей живлення. Для такої конфігурації кристала і живлення розраховується термін автономної роботи контролера.
  • У розділі Software Examples доступні готові програми для обраної серії мікроконтролерів — підключив плату, вибрав програму, запустив. За корисними прикладами варто також заглянути в меню Application Notes. До кожного документа, що описує особливості роботи з периферією, додаються ілюструють проекти.
  • Вся документація на підключену плату або вибраний мікроконтролер доступна в один клік — при установці Simplicity Studio викачуються всі доступні матеріали для вибраного сімейства мікросхем, а при оновленні Simplicity Studio підтягнеться актуальна документація.
  • Документація на програмне забезпечення мікроконтролерів — бібліотеки, драйвери, всі регістри і структури даних — доступна в розділі Software Documentation або ссылке.
  • Настройка взаємодії зі стороннім ПЗ — це меню для вибору бажаної IDE, перевірки і установки необхідних драйверів і т. п.
У правому верхньому куті розташований центр оновлень, там можна перевірити і завантажити всі доступні оновлення програм і документації для обраних серій мікроконтролерів.

До речі про оновлення. Перша Simplicity Studio, розроблена ще компанією micro energy, була чудова у своїй простоті. Наступну версію випустили вже Silicon Labs. Simplicity Studio 2.0 володіла значно більш широким набором функцій, містила IDE і підтримувала мікроконтролери C8051Fxxx, але вийшла сильно тормознутой. До нинішньої версії (3.2) ситуація повністю вирівнялася і працювати в Simplicity Studio знову вельми приємно.

Щоб познайомити читача з можливостями мікроконтролера EFM32ZG110F32, розглянемо кілька прикладів роботи з різними засобами розробки та налагодження.

Приклад #1 Перевірка готовності



Якщо у ваших руках перший раз опинилася налагоджувальна плата і ви тільки-но запустили Simplicity Studio, то має сенс запустити демо-приклад і переконатися, що весь цей програмно-апаратний комплекс працює нормально.
Після включення плати в режимі DBG переконайтеся, що плата визначилася (див. лівий нижній кут головного меню Simplicity Studio). Для плати EFM32ZG-STK3200 в першому ряду буде доступний пункт Demo, що містить готові прошивки для мікроконтролера.



Потрібно просто вибрати один з проектів і натиснути кнопку Finish. Контролер буде запрограмований готовим бінарним файлом, на платі запуститься обрана програма, а на екрані комп'ютера з'явиться графік зміни рівня споживаного струму.
Якщо все пройшло успішно, то можна починати розробку власних програм.

Всі демо-програми доступні у вигляді проектів для кожної з підтримуваних середовищ розробки. Відповідні файли після установки Simplicity Studio знаходяться в папці ...\SiliconLabs\SimplicityStudio\v3\developer\sdks\efm32\v2\kits\EFM32ZG_STK3200\examples

Для кожного прикладу:
  • проект для Keil — MDK-ARM (папка arm),
  • makefile для gcc (папка armgcc),
  • проект для Atollic TrueSTUDIO (папка atollic),
  • проект для IAR Embedded Workbench for ARM (папка iar),
  • проект для Rowley Associates — CrossWorks for ARM (папка rowley),
  • проект для Simplicity IDE — CrossWorks for ARM (папка SimplicityStudio),
  • готові файли .bin .hex і .out (папка bin).


Приклад #2 Робота з інтерфейсом Low Energy UART і утилітою energy profiler



Почнемо розбиратися з окремими блоками мікроконтролера. Повернувшись до схеми периферійних блоків мікроконтролера EFM32ZG110F32, можна помітити серед комунікаційних інтерфейсів модуль LEUART.
LEUART або Low Energy UART — це послідовний інтерфейс, що зберігає функціональність в режимах сну до EM2 включно. Оскільки в режимі EM2 для тактирования доступні тільки низькочастотні генератори на 32.768 кГц, інтерфейс LEUART підтримує тільки найнижчу швидкість роботи з стандартних швидкостей UART — 9600 бод.

Крім роботи з мінімальними енерговитратами, цей інтерфейс надає дві незвичайні для UART функції. Для LEUART може бути призначений це або стартовий кадр start frame, до приходу якого посилки не приймаються, або signal frame, тільки по приходу якого генерується переривання. В обох випадках «аналіз» вхідних сигналів проводиться контролером автоматично та без участі ядра.

Оскільки LEUART — це блок, покликаний знизити рівень енергоспоживання кристала, логічно демонструвати його можливості разом з програмним засобом профілювання енергоспоживання — утилітою energy profiler.

Суть експерименту

Від зовнішнього джерела на послідовний інтерфейс приходять посилки — масиви символів. Кожен символ має бути прийнятий і збережений, а по закінченні прийому рядка контролер повинен зробити якісь обчислення. Програма у нас тестова, а значить досить проста і практично марна.
Рядок, яка приходить з іншого пристрою передається двічі в секунду і має один і той же вид вигляд:
char hello[] = { 'H', 'E', 'L', 'L', 'O', ' ', 'H', 'A', 'B', 'R', '!', 0, '\r' };

Символом закінчення рядка будемо вважати повернення каретки '\r', а прийняті символи записувати в масив rxbuf[]. Обчислення, необхідні для «обробки» отриманої рядків, зведемо до виконання порожнього циклу for (j = 0; j < 1000; j++), на час виконання якого включається LED1.
Метою експерименту будемо вважати контроль і оптимізацію енергоспоживання кристала при виконанні завдання прийому і обробки даних.

Параметри проекту, підключення плати

В проекті для роботи low energy UART використовуються функції з EFM32 API бібліотек, наданих SilLabs-му і працюють «поверх» ARM-івських CMSIS. Для їх використання необхідно додати до проекту відповідні файли, їх можна знайти в директорії ...\SimplicityStudio\v3\developer\sdks\efm32\v2\emlib після установки Simplicity Studio.



У наведеному прикладі також використовується пакет BSP (Board Support Package), що включає готові функції, що спрощують роботу з налагоджувальні платами для EFM32. Ці функції дозволяють не замислюватися про топології плати при роботі з встановленими на ній модулями (наприклад, BSP_LedInit() і BSP_LedToggle(1)). Бібліотеки BSP не розраховані ні на роботу з іншими платами, ні навіть на роботу з фірмовою платою, розрахованої від батарейки, а не налагоджувального USB. Однак у пробному проект цілком можна собі таке дозволити.

І EFM32 API, і BSP доступні для всіх IDE, підтримують мікроконтролери EFM32.

Що стосується підключення по LEUART до передавального пристрою, то відповідно до програмної налаштуванням LEUART (див. функцію initLeuart() з наведеного нижче лістингу), потрібно
а) живити плату від налагоджувального USB-інтерфейсу,
б) підключити лінію D5 і землю до пристрою-передавача.



Перший варіант програмної реалізації

Для наочності експерименту, на першій ітерації написання програми удамо школярем і забудемо про існування переривань. Пишемо програму, що виконує нескінченний цикл опитування послідовного інтерфейсу:
//....
while (1)
{
rx_char = LEUART_Rx(LEUART0);
if(rx_char == '\r') {
rxbuf[i] = rx_char;
i = 0;
BSP_LedToggle(1);
for (j = 0; j < 1000; j++);
BSP_LedToggle(1);
}
else {
rxbuf[i] = rx_char;
i++;
}
}
}

Повний текст програми

#include "em_chip.h"
#include "em_device.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "em_leuart.h"
#include "em_gpio.h"
#include "bsp.h"

char rx_char;
int i, j;
char rxbuf[13];

LEUART_Init_TypeDef LEUART0Init =
{
.enable = leuartEnableRx, 
.refFreq = 0, 
.baudrate = 9600, 
.databits = leuartDatabits8, 
.parity = leuartNoParity, 
.stopbits = leuartStopbits2, 
};

void initLeuart(void)
{
LEUART_Reset(LEUART0);
LEUART_Init(LEUART0, &LEUART0Init);

LEUART0->ROUTE = LEUART_ROUTE_RXPEN |
LEUART_ROUTE_LOCATION_LOC0;
GPIO_PinModeSet(gpioPortD,
5,
gpioModeInputPull,
1);
}


int main(void)
{
CHIP_Init();

CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);

CMU_ClockEnable(cmuClock_CORELE, true);
CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_LEUART0, true);

initLeuart();
BSP_LedsInit();

while (1)
{
rx_char = LEUART_Rx(LEUART0);
if(rx_char == '\r') {
rxbuf[i] = rx_char;
i = 0;
BSP_LedToggle(1);
for (j = 0; j < 1000; j++);
BSP_LedToggle(1);
}
else {
rxbuf[i] = rx_char;
i++;
}
}
}


З дозволу публіки, я не буду приводити покрокову інструкцію по створенню проекту, ні порядково пояснювати наведений код. Для широких мас наводжу посилання на інструкцію зі створення порожнього проекту в Simplicity IDE, звідти по кнопці NEXT можна перейти до миганню світлодіодом і на наступні кілька десятків уроків.

Отже, щоб виміряти енергоспоживання програми з нескінченним опитуванням прапора прийому даних, слід скористатися утилітою energy profiler, що входить до складу Simplicity Studio. Якщо проект створено в Simplicity IDE, то для запуску профілювання достатньо знайти ось таку кнопку в верхньому меню. У разі, якщо ви програмуєте в іншому середовищі або хочете покопатися в налаштуваннях конфігурацій профілювання, то вам прямий шлях у вікно налаштувань Profile Configurations, доступне в випадаючому меню.



При настроюванні конфігурації повинні бути вказані виконуваний файл і налаштування bild-а, відповідні використовуваної IDE.
Багато налаштування в Profile Configurations також пов'язані з функціями Code Correlation. Code Correlation — це прив'язка результатів вимірювань енергоспоживання до виконуваного коду (кожній точці на графіку ставиться у відповідність рядок лістингу). Саме завдяки цій опції ми і говоримо про профілюванні, а не просто про вимірювання енергоспоживання. Звучить, звичайно, здорово, але для мікроконтролерів серії Zero Gecko функція Code Correlation недоступна. Для того щоб співвіднести вимірювання та текст програми, з плати повинно додатково зніматися значення лічильника команд. Такі дані передаються по лінії SWO, якій на мікроконтролерах на базі Cortex-M0 не передбачено. Тому ми будемо задовольнятися тільки графіком зміни струму, що будуються в процесі виконання програми, що теж досить непогано.

Починаємо профілювання першого варіанту реалізації програми.



Дійсно, раз в 500 мс мікроконтролер приймає посилку і обробляє її. Підтверджуючи дані з графіка, світлодіод на платі підморгує двічі в секунду.
В середньому при постійному опитуванні прапора споживається приблизно 1.6 мА. Це багато, тому програму потрібно оптимізувати.

Другий варіант програмної реалізації

Очевидний варіант оптимізації — це використання переривань від послідовного інтерфейсу і «усыпение» контролера на час очікування переривання. Виконувати порожній цикл і включати LED1 будемо вже в обробника переривання.

Фрагмент функції main()

int main(void)
{
CHIP_Init();
i = 0;

...

while (1)
{
EMU_EnterEM2(true);
}
}

Параметри переривань

void setupLeuart(void)
{
LEUART_IntEnable(LEUART0, LEUART_IEN_RXDATAV);

NVIC_EnableIRQ(LEUART0_IRQn);
LEUART0->CTRL = LEUART_CTRL_RXDMAWU;
}

Обробка переривань

void LEUART0_IRQHandler(void)
{
leuartif = LEUART_IntGet(LEUART0);
LEUART_IntClear(LEUART0, leuartif);
rx_char = LEUART0->RXDATA;

if (rx_char == '\r')
{
rxbuf[i] = rx_char;
i = 0;
BSP_LedToggle(1);
for (j=0; j<1000; j++);
BSP_LedToggle(1);
}
else
{
rxbuf[i] = rx_char;
i++;
}
}


Повний текст програмиПрограма майже повністю повторює приклад роботи з LEUART, доступний в Simplicity Studio


#include "em_chip.h"
#include "em_device.h"
#include "em_cmu.h"
#include "em_emu.h"

#include "em_leuart.h"
#include "em_dma.h"

char rx_char;
int i, j;
char rxbuf[12];

uint32_t leuartif;
uint32_t len;

LEUART_Init_TypeDef LEUART0Init =
{
.enable = leuartEnableRx, 
.refFreq = 0, 
.baudrate = 9600, 
.databits = leuartDatabits8, 
.parity = leuartNoParity, 
.stopbits = leuartStopbits2, 
};

void LEUART0_IRQHandler(void)
{
leuartif = LEUART_IntGet(LEUART0);
LEUART_IntClear(LEUART0, leuartif);

rx_char = LEUART0->RXDATA;

if (rx_char == '\r')
{
rxbuf[i] = rx_char;
i = 0;
BSP_LedToggle(1);
for (j=0; j<1000; j++);
BSP_LedToggle(1);
}
else
{
rxbuf[i] = rx_char;
i++;
}
}

void initLeuart(void)
{
LEUART_Reset(LEUART0);
LEUART_Init(LEUART0, &LEUART0Init);

LEUART0->ROUTE = LEUART_ROUTE_RXPEN |
LEUART_ROUTE_LOCATION_LOC0;

GPIO_PinModeSet(gpioPortD, 
5, 
gpioModeInputPull, 
1); 
}


void setupLeuart(void)
{
LEUART_IntEnable(LEUART0, LEUART_IEN_RXDATAV);
NVIC_EnableIRQ(LEUART0_IRQn);
}


int main(void)
{
CHIP_Init();
i = 0;

CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);

CMU_ClockEnable(cmuClock_CORELE, true); /* Enable CORELE clock */
CMU_ClockEnable(cmuClock_GPIO, true); /* Enable GPIO clock */
CMU_ClockEnable(cmuClock_LEUART0, true); /* Enable LEUART0 clock */

initLeuart();
setupLeuartDma();
BSP_LedsInit();
while (1)
{
EMU_EnterEM2(true);
}
}



Після зміни коду достатньо один раз натиснути на іконку profiler, програма буде скомпільована, запрограмований контролер, а результати вимірювань будуть виведені на екран. За результатами видно, що споживання багаторазово знизилась — у середньому 224 мкА замість 1.6 мА.



Очікування посилки мікроконтролер проводить в режимі EM2, це найбільш глибокий сон, який ми можемо собі дозволити для збереження функціональності LEUART. Обробку результатів змінювати в загальному-то нікуди, значить подальша оптимізація програми можлива тільки для процесу отримання посилки. Подивимося на відповідний ділянку графіка ближче.



По приходу кожного символу рядка { 'H', 'E', 'L', 'L', 'O', ' ', 'H', 'A', 'B', 'R', '!', 0, '\r' } викликається обробник переривання, в якому знову прийшов символ порівнюється з '\r'. Згадавши, що перед нами не звичайний послідовний інтерфейс, а LEUART, можна використовувати не переривання по приходу символу, а переривання по приходу SIGFRAME. Спробуємо.

Третій варіант програмної реалізації

За умовами завдання, в пам'ять контролера повинен заноситися кожен прийшов символ рядка. Якщо б змінити тип переривання, то зберегти зробити це буде неможливо. Рішенням проблеми буде використання DMA, за нульового каналу якого дані будуть переправлятися» з LEUART без виходу з енергозберігаючого режиму EM2.

Параметри переривань

void setupLeuartDma(void)
{
DMA_Init(&dmaInit);
DMA_CfgChannel(DMA_CHANNEL, &chnlCfg);
DMA_CfgDescr(DMA_CHANNEL, true, &descrCfg);

DMA_ActivateBasic(DMA_CHANNEL,
true,
false,
(void *) &rxbuf,
(void *) &LEUART0->RXDATA,
BUF_MAX-1);

//------------------------------- дозвіл переривання по приходу символу '\r' --------------------------------//
LEUART0->SIGFRAME = '\r';
LEUART_IntEnable(LEUART0, LEUART_IEN_SIGF);
//-----------------------------------------------------------------------------------------------------------//

NVIC_EnableIRQ(LEUART0_IRQn);
LEUART0->CTRL = LEUART_CTRL_RXDMAWU;
}


Обробка переривань

void LEUART0_IRQHandler(void)
{
leuartif = LEUART_IntGet(LEUART0);
LEUART_IntClear(LEUART0, leuartif);

if (leuartif & LEUART_IF_SIGF)
{
DMA_ActivateBasic(DMA_CHANNEL, true, false, NULL, NULL, BUF_MAX-1);
BSP_LedToggle(1);
for (j = 0; j < 1000; j++);
BSP_LedToggle(1);
}
}


Повний текст програми

#include "em_chip.h"
#include "em_device.h"
#include "em_cmu.h"
#include "em_emu.h"

#include "em_leuart.h"
#include "em_dma.h"
#include "em_gpio.h"

#define DMA_CHANNEL 0
#define BUF_MAX 1023

char rx_char;
int i, j;

/* DMA control block, must be aligned to 256. */
#if defined (__ICCARM__)
#pragma data_alignment=256
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2];
#elif defined (__CC_ARM)
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
#elif defined (__GNUC__)
DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256)));
#else
#error Undefined toolkit, need to define alignment
#endif

uint32_t leuartif;
uint32_t len;

/* Defining the LEUART0 initialization data */
LEUART_Init_TypeDef LEUART0Init =
{
.enable = leuartEnableRx, /* Activate data reception on LEUn_RX pin. */
.refFreq = 0, /* Inherit the clock frequenzy from the LEUART clock source */
.baudrate = 9600, /* Baudrate = 9600 bps */
.databits = leuartDatabits8, /* Each LEUART frame containes 8 databits */
.parity = leuartNoParity, /* No parity bits in use */
.stopbits = leuartStopbits2, /* Setting the number of stop bits in a frame to 2 bitperiods */
};

/* DMA init structure */
DMA_Init_TypeDef dmaInit =
{
.hprot = 0, /* No descriptor protection */
.controlBlock = dmaControlBlock, /* DMA control block alligned to 256 */
};

/* Setting up channel */
DMA_CfgChannel_TypeDef chnlCfg =
{
.highPri = false, /* Normal priority */
.enableInt = false, /* No interupt enabled for callback functions */
.select = DMAREQ_LEUART0_RXDATAV, /* Set LEUART0 RX data avalible as source of DMA signals */
.cb = NULL, /* No callback funtion */
};

/* Setting up channel descriptor */
DMA_CfgDescr_TypeDef descrCfg =
{
.dstInc = dmaDataInc1, /* Increment destination address by one byte */
.srcInc = dmaDataIncNone, /* Do no increment source address */
.size = dmaDataSize1, /* Data size is one byte */
.arbRate = dmaArbitrate1, /* Rearbitrate for each byte recieved*/
.hprot = 0, /* No read/write source protection */
};

void LEUART0_IRQHandler(void)
{
leuartif = LEUART_IntGet(LEUART0);
LEUART_IntClear(LEUART0, leuartif);

if (leuartif & LEUART_IF_SIGF)
{
DMA_ActivateBasic(DMA_CHANNEL, true, false, NULL, NULL, BUF_MAX-1);
BSP_LedToggle(1);
for (j = 0; j < 1000; j++);
BSP_LedToggle(1);
}
}

void initLeuart(void)
{
LEUART_Reset(LEUART0);
LEUART_Init(LEUART0, &LEUART0Init);

LEUART0->ROUTE = LEUART_ROUTE_RXPEN |
LEUART_ROUTE_LOCATION_LOC0;

GPIO_PinModeSet(gpioPortD, 
5, 
gpioModeInputPull, 
1); 
}


void setupLeuartDma(void)
{
DMA_Init(&dmaInit);
DMA_CfgChannel(DMA_CHANNEL, &chnlCfg);
DMA_CfgDescr(DMA_CHANNEL, true, &descrCfg);

DMA_ActivateBasic(DMA_CHANNEL,
true,
false,
(void *) &rxbuf,
(void *) &LEUART0->RXDATA,
BUF_MAX-1);

LEUART0->SIGFRAME = '\r';
LEUART_IntEnable(LEUART0, LEUART_IEN_SIGF);

NVIC_EnableIRQ(LEUART0_IRQn);
LEUART0->CTRL = LEUART_CTRL_RXDMAWU;
}


int main(void)
{
CHIP_Init();
i = 0;

CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);

CMU_ClockEnable(cmuClock_CORELE, true); 
CMU_ClockEnable(cmuClock_DMA, true); 
CMU_ClockEnable(cmuClock_GPIO, true); 
CMU_ClockEnable(cmuClock_LEUART0, true); 

initLeuart();
setupLeuartDma();
BSP_LedsInit();

while (1)
{
EMU_EnterEM2(true);
}

}



Запускаємо профілювання третій раз і отримуємо доказ того, що проведена оптимізація має сенс — споживання знизилося з 224 до 139 мкА.



Зникли «зубчики», відповідні обробці переривань по кожному прийшов символу. За рахунок цього помітно знизилися і енергоспоживання за прийом/обробку даних, і середнє значення.

Мені не хотілося б вдаватися до порівняння конкретних цифр (рядок могла б, наприклад, бути довшим, а посилки частіше), але думаю що принцип зниження споживання з використанням low energy UART і energy profiler описаний досить зрозуміло.

Приклад #3 Робота з апаратним лічильником імпульсів PCNT і конфігуратором кристала



Розглянемо інший цікавий інструмент розробки, конфігуратор периферії і ліній вводу/виводу. Вибравши відповідний пункт головного меню Simplicity Studio і вказавши використовуваний part number, можна розпочати створення нового проекту в графічному середовищі налаштування контролера.

Для мікроконтролера EFM32ZG110F32 (так-так, все ще $0.96 за штуку) користувачеві доступний ось такий інтерфейс:

Вікно налаштування ліній введення/виводу



Вікно налаштування периферії



Загальний принцип роботи в Configurator такий: вибирається необхідна периферія, для кожного блоку настроюється режим роботи, після цього призначаються необхідні для роботи блоків лінії вводу/виводу, для кожної лінії задається конфігурація. Після установки запускається генерація заготовки проекту для вашого середовища розробки.
Конфігуратор дозволяє спростити початковий етап програмування — замість отримання налаштувань периферії документації використовується графічний інтерфейс. До того ж, ця утиліта дозволяє швидко оцінити можливості обраного кристала і зробити простий пробний проект. Подібний конфігуратор є у більшості виробників мікроконтролерів.

З використанням конфігуратора познайомимося з 16-розрядним лічильником імпульсів. Також як LEUART, цей модуль рідко можна знайти на мікроконтролерах, і, також як LEUART, лічильник імпульсів дозволяє знизити енергоспоживання пристрою.

Отже, в меню налаштування периферії мікроконтролера EFM32ZG110F32 ставимо галочку на PCNT0 і оглядываем доступні налаштування.



Модуль може бути налаштований на підрахунок кількості імпульсів, що приходять на один з портів кристала, в цьому випадку переривання генерується по досягненні заданої кількості імпульсів. Інший варіант роботи модуля — це режим квардатурного енкодера з перериванням по зміні напряму рахунку (за годинниковою стрілкою / проти годинникової стрілки).
Лічильник PCNT може використовувати один або два вхідних сигналу. В режимах підрахунку імпульсів «Single input, LFACLK oversampling» і «Single input, externally clocked» використовується тільки лінія S0, а сигнал S1 ігнорується. У режимі «Квадратура decoder mode, externally clocked» використовуються обидва вхідних сигналу.

Лічильник PCNT доступний в режимах сну аж до EM3, однак в режимі підрахунку імпульсів «Single input, LFACLK oversampling» використовується внутрішній, а не зовнішній джерело тактирования, тому можливе використання режимів енергоспоживання не нижче ніж EM2. Робота блоку в режимі EM3 також неможлива, якщо в якості входів блоку PCNT використовуються лінії вводу/виводу мікроконтролера, а канали Peripheral Reflex System. З іншого боку, EM2 — це енергоспоживання в одиниці мікроампер, що цілком прийнятно для енкодера.

Задамо через конфігуратор налаштування самого простого режиму PCNT. Нехай детектується п'ятий імпульс на одній з ліній GPIO.
Виставляємо режим роботи в «Single input, LFACLK oversampling», значення Initial top value «5», залишаємо налаштування рахунку (підрахунок фронтів «Count positive edges» та напрям рахунку «Count up») за замовчуванням, включаємо фільтр Filter out pulses shorter then 5 clockcycles» для захисту від брязкоту. Налаштування вхідних каналів залишаються за замовчуванням, т. к. другий канал в режимі Single input ігнорується, а для першого використовується ніжка контролера, а не канал PRS. Інші властивості меню Pulse Counter ставляться до режиму квадратурного енкодера, тому на них не дивимося зовсім.



Побачивши наші налаштування, конфігуратор справедливо зауважує, що раз вже підсумовуються імпульси, що приходять на одну з ліній вводу/виводу, то цю лінію потрібно вибрати і налаштувати.



По кліку на повідомлення про помилку переходимо у вікно налаштування ліній вводу/виводу, де для лінії S0IN є дві локації:



Припустимо, що друга локація, тобто лінія PC0, нам підходить більше. Знову дивимося у вікно помилок.



І, знову погоджуючись з конфігуратором, змінюємо режим роботи ніжки контролера з Disabled на Input.



Тепер можна генерувати вихідний код для заданої конфігурації мікроконтролера EFM32ZG110F32. У випадаючому по правому кліку миші меню знаходимо кнопку Generate Source і отримуємо готовий проект. Проект містить функції ініціалізації кристала — налаштування тактирования, лічильника імпульсів і GPIO, а також порожній цикл while (1) у функції main().


extern void enter_DefaultMode_from_RESET(void) 
{
CMU_enter_DefaultMode_from_RESET();
PCNT0_enter_DefaultMode_from_RESet();
PORTIO_enter_DefaultMode_from_REset();
}

extern void CMU_enter_DefaultMode_from_RESET(void) {
CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
CMU_ClockEnable(cmuClock_CORELE, true);
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
CMU_ClockEnable(cmuClock_PCNT0, true);
CMU_ClockEnable(cmuClock_GPIO, true);
}

extern void PCNT0_enter_DefaultMode_from_RESet(void) {
PCNT_Init_TypeDef init = PCNT_INIT_DEFAULT;

init.counter = 0;
init.top = 5;
init.negEdge = 0;
init.countDown = 0;
init.filter = 1;
init.hyst = 0;
init.s1CntDir = 0;
init.cntEvent = pcntCntEventUp;
init.auxCntEvent = pcntCntEventNone;
init.s0PRS = pcntPRSCh0;
init.s1PRS = pcntPRSCh0;

PCNT_Init(PCNT0, &init);
PCNT_Enable(PCNT0, pcntModeOvsSingle);
}

extern void PORTIO_enter_DefaultMode_from_REset(void) {
/* Pin PC0 is configured to Input enabled */
GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE0_MASK)
| GPIO_P_MODEL_MODE0_INPUT;
/* Module PCNT0 is configured to location 2 */
PCNT0->ROUTE = (PCNT0->ROUTE & ~_PCNT_ROUTE_LOCATION_MASK)
| PCNT_ROUTE_LOCATION_LOC2;
}


Повний текст програмиФайл main.c

/**************************************************************************//**
* @file
* @brief Empty Project
* @author Micro Energy AS
* @version 3.20.2
******************************************************************************
* @section License
* <b>© Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* This file is licensed under the Silicon Labs Software License Agreement. See 
* "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" 
* for details. Before using this software for any purpose, you must agree to the 
* terms of that agreement.
*
******************************************************************************/
#include "em_device.h"
#include "em_chip.h"

/**************************************************************************//**
* @brief Main function
*****************************************************************************/
int main(void)
{
/* Chip errata */
CHIP_Init();

/* Infinite loop */
while (1) {
}
}


Файл InitDevice.c


//=========================================================
// src/InitDevice.c: generated by Hardware Configurator
//
// This file will be regenerated when saving a document.
// leave the sections inside the "$[...]" comment tags alone
// or they will be overwritten!
//=========================================================

// USER INCLUDES
#include "InitDevice.h"

// USER PROTOTYPES
// USER FUNCTIONS

// $[Library includes]
#include "em_system.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_device.h"
#include "em_chip.h"
#include "em_pcnt.h"
// [Library includes]$

//==============================================================================
// enter_DefaultMode_from_RESET
//==============================================================================
extern void enter_DefaultMode_from_RESET(void) {
// $[Config Calls]
CMU_enter_DefaultMode_from_RESET();
PCNT0_enter_DefaultMode_from_RESet();
PORTIO_enter_DefaultMode_from_REset();
// [Config Calls]$

}

//================================================================================
// HFXO_enter_DefaultMode_from_RESEt
//================================================================================
extern void HFXO_enter_DefaultMode_from_RESEt(void) {
// $[HFXO]
// [HFXO]$

}

//================================================================================
// LFXO_enter_DefaultMode_from_RESEt
//================================================================================
extern void LFXO_enter_DefaultMode_from_RESEt(void) {
// $[Use oscillator source]
// [Use oscillator source]$

// $[LFXO Boost Percent]
// [LFXO Boost Percent]$

// $[REDLFXO Boost]
// [REDLFXO Boost]$

}

//================================================================================
// CMU_enter_DefaultMode_from_RESET
//================================================================================
extern void CMU_enter_DefaultMode_from_RESET(void) {
// $[LFXO enable]
// [LFXO enable]$

// $[HFXO enable]
// [HFXO enable]$

// $[LFACLK Setup]
/* Enable LFRCO oscillator */
CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);

/* Select LFRCO as source for clock LFACLK */
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);

// [LFACLK Setup]$

// $[High Frequency Clock select]
/* Using HFRCO at 14MHz as high frequency clock, HFCLK */
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
// [High Frequency Clock select]$

// $[LF clock tree setup]
/* Enable LF clocks */
CMU_ClockEnable(cmuClock_CORELE, true);
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
// [LF clock tree setup]$
// $[Peripheral Clock enables]
/* Enable clock for PCNT0 */
CMU_ClockEnable(cmuClock_PCNT0, true);

/* Enable clock for GPIO by default */
CMU_ClockEnable(cmuClock_GPIO, true);

// [Peripheral Clock enables]$

}

//================================================================================
// ADC0_enter_DefaultMode_from_RESEt
//================================================================================
extern void ADC0_enter_DefaultMode_from_RESEt(void) {
// $[ADC_Init]
// [ADC_Init]$

// $[ADC_InitSingle]
// [ADC_InitSingle]$

// $[ADC_InitScan]
// [ADC_InitScan]$

}

//================================================================================
// ACMP0_enter_DefaultMode_from_RESet
//================================================================================
extern void ACMP0_enter_DefaultMode_from_RESet(void) {
// $[ACMP Initialization]
// [ACMP Initialization]$

// $[ACMP Channel config]
// [ACMP Channel config]$

}

//================================================================================
// IDAC0_enter_DefaultMode_from_RESet
//================================================================================
extern void IDAC0_enter_DefaultMode_from_RESet(void) {
// $[IDAC Initialization]
// [IDAC Initialization]$

// $[IDAC optional configurations]
// [IDAC optional configurations]$

// $[IDAC enable]
// [IDAC enable]$

}

//================================================================================
// RTC_enter_DefaultMode_from_RESET
//================================================================================
extern void RTC_enter_DefaultMode_from_RESET(void) {
// $[RTC_Init]
// [RTC_Init]$

}

//================================================================================
// USART1_enter_DefaultMode_from_REset
//================================================================================
extern void USART1_enter_DefaultMode_from_REset(void) {
// $[USART_InitAsync]
// [USART_InitAsync]$

// $[USART_InitSync]
// [USART_InitSync]$

// $[USART_InitPrsTrigger]
// [USART_InitPrsTrigger]$

}

//================================================================================
// LEUART0_enter_DefaultMode_from_Reset
//================================================================================
extern void LEUART0_enter_DefaultMode_from_Reset(void) {
// $[LEUART0 initialization]
// [LEUART0 initialization]$

}

//================================================================================
// VCMP_enter_DefaultMode_from_RESEt
//================================================================================
extern void VCMP_enter_DefaultMode_from_RESEt(void) {
// $[VCMP_Init]
// [VCMP_Init]$

}

//================================================================================
// WDOG_enter_DefaultMode_from_RESEt
//================================================================================
extern void WDOG_enter_DefaultMode_from_RESEt(void) {
// $[CMU_ClockEnable]
// [CMU_ClockEnable]$

// $[CMU_OscillatorEnable]
// [CMU_OscillatorEnable]$

// $[WDOG_Init]
// [WDOG_Init]$

}

//================================================================================
// I2C0_enter_DefaultMode_from_RESEt
//================================================================================
extern void I2C0_enter_DefaultMode_from_RESEt(void) {
// $[I2C0 initialization]
// [I2C0 initialization]$

}

//================================================================================
// TIMER0_enter_DefaultMode_from_REset
//================================================================================
extern void TIMER0_enter_DefaultMode_from_REset(void) {
// $[TIMER0 initialization]
// [TIMER0 initialization]$

// $[TIMER0 CC0 init]
// [TIMER0 CC0 init]$

// $[TIMER0 CC1 init]
// [TIMER0 CC1 init]$

// $[TIMER0 CC2 init]
// [TIMER0 CC2 init]$

}

//================================================================================
// TIMER1_enter_DefaultMode_from_REset
//================================================================================
extern void TIMER1_enter_DefaultMode_from_REset(void) {
// $[TIMER1 initialization]
// [TIMER1 initialization]$

// $[TIMER1 CC0 init]
// [TIMER1 CC0 init]$

// $[TIMER1 CC1 init]
// [TIMER1 CC1 init]$

// $[TIMER1 CC2 init]
// [TIMER1 CC2 init]$

}

//================================================================================
// PCNT0_enter_DefaultMode_from_RESet
//================================================================================
extern void PCNT0_enter_DefaultMode_from_RESet(void) {
// $[PCNT0 initialization]
PCNT_Init_TypeDef init = PCNT_INIT_DEFAULT;

init.counter = 0;
init.top = 5;
init.negEdge = 0;
init.countDown = 0;
init.filter = 1;
init.hyst = 0;
init.s1CntDir = 0;
init.cntEvent = pcntCntEventUp;
init.auxCntEvent = pcntCntEventNone;
init.s0PRS = pcntPRSCh0;
init.s1PRS = pcntPRSCh0;
PCNT_Init(PCNT0, &init);

/* Activating PCNT0 */
PCNT_Enable(PCNT0, pcntModeOvsSingle);
// [PCNT0 initialization]$

}

//================================================================================
// PRS_enter_DefaultMode_from_RESET
//================================================================================
extern void PRS_enter_DefaultMode_from_RESET(void) {
// $[PRS initialization]
// [PRS initialization]$

}

extern void PORTIO_enter_DefaultMode_from_REset(void) {

// $[Port A Configuration]
// [Port A Configuration]$

// $[Port B Configuration]
// [Port B Configuration]$

// $[Port C Configuration]

/* Pin PC0 is configured to Input enabled */
GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE0_MASK)
| GPIO_P_MODEL_MODE0_INPUT;
// [Port C Configuration]$

// $[Port D Configuration]
// [Port D Configuration]$

// $[Port E Configuration]
// [Port E Configuration]$

// $[Port F Configuration]
// [Port F Configuration]$

// $[Route Configuration]

/* Module PCNT0 is configured to location 2 */
PCNT0->ROUTE = (PCNT0->ROUTE & ~_PCNT_ROUTE_LOCATION_MASK)
| PCNT_ROUTE_LOCATION_LOC2;
// [Route Configuration]$

}


Таким чином без детального вивчення даташита можна отримати коректний код ініціалізації контролера. Природно, це не скасовує необхідності вивчення документації, просто зробить ваше життя трохи простіше при вивченні кристала.

Останні два приклади описують додаткові можливості при роботі з налагоджувальною платою EFM32ZG-STK3200.

Приклад #4 Використання налагоджувальної плати як програматора-налагоджувача



Як було сказано вище, відладчик J-Link, вбудований на EFM32ZG-STK3200 може використовуватися не тільки для програмування распаенного на платі кристала, але і для програмування і налагодження «сторонніх» мікроконтролерів EFM32. Важливо, що такий спосіб налагодження дозволяє в тому числі вимірювати енергоспоживання підключеної до EFM32ZG-STK3200 плати і працювати в energy profiler.
Щоб використовувати EFM32ZG-STK3200 як відладчик потрібно виконати наступні дії.

1. Конфігурування плати

Підключивши EFM32ZG-STK3200 через USB інтерфейс, потрібно через головне меню Simplicity Studio перейти до Kit Manager. У вікні всього лише змінити Debug Mode з MCU на Out.



2. Підключення плати

У правому верхньому куті плати EFM32ZG-STK3200 розташований стандартний для Cortex-ів 20-выводный налагоджувальний роз'єм SWD (Serial Wire Debug). Через цей роз'єм потрібно підключитися до налагоджують платі, причому з 20 висновків знадобляться п'ять.



Сигнал SWO не є обов'язковим для програмування і налагодження. У мікроконтролерах EFM32 Zero Gecko, і в будь-яких інших мікроконтролерах Cortex-M0/-M0+, лінії SWO не передбачено, проте якщо через вбудований на плату EFM32ZG-STK3200 J-Link ви програмуєте кристал на базі Cortex-M3 і вище, підключення SWO дозволить використовувати для налагодження дані трасування.

Сигнал Reset формально також не є обов'язковим, але, цитую документацію, highly recommended. Якщо при виконанні програми на цільовому контролері відключаться джерела тактирования або порти, що використовуються для налагодження, то потім до отлаживаемого контролера можна буде не достукатися.

Також потрібно зауважити, що цільовий контролер не живиться по лінії VMCU. Сигнал з VMCU служить для вимірювання енергоспоживання, що дозволяє використовувати energy profiler для оптимізації енергоспоживання кристала, розташованого на інший платі.

3. Налаштування IDE

У Simplicity IDE процес налагодження при використанні плати EFM32ZG-STK3200 в режимі Debug Out не відрізняється від стандартного. При використанні Keil або IAR краще звіритися з налаштуваннями J-Link, описаними в документі AN0043 — EFM32 Debug and Trace.

Приклад #5 Робота з EFM32 в середовищі mbed



В останньому прикладі хотілося б описати принцип розробки програм для мікроконтролерів EFM32 Zero Gecko з використанням платформи mbed від компанії ARM.
mbed — це масштабний проект, який повинен повністю покрити потреби розробників IoT-додатків. У складі платформи і mbed OS для систем на базі ядра Cortex-M, і онлайн-IDE, і бібліотеки для підтримки апаратних модулів різного роду (інтерфейси, датчики, пам'ять, приводи і т. д.), хмарні сервіси і бог знає що ще. Платформа поступово розвивається і поки залишає у розробників суперечливі враження.
Утримаюся від оцінки mbed і огляду всіх її функцій і обмежуся невеликим керівництвом по швидкому старту роботи в mbed з використанням мікроконтролерів EFM32 Zero Gecko.

SiLabs — це один з десятка виробників мікроконтролерів, чиї контролери підтримуються в mbed. , присвяченому EFM32ZG поки не так багато розробок, але все ж є три готових програми, за якими можна зрозуміти що до чого і випробувати онлайн-компілятор. Цим і займемося.

Налагоджувальна плата повинна бути налаштована стандартний режим відладки (див. Debug Mode: MCU в прикладі #4) і підключена до комп'ютера через USB-інтерфейс. Потрібно також переконатися, що харчування плати здійснюється за отладочному інтерфейсу (перемикач живлення в положенні DBG), а прошивка плати оновлено до останньої версії. Прошивка плати не має ніякого відношення до прошивці мікроконтролера, все що потрібно про неї знати — це те, що існує два варіанти: прошивка без підтримки mbed і прошивка з підтримкою mbed. На нових платах підтримка mbed є за замовчуванням, а для випущених рік-два-три тому китах оновитися потрібно вручну. Для цього досить зайти в Kit Manager з головного меню Simplicity Studio. Якщо оновлення необхідно, але Kit Manager відразу запропонує це зробити. Залишиться натиснути Ок і почекати пару секунд.

Розробка за допомогою mbed повністю проходить онлайн. Для початку на сайті developer.mbed.org потрібно зареєструватися, після цього потрібно перейти в розділ Platforms і знайти плату EFM32ZG-STK3200.



Кожен зареєстрований в mbed користувач може додавати в свій онлайн-компілятор скільки завгодно плат від різних виробників. Додаємо EFM32ZG-STK3200, і переходимо у вікно IDE.



Далі пропонується вибрати приклад для завантаження. Приклад з виведенням на РКІ стандартної картинки і годин у форматі години: хвилини: секунди підійде.


Готовий приклад можна скомпілювати, не вносячи змін в код. Після компіляції бінарний файл автоматично завантажується на комп'ютер.


А тепер найцікавіше. Всі налагоджувальні плати для мікроконтролерів EFM32, що володіють підтримкою mbed, визначаються комп'ютером як Mass Storage Device.



Завантажений з developer.mbed.org файл достатньо скопіювати на зовнішній диск STK3200, в ту ж секунду контролер буде запрограмований і на РКІ буде виведено час в заданому форматі.



Словом, почати розробку в mbed досить просто. Процес розробки програм також намагаються спростити та уніфікувати, весь серед основних цілей mbed зниження порогу входження в розробку вбудованих систем. Добру справу.

Для прикладу також наводжу код mbed для миготіння світлодіодом. За винятком функції sleep(), код універсальний і може бути запущений на налагоджувальних платах від інших партнерів mbed. Оскільки головною особливістю EFM32 є низьке енергоспоживання, для mbed написаний sleep API, що дозволяє використовувати режими енергоспоживання навіть при розробці засобами ARM mbed.


#include "mbed.h"

DigitalOut myled(LED1);
LowPowerTicker toggleTicker;

void ledToggler(void) {
myled = !myled;
}

int main() {
toggleTicker.attach(&ledToggler, 0.2 f);
while(1) {
sleep();
}
}


Висновок



Дякую за увагу. Хочеться вірити, що кристал EFM32ZG110F32 і вся серія EFM32 зацікавила шановного читача. Якщо ви хочете взяти на пробу мікроконтролер або налагоджувальну плату, то найпростіше написати мені тут або на email, вказаний в профілі.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.