cancel
Showing results for 
Search instead for 
Did you mean: 

PWM Feedback STM32F103ZE

liviana
Associate II
Posted on February 03, 2014 at 08:00

The original post was too long to process during our migration. Please click on the attachment to read the original post.
6 REPLIES 6
Posted on February 03, 2014 at 09:43

Boy there are a jumble of thoughts there, code that's not called, references to a lot of different timers, variables that are not read, etc. Enabling interrupts on the wrong timer.

Diagram clearly what it is the code is supposed to be doing.

Explain why three timers are involved.

Trim out all the irrelevant stuff.

Take the RTOS, or whatever, out of the equation.

Use the form &ADC1->DR and &TIM1->CCR2, instead of hard addresses.

Use M2M DMA when having two peripheral talk to each other.

Do some of this, and I might be able to help you.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
liviana
Associate II
Posted on February 03, 2014 at 17:19

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6nn&d=%2Fa%2F0X0000000bvl%2FvbKKZvkbTTWktNIBUSGIEzNj_HLWYVvddisGYzZ5RBA&asPdf=false
Posted on February 03, 2014 at 18:22

I'm not actively using F1 parts these days, but I think you're using the the wrong DMA channel for the ADC/TIM1 function. I'm also not using CooCox, and don't plan too.

Let's decompose the problem, this is a blind stab at the ADC Ch 13 (PC3) Analogue, to TIM1_CH1 PWM. The base frequency should be ~244 Hz if the CPU clocks at 72 MHz.

// STM32F103 PWM1 TIM1_CH1(PA8) from ADC123_IN13(PC3) - sourcer32@gmail.com
#include ''stm32f10x.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
/* ADCCLK = PCLK2/8 */
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* TIM1, ADC1, GPIOA and GPIOC clocks enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_ADC1 |
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // PA8 TIM1_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // PC3 ADC123_IN13
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**************************************************************************************/
void TIM1_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; // 1MHz timebase from 72 MHz bus
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 0x1000 - 1; // 12-bit range
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Channel 1 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_Pulse = 0; // Off for now
TIM_OC1Init(TIM1, &TIM_OCInitStructure); // Channel 1
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
/**************************************************************************************/
void DMA1_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA1 Channel1 configuration ----------------------------------------------*/
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // ADC1 DMA Channel 1 hardware request on EOC
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&TIM1->CCR1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // From the triggering DMA source peripheral
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Registers not moving
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Repetitive
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // Perhaps, I want the ADC to trigger, not SW
// DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; // Peripheral to Peripheral (ie through buffer, not directly wired)
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA1 Channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
}
/**************************************************************************************/
void ADC1_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // Single Channel
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Over and Over
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1; // Single Channel
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 RegularChannelConfig Test */
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 1, ADC_SampleTime_55Cycles5); // PC3 ADC123_IN13
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
/* Enable ADC1 DMA interface, after calibration */
ADC_DMACmd(ADC1, ENABLE);
/* Start ADC1 conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
DMA1_Configuration();
TIM1_Configuration();
ADC1_Configuration();
while (1); /* Infinite loop */
}
/**************************************************************************************/
#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 can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**************************************************************************************/

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
indra_sanusi92
Associate
Posted on February 04, 2014 at 04:38

ah ... glad to see this thread, I'm facing the same problem right now. I'm also confuse about how to use the IRQ after enabling it. Obvious explanation for this problem would be very helpful for me. Thanks brother.

liviana
Associate II
Posted on February 04, 2014 at 04:41

Hai, Clive.

Thank you for the respond. In my thought, the DMA  is chosen by the destination peripheral. Is that right? I have tried your code but it didnt work. Actually my code had already worked in PWM with analog input, but not work for PWM Input. 

My consideration is :

1. Is my code use a wrong interrupt in PWM input_PWM Output task? And may you helpme to explain  a little about the interrupt, how to activate the IRQ handler ? I had made the IRQ handler, and tried to enable the interupt with TIM_IT_CC2, for TIM3 but when i try to debug the source code  and place a break point inside the IRQ the process never reach the IRQ.

Thank you so much clive for your help 🙂

Posted on February 04, 2014 at 04:50

Working blind here.

Your code had the DMA set up to trigger on the timer update, I was trying to get it to trigger from the ADC EOC
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..