2021-07-01 05:00 AM
Hello!
I have never before worked with a microcontroller so all of this is very new to me. I am using the MC-kit IHM07M1 with the NUCLEO-F302R8 as a control board. I am trying to implement chaotic PWM in the microcontroller like in the figure attached. The sawtooth pulse is, as seen in the figure, an upcounting timer.
The ARR needs to be constant and the CCRx values of each channel are going to vary chaoticly. My problem is that no matter what I do I simply can't implement this in my code. I am starting with a project in MotorControl Workbench (just a default Bull-Running-Program), and from there I generete my code. This is how I set up the workflow for my code:
This is my main()-function:
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_DAC_Init();
MX_TIM1_Init();
MX_USART2_UART_Init();
MX_MotorControl_Init();
/* Initialize interrupts */
MX_NVIC_Init();
while (1)
{
}
}
The MX_NVIC_INIT(void)-function:
static void MX_NVIC_Init(void)
{
/* TIM1_BRK_TIM15_IRQn interrupt configuration */
HAL_NVIC_SetPriority(TIM1_BRK_TIM15_IRQn, 4, 1);
HAL_NVIC_EnableIRQ(TIM1_BRK_TIM15_IRQn);
/* TIM1_UP_TIM16_IRQn interrupt configuration */
HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
/* ADC1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(ADC1_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(ADC1_IRQn);
/* USART2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(USART2_IRQn, 3, 1);
HAL_NVIC_EnableIRQ(USART2_IRQn);
/* EXTI15_10_IRQn interrupt configuration */
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
/* Capture Compare interrupt for TIM1 */
HAL_NVIC_SetPriority(TIM1_CC_IRQn, 4, 1);
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
}
The MX_TIM1_Init(void)-function:
static void MX_TIM1_Init(void)
{
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = ((TIM_CLOCK_DIVIDER) - 1);
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
htim1.Init.Period = 2399;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;
htim1.Init.RepetitionCounter = (REP_COUNTER);
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR1;
if (HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC4REF;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 1199;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM2;
sConfigOC.Pulse = (2399 - (HTMIN));
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_ENABLE;
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_LOW;
sBreakDeadTimeConfig.Break2Filter = 7;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim1);
}
An at last the Interrupt Handler
void TIM1_UP_TIM16_IRQHandler(void){
HAL_TIM_IRQHandler(&htim1);
volatile unsigned int Delta_f; //Change in frequency
volatile unsigned int fc; //Center frequency
volatile float f[200]; //Timer frequency
volatile float x[200]; //Array for pseudorandom variable
volatile unsigned int D; //Duty cycle
volatile unsigned int F_CLK; //Clock frequency
volatile int i = 0; //Iteration variable
volatile const int mu = 4; //Constant in logistic map
volatile int FirstSwitchPeriod;
volatile int FirstSwitchCycle;
volatile unsigned int UpdateCycle;
volatile unsigned int UpdatePeriod;
Delta_f = 10000; //Hz
fc = 30000; //Hz
D = 50; //%
F_CLK = 72000000;
x[0] = 0.15; //Initialization of Logistic Map variable
f[0] = fc;
//Calculate the needed number to fulfill the next switching cycle period and duty cycle
FirstSwitchPeriod = (F_CLK/fc) - 1; //30kHz makes the switching frequency 50kHz
FirstSwitchCycle = (FirstSwitchPeriod + 1)*D/(100-1);
i++;
/* The math that makes the PWM chaotic: */
//Logistic map
x[i] = mu*x[i-1]*(1-x[i-1]);
//Timer frequency
f[i] = fc + (2*x[i] - 1)*Delta_f;
//Calculate the needed number to fulfill the next switching cycle period and duty cycle:
UpdateCycle = (F_CLK/f[i])*D/(100-1);
//Set up PWN period register and duty cycle register:
htim1.Instance->CCR1 = UpdateCycle;
htim1.Instance->CCR2 = UpdateCycle;
htim1.Instance->CCR3 = UpdateCycle;
//The ARR statys the same, which is the value initiated in MX_TIM1_INIT
}
There's more code, but these are the only functions I have made changes in. The problem is that when debugging the IRQ-Handler is never entered and therefore the CRRx's is never assigned their new values.
When I run the code simply nothing happens, all the channels in Timer 1 is constantly on low (I have a LA to check this) and the motor won't run (of course) because of that.
I have been stuck for days, I hope someone can help me!
2021-07-01 06:35 AM
Do you start TIM1 anywhere? I don't see it. You also need to ensure the update interrupt bit (UIE) is set.
2021-07-01 08:11 AM
While TDK has probably guessed the main problem and there's probably some HAL_TIM_start_IT_something() function which accomplishes both, I'd recommend you to start with reading the TIM chapter and then reading out and checking/posting TIM registers content.
Clicking in Cube and kin may be fun, but does not go too far in way of understanding how things work.
JW
2021-07-01 08:23 AM
I added __HAL_TIM_ENABLE(&htim1) and __HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE) in main(). I also added LL_TIM_ClearFlag_UPDATE(TIM1) and R3_1_TIMx_UP_IRQHandler(&PWM_Handle_M1) to the interrupt handler.
And now I acutally get the desired output, but it only lasts for about 5-6 seconds and then every channel is on low, and during this time the motor is not running at all. Right now I am going step by step with the debugger to see when and where in the code everything becomes zero.
2021-07-01 08:35 AM
I also added
HAL_TIM_Base_Start(&htim1);
HAL_TIM_Base_Start_IT(&htim1);
to main(), after enabling TIM1 and interrupts in TIM1. But the problem remains. The chaotic pulse is only active for 5-6 s and the motor is not running.
2021-07-01 09:08 AM
Found the problem. For some reason one element in
//Logistic map
x[i] = mu*x[i-1]*(1-x[i-1]);
becomes negative and after that hell breaks loose and it start wandering off to infinity making
//Timer frequency
f[i] = fc + (2*x[i] - 1)*Delta_f;
also infinite. Therefore
//Calculate the needed number to fulfill the next switching cycle period and duty cycle:
UpdateCycle = (F_CLK/f[i])*D/(100-1);
approaches zero. Which explaines why the PWM pulses disappears after a few seconds.