2014-05-23 11:15 AM
whenever i perform the dma transfer, I always get a transfer error on the write to TIM1->BDTR. If I write to a different peripheral register, such as TIM3->ARR, it succeeds. Any thoughts?
TIM_TimeBaseInitTypeDef TIM1_TimeBaseStructure;
TIM_OCInitTypeDef TIM1_OCInitStructure;
TIM_BDTRInitTypeDef TIM1_BDTRInitStruct;
TIM_TimeBaseInitTypeDef TIM3_TimeBaseStructure;
TIM_OCInitTypeDef TIM3_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_ClocksTypeDef RCC_Clocks;
uint16_t period;
uint8_t dc = 30;
uint16_t pulse1;
uint16_t pulse2;
TIM_TypeDef const * tim1;
TIM_TypeDef const * tim3;
TIM_TypeDef const * tim8;
DMA_InitTypeDef sDMAInitStructureTx;
tim1 = (TIM_TypeDef*)TIM1_BASE;
tim3 = (TIM_TypeDef*)TIM3_BASE;
tim8 = (TIM_TypeDef*)TIM8_BASE;
RCC_GetClocksFreq(&RCC_Clocks);
/* Compute the value for the ARR register to have a period of 350 KHz */
period = (RCC_Clocks.HCLK_Frequency / 350000 ) - 1;
/* Compute the CCR2 value */
pulse1 = (uint16_t) (((uint32_t) (100 - dc) * (period - 1)) / 100);
/* Compute the CCR3 value */
pulse2 = (uint16_t) (((uint32_t) (dc) * (period - 1)) / 100);
/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);
/* GPIOB clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/* TIM1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
/* DMA1 clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/* Initialize PB0, Alternative Function, 100Mhz, Output, Push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_TIM1);
/* Timer Base configuration */
TIM_TimeBaseStructInit(&TIM1_TimeBaseStructure);
TIM1_TimeBaseStructure.TIM_Prescaler = 0;
TIM1_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM1_TimeBaseStructure.TIM_Period = period;
TIM1_TimeBaseStructure.TIM_ClockDivision = 0;
TIM1_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM1_TimeBaseStructure);
/* Channel 2 output configuration */
TIM_OCStructInit(&TIM1_OCInitStructure);
TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM1_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM1_OCInitStructure.TIM_Pulse = pulse2;
TIM1_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM1_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC2Init(TIM1, &TIM1_OCInitStructure);
/* Enable Preload register on CCR2. */
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
/* Channel 3 output configuration */
TIM1_OCInitStructure.TIM_Pulse = pulse1;
TIM1_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM1_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC3Init(TIM1, &TIM1_OCInitStructure);
/* Enable Preload register on CCR3. */
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
// Setup dead time register (p-fet delay)
TIM_BDTRStructInit(&TIM1_BDTRInitStruct);
TIM1_BDTRInitStruct.TIM_DeadTime = 0U;
TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStruct);
// Setup Timer 1 output compare Ch1 (Used for timer 3 clock source)
TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing; // Timing mode only(no I/O output)
TIM1_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; // don't care
TIM1_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; // don't care
TIM1_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // don't care
TIM1_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; // don't care
TIM1_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM1_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM1_OCInitStructure.TIM_Pulse = 1;
TIM_OC1Init(TIM1, &TIM1_OCInitStructure);
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); // Used to clock timer 3
// Setup Timer 3 to gate H-Bridge drive signals
TIM_TimeBaseStructInit(&TIM3_TimeBaseStructure);
TIM3_TimeBaseStructure.TIM_ClockDivision = 0;
TIM3_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM3_TimeBaseStructure.TIM_Period = 1;
TIM3_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseInit(TIM3, &TIM3_TimeBaseStructure);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_External1); // Clock timer 3 via timer 1
TIM_ITRxExternalClockConfig(TIM3, TIM_TS_ITR0); // drive timer 3 via timer 1
TIM_ARRPreloadConfig(TIM3, ENABLE); // Enable pre-load
TIM_SetAutoreload(TIM3, 1);
// Setup Timer 3 output compare 1 to load burst duration
TIM3_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM3_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM3_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM3_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM3_OCInitStructure.TIM_Pulse = 1;
TIM_OC1Init(TIM3, &TIM3_OCInitStructure);
/* Enable Preload register on CCR1. */
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
// Enable DMA channel 2
DMA_Cmd(DMA1_Stream2, DISABLE);
// Enable DMA channel 4
DMA_Cmd(DMA1_Stream4, DISABLE);
// Setup DMA 1 stream 4 to modulate fet drive on/off
DMA_StructInit(&sDMAInitStructureTx);
sDMAInitStructureTx.DMA_Channel = DMA_Channel_5;
sDMAInitStructureTx.DMA_PeripheralBaseAddr = (uint32_t)&(tim1->BDTR);
sDMAInitStructureTx.DMA_BufferSize = 2;
sDMAInitStructureTx.DMA_DIR = DMA_DIR_MemoryToPeripheral;
sDMAInitStructureTx.DMA_Memory0BaseAddr = (uint32_t)gBurstEnable;
sDMAInitStructureTx.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
sDMAInitStructureTx.DMA_MemoryInc = DMA_MemoryInc_Enable;
sDMAInitStructureTx.DMA_Mode = DMA_Mode_Circular;
sDMAInitStructureTx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
sDMAInitStructureTx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
sDMAInitStructureTx.DMA_Priority = DMA_Priority_VeryHigh;
// Initialize DMA
DMA_DeInit(DMA1_Stream4);
DMA_Init(DMA1_Stream4, &sDMAInitStructureTx);
// Setup DMA 1 stream 2 to update burst table
DMA_StructInit(&sDMAInitStructureTx);
sDMAInitStructureTx.DMA_Channel = DMA_Channel_5;
sDMAInitStructureTx.DMA_PeripheralBaseAddr = (uint32_t)&(tim3->ARR);
sDMAInitStructureTx.DMA_BufferSize = 8;
sDMAInitStructureTx.DMA_DIR = DMA_DIR_MemoryToPeripheral;
sDMAInitStructureTx.DMA_Memory0BaseAddr = (uint32_t)TimeData;
sDMAInitStructureTx.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
sDMAInitStructureTx.DMA_MemoryInc = DMA_MemoryInc_Enable;
sDMAInitStructureTx.DMA_Mode = DMA_Mode_Circular;
sDMAInitStructureTx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
sDMAInitStructureTx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
sDMAInitStructureTx.DMA_Priority = DMA_Priority_VeryHigh;
// Initialize DMA
DMA_DeInit(DMA1_Stream2);
DMA_Init(DMA1_Stream2, &sDMAInitStructureTx);
// Enable Timer DMA request on update
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
/* TIM3 counter enable */
TIM_Cmd(TIM3, ENABLE);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
// Enable DMA channel 2
DMA_Cmd(DMA1_Stream2, ENABLE);
// Enable DMA channel 4
DMA_Cmd(DMA1_Stream4, ENABLE);
/* forever... */
while (1) {
__asm(''nop'');
}
2014-05-23 11:30 AM
TIM1 is on APB2, you should perhaps be using DMA2?
2014-05-23 02:13 PM
Worked like a charm.
Thanks Clive.