Это часть 4 мини-серии. В части 3 я описал концепции программного обеспечения (см. « Учебное пособие: NeoPixels Adafruit WS2812B с платой Freescale FRDM-K64F — Часть 3: Основные понятия »). В этом посте я опишу, как настроить таймер для запуска последующих операций DMA. Цель состоит в том, чтобы запустить NeoPixel от Adafruit (WS2812B) с платой Freescale FRDM-K64F :
Неопиксели с FRDM-K64F
Список учебников Mini Series
- Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 1. Аппаратное обеспечение
- Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 2. Инструменты программного обеспечения
- Учебное пособие: Adafruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 3. Основные понятия
- Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 4. Таймер
- Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 5. DMA
Контур
В этой статье я объясню, как использовать FTM (модуль Flex Timer) Kinetis для генерации 3 сигналов, описанных в предыдущей статье (см. « Учебное пособие: NeoPixels Adafruit WS2812B с платой Freescale FRDM-K64F — Часть 3: Основные понятия ») , Чтобы иметь возможность проверять формы сигналов, я настраиваю таймер для переключения внешних выводов в режиме ШИМ, чтобы я мог проверять сигналы. Я использую Kinetis Design Studio V3.0.0 с Kinetis SDK V1.2.
Добавление файлов Kinetis SDK
Хотя DMA будет рассмотрено в следующей статье, я добавляю все необходимые файлы в проект. Я предпочитаю копировать файлы в мой проект: копировать файлы и папки из установки SDK в структуру проекта Eclipse. Мне нужны следующие основные файлы / папки, добавленные в мой проект:
- EDMA : SDK \ платформа \ src \ edma
- FTM : SDK \ платформа \ драйверы \ ftm
- GPIO : SDK \ платформа \ драйверы \ gpio
: idea: На GitHub есть ссылка на исходники / файлы проекта.
Основные файлы SDK
Реальность такова, что из-за сложной структуры каталогов SDK и всех файлов HAL (Уровень аппаратной абстракции) также необходимы тонны других файлов ? .
На рисунке ниже показаны все необходимые файлы:
Kinetis SDK Files
Из-за этого большого количества каталогов, мне нужно добавить папки в компилятор, включая настройки пути :-(:
: idea: Я надеюсь, что в будущем SDK будет только одной исходной папкой и одной папкой для заголовочных файлов.
Поэтому в настройках проекта мне нужно настроить пути включения:
: idea: На GitHub есть ссылка на исходники / файлы проекта.
Компилятор включает пути
: idea: Другой вариант — использовать Processor Expert: Processor Expert будет знать, какие файлы необходимы, и автоматически добавлять их в проект и обновлять настройки проекта. Но поскольку Маня не хотел использовать Processor Expert, сейчас все гораздо сложнее. Это все твоя вина, Маня! ?
Для справки (вы можете скопировать и вставить строки в настройки проекта), вот мои пути включения:
"../Sources"
"../Project_Settings/Startup_Code"
"../SDK/platform/CMSIS/include"
"../SDK/platform/hal/src/mcg"
"../SDK/platform/hal/src/ftm"
"../SDK/platform/drivers/inc"
"../SDK/platform/system/src/clock"
"../SDK/platform/drivers/src/gpio"
"../SDK/platform/devices"
"../SDK/platform/system/src/clock/MK64F12"
"../SDK/platform/drivers/src/edma"
"../SDK/platform/drivers/src/ftm"
"../SDK/platform/hal/src/gpio"
"../SDK/platform/hal/src/osc"
"../SDK/platform/hal/src/dmamux"
"../SDK/platform/system/inc"
"../SDK/platform/system/src/interrupt"
"../SDK/platform/osa/src"
"../SDK/platform/hal/src/edma"
"../SDK/platform/osa/inc"
"../SDK/platform/hal/src/sim/MK64F12"
"../SDK/platform/hal/inc"
"../SDK/platform/hal/src/port"
: idea: Я использую относительные пути проекта («../SDK/», потому что я хочу, чтобы мой проект был автономным от установки Kinetis SDK.
Конфигурация часов и таймера
Следующее — два определения, которые мне нужно добавить в настройки препроцессора компилятора:
CLOCK_SETUP
"FSL_OSA_BM_TIMER_CONFIG=0"
Препроцессор Определяет
Первый включает 60 МГц периферийные / системные часы во время запуска, второй говорит, что я не хочу и не нуждаюсь в таймере для уровня OS-Awareness.
Добавление файлов DMAPixel
Время начать с кодирования ? . Я хочу сохранить все мои низкоуровневые таймеры и DMA в модуле DMAPixel . Поэтому я создаю (используйте контекстное меню для папки, затем New> Header File и New> Source File ) файлы DMAPixel.c и DMAPixel.h :
Добавлен DMAPixel
Интерфейс на данный момент очень прост, просто процедура инициализации:
#ifndef SOURCES_DMAPIXEL_H_
#define SOURCES_DMAPIXEL_H_
/*! \brief Initialize the timer and DMA */
void DMA_Init(void);
#endif /* SOURCES_DMAPIXEL_H_ */
Процедура инициализации на данный момент выглядит следующим образом:
void DMA_Init(void) {
InitHardware();
ResetFTM(FTM0_IDX);
StartStopFTM(FTM0_IDX, true); /* start FTM timer */
for(;;) {
/* for test only, let the FTM run */
}
}
Инициализация оборудования
Я собираюсь использовать PTC1, PTC2 и PTC3 как переключатели / выходные контакты таймера. Я должен синхронизировать периферийный домен для порта C с помощью SIM_HAL_EnableClock () . С InitFlexTimer () таймер инициализируется (охватит это позже). И, наконец, три пина должны быть смешаны:
static void InitHardware(void) {
/* Enable clock for PORTs */
SIM_HAL_EnableClock(SIM, kSimClockGatePortC);
/* Setup board clock source. */
g_xtal0ClkFreq = 50000000U; /* Value of the external crystal or oscillator clock frequency of the system oscillator (OSC) in Hz */
g_xtalRtcClkFreq = 32768U; /* Value of the external 32k crystal or oscillator clock frequency of the RTC in Hz */
/* FTM and FTM Muxing */
InitFlexTimer(FTM0_IDX);
PORT_HAL_SetMuxMode(PORTC,1UL,kPortMuxAlt4); /* use PTC1 for channel 0 of FTM0 */
PORT_HAL_SetMuxMode(PORTC,2UL,kPortMuxAlt4); /* use PTC2 for channel 1 of FTM0 */
PORT_HAL_SetMuxMode(PORTC,3UL,kPortMuxAlt4); /* use PTC3 for channel 2 of FTM0 */
}
Блок-схема FTM
На рисунке ниже показан FTM (модуль Flex Timer) K64F:
Блок-схема FTM
Существует выбор часов (CLKS), который выбирает источник часов. В качестве входных часов я собираюсь использовать системные часы с тактовой частотой 60 МГц и прескалером 1
Чтобы получить период 1,25 мкс, я использую значение совпадения таймера 0x4B:
(1/60'000'000)/0.00000125 = 75 = 0x4B
Соответствующие значения для каналов:
- Канал 0: 0x10
- Канал 1: 0x2A
- Канал 2: 0x40
Я буду использовать эти значения в инициализации таймера, которая будет дальше.
Инициализация таймера FTM
Следующая функция инициализирует таймер. Он использует Kinetis SDK API для инициализации периферийного устройства и его настройки.
/* FTM related */
#define NOF_FTM_CHANNELS 3 /* using three FTM0 channels, running with 60 MHz system clock */
#define FTM_CH0_TICKS (0x10) /* delay until 0xFF */
#define FTM_CH1_TICKS (0x2A) /* at 0.4us write data */
#define FTM_CH2_TICKS (0x40) /* at 0.8us clear bits */
#define FTM_PERIOD_TICKS (0x4B) /* 1.25 us period */
static void InitFlexTimer(uint32_t instance) {
ftm_pwm_param_t flexTimer0_ChnConfig0 = { /* FTM channel configuration */
.mode = kFtmEdgeAlignedPWM,
.edgeMode = kFtmHighTrue,
.uFrequencyHZ = 1000U, /* dummy value, will change it later on */
.uDutyCyclePercent = 10U, /* dummy value, will change it later on */
.uFirstEdgeDelayPercent = 0U,
};
ftm_user_config_t flexTimer0_InitConfig0 = {
.tofFrequency = 0U,
.isWriteProtection = false, /* FTM is not write protected */
.BDMMode = kFtmBdmMode_00, /* default mode for debug: timer will be stopped, can modify registers */
.syncMethod = (uint32_t)(kFtmUseSoftwareTrig) /* using software synchronization */
};
FTM_Type *ftmBase = g_ftmBase[instance];
/* initialize the driver */
FTM_DRV_Init(instance, &flexTimer0_InitConfig0); /* initialize the driver with a default configuration */
FTM_DRV_SetTimeOverflowIntCmd(instance, false); /* disable interrupt */
FTM_DRV_SetFaultIntCmd(instance, false); /* disable interrupt */
FTM_DRV_SetClock(instance, kClock_source_FTM_SystemClk, kFtmDividedBy1); /* use system clock with a divider of 1 */
/* configure timer */
FTM_HAL_ClearTimerOverflow(ftmBase); /* clear timer overflow */
/* enable PWM mode for the channels */
FTM_HAL_EnablePwmMode(ftmBase, (ftm_pwm_param_t*)&flexTimer0_ChnConfig0, 0);
FTM_HAL_EnablePwmMode(ftmBase, (ftm_pwm_param_t*)&flexTimer0_ChnConfig0, 1);
FTM_HAL_EnablePwmMode(ftmBase, (ftm_pwm_param_t*)&flexTimer0_ChnConfig0, 2);
/* based on Ref manual, in PWM mode CNTIN is to be set 0*/
FTM_HAL_SetCounterInitVal(ftmBase, 0);
/* set the module counters */
FTM_HAL_SetMod(ftmBase, FTM_PERIOD_TICKS);
FTM_HAL_SetChnCountVal(ftmBase, 0, FTM_CH0_TICKS);
FTM_HAL_SetChnCountVal(ftmBase, 1, FTM_CH1_TICKS);
FTM_HAL_SetChnCountVal(ftmBase, 2, FTM_CH2_TICKS);
}
: idea: Вы можете заметить, что я использую много низкоуровневых вызовов API HAL (Hardware Abstraction Layer) Kinetis SDK, и * не * большую часть API SDK. Причина в том, что существующий API в V1.2 не позволяет настраивать три канала без их запуска, помимо прочего мне нужно, чтобы они работали с DMA.
Проверка регистров FTM
Хороший способ взглянуть на значения регистра FTM — это, конечно, прочитать справочное руководство ? . Но еще один хороший способ — использовать средство просмотра реестра (см. « Обновленное средство просмотра Eclipse EmbSysReg с дополнительными файлами SVD Freescale ») в Eclipse:
Настройки Регистрации FTM
: idea: Будьте осторожны с тем, что вы отображаете в представлении регистров, поскольку чтение некоторых битов и периферийных устройств может иметь побочные эффекты. Я когда-то читал слишком много регистров, остановил работу FTM. Закройте представление и снова откройте его, чтобы решить проблему, если вы больше не помните, какие регистры вы читаете.
Запуск таймера FTM
Код выше только инициализирует таймер. Начинается с
StartStopFTM(FTM0_IDX, true); /* start FTM timer */
С реализацией, как показано ниже:
static void StartStopFTM(uint32_t instance, bool startIt) {
FTM_Type *ftmBase = g_ftmBase[instance];
if (startIt) {
FTM_HAL_SetClockSource(ftmBase, kClock_source_FTM_SystemClk); /* clock timer */
} else {
FTM_HAL_SetClockSource(ftmBase, kClock_source_FTM_None); /* disable clock */
}
}
Поэтому все, что он делает, это либо синхронизирует FTM, либо отключает тактирование для него.
Звонок с основного ()
Чтобы проверить мои таймеры, я должен вызвать DMA_Init () из main ():
#include "fsl_device_registers.h"
#include "DMAPixel.h"
int main(void) {
int i = 0;
DMA_Init();
for (;;) {
i++;
}
/* Never leave main */
return 0;
}
Тестирование сигналов таймера
Таким образом, с помощью логического анализатора я могу убедиться, что каналы таймера работают правильно:
Зондирование сигналов с помощью логического анализатора
И действительно, они хорошо выглядят ?
Форма волны и время
Резюме
В этой статье я использую Kinetis SDK с Kinetis Design Studio для генерации 3 сигналов с использованием 3 каналов Kinetis FTM (Flex Timer Module). Kinetis SDK предоставляет множество драйверов, но в то же время требует обучения. К сожалению, в SDK не было функций, которые я ожидал, например, чтобы FTM мог правильно инициализировать несколько каналов и запустить его. Это легко возможно с Processor Expert, который Маня не хотел использовать, поэтому мне пришлось в конечном итоге использовать макросы и методы HAL. Хорошая вещь с этим подходом HAL — то, что я легко могу обойти SDK и приблизиться к голому металлу. Я все еще могу использовать функции SDK для вдохновения, но вместо этого использую HAL. По крайней мере, для этого проекта, который работал для меня. Все еще,использовать SDK с Processor Expert намного проще, так как он занимается настройкой проекта и добавлением всех файлов в проект.
Источники проекта можно найти на GitHub:
https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_NeoPixel_SDK
В следующем посте я объясню, как вызывать запросы DMA от него. Так что следите за обновлениями …
Счастливого времени ?
ССЫЛКИ
- Руководство Adafruit по NeoPixels: https://learn.adafruit.com/adafruit-neopixel-uberguide/overview
- Плата Freescale Freedom FRDM-K64F: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-K64F
- Студия дизайна Freescale Kinetis: http://www.freescale.com/kds
- Freescale Kinetis SDK: http://www.freescale.com/kds
- Справочное руководство по подсемейству K64 (K64P144M120SF5RM): http://cache.freescale.com/files/microcontrollers/doc/ref_manual/K64P144M120SF5RM.pdf
- Проект на GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/FRDM-K64F120M/FRDM-K64F_NeoPixel_SDK