Uso la placa STM32F031 y soy un principiante.
Quiero copiar los valores de la tabla sinusoidal directamente en el periférico TIM- > CCRx.
Uso 2 temporizadores, uno para generar PWM y el otro como captura de salida para generar eventos.
Para generar PWM para el control del motor, uso 3 punteros a una tabla sinusoidal (distancia constante entre ellos. 1/3 cada uno) y en cada evento del temporizador copio los valores de la tabla en la memoria en los registros CCR1 / 2/3 del temporizador .
Este proceso lleva mucho tiempo debido a la interrupción generada y la entrada a la función TIMx_IRQHandler () (que copia los valores de la tabla a los registros).
Quiero ahorrar tiempo a la CPU sin molestarme en copiar estos valores en cada evento del temporizador. Y lo más importante es no ingresar un IRQHandler () con la CPU (para ahorrar tiempo de "cambio de contexto", etc.)
¿Cómo puedo configurar el DMA y el TIMx (evento generador) para que el temporizador genere de forma independiente un evento para que el DMA copie el valor de uint32_t sine_table[LENGTH_OF_TABLE]
al periférico TIMx->CCRy
?
Mi código en este momento es el siguiente:
void init_dma1_ch1(void){
DMA_InitTypeDef_USR DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Enable DMA1 clock
DMA_DeInit(DMA1_Channel1); // Reset DMA1 channe1 to default values;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // M2M Disabled- Peripheral mode (requires timer trigger)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Circular mode
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // High priority
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // Memory to Peripheral
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit Register
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Always write to same register
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM1->CCR1; // Output data for GPIO
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 16-bit array
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment through array
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&sine_wave; // 16-bit Source data
DMA_InitStructure.DMA_BufferSize = PWM_BUFFER_SIZE / 3; // Size of source array
DMA_Init_USR(DMA1_Channel2, &DMA_InitStructure); // Initialize DMA
//Enable DMA1 channel IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable DMA1 Channel Transfer Complete interrupt
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); }
(Para los otros dos valores, uso los mismos parámetros, excepto que uso otro canal de DMA , por ejemplo, DMA1_Channel2
DMA1_Channel3
en lugar de Channel1. ¿Es correcto?)
El temporizador se configura de la siguiente manera (temporizador de evento de generación):
void TIM14_Init(void) {
//Clock enable: TIM14
RCC->APB1ENR |= RCC_APB1ENR_TIM14EN;
TIM14->CR1 |= TIM_CR1_ARPE;
TIM14->PSC = TIM14_PWM_PSC_VALUE;
TIM14->RCR = TIM14_PWM_REPETITION_VALUE;
///Update interrupt enable
TIM14->DIER |= TIM_DIER_UIE;
//TIM auto-reload register
TIM14->ARR = TIM1->ARR;
//Counter enable
TIM14->CR1 |= TIM_CR1_CEN;
NVIC_SetPriority(TIM14_IRQn, 3);
NVIC_EnableIRQ(TIM14_IRQn); }
Y el IRQHandler (lo que lleva tiempo de CPU en este momento):
void TIM14_IRQHandler (void){
update_motors_tim_ccr_from_table();
//Reset flag
TIM14->SR &= ~TIM14->SR; }