Добрый день! Я совсем новичок, опыт с МК вообще нулевой. Сижу разбираю исходный код суть которого выдать на ногу меняющуюся последовательность сигналов ( что-то вроде 100 мс высокий, 200 низкий, 500 высокий, 300 низкий и тп), в общем генерациия радиосигнала.
Этот алгоритм работает на таймере и ДМА. Таймер запускается, а затем при каждом событии таймера с помощью ДМА меняется регистр ARR чтоб поменять длительность работы таймера на следующее значение из буфера таймингов, режим работы togle переключает сигнал на ноге по достижении очередного заданного значения счетчика.
Казалось бы все просто - досчитали такты до нужного тайминга, переключили ногу на противоположную, вызвали событие чтоб ДМА подгрузило новый тайминг и считаем такты дальше, но в коде есть строка которая немного меня запутала. TIM_OC_InitStruct.CompareValue = 0;
В моем понимании эта строка добавляет к обычному событию таймера по переполнении счетчика еще одно событие при нулевом счетчике. И фактически мы имеем 2 последовательных события вызывающих ДМА - о переполнении таймера и о его нулевом значении.
Где пробел в моих знаниях и логике ? Контроллер STM32WB55
Код:
// Configure DMA
LL_DMA_InitTypeDef dma_config = {0};
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_async_tx.buffer;
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_CIRCULAR;
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.NbData = FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL;
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
// Configure TIM2
LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
LL_TIM_SetAutoReload(TIM2, 1000);
LL_TIM_SetPrescaler(TIM2, 64 - 1);
LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_DisableARRPreload(TIM2);
// Configure TIM2 CH2
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_TOGGLE;
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.CompareValue = 0;
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH2, &TIM_OC_InitStruct);
LL_TIM_OC_DisableFast(TIM2, LL_TIM_CHANNEL_CH2);
LL_TIM_DisableMasterSlaveMode(TIM2);
LL_TIM_EnableDMAReq_UPDATE(TIM2);
LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2);
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);