Статьи

Adafruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 4. Таймер

Это  часть 4  мини-серии. В части 3 я описал концепции программного обеспечения (см. « Учебное пособие: NeoPixels Adafruit WS2812B с платой Freescale FRDM-K64F — Часть 3: Основные понятия »). В этом посте я опишу, как настроить таймер для запуска последующих операций DMA. Цель состоит в том, чтобы запустить NeoPixel от Adafruit (WS2812B) с  платой Freescale FRDM-K64F  :

Неопиксели с FRDM-K64F

Неопиксели с FRDM-K64F

Список учебников Mini Series

  1. Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 1.  Аппаратное обеспечение
  2. Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 2.  Инструменты программного обеспечения
  3. Учебное пособие: Adafruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 3.  Основные понятия
  4. Учебник. AdoPruit WS2812B NeoPixels с платой Freescale FRDM-K64F — Часть 4.  Таймер
  5. Учебник. 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. Мне нужны следующие основные файлы / папки, добавленные в мой проект:

  1. EDMA : SDK \ платформа \ src \ edma
  2. FTM : SDK \ платформа \ драйверы \ ftm
  3. GPIO : SDK \ платформа \ драйверы \ gpio

: idea:  На GitHub есть ссылка на исходники / файлы проекта.

Основные файлы SDK

Основные файлы SDK

Реальность такова, что из-за сложной структуры каталогов SDK и всех файлов HAL (Уровень аппаратной абстракции) также необходимы тонны других файлов  🙁 .

На рисунке ниже показаны все необходимые файлы:

Kinetis SDK Files

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

Добавлен 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

Блок-схема 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

Настройки Регистрации 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 от него. Так что следите за обновлениями …

Счастливого времени  🙂

ССЫЛКИ