Синхронизация вывода и обработки

Юрий48
Offline
Зарегистрирован: 19.06.2018

Прошу совета по решению такой задачи для STM32F103C8T6.

1. Надо сгенерировать и передать на выходы два квадратурных меандра частотой 12,5 кГц. Т.е. имеющих скважность 2 и сдвинутых друг относительно друга на четверть своего периода, назовём их модулятор.

2. При этом запуск АЦП надо синхронизировать относительно этих сигналов так, что бы преобразование не попадало на фронты модулятора и составляло 10 отсчётов на четверть периода. То есть это получается частота опроса 500 кГц. При преобразовании АЦП в 1 мкс (1 мГц), я так полагаю, что можно обеспечить требование 2 сдвинув запуск АЦП на 0,5 мкс относительно фронтов модулятора.

Вопрос первый. Можно ли осуществить эту задачу с такими параметрами на STM32F103C8T6 в среде ардуино?

2. Какие решения должны быть для обеспечения нужных синхронизаций?

Другая группа вопросов. Предполагаю данные с АЦП усреднять, накапливая по 100 отсчётов. Это получается выходная дискретизация измерений 125 Гц. Проводить не очень объёмную обработку и результаты передавать по последовательному порту. Ну и выводить на индикацию, скажем, с частотой 2 Гц. В связи с этим вопросы:

1. Получится ли эту часть действий сделать в фоновом режиме по отношению к первой части или на время выполнения обработки и передачи данных часть измерений может пропуститься. И в этом случае  надо будет обеспечить новый цикл измерений с выполнением всех необходимых синхронизаций?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

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

Юрий48
Offline
Зарегистрирован: 19.06.2018

andriano пишет:

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

Что надо будет использовать таймеры это и мне понятно, но совершенно не чувствую как обеспечить их синхронизацию, что бы получить сдвиг опроса 0,5 мкс относительно фронтов модулятора, да и квадратурный сдвиг сигналов модулятора.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

 квадратурный сдвиг сигналов модулятора.

квадратурный сдвиг, если я правильно понимаю, называется Push-Pull

вот как раз про это интересное обсуждение:

Complementary-pwm-i-push-pull-rezhimy

nik182
Offline
Зарегистрирован: 04.05.2015

В среде ардуино это можно обеспечить только перейдя на уровень CMSIS - т.е. только читая datasheet и прямо писать конфигурацию в регистры.  В нормальных средах все ваши запросы решаются нажиманием нескольких десятков кнопок в CUBE_MX и дописывания процедур запуска оборудования и обработки. Таймеры все тактируются от одного источника. У АЦП есть режим запуска от таймера и сброса данных по DMA. Все тайминги можно обеспечить с точностью около 0.1 мкс. Если ещё углубиться в режимы мастер-слейв таймеров то можно обеспечить практически нулевые задержки между сигналами. С АЦП надо быть осторожным. Точность на скоростях выше 100 кГц можно обеспечить только если выходное сопротивление сигнала около 50 Ом.  

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

Юрий48 пишет:

 квадратурный сдвиг сигналов модулятора.

квадратурный сдвиг, если я правильно понимаю, называется Push-Pull

вот как раз про это интересное обсуждение:

Complementary-pwm-i-push-pull-rezhimy

Ну, там больно широко и расплывчато используется понятие квадратурности. Я то его использую в обычном понимании, в смысле ортогональности, т.е. два периодических сигнала, сдвинутых по фазе на 90 градусов. Такое представление данных обеспечивает однозначность получения аргумента (фазы) в пределах периода. В моём случае это однозначное знание о номере четверти периода. А что касается генерации таких сигналов в STM32, то в той статье, может, и есть что полезное для этого, но я пока не могу с ходу это оценить.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

Ну, там больно широко и расплывчато используется понятие квадратурности.

если быть точном, оно там вообще не используется :) Автор пишет про какой-то "двухтактный режим". Но чисто практически, "квадратурный" в вашем понимании есть частный сдучай рассмотренного в статье "двухтактного" при duty = 50%. И как это формировать, там подробно описано.

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

В среде ардуино это можно обеспечить только перейдя на уровень CMSIS - т.е. только читая datasheet и прямо писать конфигурацию в регистры.  В нормальных средах все ваши запросы решаются нажиманием нескольких десятков кнопок в CUBE_MX и дописывания процедур запуска оборудования и обработки. Таймеры все тактируются от одного источника. У АЦП есть режим запуска от таймера и сброса данных по DMA. Все тайминги можно обеспечить с точностью около 0.1 мкс. Если ещё углубиться в режимы мастер-слейв таймеров то можно обеспечить практически нулевые задержки между сигналами. С АЦП надо быть осторожным. Точность на скоростях выше 100 кГц можно обеспечить только если выходное сопротивление сигнала около 50 Ом.  

Вот Вы и опять заставили меня задуматься: "В какой же среде программировать?". Если я правильно понял, то в ардуино всё же можно это оптимально осуществить, только надо более глубоко разобраться с железом, регистрами и т. д.? На АЦП сигнал пойдёт с ОУ с достаточным единичным усилением.

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

Юрий48 пишет:

Ну, там больно широко и расплывчато используется понятие квадратурности.

если быть точном, оно там вообще не используется :) Автор пишет про какой-то "двухтактный режим". Но чисто практически, "квадратурный" в вашем понимании есть частный сдучай рассмотренного в статье "двухтактного" при duty = 50%. И как это формировать, там подробно описано.

 Судя по картинкам - не получается. При duty = 50% это будут просто противофазные сигналы, а жаль - почерпнуть нечего.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

 Судя по картинкам - не получается. При duty = 50% это будут просто противофазные сигналы, а жаль - почерпнуть нечего.

Вы, по-моему, путаете. "Протифофазные" сигналы будут, если настроить комплиментарные выходы. Это первый случай, рассмотренный по ссылке. Но там же ниже есть и второй - который точно соответвует вашему - сигналы двух каналов сдвинуты четко на половину периода.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

nik182 пишет:

 В нормальных средах все ваши запросы решаются нажиманием нескольких десятков кнопок в CUBE_MX

Вот Вы и опять заставили меня задуматься: "В какой же среде программировать?".

Cube можно использовать вовсе без всякой среды - он умеет генерировать набор файлов для make. Но, конечно, gcc-toolchain все же нужен. Я несколько тестовых проектов собрал просто из Куба, без всяких IDE. Редактировать код можно в чем угодно, например в Notepad++

nik182
Offline
Зарегистрирован: 04.05.2015

Зачем делать лишние движения, если есть

https://atollic.com/truestudio/

Совершенно бесплатная, заточенная под куб и STM среда , да ещё с отладкой. Тот же gcc только более дружественный.

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

Юрий48 пишет:

 Судя по картинкам - не получается. При duty = 50% это будут просто противофазные сигналы, а жаль - почерпнуть нечего.

Вы, по-моему, путаете. "Протифофазные" сигналы будут, если настроить комплиментарные выходы. Это первый случай, рассмотренный по ссылке. Но там же ниже есть и второй - который точно соответвует вашему - сигналы двух каналов сдвинуты четко на половину периода.

Вот и получается, что при duty = 50% это будут просто противофазные сигналы. А надо то на четверть периода.

Юрий48
Offline
Зарегистрирован: 19.06.2018

b707 пишет:

Cube можно использовать вовсе без всякой среды - он умеет генерировать набор файлов для make. Но, конечно, gcc-toolchain все же нужен. Я несколько тестовых проектов собрал просто из Куба, без всяких IDE. Редактировать код можно в чем угодно, например в Notepad++

nik182 пишет:

Зачем делать лишние движения, если есть

https://atollic.com/truestudio/

Совершенно бесплатная, заточенная под куб и STM среда , да ещё с отладкой. Тот же gcc только более дружественный.

Что бы принять решение я должен разобраться с этими вариантами. Для меня совершенно новые понятия make, gcc-toolchain, truestudio, поэтому мысли разбегаются. Надо понять, что за ними стоит и как они должны взаимодействовать. Но самый первый вопрос это: "Можно ли готовые библиотеки ардуино применятьт в этих вариантах и в каком проще, технология приручения и т.д. У меня уже кое чего сдалано под ардуино. Насколько сложный перенос? Вообще, когда то лет 15 назад, совсем немного программировал в Keil для силабовских микросхем и сейчас хотел  подсесть на него. Но при общем ознакомление получилось, что использовать PackInstaller невозможно из за блокировки их сайта. Может, это сейчас и не нужно, но когда ни буть это может и ударить, поэтому пока отказался. Честно говоря всеми силами хотел увернуться от ардуино IDE, но готовые библиотеки подкупили.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

Вот и получается, что при duty = 50% это будут просто противофазные сигналы. А надо то на четверть периода.

ну да. ступил, согласен. Однако, считаю что статья все ж полезная - принцип регулирования, изложенный в ней - можно использовать и для произвольного смещения каналов друг против друга...

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 пишет:

самый первый вопрос это: "Можно ли готовые библиотеки ардуино применятьт в этих вариантах

насколько я понимаю - нет.

Но как только вы переходите на уровень CMSIS - то есть на работу напрямую с регистрами МК - ардуино библиотеки начинают только мешать. Дело в том, что проект STM32duino охватывает далеко не все возможности камня, как пример - запустить PWM с комплиментарными выводами непосредственно из ардуино не выйдет, нужны трюки с прямой записью в регистр. А поскольку в ардуино многое делается "втемную" - как только вы начинаете смешивать ардуино-либы и регистры - все может вовсе развалится.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Посмотрел вскользь связку truestudio и кубе. Чувствую, что это более для меня чем ардуино, особенно для конкретной здесь описанной задачи. Но как подумаю о подключнии дисплейчиков (LCD 1602 и в перспективе TFT), то руки опускаются. Неужели всё придётся писать с нуля, поскольку готовых решений для этих сред не нашёл, хотя пролазал весь вечер. Конечно, ещё полазаю, но, может, кто то укажет на рабочие варианты под truestudio.

nik182
Offline
Зарегистрирован: 04.05.2015

По запросу github stm32 lcd  выпадает куча ссылок на драйвера LCD. Можно выбрать на любой вкус. Подстройка под себя минимальна. 

ВН
Offline
Зарегистрирован: 25.02.2016

b707 пишет:
квадратурный сдвиг, если я правильно понимаю, называется Push-Pull

Push-Pull - вид выходного узла, т.е. это схемотехнический термин  

ВН
Offline
Зарегистрирован: 25.02.2016

Юрий48,  можно сделать достаточно примитивно в среде ардуино

в такте 4 четверьть периода, вот на четверть периода запускаете циклический таймер, ловите с него прерывание 

в прерывании переключаете выходы, одновременно ставите флаг фронта

ацп работает асинхронно, по его прерыванию, если выставлен флаг фронта,  значение ацп отбрасываете и сбрасываете флаг,

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

Юрий48
Offline
Зарегистрирован: 19.06.2018

ВН пишет:

Юрий48,  можно сделать достаточно примитивно в среде ардуино

в такте 4 четверьть периода, вот на четверть периода запускаете циклический таймер, ловите с него прерывание 

в прерывании переключаете выходы, одновременно ставите флаг фронта

ацп работает асинхронно, по его прерыванию, если выставлен флаг фронта,  значение ацп отбрасываете и сбрасываете флаг,

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

Чего чего, а асинхронность преобразования АЦП не надо. Дело в том, что обработка сигнала идёт для каждой четверти отдельно и в вашем случае придётся подсчитывать количество отсчётов для кажной четверти отдельно. Конечно это можно осуществить, но ссовершенно не рационально.

ВН
Offline
Зарегистрирован: 25.02.2016

Юрий48 пишет:
... но ссовершенно не рационально.

мда .. прикольно ... и на елку влезть и ....

рацинально через кейл, например. конфигуратор стм32 там уже давным давно был прикручен

 

Юрий48
Offline
Зарегистрирован: 19.06.2018

Вопрос по каскадному подключению таймеров. В описании увидел, что на вход тактирования таймера можно подключить выход TRGO другого таймера. А, вот, о выходе CHx подобного варианта не нашёл. А было бы очень здорово, если это возможно. Кто знает, скажите пожалуйста возможно это или нет?

a5021
Offline
Зарегистрирован: 07.07.2013

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

-NMi-
Offline
Зарегистрирован: 20.08.2018

nik182 пишет:

 если есть

Совершенно бесплатная, заточенная под куб и STM среда , да ещё с отладкой. 

Реально лучше кокоса, еклипса и кейла?

Я в плане совместимости и удобства сборки. Сами реально "гамили" в ней???

nik182
Offline
Зарегистрирован: 04.05.2015

Я не сказал лучше. Я сказал бесплатный. К тому же в отличии от кокоса поддерживает все stm32 контроллеры. А по удобству примерно одно и то же, но всё хуже IAR. Удобен тот с которым привык работать. Переход на другой, даже более удобный инструмент всегда требует время на переучивание.

Про таймеры. Один таймер может выступить в качестве источника запуска других. Режим мастер - слейв. Почитать можно в datasheet или например http://mycontroller.ru/old_site/stm32-timer-general-purpose-vneshnyaya-sinhronizatsiya/default.htm . Достаточно прочитать первые 6 абзацев.  

a5021
Offline
Зарегистрирован: 07.07.2013

nik182 пишет:
А по удобству примерно одно и то же, но всё хуже IAR. Удобен тот с которым привык работать. Переход на другой, даже более удобный инструмент всегда требует время на переучивание.

Выбор инструментов -- дело во многом субъективное, но будучи убежденным приверженцем IAR-а, в последнее время испытываю повышенный интерес к SES -- SEGGER Embedded Studio. Для некоммерческого использования он бесплатен, а по заряженности или не уступает IAR-у или превосходит. Компилятор на выбор GCC или CLANG.  Обладает уникальными фишками, которые в других средах для эмбеда мне не встречались. Например, в составе отладчика Ozone имеется профилировщик, с помощью которого можно посмотреть статистику по выполнению кода, вызовам процедур и т.п.

nik182
Offline
Зарегистрирован: 04.05.2015
Примерный код из куба. Все что находитсся между строчками user code begin ..... user code end... дописано руками. Получилось чуть больше 10 строк. Программа инициализирует железо в режимы
таймер 1 мастер. Однократное срабатывание и выдаче сигнала ITR0
таймер 2 слейв. Канал 1 выдаёт PWM mode 2 на ноге РА0. Запуск от ITR0. Период 80 мкс.
таймер 3 слейв. Канал 1 выдаёт PWM mode 1 (сдвиг на четверть периода) на ноге РА6. Запуск от ITR0. Период 80 мкс.
таймер 4 слейв. Канал 4 выдаёт PWM mode 2 выдает внутренний такт для АЦП 2мкс. Запуск АЦП через 0.5 мкс от ITR0. 
АЦП через DMA сохраняет в массиве 2000 точек и останавливает таймеры в прерывании. 
Программа работае 4 мс и останавливается до перезапуска. 
 
Не знаю как прикрепить рапорт из куба, поэтому ссылка на PDF mail.ru: https://cloud.mail.ru/public/7RLb/Y2BRytafn
( что бы увидеть файл в конце ссылки удалить все символы с %)
Generate build reports...
Print size information
   text    data     bss     dec     hex filename
   7572      20    5940   13532    34dc timers.elf
Print size information done
Generate listing file
Output sent to: timers.list
Generate listing file done
Generate build reports done
arm-atollic-eabi-objcopy.exe -O ihex timers.elf timers.hex 
 
22:19:58 Build Finished (took 13s.137ms)

/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim4;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define ADCCONVERTEDVALUES_BUFFER_SIZE ((uint32_t)  2000)
__IO uint16_t   aADCConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE];

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM4_Init(void);
static void MX_ADC1_Init(void);

void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
                                
                                

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */



/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  *
  * @retval None
  */
int main(void)
{
  /* USER CODE BEGIN 1 */



  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */

  if (HAL_ADC_Start_DMA(&hadc1,
                                   (uint32_t *)aADCConvertedValues,
                                    ADCCONVERTEDVALUES_BUFFER_SIZE
                                  ) != HAL_OK)
  {
    /* Start Error */
    Error_Handler();
  };

  if (HAL_TIM_OC_Start(&htim4,TIM_CHANNEL_4) != HAL_OK)
  {
    /* Counter Enable Error */
    Error_Handler();
  };

  if (HAL_TIM_Base_Start(&htim1) != HAL_OK)
{
/* Counter Enable Error */
Error_Handler();
};

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* ADC1 init function */
static void MX_ADC1_Init(void)
{

  ADC_ChannelConfTypeDef sConfig;

    /**Common config 
    */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T4_CC4;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_7CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/* TIM1 init function */
static void MX_TIM1_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 71;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 100;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/* TIM2 init function */
static void MX_TIM2_Init(void)
{

  TIM_SlaveConfigTypeDef sSlaveConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 79;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;
  if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM2;
  sConfigOC.Pulse = 40;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  HAL_TIM_MspPostInit(&htim2);

}

/* TIM3 init function */
static void MX_TIM3_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_SlaveConfigTypeDef sSlaveConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 71;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 79;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
  sSlaveConfig.InputTrigger = TIM_TS_ITR0;
  if (HAL_TIM_SlaveConfigSynchronization(&htim3, &sSlaveConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 40;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  HAL_TIM_MspPostInit(&htim3);

}

/* TIM4 init function */
static void MX_TIM4_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 71;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 1;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM2;
  sConfigOC.Pulse = 1;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/** 
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle)
{

	  if (HAL_TIM_Base_Stop(&htim4) != HAL_OK)
	{
	/* Counter Enable Error */
	Error_Handler();
	};
	  if (HAL_TIM_Base_Stop(&htim2) != HAL_OK)
	{
	/* Counter Enable Error */
	Error_Handler();
	};
	  if (HAL_TIM_Base_Stop(&htim3) != HAL_OK)
	{
	/* Counter Enable Error */
	Error_Handler();
	};

}


/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 

 

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

Примерный код из куба.

Ну, это так неожиданно, огромное спасибо, тронут. А я, как слепой котёнок, уж попробовал потыкаться в Кубе. Вот теперь точно пришпилили меня к Кубу и иже с ним. А в чём проблема, что сам проект то не скинули? Завтра вечерком буду разбираться, всего то у меня на это дело пару тройку часов вечером. Вообще то я не планировал иметь массив, хотя на этапе отладки и не плохо посмотреть сигнал. В окончательном варианте вместо массива думается иметь всего четыре 32-х разрядных ячейки (для каждой четверти отдельно) куда по ходу дела будут суммироваться по прерываниям значения АЦП. То есть надо будет иметь прерывания не только по завершения преобразования АЦП, но и формировать их по четвертям. Вот написал это и задумался, а, может, всё же массив рациональнее? Если память не поджимает, то и фиг с ним. А Вы как думаете? Даа, вот это подарок к началу Рождественского поста.

nik182
Offline
Зарегистрирован: 04.05.2015

А смысл во всём проекте? Я не знаю вашей задачи, просто показал что можно синхронно запустить 3 таймера. Вообще вам хватит двух. Один может двумя каналами выдавать меандры, второй тактовать АЦП. Создайте новый проект в кубе, заинициализируйте всё тоже оборудование как в рапорте и в следующий раз не бУдите тыркаться как слепой котёнок. Памяти много. Массив можно раз в 5 увеличить. Вот с обработкой в реальном времени при таких скоростях оцифровки могут возникнуть проблемы. Опять же без знания конечной задачи трудно что то посоветовать.

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:
Создайте новый проект в кубе, заинициализируйте всё тоже оборудование как в рапорте

Так и сделал. Конечно это лучше, а то можно и на шею сесть. Но что меня задолбало, так это то, что не смог открыть кубовский проект в Atollic, просто стыдоба. Продолбался пол вечера, так и ничего не смог сделать и "счас взорвусь, как 1000 тонн тротила".

И что только не делал, а в колонке Import as не появляется долгожданного "TrueSTUDIO project", совсем тупой стал. А структура файлов такая:

Ничего не могу понять. Казалось бы проблема выеденного яйца не стоит.

nik182
Offline
Зарегистрирован: 04.05.2015

Не надо ничего импортировать. Открываем свойства проекта. Пишем папку проектов (или оставляем по умолчанию), даем имя проекту, выбираем ide truestudio. Закрываем свойства, нажимаем кнопку генерация проекта. Куб генерит и в конце предлагает открыть проект в true studio. 

Юрий48
Offline
Зарегистрирован: 19.06.2018

Как и следовало ожидать - сам дурак. Надо было подкачать зтот самый генератор. Сейчас всё сгенерилось и в конце, как вами и указывалось, предложено было открыть проект в true studio, true studio открылось, но ничего в нём не отобразилось, хотя в папке появилось куча новых файлов. Разбираться уже нет сил - завтра. Всё же скольно нужно времени и нервов, что бы настроить среду, казалось бы полностью заточенную под требуемую задачу.

nik182
Offline
Зарегистрирован: 04.05.2015

Как это не открылось? А слева на панели? Там список загруженных проектов. Щелкаете по нужному иразворачивается список папок и файлов. Выбираете нужный (main.c) и отрываете.

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:
Как это не открылось? А слева на панели? Там список загруженных проектов. Щелкаете по нужному иразворачивается список папок и файлов. Выбираете нужный (main.c) и отрываете.

Как то так. Хотя, судя по заголовку, проект тот и файлов в нём до фига, в том числе и main.c.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Пока не решён этот заколдун с Atollic, с которым я не знаю, что делать, отвлёкся на изучение программы. Первое, что заинтересовало так это сдвиг на четверть периода. Вы (nik182), пишите: "таймер 3 слейв. Канал 1 выдаёт PWM mode 1 (сдвиг на четверть периода)". Вот это я никак не могу понять, поскольку в AN4013 написано:

2.5 Timer PWM mode
The timer is able to generate PWM in edge-aligned mode or in center-aligned mode with a frequency determined by the value of the TIMx_ARR register, and a duty cycle determined by the value of the TIMx_CCRx register.
PWM mode 1
• In up-counting, channelx is active as long as CNT< CCRx, otherwise it is inactive.
• In down-counting, channelx is inactive as long as CNT> CCRx, otherwise it is active.
PWM mode 2
• In up-counting, channelx is inactive as long as CNT < CCRx, otherwise it is active.
• In down-counting, channelx is active as long as CNT > CCRx, otherwise it is inactive.
Note:Active when OCREF = 1, inactive when OCREF = 0.

То есть, если я правильно понимаю, то это просто инверсные сигналы. Если это так, то чисто умозрительно вижу такой вариант решения. Перед общим запуском в один счётчик записывать 0, а в другой значение, соответствующее сдвигу на четверть периода. Сейчас полезу искать есть ли такая возможность в этом кристале. Если кто знает, то пожалуйста отпишитесь, лишним не будет.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Пока такой возможности не обнаружил, но в процессе поиска пришла такая идея, на мой взгляд очень даже хорошая. Теперь надо писать, а "лопата" погнута. Хоть переходи к другой. Ну, что с ней может быть такое?

nik182
Offline
Зарегистрирован: 04.05.2015

Посмотрите здесь чем различаются две моды PWM https://arm-stm.blogspot.com/2014/12/timer-pwm-mode.html . Возможно у таймера в моде PWM2 надо уменьшить порог в два раза - он считает вверх - вниз. Но я точно помню что у меня получалось делать сдвинутые на четверть периода сигналы именно этими двумя модами. К сожелению я только после следующих выходных доеду до осцилографа и проверю точно цифры.

Раздвинте колонку проект в студии и увидите все файлы. Щелчок по файлу отрывает его в редакторе. Две правые панели можно закрыть без ущерба для дела.     

Юрий48
Offline
Зарегистрирован: 19.06.2018

nik182 пишет:

Посмотрите здесь чем различаются две моды PWM https://arm-stm.blogspot.com/2014/12/timer-pwm-mode.html . Возможно у таймера в моде PWM2 надо уменьшить порог в два раза - он считает вверх - вниз. Но я точно помню что у меня получалось делать сдвинутые на четверть периода сигналы именно этими двумя модами. К сожелению я только после следующих выходных доеду до осцилографа и проверю точно цифры.

Вот эта то картинка и привела меня к мысле, изложенной в посте 36. Если PWM mode 1 и PWM mode 2 как раз и есть выравнивание по фронту и по центру, то тогда всё стыкуется, но это не соответствует описанию, приведённому в посте 35. Где то что то не то. Правда в настройках PWM Generation Chennel есть два параметра со словом mode, это просто mode с вариантами PWM mode 1 или PWM mode 2 и параметр Fast Mode с вариантом Disable или Enable. Если знаете, то раскажите, пожалуйста, что есть что.

Цитата:

Раздвинте колонку проект в студии и увидите все файлы. Щелчок по файлу отрывает его в редакторе. Две правые панели можно закрыть без ущерба для дела.     

Да уж конечно подвигал всем, чем мог. Но и тут что то не то.

nik182
Offline
Зарегистрирован: 04.05.2015

К меня выглядит так.

mixail844
Offline
Зарегистрирован: 30.04.2012

 

в Atollic  генерируемый проeкт в первый раз добавляеться через File->Import..->General->Existing Project Into Workspace.

найти папку  куда CubeSTM32 сгенерировал проэкт и импортировать (естественно убедиться что сам CubeMX сгенерировал проект для AtollicStudio)

импортировать можно двумя способами :

1.с копированием проекта в Workspace (Галочка "Copy projects into workspace" отмечена )отркрытый в даный момент в AtollicStudio(скопируеться все,включая исходный файл CubeMХ,который потом можно открыть и последующие генерации будут вноситься сразу в проект,без импортирования)

2.создать/скопировать ссылки на проект(Галочка "Copy projects into workspace" не отмечена ) (наверное удобно когда 2 или более проекта делят между собой какие то общие ресурсы,например графические библиотеки и ненадо копировать по многу раз,наверное еще есть случаи..но сейачс не об этом )

важное замечаение 1 : если вы создали Atollic's Workspace в том месте где сгенерировали проект CubeMX,то при импортировании галочка "Copy .. " будет неактивна,но импортирование возможно,тогда будет просто как в п.1

важное замечание 2 : генерируя код,CubeMX в самом коде создает коментарии типа 

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

 между этих полей  и стоит писать свой код - только в этом случае CubeMX гарантирует что пользовательский код при последующих генерациях кода небудет удален .так же CubeMX не удаляет добавленные пользователем файлыв ручную.

mixail844
Offline
Зарегистрирован: 30.04.2012

Юрий48]</p> <p>[quote=nik182 пишет:

Вот эта то картинка и привела меня к мысле, изложенной в посте 36. Если PWM mode 1 и PWM mode 2 как раз и есть выравнивание по фронту и по центру, то тогда всё стыкуется, но это не соответствует описанию, приведённому в посте 35. Где то что то не то. Правда в настройках PWM Generation Chennel есть два параметра со словом mode, это просто mode с вариантами PWM mode 1 или PWM mode 2 и параметр Fast Mode с вариантом Disable или Enable. Если знаете, то раскажите, пожалуйста, что есть что.

PWM mode 2 = Clear on compare match

PWM mode 1 = Set on compare match

так в же настройках таймера есть настройка polarity : High/Low , совмещая с PWM mode получаються разные вариации из "вначале на выходе 0,при совпадении Counter и CCR переходит в 1" и наоборот "вначале на выходе 1,при совпадении Counter и CCR переходит в 0"

mixail844
Offline
Зарегистрирован: 30.04.2012

Юрий48 пишет:

То есть, если я правильно понимаю, то это просто инверсные сигналы. Если это так, то чисто умозрительно вижу такой вариант решения. Перед общим запуском в один счётчик записывать 0, а в другой значение, соответствующее сдвигу на четверть периода. Сейчас полезу искать есть ли такая возможность в этом кристале. Если кто знает, то пожалуйста отпишитесь, лишним не будет.

это варианть,надо подумать.

вы можете писать в счетчик непосредственно в коде ,допустим вы выбрали Timer1 в качестве источника сигнала и насторили на частоту 1Mhz то есть каждый "тик" таймера = 1мкс ,обратиться к его счетчку можно так : 

htim1.Instance->CNT = value;

кстати, в некоторых таймерах есть фунционал ,когда у одного таймера настраиваються 2 канала со сдвигом ..но это я не помню - смотреть надо.

 

 

mixail844
Offline
Зарегистрирован: 30.04.2012

Юрий48 пишет:

Посмотрел вскользь связку truestudio и кубе. Чувствую, что это более для меня чем ардуино, особенно для конкретной здесь описанной задачи. Но как подумаю о подключнии дисплейчиков (LCD 1602 и в перспективе TFT), то руки опускаются. Неужели всё придётся писать с нуля, поскольку готовых решений для этих сред не нашёл, хотя пролазал весь вечер. Конечно, ещё полазаю, но, может, кто то укажет на рабочие варианты под truestudio.

true studio отлично работает сязыком C,ненадо никаки ардуино библиотек. А для более менее популярных моделей экранов (1602 (набор команд HD44780) или графических эранов можно легко найти Cи-шную библиотеку где нужно будет указать интерфейс общения (parallel 4/8 bit или SPI) с экраном.

mixail844
Offline
Зарегистрирован: 30.04.2012

вообщем почитал я  тут статью : http://www.micromouseonline.com/2016/02/05/clock-pulses-with-variable-phase-stm32/

и получаеться ненужен режим ШИМ, достаточно настроить OutputCompare .в статье описан код на старой StdPeriph библиотеке.

но судя по графикам в начале статьи,это то что надо.

на камне STM32F103C8T6 можно сделать на Timer2

Изначальная такировка Timer2 :  72Mhz

 

"-1" это только для наглядности , сам камень , когда будет использовать prescaler ,добавит + 1 (24 - 1 +1) ибо на 0 делить нельзя. 

по моей задумке : сам таймер настроен на частоту 72 / 3 = 24 Mhz , он будет считать до значения CouterPeriod(24) ,это случиться ровно через 1 мкс после начала счета т.к. 1/(72Мhz/3/24) = 1мкс.

соответственно вывод TIM_CH1 переключиться (toggle) через 6/24 = 0.25 мкс от начала счета.а вывод TIM_CH2 после 18/24  = 0.75 мкс ,между ними разница как раз 0.5 мкс.затем таймер досчитает до 24 и обнулиться, и начнет считать даельше,дойдя до значения 6 и 18, TIM_CH1 и TIM_CH2 соответсвенно опять переключиться (toggle) и такой цикл продолжиться.

p.s. никогда в таком режиме таймеры не запускал,поэтому сказать как оно все будет на самом деле сказать немогу.может надо будет с настройками Trigger Event "поиграться" . но тайминги вроде норм.

b707
Offline
Зарегистрирован: 26.05.2017

Юрий48 - как вариант - вашу задачку можно решить вообще "вручную"

На любом таймере настраиваете прерывание с периодом в 1/4 ваших сигналов - а дальше в прерывании просто тупо включаете и выключаете нужные выходы. Некрасиво... но как бонус - смещение сигналов в этом случае можно сделать абсолютно произвольным

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Как говорил Шерлок Холмс -дело на одну трубку :)

void setup() {
pinMode(PA8,PWM); 
pinMode(PA9,PWM); 
TIMER1_BASE->CCER=(1<<4)|(1<<0);//cc1e/cc2e enable 
TIMER1_BASE->CCMR1=(1<<13)|(1<<12)|(1<<5)|(1<<4);//toogle mode 
TIMER1_BASE->PSC=0;
TIMER1_BASE->ARR=2879;
TIMER1_BASE->CCR1=0 ;
TIMER1_BASE->CCR2=1439 ;
TIMER1_BASE->CR1=1;

}

void loop() {}

C АЦП-шкой я не так хорошо дружу, там уже головой думать нужно...

Юрий48
Offline
Зарегистрирован: 19.06.2018

mixail844 пишет:
в Atollic  генерируемый проeкт в первый раз добавляеться через File->Import..->General->Existing Project Into Workspace.

найти папку  куда CubeSTM32 сгенерировал проэкт и импортировать (естественно убедиться что сам CubeMX сгенерировал проект для AtollicStudio)

импортировать можно двумя способами :

1.с копированием проекта в Workspace (Галочка "Copy projects into workspace" отмечена )отркрытый в даный момент в AtollicStudio(скопируеться все,включая исходный файл CubeMХ,который потом можно открыть и последующие генерации будут вноситься сразу в проект,без импортирования)

2.создать/скопировать ссылки на проект(Галочка "Copy projects into workspace" не отмечена ) (наверное удобно когда 2 или более проекта делят между собой какие то общие ресурсы,например графические библиотеки и ненадо копировать по многу раз,наверное еще есть случаи..но сейачс не об этом )

Ну и наплясался с первым входом и ещё пляски не закончились. Запустил Atollic, вышло окно, в котором выбрал свой проект.

Открыл его - ничего нет. Начал делать по первому варианту - указал проект, нажал Finish, вышло окно с сообщением "some projects cannot be imported because they already exist in the workspace or their project description file is corrupted". Перезапустил Atollic. В выпавшем окне указал нечто фиктивное.

Опять открылся пустой Atollic, но это и понятно. Повторил действия с первым вариантом и проект открылся, что очень обрадовало. Решил перезапуститься и опять нифига. И теперь самое интересное - перезапустился с "нечто фиктивным", см. последнюю картинку. Открылся мой проект с именем "л", хотя в структуре файлов файла с такм именем нет.

Наверно, работать можно, но как к этому относится? Что ещё придумает этот Atollic, где подставит ногу. Но самое вероятное, что сам что то натворил, тогда как исправить? Даааа, сколько ещё буду танцевать с бубном. А мне уже больше нравится смотреть, как танцуют другие.

Юрий48
Offline
Зарегистрирован: 19.06.2018

mixail844 пишет:

вообщем почитал я  тут статью : http://www.micromouseonline.com/2016/02/05/clock-pulses-with-variable-phase-stm32/

и получаеться ненужен режим ШИМ, достаточно настроить OutputCompare .в статье описан код на старой StdPeriph библиотеке.

но судя по графикам в начале статьи, это то что надо.

Спасибо, с этим понятно, может, я его и применю. Но пока мне больше по душе вариант nik182. Мне кажется, что он более устойчив ко всяким сбоям.

b707 пишет:

На любом таймере настраиваете прерывание с периодом в 1/4 ваших сигналов - а дальше в прерывании просто тупо включаете и выключаете нужные выходы. Некрасиво... но как бонус - смещение сигналов в этом случае можно сделать абсолютно произвольным

Этот вариант первый что пришёл мне в голову. Но, если я правильно представляю, то здесь надо допиливать уже на программном уровне, что минус по отношению к остальным.

dimax, вам спасибо тоже. Наверняка пригодится.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Вопрос к nik182. У вас в main.c в строке 438 sConfigOC.OCMode = TIM_OCMODE_PWM2; стоит PWM2, а по Report mode равно PWM mode 1. Чему верить? Конечно со временем сам разберусь, но сейчас голова просто раскалывается. Это всё truestudio.

nik182
Offline
Зарегистрирован: 04.05.2015

Верить main.c .Рапорт более ранней версии. Да и тики таймера с PWM2 я ещё не проверил.