Открытый проект модуля IoT K66BLEZv1 продолжает развиваться.
Здесь рассмотрим следующие вопросы важные на первом этапе освоения:
— технология быстрого создания приложений для модуля в среде IAR Embedded Workbench без сложных SDK
— время активизации программы от момента подачи питания
— максимальная скорость программного переключения состояния пинов
— пример управления светодиодом по прерываниям на основе автомата состояний
Знакомство с модулем K66BLEZ1 было начато в этих статьях:
Модуль универсального контроллера для интернета вещей. Вдыхаем жизнь
Модуль универсального контроллера для интернета вещей. Тестирование FatFs
Схема модуля
Репозитарий проекта
Технология быстрой разработки.
В последнее время программное обеспечение для микроконтроллеров на ядре ARM Cortex-M стало таким сложным, что иногда кажется без специального API нельзя даже пином пошевелить. Производители чипов не жалеют сил чтобы максимально «абстрагировать» разработчиков от периферии снабжая нас различными SDK с библиотеками драйверов, уровнями абстракций (HAL), логическими уровнями и прочими прослойками. Это вроде бы должно ускорить разработку приложений, упростить вхождение в тему, избавить от необходимости чтения справочных руководств, обеспечить реюзинг кода.
Но это не всегда работает. Т.е. это работает только до встречи с первыми аппаратными проблемами микроконтроллера или до той поры пока не пришло время раскрыть весь потенциал чипа, из-за которого он и был выбран для создания собственной платформы.
Поэтому я всегда начинаю с создания своей минималистичной библиотеки функций работы с периферией. В моих функциях я не пытаюсь создать единые интерфейсы доступа к разной периферии, везде где можно обращаюсь к периферии напрямую, не придаю особое значение реюзингу низкоуровневых функций и часто переписываю их код или делаю его полный рефактринг.
Здесь я продемонстрирую несколько простых исходников с помощью которых начинающие могут завести и эффективно использовать модуль K66BLEZv1 без необходимости изучения и использования библиотек драйверов и уровня абстракций периферии из стандартного SDK для микроконтроллеров семейства Kinetis.
Установка среды разработки.
Начнём с установки среды разработки. Это будет IAR Embedded Workbench. Пакет коммерческий, но нам достаточно возможностей тестовой бесплатной версии. Качество и быстрота компиляции в IAR не уступают уровню Keil MDK и ARM GCC. Актуальный сравнительный анализ можно найти здесь.
Скачивается IAR Embedded Workbench легко и через простую форму регистрации получается триальная лицензия.
Пишем приложение.
Точнее изучаем, поскольку приложение уже создано. Проект находится здесь.
Скриншот первого простейшего приложения показан ниже. Традиционно моргаем светодиодом.
Пишем на языке C, но с расширениями, предоставляемыми компилятором IAR. Перейти на C++ в IAR не составляет труда, достаточно у файлов c расширением .c поменять расширение на .cpp.
Первое с чего приходится начинать писать программу для таких развитых микроконтроллеров как Kinetis это инициализация подсистемы тактирования ядра и периферии. В чипе несколько генераторов, умножителей частоты, делителей и прочего. Все нужно правильно настроить и включить в строго определённом порядке. В стандартном SDK это реализовано весьма избыточно, запутанно и в стиле магических чисел. В этом примере у меня все поместилось в одну простую процедуру в файле K66BLEZ1_INIT_SYS.c
Вот её текст:
//-------------------------------------------------------------------------------------------------------
// Инициализация чипа MK66FN2M0VLQ18 на плате K66BLEZ1
//-------------------------------------------------------------------------------------------------------
int Init_MK66FN2M0VLQ18_K66BLEZ1(void)
{
WDOG_MemMapPtr WDOG = WDOG_BASE_PTR;
// Выключать WATCHDOG надо сразу, иначе может возникнуть нестабильный запуск кода после холодного рестарта
//--------------------------------------------------------------------------------------------------------------------------------------
WDOG->UNLOCK = 0xC520; // Откроем доступ на запись в регитры управления WDOG
WDOG->UNLOCK = 0xD928;
WDOG->STCTRLH = 0
+ LSHIFT(0x00, 14) // DISTESTWDOG | Allows the WDOG’s functional test mode to be disabled permanently| 0 WDOG functional test mode is not disabled.
+ LSHIFT(0x00, 12) // BYTESEL[1:0]| This 2-bit field select the byte to be tested ... | 00 Byte 0 selected
+ LSHIFT(0x00, 11) // TESTSEL | Selects the test to be run on the watchdog timer | 0 Quick test
+ LSHIFT(0x00, 10) // TESTWDOG | Puts the watchdog in the functional test mode |
+ LSHIFT(0x01, 8) // Reserved |
+ LSHIFT(0x01, 7) // WAITEN | Enables or disables WDOG in wait mode. | 1 WDOG is enabled in CPU wait mode.
+ LSHIFT(0x01, 6) // STOPEN | Enables or disables WDOG in stop mode | 1 WDOG is enabled in CPU stop mode.
+ LSHIFT(0x00, 5) // DBGEN | Enables or disables WDOG in Debug mode | 0 WDOG is disabled in CPU Debug mode.
+ LSHIFT(0x01, 4) // ALLOWUPDATE | Enables updates to watchdog write once registers | 1 WDOG write once registers can be unlocked for updating
+ LSHIFT(0x00, 3) // WINEN | Enable windowing mode. | 0 Windowing mode is disabled.
+ LSHIFT(0x00, 2) // IRQRSTEN | Used to enable the debug breadcrumbs feature | 0 WDOG time-out generates reset only.
+ LSHIFT(0x01, 1) // CLKSRC | Selects clock source for the WDOG | 1 WDOG clock sourced from alternate clock source
+ LSHIFT(0x00, 0) // WDOGEN | Enables or disables the WDOG’s operation | 1 WDOG is enabled.
;
Init_pins();
Init_cpu();
return 1;
}
//-------------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------------
void Init_cpu(void)
{
//SCB_MemMapPtr SCB = SystemControl_BASE_PTR;
//NVIC_MemMapPtr NVIC = NVIC_BASE_PTR;
SIM_MemMapPtr SIM = SIM_BASE_PTR;
RTC_MemMapPtr RTC = RTC_BASE_PTR;
MCG_MemMapPtr MCG = MCG_BASE_PTR;
PIT_MemMapPtr PIT = PIT_BASE_PTR;
FMC_MemMapPtr FMC = FMC_BASE_PTR;
//CRC_MemMapPtr CRC = CRC_BASE_PTR;
RCM_MemMapPtr RCM = RCM_BASE_PTR;
PMC_MemMapPtr PMC = PMC_BASE_PTR;
MPU_BASE_PTR->CESR = 0; // 0 MPU is disabled. All accesses from all bus masters are allowed.
//--------------------------------------------------------------------------------------------------------------------------------------
SIM->SCGC6 |= BIT(29); // RTC | RTC clock gate control | 1 Clock is enabled.
if ( (RTC->CR & BIT(8)) == 0u ) // If 0, 32.768 kHz oscillator is disabled.
{
RTC->CR = 0
+ LSHIFT(0x00, 13) // SC2P | Oscillator 2pF load configure | 0 Disable the load.
+ LSHIFT(0x00, 12) // SC4P | Oscillator 4pF load configure | 0 Disable the load.
+ LSHIFT(0x00, 11) // SC8P | Oscillator 8pF load configure | 0 Disable the load.
+ LSHIFT(0x00, 10) // SC16P| Oscillator 16pF load configure | 0 Disable the load.
+ LSHIFT(0x00, 9) // CLKO | Clock Output | 1 The 32kHz clock is not output to other peripherals
+ LSHIFT(0x01, 8) // OSCE | Oscillator Enable | 1 32.768 kHz oscillator is enabled.
+ LSHIFT(0x00, 3) // UM | Update Mode | 0 Registers cannot be written when locked.
+ LSHIFT(0x00, 2) // SUP | Supervisor Access | 0 Non-supervisor mode write accesses are not supported and generate a bus error.
+ LSHIFT(0x00, 1) // WPE | Wakeup Pin Enable | 0 Wakeup pin is disabled.
+ LSHIFT(0x00, 0) // SWR | Software Reset | 0 No effect
;
}
//--------------------------------------------------------------------------------------------------------------------------------------
// Загрузка регистров из области чипа с заводскими установками
if ( *((uint8_t *)0x03FFU) != 0xFFU )
{
MCG->C3 = *((uint8_t *)0x03FFU);
MCG->C4 = (MCG_C4 & 0xE0U) | ((*((uint8_t *)0x03FEU)) & 0x1FU);
}
//--------------------------------------------------------------------------------------------------------------------------------------
SIM->CLKDIV1 = 0
+ LSHIFT(0x00, 28) // OUTDIV1 | Divide value for the core/system clock | 0000 Divide-by-1. | core/system clock = 180 MHz = CPU_CORE_CLK_HZ_CONFIG_3
+ LSHIFT(0x02, 24) // OUTDIV2 | Divide value for the peripheral clock | 0010 Divide-by-3. | bus clock = 60 MHz = CPU_BUS_CLK_HZ_CONFIG_3
+ LSHIFT(0x06, 20) // OUTDIV3 | Divide value for the FlexBus clock driven to the external pin (FB_CLK). | 0110 Divide-by-7. | FlexBus clock = 25.7 MHz = CPU_FLEXBUS_CLK_HZ_CONFIG_3
+ LSHIFT(0x06, 16) // OUTDIV4 | Divide value for the flash clock | 0110 Divide-by-7. | flash clock = 25.7 MHz = CPU_FLASH_CLK_HZ_CONFIG_3
;
SIM->CLKDIV4 = 0
+ LSHIFT(0x01, 01) // TRACEDIV | Trace clock divider divisor
+ LSHIFT(0x00, 00) // TRACEFRAC | Trace clock divider fraction
;
//
SIM->SOPT2 = 0
+ LSHIFT(0x00, 28) // ESDHCSRC | ESDHC perclk source select | 00 Core/system clock
+ LSHIFT(0x01, 26) // LPUARTSRC | LPUART clock source select | 01 MCGFLLCLK , or MCGPLLCLK, or IRC48M, or USB1 PFD
+ LSHIFT(0x01, 24) // TPMSRC | TPM clock source select | 01 MCGFLLCLK , or MCGPLLCLK, or IRC48M, or USB1 PFD
+ LSHIFT(0x00, 20) // TIMESRC | Ethernet timestamp clock source select| 00 System platform clock
+ LSHIFT(0x00, 19) // RMIISRC | RMII clock source select | 0 EXTAL clock
+ LSHIFT(0x01, 18) // USBSRC | USB clock source select | 1 MCGFLLCLK, or MCGPLLCLK, or IRC48M, or USB1 PFD
+ LSHIFT(0x01, 16) // PLLFLLSEL | PLL/FLL clock select | 01 MCGPLL0CLK !!!
+ LSHIFT(0x01, 12) // TRACECLKSEL | Debug trace clock select | 0 MCGCLKOUT
+ LSHIFT(0x03, 8) // FBSL | Flexbus security level | 11 Off-chip op code accesses and data accesses are allowed.
+ LSHIFT(0x02, 5) // CLKOUTSEL | Clock out select | 010 Flash ungated clock
+ LSHIFT(0x00, 4) // RTCCLKOUTSEL| RTC clock out select | 0 RTC 1 Hz clock drives RTC CLKOUT.
+ LSHIFT(0x00, 1) // USBREGEN | USB PHY PLL Regulator Enable | 1 USB PHY PLL Regulator enabled.
+ LSHIFT(0x00, 0) // USBSLSRC | USB Slow Clock Source | 0 MCGIRCLK
;
SIM->SOPT1 = 0
+ LSHIFT(0x01, 31) // USBREGEN | USB voltage regulator enable
+ LSHIFT(0x00, 30) // USBSSTBY | UUSB voltage regulator in standby mode during Stop, VLPS, LLS or VLLS
+ LSHIFT(0x00, 29) // USBVSTBY | USB voltage regulator in standby mode during VLPR or VLPW
+ LSHIFT(0x02, 18) // OSC32KSEL | 32K oscillator clock select | 10 RTC 32.768kHz oscillator
;
//--------------------------------------------------------------------------------------------------------------------------------------
MCG->C7 = 0; // OSCSEL | MCG OSC Clock Select | 0 Selects System Oscillator (OSCCLK). 1 Selects 32 kHz RTC Oscillator.
// При подключении к FLL синала 32 kHz RTC не происходит установка битов IREFS и CLKS
// Поэтому подключается сигнал с OSC0 который в данной схеме принимает внешний тактовый сигнал 50 МГц
// Конфигурируем осцилятор 0 (кварц 32 МГц)
MCG->C2 = 0
+ LSHIFT(0x00, 7) // LOCRE0 | Loss of Clock Reset Enable | 0 Interrupt request is generated on a loss of OSC0 external reference clock.
+ LSHIFT(0x00, 6) // FCFTRIM| Fast Internal Reference Clock Fine Trim | FCFTRIM controls the smallest adjustment of the fast internal reference clock frequency
+ LSHIFT(0x02, 4) // RANGE0 | Frequency Range Select | 1X Encoding 2 — Very high frequency range selected for the crystal oscillator ..
+ LSHIFT(0x00, 3) // HGO0 | High Gain Oscillator Select | 1 Configure crystal oscillator for high-gain operation.
+ LSHIFT(0x01, 2) // EREFS0 | External Reference Select | 1 Oscillator requested.
+ LSHIFT(0x00, 1) // LP | Low Power Select | 0 FLL (or PLL) is not disabled in bypass modes.
+ LSHIFT(0x01, 0) // IRCS | Internal Reference Clock Select| 1 Fast internal reference clock selected.
;
// Установка емкостей на осциляторе 0
OSC_CR = 0
+ LSHIFT(0x01, 7) // ERCLKEN | External Reference Enable (OSCERCLK) | 1 External reference clock is enabled.
+ LSHIFT(0x00, 5) // EREFSTEN | External Reference Stop Enable | 0 External reference clock is disabled in Stop mode.
+ LSHIFT(0x00, 3) // SC2P | Oscillator 2 pF Capacitor Load Configure | 1 Add 2 pF capacitor to the oscillator load.
+ LSHIFT(0x00, 2) // SC4P | Oscillator 4 pF Capacitor Load Configure | 1 Add 4 pF capacitor to the oscillator load.
+ LSHIFT(0x00, 1) // SC8P | Oscillator 8 pF Capacitor Load Configure | 1 Add 8 pF capacitor to the oscillator load.
+ LSHIFT(0x01, 0) // SC16P | Oscillator 16 pF Capacitor Load Configure | 1 Add 16 pF capacitor to the oscillator load.
;
// Переход в режим FBE - FLL Bypassed External ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MCG->C1 = 0
+ LSHIFT(0x02, 6) // CLKS | Clock Source Select | 10 Encoding 2 — External reference clock is selected.
+ LSHIFT(0x03, 3) // FRDIV | FLL External Reference Divider | 011 If RANGE 0 = 0 or OSCSEL=1 , Divide Factor is 32; for all other RANGE 0 values, Divide Factor is 1024.
+ LSHIFT(0x00, 2) // IREFS | Internal Reference Select | 0 External reference clock is selected.
+ LSHIFT(0x01, 1) // IRCLKEN | Internal Reference Clock Enable | 1 MCGIRCLK active.
+ LSHIFT(0x00, 0) // IREFSTEN | Internal Reference Stop Enable | 0 Internal reference clock is disabled in Stop mode.
;
// Настройка FLL
MCG->C4 = 0
+ LSHIFT(0x00, 7) // DMX32 | DCO Maximum Frequency with 32.768 kHz Reference | 0 DCO has a default range of 25%.
+ LSHIFT(0x00, 5) // DRST_DRS | DCO Range Select | 00 Encoding 0 — Low range (reset default).
+ LSHIFT(0x00, 1) // FCTRIM | Fast Internal Reference Clock Trim Setting |
+ LSHIFT(0x00, 0) // SCFTRIM | Slow Internal Reference Clock Fine Trim |
;
//
// Конфигурация PLL0 на 180 МГц
MCG->C5 = 0
+ LSHIFT(0x00, 6) // PLLCLKEN | PLL Clock Enable | 0 MCGPLL0CLK and MCGPLL0CLK2X are inactive
+ LSHIFT(0x00, 5) // PLLSTEN | PLL Stop Enable | 0 MCGPLL0CLK and MCGPLL0CLK2X are disabled in any of the Stop modes.
+ LSHIFT(0x00, 0) // PRDIV | PLL External Reference Divider | 011 Divide Factor 4. Selects the amount to divide down the external reference clock for the PLL0. The resulting frequency must be in the range of 8 MHz to 16 MHz.
;
MCG->C6 = 0
+ LSHIFT(0x00, 7) // LOLIE0 | Loss of Lock Interrrupt Enable | 0 No interrupt request is generated on loss of lock.
+ LSHIFT(0x00, 6) // PLLS | PLL Select | 0 FLL is selected.
+ LSHIFT(0x00, 5) // CME0 | Clock Monitor Enable | 0 External clock monitor is disabled for OSC0.
+ LSHIFT(0x0E, 0) // VDIV | VCO Divider | Умножаем на 30 (чтобы получить 180 МГц от 12 МГц кварца)
;
MCG->C11 = 0
+ LSHIFT(0x00, 4) // PLLCS | PLL Clock Select | 0 PLL0 output clock is selected
;
while ((MCG->S & BIT(1)) == 0) // OSCINIT0 Ждем стабилизации осцилятора OSC0
{
}
while ((MCG->S & BIT(4)) != 0) // IREFST Ждем пока FLL начнет работать от внешнего источника тактирования
{
}
while ((MCG->S & 0x0CU) != 0x08U) // CLKST Ждем пока мультиплексор CLKS установиться в режим FBE - FLL Bypassed External
{
}
// Переход в режим PBE - PLL Bypassed External ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MCG->C6 = 0
+ LSHIFT(0x00, 7) // LOLIE0 | Loss of Lock Interrrupt Enable | 0 No interrupt request is generated on loss of lock.
+ LSHIFT(0x01, 6) // PLLS | PLL Select | 1 PLLCS output clock is selected
+ LSHIFT(0x00, 5) // CME0 | Clock Monitor Enable | 0 External clock monitor is disabled for OSC0.
+ LSHIFT(0x0E, 0) // VDIV0 | VCO0 Divider | Умножаем на 30 (чтобы получить 180 МГц от 12 МГц кварца)
;
while ((MCG->S & 0x0CU) != 0x08U) // CLKST Ждем пока мультиплексор CLKS установиться в режим FBE - FLL Bypassed External
{
}
while ((MCG->S & BIT(6)) == 0x00U) // LOCK0 Ждем пока PLL0 защелкнется
{
}
// Переход в режим PEE - PLL Engaged External ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MCG->C1 = 0
+ LSHIFT(0x00, 6) // CLKS | Clock Source Select | 00 Encoding 0 — Output of FLL or PLLCS is selected (depends on PLLS control bit).
+ LSHIFT(0x03, 3) // FRDIV | FLL External Reference Divider | 101 If RANGE 0 = 0 or OSCSEL=1 , Divide Factor is 32; for all other RANGE 0 values, Divide Factor is 1024.
+ LSHIFT(0x00, 2) // IREFS | Internal Reference Select | 0 External reference clock is selected.
+ LSHIFT(0x01, 1) // IRCLKEN | Internal Reference Clock Enable | 1 MCGIRCLK active.
+ LSHIFT(0x00, 0) // IREFSTEN | Internal Reference Stop Enable | 0 Internal reference clock is disabled in Stop mode.
;
while ((MCG->S & 0x0CU) != 0x0CU) // CLKST Ждем пока мультиплексор CLKS установиться в режим PEE - PLL Engaged External
{
}
MCG->C6 |= BIT(5); // CME0 = 1 | 1 External clock monitor is enabled for OSC0.
//--------------------------------------------------------------------------------------------------------------------------------------
// Установки Reset Control Module (RCM)
RCM->RPFW = 0
+ LSHIFT(0x1F, 0) // RSTFLTSEL | Selects the reset pin bus clock filter width.| 11111 Bus clock filter count is 32
;
RCM->RPFC = 0
+ LSHIFT(0x00, 2) // RSTFLTSS | Selects how the reset pin filter is enabled in STOP and VLPS modes. | 0 All filtering disabled
+ LSHIFT(0x01, 0) // RSTFLTSRW | Selects how the reset pin filter is enabled in run and wait modes. | 01 Bus clock filter enabled for normal operation
;
if ((PMC->REGSC & BIT(3)) != 0) PMC->REGSC |= BIT(3); // Сброс бита ACKISO, чтобы разблокировать некоторую периферию
//--------------------------------------------------------------------------------------------------------------------------------------
// Установки Power Management Controller (PMC)
PMC->REGSC = 0
+ LSHIFT(0x00, 3) // ACKISO | Acknowledge Isolation | 0 Peripherals and I/O pads are in normal run state|
// Writing one to this bit when it is set releases the I/O pads and certain peripherals to their normal run mode state
+ LSHIFT(0x00, 0) // BGBE | Bandgap Buffer Enable | 0 Bandgap buffer not enabled
;
PMC->LVDSC1 = 0
+ LSHIFT(0x01, 6) // LVDACK | Low-Voltage Detect Acknowledge | This write-only bit is used to acknowledge low voltage detection errors (write 1 to clear LVDF). Reads always return 0.
+ LSHIFT(0x00, 5) // LVDIE | Low-Voltage Detect Interrupt Enable| 0 Hardware interrupt disabled (use polling)
+ LSHIFT(0x01, 4) // LVDRE | Low-Voltage Detect Reset Enable | 1 Force an MCU reset when LVDF = 1
+ LSHIFT(0x00, 0) // LVDV | Low-Voltage Detect Voltage Select | 00 Low trip point selected (V LVD = V LVDL )
;
PMC->LVDSC2 = 0
+ LSHIFT(0x01, 6) // LVWACK | Low-Voltage Warning Acknowledge |
+ LSHIFT(0x00, 5) // LVWIE | Low-Voltage Warning Interrupt Enable | 0 Hardware interrupt disabled (use polling)
+ LSHIFT(0x00, 0) // LVWV | Low-Voltage Warning Voltage Select | 00 Low trip point selected (V LVW = V LVW1 )
;
//--------------------------------------------------------------------------------------------------------------------------------------
// Инициализация Periodic Interrupt timer
SIM->SCGC6 |= BIT(23); // PIT | PIT clock gate control | 1 Clock is enabled.
PIT->MCR = 0
+ LSHIFT(0x00, 1) // MDIS | Module Disable | 0 Clock for PIT Timers is enabled.
+ LSHIFT(0x01, 0) // FRZ | Freeze | 1 Timers are stopped in debug mode.
;
//--------------------------------------------------------------------------------------------------------------------------------------
// Инициализация Flash Access Protection Register для разрешения доступа к Flash по DMA и от прочих мастеров
FMC->PFAPR = 0
+ LSHIFT(0x01, 23) // M7PFD | 1 Prefetching for this master is disabled. (Ethernet)
+ LSHIFT(0x01, 22) // M6PFD | 1 Prefetching for this master is disabled. (USB HS)
+ LSHIFT(0x01, 21) // M5PFD | 1 Prefetching for this master is disabled. ()
+ LSHIFT(0x01, 20) // M4PFD | 1 Prefetching for this master is disabled. ()
+ LSHIFT(0x00, 19) // M3PFD | 0 Prefetching for this master is enabled. (SDHC, NFC, USB FS)
+ LSHIFT(0x00, 18) // M2PFD | 0 Prefetching for this master is enabled. (DMA, EzPort)
+ LSHIFT(0x00, 17) // M1PFD | 0 Prefetching for this master is enabled. (ARM core system bus)
+ LSHIFT(0x00, 16) // M0PFD | 0 Prefetching for this master is enabled. (ARM core code bus)
+ LSHIFT(0x00, 14) // M7AP[1:0] | 00 No access may be performed by this master.
+ LSHIFT(0x00, 12) // M6AP[1:0] | 00 No access may be performed by this master.
+ LSHIFT(0x00, 10) // M5AP[1:0] | 00 No access may be performed by this master.
+ LSHIFT(0x00, 8) // M4AP[1:0] | 00 No access may be performed by this master.
+ LSHIFT(0x03, 6) // M3AP[1:0] | 11 Both read and write accesses may be performed by this master
+ LSHIFT(0x03, 4) // M2AP[1:0] | 11 Both read and write accesses may be performed by this master
+ LSHIFT(0x03, 2) // M1AP[1:0] | 11 Both read and write accesses may be performed by this master
+ LSHIFT(0x03, 0) // M0AP[1:0] | 11 Both read and write accesses may be performed by this master
;
SIM->SCGC6 |= BIT(18); // Включаем модуль CRC
SIM->SCGC4 |= BIT(19); // Включаем модуль CMP (аналоговые компараторы)
}
Текст конечно нельзя назвать коротким, но он все равно гораздо короче и понятней стандартных исходников SDK.
В процедуре Init_MK66FN2M0VLQ18_K66BLEZ1, как видно из текста перед инициализацией подсистемы тактирования стоит вызов функции Init_pins. Это единая функция инициализации всех выводов микроконтроллера. В SDK разработчики почему-то приняли метод инициализировать выводы в разных функциях драйверов совместно с периферией, которая через них будет работать. Это напоминает стиль драйверов под большие операционные системы. Но микроконтроллер — это не компьютер, всю программу включая драйвера пишет один человек (по крайней мере в моем случае), и ему не надо создавать себе искусственное разделение на «зоны ответственности». Но вот контроль за ресурсами в особенности за назначением функций выводам это ключевая проблема при разработке встраиваемых систем. Поэтому управление выводами я централизую и не отдаю его на откуп драйверам.
Вот текст процедуры инициализации выводов чипа:
typedef struct
{
GPIO_MemMapPtr gpio;
PORT_MemMapPtr port;
unsigned char pin_num;
unsigned char irqc; // Interrupt Configuration
// 0000 Interrupt/DMA Request disabled.
// 0001 DMA Request on rising edge.
// 0010 DMA Request on falling edge.
// 0011 DMA Request on either edge.
// 0100 Reserved.
// 1000 Interrupt when logic zero.
// 1001 Interrupt on rising edge.
// 1010 Interrupt on falling edge.
// 1011 Interrupt on either edge.
// 1100 Interrupt when logic one.
unsigned char lock; // if 1 Pin Control Register bits [15:0] are locked and cannot be updated until the next System Reset.
unsigned char mux; // Pin Mux Control
// 000 Pin Disabled (Analog).
// 001 Alternative 1 (GPIO).
// 010 Alternative 2 (chip specific).
// 011 Alternative 3 (chip specific).
// 100 Alternative 4 (chip specific).
// 101 Alternative 5 (chip specific).
// 110 Alternative 6 (chip specific).
// 111 Alternative 7 (chip specific / JTAG / NMI).
unsigned char DSE; // 0 Low drive strength is configured on the corresponding pin, if pin is configured as a digital output.
// 1 High drive strength is configured on the corresponding pin, if pin is configured as a digital output.
unsigned char SRE; // 0 Fast slew rate is configured on the corresponding pin, if pin is configured as a digital output.
// 1 Slow slew rate is configured on the corresponding pin, if pin is configured as a digital output.
unsigned char ODE; // 0 Open Drain output is disabled on the corresponding pin.
// 1 Open Drain output is enabled on the corresponding pin, provided pin is configured as a digital output.
unsigned char PFE; // 0 Passive Input Filter is disabled on the corresponding pin.
// 1 Passive Input Filter is enabled on the corresponding pin.
unsigned char PUPD; // 00 Internal pull-up or pull-down resistor is not enabled on the corresponding pin.
// 10 Internal pull-down resistor is enabled on the corresponding pin, if the corresponding Port Pull Enable Register bit is set.
// 11 Internal pull-up resistor is enabled on the corresponding pin, if the corresponding Port Pull Enable Register bit is set.
unsigned char dir; // 0 Pin is configured as general purpose input, if configured for the GPIO function
// 1 Pin is configured for general purpose output, if configured for the GPIO function
unsigned char init; // Init state
} T_IO_pins_configuration;
#define ANAL 0 // Pin Disabled (Analog).
#define ALT0 0 // Pin Disabled (Analog).
#define GPIO 1 // Alternative 1 (GPIO).
#define ALT1 1 // Alternative 1 (GPIO).
#define ALT2 2 //
#define ALT3 3 //
#define ALT4 4 //
#define ALT5 5 //
#define ALT6 6 //
#define ALT7 7 //
#define DSE_LO 0 // 0 Low drive strength is configured on the corresponding pin, if pin is configured as a digital output.
#define DSE_HI 1 // 1 High drive strength is configured on the corresponding pin, if pin is configured as a digital output.
#define OD_DIS 0 // 0 Open Drain output is disabled on the corresponding pin.
#define OD__EN 1 // 1 Open Drain output is enabled on the corresponding pin, provided pin is configured as a digital output.
#define PFE_DIS 0 // 0 Passive Input Filter is disabled on the corresponding pin.
#define PFE__EN 1 // 1 Passive Input Filter is enabled on the corresponding pin.
#define FAST_SLEW 0 // 0 Fast slew rate is configured on the corresponding pin, if pin is configured as a digital output.
#define SLOW_SLEW 1 // 1 Slow slew rate is configured on the corresponding pin, if pin is configured as a digital output.
#define PUPD_DIS 0 // 00 Internal pull-up or pull-down resistor is not enabled on the corresponding pin.
#define PULL__DN 2 // 10 Internal pull-down resistor is enabled on the corresponding pin, if the corresponding Port Pull Enable Register bit is set.
#define PULL__UP 3 // 11 Internal pull-up resistor is enabled on the corresponding pin, if the corresponding Port Pull Enable Register bit is set.
#define GP_INP 0 // 0 Pin is configured as general purpose input, if configured for the GPIO function
#define GP_OUT 1 // 1 Pin is configured for general purpose output, if configured for the GPIO function
void Config_pin(const T_IO_pins_configuration pinc);
// Настройки линий ввода/вывода платы K66BLEZ1 на базе микроконтроллера MK66FN2M0VLQ18
const T_IO_pins_configuration K66BLEZ1_pins_conf[] =
{
// gpio port num irqc lock mux DSE SRE ODE PFE PUPD dir init
{ PTA_BASE_PTR, PORTA_BASE_PTR, 0, 0, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // JTCLK/SWC 50 # PTA0 # Default=(JTAG_TCLK/SWD_CLK/EZP_CLK) ALT0=(TSI0_CH1) ALT1=(PTA0) ALT2=(UART0_CTS_b/UART0_COL_b) ALT3=(FTM0_CH5) ALT4=() ALT5=(LPUART0_CTS_b) ALT6=() ALT7=(JTAG_TCLK/SWD_CLK) EZPort=(EZP_CLK)
{ PTA_BASE_PTR, PORTA_BASE_PTR, 1, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 1 }, // JTDI (LED) 51 # PTA1 # Default=(JTAG_TDI/EZP_DI) ALT0=(TSI0_CH2) ALT1=(PTA1) ALT2=(UART0_RX) ALT3=(FTM0_CH6) ALT4=(I2C3_SDA) ALT5=(LPUART0_RX) ALT6=() ALT7=(JTAG_TDI) EZPort=(EZP_DI)
{ PTA_BASE_PTR, PORTA_BASE_PTR, 2, 0, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // JTDO/SWO 52 # PTA2 # Default=(JTAG_TDO/TRACE_SWO/EZP_DO) ALT0=(TSI0_CH3) ALT1=(PTA2) ALT2=(UART0_TX) ALT3=(FTM0_CH7) ALT4=(I2C3_SCL) ALT5=(LPUART0_TX) ALT6=() ALT7=(JTAG_TDO/TRACE_SWO) EZPort=(EZP_DO)
{ PTA_BASE_PTR, PORTA_BASE_PTR, 3, 0, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // JTMS/SWD 53 # PTA3 # Default=(JTAG_TMS/SWD_DIO) ALT0=(TSI0_CH4) ALT1=(PTA3) ALT2=(UART0_RTS_b) ALT3=(FTM0_CH0) ALT4=() ALT5=(LPUART0_RTS_b) ALT6=() ALT7=(JTAG_TMS/SWD_DIO) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 4, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 54 # PTA4/LLWU_P3 # Default=(NMI_b/EZP_CS_b) ALT0=(TSI0_CH5) ALT1=(PTA4/LLWU_P3) ALT2=() ALT3=(FTM0_CH1) ALT4=() ALT5=() ALT6=() ALT7=(NMI_b) EZPort=(EZP_CS_b)
{ PTA_BASE_PTR, PORTA_BASE_PTR, 5, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 55 # PTA5 # Default=(DISABLED) ALT0=() ALT1=(PTA5) ALT2=(USB0_CLKIN) ALT3=(FTM0_CH2) ALT4=(RMII0_RXER/MII0_RXER) ALT5=(CMP2_OUT) ALT6=(I2S0_TX_BCLK) ALT7=(JTAG_TRST_b) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 6, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 58 # PTA6 # Default=(DISABLED) ALT0=() ALT1=(PTA6) ALT2=() ALT3=(FTM0_CH3) ALT4=() ALT5=(CLKOUT) ALT6=() ALT7=(TRACE_CLKOUT) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 7, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 59 # PTA7 # Default=(ADC0_SE10) ALT0=(ADC0_SE10) ALT1=(PTA7) ALT2=() ALT3=(FTM0_CH4) ALT4=() ALT5=(RMII0_MDIO/MII0_MDIO) ALT6=() ALT7=(TRACE_D3) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 8, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 60 # PTA8 # Default=(ADC0_SE11) ALT0=(ADC0_SE11) ALT1=(PTA8) ALT2=() ALT3=(FTM1_CH0) ALT4=() ALT5=(RMII0_MDC/MII0_MDC) ALT6=(FTM1_QD_PHA/TPM1_CH0) ALT7=(TRACE_D2) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 9, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 61 # PTA9 # Default=(DISABLED) ALT0=() ALT1=(PTA9) ALT2=() ALT3=(FTM1_CH1) ALT4=(MII0_RXD3) ALT5=() ALT6=(FTM1_QD_PHB/TPM1_CH1) ALT7=(TRACE_D1) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 10, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 62 # PTA10/LLWU_P22 # Default=(DISABLED) ALT0=() ALT1=(PTA10/LLWU_P22) ALT2=() ALT3=(FTM2_CH0) ALT4=(MII0_RXD2) ALT5=() ALT6=(FTM2_QD_PHA/TPM2_CH0) ALT7=(TRACE_D0) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 11, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 63 # PTA11/LLWU_P23 # Default=(DISABLED) ALT0=() ALT1=(PTA11/LLWU_P23) ALT2=() ALT3=(FTM2_CH1) ALT4=(MII0_RXCLK) ALT5=(I2C2_SDA) ALT6=(FTM2_QD_PHB/TPM2_CH1) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 12, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 64 # PTA12 # Default=(CMP2_IN0) ALT0=(CMP2_IN0) ALT1=(PTA12) ALT2=(CAN0_TX) ALT3=(FTM1_CH0) ALT4=(RMII0_RXD1/MII0_RXD1) ALT5=(I2C2_SCL) ALT6=(I2S0_TXD0) ALT7=(FTM1_QD_PHA/TPM1_CH0) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 13, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 65 # PTA13/LLWU_P4 # Default=(CMP2_IN1) ALT0=(CMP2_IN1) ALT1=(PTA13/LLWU_P4) ALT2=(CAN0_RX) ALT3=(FTM1_CH1) ALT4=(RMII0_RXD0/MII0_RXD0) ALT5=(I2C2_SDA) ALT6=(I2S0_TX_FS) ALT7=(FTM1_QD_PHB/TPM1_CH1) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 14, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 66 # PTA14 # Default=(DISABLED) ALT0=() ALT1=(PTA14) ALT2=(SPI0_PCS0) ALT3=(UART0_TX) ALT4=(RMII0_CRS_DV/MII0_RXDV) ALT5=(I2C2_SCL) ALT6=(I2S0_RX_BCLK) ALT7=(I2S0_TXD1) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 15, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 67 # PTA15 # Default=(CMP3_IN1) ALT0=(CMP3_IN1) ALT1=(PTA15) ALT2=(SPI0_SCK) ALT3=(UART0_RX) ALT4=(RMII0_TXEN/MII0_TXEN) ALT5=() ALT6=(I2S0_RXD0) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 16, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 68 # PTA16 # Default=(CMP3_IN2) ALT0=(CMP3_IN2) ALT1=(PTA16) ALT2=(SPI0_SOUT) ALT3=(UART0_CTS_b/UART0_COL_b) ALT4=(RMII0_TXD0/MII0_TXD0) ALT5=() ALT6=(I2S0_RX_FS) ALT7=(I2S0_RXD1) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 17, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 69 # PTA17 # Default=(ADC1_SE17) ALT0=(ADC1_SE17) ALT1=(PTA17) ALT2=(SPI0_SIN) ALT3=(UART0_RTS_b) ALT4=(RMII0_TXD1/MII0_TXD1) ALT5=() ALT6=(I2S0_MCLK) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 18, 0, 0, ALT0, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // EXTAL 72 # PTA18 # Default=(EXTAL0) ALT0=(EXTAL0) ALT1=(PTA18) ALT2=() ALT3=(FTM0_FLT2) ALT4=(FTM_CLKIN0) ALT5=() ALT6=() ALT7=(TPM_CLKIN0) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 19, 0, 0, ALT0, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // XTAL 73 # PTA19 # Default=(XTAL0) ALT0=(XTAL0) ALT1=(PTA19) ALT2=() ALT3=(FTM1_FLT0) ALT4=(FTM_CLKIN1) ALT5=() ALT6=(LPTMR0_ALT1) ALT7=(TPM_CLKIN1) EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 24, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 75 # PTA24 # Default=(CMP3_IN4) ALT0=(CMP3_IN4) ALT1=(PTA24) ALT2=() ALT3=() ALT4=(MII0_TXD2) ALT5=() ALT6=(FB_A29) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 25, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 76 # PTA25 # Default=(CMP3_IN5) ALT0=(CMP3_IN5) ALT1=(PTA25) ALT2=() ALT3=() ALT4=(MII0_TXCLK) ALT5=() ALT6=(FB_A28) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 26, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 77 # PTA26 # Default=(DISABLED) ALT0=() ALT1=(PTA26) ALT2=() ALT3=() ALT4=(MII0_TXD3) ALT5=() ALT6=(FB_A27) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 27, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 78 # PTA27 # Default=(DISABLED) ALT0=() ALT1=(PTA27) ALT2=() ALT3=() ALT4=(MII0_CRS) ALT5=() ALT6=(FB_A26) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 28, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 79 # PTA28 # Default=(DISABLED) ALT0=() ALT1=(PTA28) ALT2=() ALT3=() ALT4=(MII0_TXER) ALT5=() ALT6=(FB_A25) ALT7=() EZPort=()
{ PTA_BASE_PTR, PORTA_BASE_PTR, 29, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 80 # PTA29 # Default=(DISABLED) ALT0=() ALT1=(PTA29) ALT2=() ALT3=() ALT4=(MII0_COL) ALT5=() ALT6=(FB_A24) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 0, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 81 # PTB0/LLWU_P5 # Default=(ADC0_SE8/ADC1_SE8/TSI0_CH0) ALT0=(ADC0_SE8/ADC1_SE8/TSI0_CH0) ALT1=(PTB0/LLWU_P5) ALT2=(I2C0_SCL) ALT3=(FTM1_CH0) ALT4=(RMII0_MDIO/MII0_MDIO) ALT5=(SDRAM_CAS_b) ALT6=(FTM1_QD_PHA/TPM1_CH0) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 1, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 82 # PTB1 # Default=(ADC0_SE9/ADC1_SE9/TSI0_CH6) ALT0=(ADC0_SE9/ADC1_SE9/TSI0_CH6) ALT1=(PTB1) ALT2=(I2C0_SDA) ALT3=(FTM1_CH1) ALT4=(RMII0_MDC/MII0_MDC) ALT5=(SDRAM_RAS_b) ALT6=(FTM1_QD_PHB/TPM1_CH1) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 2, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 83 # PTB2 # Default=(ADC0_SE12/TSI0_CH7) ALT0=(ADC0_SE12/TSI0_CH7) ALT1=(PTB2) ALT2=(I2C0_SCL) ALT3=(UART0_RTS_b) ALT4=(ENET0_1588_TMR0) ALT5=(SDRAM_WE) ALT6=(FTM0_FLT3) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 3, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 84 # PTB3 # Default=(ADC0_SE13/TSI0_CH8) ALT0=(ADC0_SE13/TSI0_CH8) ALT1=(PTB3) ALT2=(I2C0_SDA) ALT3=(UART0_CTS_b/UART0_COL_b) ALT4=(ENET0_1588_TMR1) ALT5=(SDRAM_CS0_b) ALT6=(FTM0_FLT0) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 4, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 85 # PTB4 # Default=(ADC1_SE10) ALT0=(ADC1_SE10) ALT1=(PTB4) ALT2=() ALT3=() ALT4=(ENET0_1588_TMR2) ALT5=(SDRAM_CS1_b) ALT6=(FTM1_FLT0) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 5, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 86 # PTB5 # Default=(ADC1_SE11) ALT0=(ADC1_SE11) ALT1=(PTB5) ALT2=() ALT3=() ALT4=(ENET0_1588_TMR3) ALT5=() ALT6=(FTM2_FLT0) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 6, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 87 # PTB6 # Default=(ADC1_SE12) ALT0=(ADC1_SE12) ALT1=(PTB6) ALT2=() ALT3=() ALT4=() ALT5=(FB_AD23/SDRAM_D23) ALT6=() ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 7, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // INT from LDC1000 88 # PTB7 # Default=(ADC1_SE13) ALT0=(ADC1_SE13) ALT1=(PTB7) ALT2=() ALT3=() ALT4=() ALT5=(FB_AD22/SDRAM_D22) ALT6=() ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 8, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 89 # PTB8 # Default=(DISABLED) ALT0=() ALT1=(PTB8) ALT2=() ALT3=(UART3_RTS_b) ALT4=() ALT5=(FB_AD21/SDRAM_D21) ALT6=() ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 9, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 1 }, // SPI1_PCS1 90 # PTB9 # Default=(DISABLED) ALT0=() ALT1=(PTB9) ALT2=(SPI1_PCS1) ALT3=(UART3_CTS_b) ALT4=() ALT5=(FB_AD20/SDRAM_D20) ALT6=() ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 10, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 91 # PTB10 # Default=(ADC1_SE14) ALT0=(ADC1_SE14) ALT1=(PTB10) ALT2=(SPI1_PCS0) ALT3=(UART3_RX) ALT4=() ALT5=(FB_AD19/SDRAM_D19) ALT6=(FTM0_FLT1) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 11, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SPI1_SCK 92 # PTB11 # Default=(ADC1_SE15) ALT0=(ADC1_SE15) ALT1=(PTB11) ALT2=(SPI1_SCK) ALT3=(UART3_TX) ALT4=() ALT5=(FB_AD18/SDRAM_D18) ALT6=(FTM0_FLT2) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 16, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SPI1_SOUT 95 # PTB16 # Default=(TSI0_CH9) ALT0=(TSI0_CH9) ALT1=(PTB16) ALT2=(SPI1_SOUT) ALT3=(UART0_RX) ALT4=(FTM_CLKIN0) ALT5=(FB_AD17/SDRAM_D17) ALT6=(EWM_IN) ALT7=(TPM_CLKIN0) EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 17, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SPI1_SIN 96 # PTB17 # Default=(TSI0_CH10) ALT0=(TSI0_CH10) ALT1=(PTB17) ALT2=(SPI1_SIN) ALT3=(UART0_TX) ALT4=(FTM_CLKIN1) ALT5=(FB_AD16/SDRAM_D16) ALT6=(EWM_OUT_b) ALT7=(TPM_CLKIN1) EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 18, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 97 # PTB18 # Default=(TSI0_CH11) ALT0=(TSI0_CH11) ALT1=(PTB18) ALT2=(CAN0_TX) ALT3=(FTM2_CH0) ALT4=(I2S0_TX_BCLK) ALT5=(FB_AD15/SDRAM_A23) ALT6=(FTM2_QD_PHA/TPM2_CH0) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 19, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 98 # PTB19 # Default=(TSI0_CH12) ALT0=(TSI0_CH12) ALT1=(PTB19) ALT2=(CAN0_RX) ALT3=(FTM2_CH1) ALT4=(I2S0_TX_FS) ALT5=(FB_OE_b) ALT6=(FTM2_QD_PHB/TPM2_CH1) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 20, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 99 # PTB20 # Default=(DISABLED) ALT0=() ALT1=(PTB20) ALT2=(SPI2_PCS0) ALT3=() ALT4=() ALT5=(FB_AD31/SDRAM_D31) ALT6=(CMP0_OUT) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 21, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 100 # PTB21 # Default=(DISABLED) ALT0=() ALT1=(PTB21) ALT2=(SPI2_SCK) ALT3=() ALT4=() ALT5=(FB_AD30/SDRAM_D30) ALT6=(CMP1_OUT) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 22, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 101 # PTB22 # Default=(DISABLED) ALT0=() ALT1=(PTB22) ALT2=(SPI2_SOUT) ALT3=() ALT4=() ALT5=(FB_AD29/SDRAM_D29) ALT6=(CMP2_OUT) ALT7=() EZPort=()
{ PTB_BASE_PTR, PORTB_BASE_PTR, 23, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 102 # PTB23 # Default=(DISABLED) ALT0=() ALT1=(PTB23) ALT2=(SPI2_SIN) ALT3=(SPI0_PCS5) ALT4=() ALT5=(FB_AD28/SDRAM_D28) ALT6=(CMP3_OUT) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 0, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 103 # PTC0 # Default=(ADC0_SE14/TSI0_CH13) ALT0=(ADC0_SE14/TSI0_CH13) ALT1=(PTC0) ALT2=(SPI0_PCS4) ALT3=(PDB0_EXTRG) ALT4=(USB0_SOF_OUT) ALT5=(FB_AD14/SDRAM_A22) ALT6=(I2S0_TXD1) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 1, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 0 }, // FTM0_CH0(Solenoid) 104 # PTC1/LLWU_P6 # Default=(ADC0_SE15/TSI0_CH14) ALT0=(ADC0_SE15/TSI0_CH14) ALT1=(PTC1/LLWU_P6) ALT2=(SPI0_PCS3) ALT3=(UART1_RTS_b) ALT4=(FTM0_CH0) ALT5=(FB_AD13/SDRAM_A21) ALT6=(I2S0_TXD0) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 2, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // FTM0_CH1(LDC1000 clk)105 # PTC2 # Default=(ADC0_SE4b/CMP1_IN0/TSI0_CH15) ALT0=(ADC0_SE4b/CMP1_IN0/TSI0_CH15) ALT1=(PTC2) ALT2=(SPI0_PCS2) ALT3=(UART1_CTS_b) ALT4=(FTM0_CH1) ALT5=(FB_AD12/SDRAM_A20) ALT6=(I2S0_TX_FS) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 3, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 106 # PTC3/LLWU_P7 # Default=(CMP1_IN1) ALT0=(CMP1_IN1) ALT1=(PTC3/LLWU_P7) ALT2=(SPI0_PCS1) ALT3=(UART1_RX) ALT4=(FTM0_CH2) ALT5=(CLKOUT) ALT6=(I2S0_TX_BCLK) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 4, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 109 # PTC4/LLWU_P8 # Default=(DISABLED) ALT0=() ALT1=(PTC4/LLWU_P8) ALT2=(SPI0_PCS0) ALT3=(UART1_TX) ALT4=(FTM0_CH3) ALT5=(FB_AD11/SDRAM_A19) ALT6=(CMP1_OUT) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 5, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 110 # PTC5/LLWU_P9 # Default=(DISABLED) ALT0=() ALT1=(PTC5/LLWU_P9) ALT2=(SPI0_SCK) ALT3=(LPTMR0_ALT2) ALT4=(I2S0_RXD0) ALT5=(FB_AD10/SDRAM_A18) ALT6=(CMP0_OUT) ALT7=(FTM0_CH2) EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 6, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 111 # PTC6/LLWU_P10 # Default=(CMP0_IN0) ALT0=(CMP0_IN0) ALT1=(PTC6/LLWU_P10) ALT2=(SPI0_SOUT) ALT3=(PDB0_EXTRG) ALT4=(I2S0_RX_BCLK) ALT5=(FB_AD9/SDRAM_A17) ALT6=(I2S0_MCLK) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 7, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 112 # PTC7 # Default=(CMP0_IN1) ALT0=(CMP0_IN1) ALT1=(PTC7) ALT2=(SPI0_SIN) ALT3=(USB0_SOF_OUT) ALT4=(I2S0_RX_FS) ALT5=(FB_AD8/SDRAM_A16) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 8, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 113 # PTC8 # Default=(ADC1_SE4b/CMP0_IN2) ALT0=(ADC1_SE4b/CMP0_IN2) ALT1=(PTC8) ALT2=() ALT3=(FTM3_CH4) ALT4=(I2S0_MCLK) ALT5=(FB_AD7/SDRAM_A15) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 9, 0, 0, ALT3, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 114 # PTC9 # Default=(ADC1_SE5b/CMP0_IN3) ALT0=(ADC1_SE5b/CMP0_IN3) ALT1=(PTC9) ALT2=() ALT3=(FTM3_CH5) ALT4=(I2S0_RX_BCLK) ALT5=(FB_AD6/SDRAM_A14) ALT6=(FTM2_FLT0) ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 10, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 115 # PTC10 # Default=(ADC1_SE6b) ALT0=(ADC1_SE6b) ALT1=(PTC10) ALT2=(I2C1_SCL) ALT3=(FTM3_CH6) ALT4=(I2S0_RX_FS) ALT5=(FB_AD5/SDRAM_A13) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 11, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 116 # PTC11/LLWU_P11 # Default=(ADC1_SE7b) ALT0=(ADC1_SE7b) ALT1=(PTC11/LLWU_P11) ALT2=(I2C1_SDA) ALT3=(FTM3_CH7) ALT4=(I2S0_RXD1) ALT5=(FB_RW_b) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 12, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 117 # PTC12 # Default=(DISABLED) ALT0=() ALT1=(PTC12) ALT2=() ALT3=(UART4_RTS_b) ALT4=(FTM_CLKIN0) ALT5=(FB_AD27/SDRAM_D27) ALT6=(FTM3_FLT0) ALT7=(TPM_CLKIN0) EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 13, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 118 # PTC13 # Default=(DISABLED) ALT0=() ALT1=(PTC13) ALT2=() ALT3=(UART4_CTS_b) ALT4=(FTM_CLKIN1) ALT5=(FB_AD26/SDRAM_D26) ALT6=() ALT7=(TPM_CLKIN1) EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 14, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 119 # PTC14 # Default=(DISABLED) ALT0=() ALT1=(PTC14) ALT2=() ALT3=(UART4_RX) ALT4=() ALT5=(FB_AD25/SDRAM_D25) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 15, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 120 # PTC15 # Default=(DISABLED) ALT0=() ALT1=(PTC15) ALT2=() ALT3=(UART4_TX) ALT4=() ALT5=(FB_AD24/SDRAM_D24) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 16, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 123 # PTC16 # Default=(DISABLED) ALT0=() ALT1=(PTC16) ALT2=(CAN1_RX) ALT3=(UART3_RX) ALT4=(ENET0_1588_TMR0) ALT5=(FB_CS5_b/FB_TSIZ1/FB_BE23_16_BLS15_8_b/SDRAM_DQM2) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 17, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 124 # PTC17 # Default=(DISABLED) ALT0=() ALT1=(PTC17) ALT2=(CAN1_TX) ALT3=(UART3_TX) ALT4=(ENET0_1588_TMR1) ALT5=(FB_CS4_b/FB_TSIZ0/FB_BE31_24_BLS7_0_b/SDRAM_DQM3) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 18, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 125 # PTC18 # Default=(DISABLED) ALT0=() ALT1=(PTC18) ALT2=() ALT3=(UART3_RTS_b) ALT4=(ENET0_1588_TMR2) ALT5=(FB_TBST_b/FB_CS2_b/FB_BE15_8_BLS23_16_b/SDRAM_DQM1) ALT6=() ALT7=() EZPort=()
{ PTC_BASE_PTR, PORTC_BASE_PTR, 19, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 126 # PTC19 # Default=(DISABLED) ALT0=() ALT1=(PTC19) ALT2=() ALT3=(UART3_CTS_b) ALT4=(ENET0_1588_TMR3) ALT5=(FB_CS3_b/FB_BE7_0_BLS31_24_b/SDRAM_DQM0) ALT6=(FB_TA_b) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 0, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 127 # PTD0/LLWU_P12 # Default=(DISABLED) ALT0=() ALT1=(PTD0/LLWU_P12) ALT2=(SPI0_PCS0) ALT3=(UART2_RTS_b) ALT4=(FTM3_CH0) ALT5=(FB_ALE/FB_CS1_b/FB_TS_b) ALT6=() ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 1, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 128 # PTD1 # Default=(ADC0_SE5b) ALT0=(ADC0_SE5b) ALT1=(PTD1) ALT2=(SPI0_SCK) ALT3=(UART2_CTS_b) ALT4=(FTM3_CH1) ALT5=(FB_CS0_b) ALT6=() ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 2, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 129 # PTD2/LLWU_P13 # Default=(DISABLED) ALT0=() ALT1=(PTD2/LLWU_P13) ALT2=(SPI0_SOUT) ALT3=(UART2_RX) ALT4=(FTM3_CH2) ALT5=(FB_AD4/SDRAM_A12) ALT6=() ALT7=(I2C0_SCL) EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 3, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 130 # PTD3 # Default=(DISABLED) ALT0=() ALT1=(PTD3) ALT2=(SPI0_SIN) ALT3=(UART2_TX) ALT4=(FTM3_CH3) ALT5=(FB_AD3/SDRAM_A11) ALT6=() ALT7=(I2C0_SDA) EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 4, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 131 # PTD4/LLWU_P14 # Default=(DISABLED) ALT0=() ALT1=(PTD4/LLWU_P14) ALT2=(SPI0_PCS1) ALT3=(UART0_RTS_b) ALT4=(FTM0_CH4) ALT5=(FB_AD2/SDRAM_A10) ALT6=(EWM_IN) ALT7=(SPI1_PCS0) EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 5, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 132 # PTD5 # Default=(ADC0_SE6b) ALT0=(ADC0_SE6b) ALT1=(PTD5) ALT2=(SPI0_PCS2) ALT3=(UART0_CTS_b/UART0_COL_b) ALT4=(FTM0_CH5) ALT5=(FB_AD1/SDRAM_A9) ALT6=(EWM_OUT_b) ALT7=(SPI1_SCK) EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 6, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 133 # PTD6/LLWU_P15 # Default=(ADC0_SE7b) ALT0=(ADC0_SE7b) ALT1=(PTD6/LLWU_P15) ALT2=(SPI0_PCS3) ALT3=(UART0_RX) ALT4=(FTM0_CH6) ALT5=(FB_AD0) ALT6=(FTM0_FLT0) ALT7=(SPI1_SOUT) EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 7, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 136 # PTD7 # Default=(DISABLED) ALT0=() ALT1=(PTD7) ALT2=(CMT_IRO) ALT3=(UART0_TX) ALT4=(FTM0_CH7) ALT5=(SDRAM_CKE) ALT6=(FTM0_FLT1) ALT7=(SPI1_SIN) EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 8, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD__EN, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SCL 137 # PTD8/LLWU_P24 # Default=(DISABLED) ALT0=() ALT1=(PTD8/LLWU_P24) ALT2=(I2C0_SCL) ALT3=() ALT4=() ALT5=(LPUART0_RX) ALT6=(FB_A16) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 9, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD__EN, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SDA 138 # PTD9 # Default=(DISABLED) ALT0=() ALT1=(PTD9) ALT2=(I2C0_SDA) ALT3=() ALT4=() ALT5=(LPUART0_TX) ALT6=(FB_A17) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 10, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 0 }, // PSEL 139 # PTD10 # Default=(DISABLED) ALT0=() ALT1=(PTD10) ALT2=() ALT3=() ALT4=() ALT5=(LPUART0_RTS_b) ALT6=(FB_A18) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 11, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 140 # PTD11/LLWU_P25 # Default=(DISABLED) ALT0=() ALT1=(PTD11/LLWU_P25) ALT2=(SPI2_PCS0) ALT3=() ALT4=(SDHC0_CLKIN) ALT5=(LPUART0_CTS_b) ALT6=(FB_A19) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 12, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // MKW40_SPI1_SCK 141 # PTD12 # Default=(DISABLED) ALT0=() ALT1=(PTD12) ALT2=(SPI2_SCK) ALT3=(FTM3_FLT0) ALT4=(SDHC0_D4) ALT5=() ALT6=(FB_A20) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 13, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // MKW40_SPI1_SIN 142 # PTD13 # Default=(DISABLED) ALT0=() ALT1=(PTD13) ALT2=(SPI2_SOUT) ALT3=() ALT4=(SDHC0_D5) ALT5=() ALT6=(FB_A21) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 14, 0, 0, ALT2, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // MKW40_SPI1_SOUT 143 # PTD14 # Default=(DISABLED) ALT0=() ALT1=(PTD14) ALT2=(SPI2_SIN) ALT3=() ALT4=(SDHC0_D6) ALT5=() ALT6=(FB_A22) ALT7=() EZPort=()
{ PTD_BASE_PTR, PORTD_BASE_PTR, 15, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // INT 144 # PTD15 # Default=(DISABLED) ALT0=() ALT1=(PTD15) ALT2=(SPI2_PCS1) ALT3=() ALT4=(SDHC0_D7) ALT5=() ALT6=(FB_A23) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 0, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SD_D1 1 # PTE0 # Default=(ADC1_SE4a) ALT0=(ADC1_SE4a) ALT1=(PTE0) ALT2=(SPI1_PCS1) ALT3=(UART1_TX) ALT4=(SDHC0_D1) ALT5=(TRACE_CLKOUT) ALT6=(I2C1_SDA) ALT7=(RTC_CLKOUT) EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 1, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SD_D0 2 # PTE1/LLWU_P0 # Default=(ADC1_SE5a) ALT0=(ADC1_SE5a) ALT1=(PTE1/LLWU_P0) ALT2=(SPI1_SOUT) ALT3=(UART1_RX) ALT4=(SDHC0_D0) ALT5=(TRACE_D3) ALT6=(I2C1_SCL) ALT7=(SPI1_SIN) EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 2, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SD_CLK 3 # PTE2/LLWU_P1 # Default=(ADC1_SE6a) ALT0=(ADC1_SE6a) ALT1=(PTE2/LLWU_P1) ALT2=(SPI1_SCK) ALT3=(UART1_CTS_b) ALT4=(SDHC0_DCLK) ALT5=(TRACE_D2) ALT6=() ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 3, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SD_CMD 4 # PTE3 # Default=(ADC1_SE7a) ALT0=(ADC1_SE7a) ALT1=(PTE3) ALT2=(SPI1_SIN) ALT3=(UART1_RTS_b) ALT4=(SDHC0_CMD) ALT5=(TRACE_D1) ALT6=() ALT7=(SPI1_SOUT) EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 4, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SD_D3 7 # PTE4/LLWU_P2 # Default=(DISABLED) ALT0=() ALT1=(PTE4/LLWU_P2) ALT2=(SPI1_PCS0) ALT3=(UART3_TX) ALT4=(SDHC0_D3) ALT5=(TRACE_D0) ALT6=() ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 5, 0, 0, ALT4, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // SD_D2 8 # PTE5 # Default=(DISABLED) ALT0=() ALT1=(PTE5) ALT2=(SPI1_PCS2) ALT3=(UART3_RX) ALT4=(SDHC0_D2) ALT5=() ALT6=(FTM3_CH0) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 6, 0, 0, ALT6, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 9 # PTE6/LLWU_P16 # Default=(DISABLED) ALT0=() ALT1=(PTE6/LLWU_P16) ALT2=(SPI1_PCS3) ALT3=(UART3_CTS_b) ALT4=(I2S0_MCLK) ALT5=() ALT6=(FTM3_CH1) ALT7=(USB0_SOF_OUT) EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 7, 0, 0, ALT6, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 10 # PTE7 # Default=(DISABLED) ALT0=() ALT1=(PTE7) ALT2=() ALT3=(UART3_RTS_b) ALT4=(I2S0_RXD0) ALT5=() ALT6=(FTM3_CH2) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 8, 0, 0, ALT6, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 11 # PTE8 # Default=(DISABLED) ALT0=() ALT1=(PTE8) ALT2=(I2S0_RXD1) ALT3=() ALT4=(I2S0_RX_FS) ALT5=(LPUART0_TX) ALT6=(FTM3_CH3) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 9, 0, 0, ALT6, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 12 # PTE9/LLWU_P17 # Default=(DISABLED) ALT0=() ALT1=(PTE9/LLWU_P17) ALT2=(I2S0_TXD1) ALT3=() ALT4=(I2S0_RX_BCLK) ALT5=(LPUART0_RX) ALT6=(FTM3_CH4) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 10, 0, 0, ALT7, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // USB_HS_DI 13 # PTE10/LLWU_P18 # Default=(DISABLED) ALT0=() ALT1=(PTE10/LLWU_P18) ALT2=(I2C3_SDA) ALT3=() ALT4=(I2S0_TXD0) ALT5=(LPUART0_CTS_b) ALT6=(FTM3_CH5) ALT7=(USB1_ID) EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 11, 0, 0, ALT6, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 14 # PTE11 # Default=(DISABLED) ALT0=() ALT1=(PTE11) ALT2=(I2C3_SCL) ALT3=() ALT4=(I2S0_TX_FS) ALT5=(LPUART0_RTS_b) ALT6=(FTM3_CH6) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 12, 0, 0, ALT6, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 15 # PTE12 # Default=(DISABLED) ALT0=() ALT1=(PTE12) ALT2=() ALT3=() ALT4=(I2S0_TX_BCLK) ALT5=() ALT6=(FTM3_CH7) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 24, 0, 0, ALT3, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // Debug port 45 # PTE24 # Default=(ADC0_SE17) ALT0=(ADC0_SE17) ALT1=(PTE24) ALT2=(CAN1_TX) ALT3=(UART4_TX) ALT4=() ALT5=(I2C0_SCL) ALT6=(EWM_OUT_b) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 25, 0, 0, ALT3, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // Debug port 46 # PTE25/LLWU_P21 # Default=(ADC0_SE18) ALT0=(ADC0_SE18) ALT1=(PTE25/LLWU_P21) ALT2=(CAN1_RX) ALT3=(UART4_RX) ALT4=() ALT5=(I2C0_SDA) ALT6=(EWM_IN) ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 26, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_INP, 0 }, // 47 # PTE26 # Default=(DISABLED) ALT0=() ALT1=(PTE26) ALT2=(ENET_1588_CLKIN) ALT3=(UART4_CTS_b) ALT4=() ALT5=() ALT6=(RTC_CLKOUT) ALT7=(USB0_CLKIN) EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 27, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 1 }, // 48 # PTE27 # Default=(DISABLED) ALT0=() ALT1=(PTE27) ALT2=() ALT3=(UART4_RTS_b) ALT4=() ALT5=() ALT6=() ALT7=() EZPort=()
{ PTE_BASE_PTR, PORTE_BASE_PTR, 28, 0, 0, GPIO, DSE_HI, FAST_SLEW, OD_DIS, PFE_DIS, PUPD_DIS, GP_OUT, 0 }, // 49 # PTE28 # Default=(DISABLED) ALT0=() ALT1=(PTE28) ALT2=() ALT3=() ALT4=() ALT5=() ALT6=() ALT7=() EZPort=()
};
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void Config_pin(const T_IO_pins_configuration pinc)
{
pinc.port->PCR[pinc.pin_num] = LSHIFT(pinc.irqc, 16) |
LSHIFT(pinc.lock, 15) |
LSHIFT(pinc.mux, 8) |
LSHIFT(pinc.DSE, 6) |
LSHIFT(pinc.ODE, 5) |
LSHIFT(pinc.PFE, 4) |
LSHIFT(pinc.SRE, 2) |
LSHIFT(pinc.PUPD, 0);
if ( pinc.init == 0 ) pinc.gpio->PCOR = LSHIFT(1, pinc.pin_num);
else pinc.gpio->PSOR = LSHIFT(1, pinc.pin_num);
pinc.gpio->PDDR = (pinc.gpio->PDDR & ~LSHIFT(1, pinc.pin_num)) | LSHIFT(pinc.dir, pinc.pin_num);
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
int Init_pins(void)
{
int i;
// Включаем тактирование на всех портах
SIM_SCGC5 |= SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK;
for (i = 0; i < (sizeof(K66BLEZ1_pins_conf) / sizeof(K66BLEZ1_pins_conf[0])); i++)
{
Config_pin(K66BLEZ1_pins_conf[i]);
}
return 0;
}
Этого текста полностью хватает чтобы правильно настроить все выводы включая правильные номера всех альтернативных функций. Нет необходимости обращения к справочному руководству или описанию каких-либо API. Комментарии содержат много информации, но она корректная поскольку сгенерирована автоматически из мануала на чип.
Наконец в файле main.c содержится основное приложение.
Переключение светодиода всего одной строчкой — GPIOA_PTOR = BIT(1);
Макрос GPIOA_PTOR объявлен в файле MK65F18.h и представляет собой просто ссылку на адрес регистра PTOR (Port Toggle Output Register) порта A. При записи единицы в определённый бит этого регистра на соответствующей линии порта A происходит переключение логического состояния (стр. 2191. Справочное руководство: K66P144M180SF5RMV2).
А макрос BIT(x) определён мной в файле main.h и означает всего лишь (1u << x), т.е. установленный в заданной позиции бит.
(Кликнуть для увеличения)
Важно заметить, в проекте только четыре файла с исполняемым кодом. Никаких библиотек CMSIS, никаких драйверов SDK и уровня HAL. Компиляция занимает доли секунды.
Это проще чем Arduino!
Вторая строчка: DELAY_ms(20); обеспечивает прецизионную программную задержку в 20 мс. Это макрос передающий пересчитанный аргумент в функцию на ассемблере вставленную мной в файл startup_MK66F18.s. Вот её вид:
; Для Cortex-M4
; (R0+1)*7
Delay_m7
SUBS r0,r0,#1 ; 1
NOP ; 1
NOP ; 1
NOP ; 1
CMP r0,#0x00 ; 1
BGT Delay_m7 ; 2/1
NOP ; 1
NOP ; 1
NOP ; 1
NOP ; 1
BX lr ; 2
Функция выполняется количество тактов расчитываемое по формуле (R0+1)*7, где R0 — содержимое регистра R0.
Очень полезная функция как для организации точных произвольных задержек, так и для контроля быстродействия ядра и настройки тактирования с помощью дополнительных инструментов.
Загружаем приложение.
Среда IAR имеет готовые загрузчики Flash памяти для всех чипов, которые она поддерживает. Поэтому нам остаётся только подключить JTAG/SWD адаптер к модулю. IAR поддерживает много адаптеров. В их числе есть класс очень дешёвых адаптеров с прошивкой CMSIS DAP (встроен во все отладочные платы с Kinetis от NXP), можно работать через ST-Link как показано на фотографии в заголовке (вариант с гальвано изоляцией, к сожалению, с модулем не совместим). Я чаще использую J-Link, поскольку в нем присутствует виртуальный COM порт, есть поддержка Real Time Terminal (RTT), поддерживается неограниченное количество точек останова и ещё ряд полезных функций.
Тестирование времени активации программы после включения питания
Вопрос времени активации программы не праздный. Это время определяет количество энергии затрачиваемой чипом впустую на ожидание готовности и минимальный интервал времени потери контроля при непреднамеренных сбоях.
Осциллограмма, показанная ниже даёт ответ на вопрос насколько быстро после подачи питания может начать выполняться программа на микроконтроллере. Начало нарастание напряжения питания 3.3В соответствует моменту подключения кабеля USB к плате.
Как видно первые инструкции программа начинает выполнять спустя приблизительно 1.5 мс от момента подачи напряжения 5В с USB интерфейса. А на полной скорости программа начинает выполняться спустя 3 мс.
(Кликнуть для увеличения)
С какой скоростью мы можем переключать логические состояния на выводах микроконтроллера?
Здесь есть нюанс. Он заключается в том, что программа, выполняющаяся из Flash памяти, не обладает детерминизмом.
Заменим нашу первую программу на следующий код:
int main()
{
for (;;)
{
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
}
}
Это 128 команд переключения состояния светодиода.
Но осциллограмма этих переключений будет выглядеть так:
(Кликнуть для увеличения)
Странные паузы между пачками монотонных переключений — это задержки при считывании блоков кода из Flash. Flash память работает на частоте гораздо более низкой чем частота ядра, и в чипе применено некое подобие кэширования блоков по 128 байт, это соответствует 32-м командам ядра ARM. В результате монотонная пачка переключений не может быть длиннее 32-х команд, а потом возникает пауза. Стоит также отметить влияние выравнивания команд во Flash памяти если наш фрагмент не превышает 32-х команд, от этого зависит появится ли в нашем фрагменте пауза на кэширование или нет.
Ситуацию можно исправить если поместить код в RAM. Для этого надо вызов функции написать следующим образом:
__ramfunc int main()
{
for (;;)
{
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
GPIOA_PTOR = BIT(1);
.
.
.
}
}
Тогда осциллограмма будет выглядеть так:
(Кликнуть для увеличения)
А частота переключений будет такая:
(Кликнуть для увеличения)
Т.е. получаем частоту в 90 МГц на светодиоде. Это означает, что команды вывода в порт выполняются с частотой ядра.
Пример управления светодиодом по прерываниям на основе автомата состояний.
Проект находится здесь.
В данном проекте показано как инициализировать системный таймер ядра ARM (он используется для вызова периодических прерываний), как очень просто можно инициализировать UART и выводить через него текст в терминал компьютера и как задавать диаграмму сигналов светодиода простым массивом.
Традиционный стиль реализации мигания светодиодом мог бы выглядеть так в нашей программе:
for(;;)
{
GPIOA_PSOR = BIT(1); // Включить светодиод
DELAY_ms(500); // Задержка на 0.5 сек
GPIOA_PСOR = BIT(1); // Выключить светодиод
DELAY_ms(500); // Задержка на 0.5 сек
}
Сложность здесь в том, что трудно вставить ещё какую-нибудь функциональность, не нарушив задержки в состояниях светодиода и его равномерное мигание. Если бы у нас была операционная система реального времени (RTOS), то такой сложности бы не возникло. Мы бы просто поместили эту процедуру в отдельную задачу.
Но за отсутствием RTOS приходится использовать автоматы состояний.
Для работы с этим примером нужна программ эмулятор терминала на PC с поддержкой управляющих символов по спецификации VT100. Такой программой может быть, например, TeraTerm.
Автомат состояний светодиода — это функция LEDS_state_automat вызываемая из процедуры обслуживания прерывания системного таймера. Она находится в файле LED_StateMachine.c. Чтобы задать тот или иной стиль мигания светодиода вызывается функция Set_LED_pattern находящаяся в том же файле. В качестве аргумента передаём массив с состояниями и длительностями состояний светодиода, например, такого вида:
const int32_t LED_2_BLINK[] =
{
LED__ON, 5,
LED_OFF, 5,
LED__ON, 5,
LED_OFF, 35,
0, 0
}; -
Первое число в массиве это состояние (0 или 1 в нашем случае, но представленные макросами, чтобы в случае необходимости перейти на более разрядные числа для регулируемых светодиодов). Второе число — это длительность состояния в количестве циклов. Цикл — это период между прерываниями системного таймера.
Таким образом получаем управление светодиодом из прерываний с удобным способом кодирования стиля миганий и без влияния на основной цикл приложения.
Здесь хранятся все материалы, связанные с этим проектом — https://github.com/Indemsys/K66BLEZ1
Автор: Indemsys