cancel
Showing results for 
Search instead for 
Did you mean: 

STSPIN32f0 - cannot generate PWM

Misha K
Associate III
Posted on August 28, 2017 at 13:19

Hey guys! I'm trying to write custom firmware for

http://www.st.com/en/motor-drivers/stspin32f0.html

and I'm desperately stuck

:(

 

STSPIN32f0 is a system-in-package based on 

STM32F031C6.

My code works fine on

STM32F031C6. 

My code fails miserably both on my custom 

STSPIN32f0 board and on

http://www.st.com/en/evaluation-tools/steval-spin3201.html

.

What I'm trying to achieve is pretty simple: I configure TIM1 in 6-PWM mode. On 

STM32F031C6 I can see 6 signals exactly as expected, on STSPIN32f0 I can see nothing.

Does anyone have experience with STSPIN32f0 please? Can anyone please give me any hint(s)? Can anyone please share their working code samples?

1 ACCEPTED SOLUTION

Accepted Solutions
Enrico Poli
ST Employee
Posted on August 31, 2017 at 09:57

Hi,

I see two issues:

  1. The OCTH_STBY1 (PF7) and the OCTH_STBY2 (PF6) lines of the embedded gate driver are not configured. In this condition the gate driver is in standby mode and then not operative. You can also verify this measuring the VREF12 voltage, it should be zero instead of 12 V.
  2. In the initialization code for the TIM1 the dead-time value is missing. When you are driving the power stage dead-time is a must. Without it a cross-conduction occurs at each commutation of the outputs.

    For the STEVAL-SPIN3201 a good dead-time value is about 800 ns. For your custom board, it depends on the power stage you designed.

P.S. Even if the STSPIN32F0 embeds an actual STM32F031C6 microcontroller, you can find more experts about it in the 'Motor Control' forum of the Community

View solution in original post

3 REPLIES 3
Misha K
Associate III
Posted on August 28, 2017 at 13:22

Just in case here is my code:

int main(void)

{

RCC->AHBENR |= RCC_AHBENR_GPIOAEN | // enable clock for GPIOA

RCC_AHBENR_GPIOBEN; // enable clock for GPIOB

RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // enable timer 2

RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // enable timer 1

TIM1->ARR = 0xA0; // tim1 period

// over-current config (pin A-11)

GPIOA->MODER |= (0x01 << GPIO_MODER_MODER11_Pos); // output

GPIOA->OSPEEDR |= (0x01 << GPIO_OSPEEDR_OSPEEDR11_Pos); // medium speed

GPIOA->PUPDR |= (0x01 << GPIO_PUPDR_PUPDR11_Pos); // pull-up

GPIOA->ODR &= ~(1 << 11); // set zero

//

TIM1->CCMR1 |= TIM_CCMR1_OC1PE | // Output compare on channel 1 preload enable (for pin B-13, low-side 1)

(0x06 << TIM_CCMR1_OC1M_Pos) | // Output compare on channel 1 mode = 110 (PWM mode 1)

TIM_CCMR1_OC2PE | // Output compare on channel 2 preload enable (for pin B-14, low-side 2)

(0x06 << TIM_CCMR1_OC2M_Pos); // Output compare on channel 2 mode = 110 (PWM mode 1)

TIM1->CCMR2 |= TIM_CCMR2_OC3PE | // Output compare channel 3 preload enable (for pin A-10, high-side and pin B-15, low-side)

(0x06 << TIM_CCMR2_OC3M_Pos); // Output compare 3 mode = 110 (PWM mode 1)

GPIOA->MODER |= (0x02 << GPIO_MODER_MODER8_Pos) | // alternative function for pin A-8 (pwm channel 1, positive)

(0x02 << GPIO_MODER_MODER9_Pos) | // alternative function for pin A-9 (pwm channel 2, positive)

(0x02 << GPIO_MODER_MODER10_Pos); // alternative function for pin A-10 (pwm channel 3, positive)

GPIOB->MODER |= (0x02 << GPIO_MODER_MODER13_Pos) | // alternate function for pin B-13 (PWM channel 1, negative)

(0x02 << GPIO_MODER_MODER14_Pos) | // alternate function for pin B-14 (PWM channel 2, negative)

(0x02 << GPIO_MODER_MODER15_Pos); // alternate function for pin B-15 (PWM channel 3, negative)

GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEEDR8 | // high speed for pin A-8 (pwm channel 1, positive)

GPIO_OSPEEDR_OSPEEDR9 | // high speed for pin A-9 (pwm channel 2, positive)

GPIO_OSPEEDR_OSPEEDR10; // high speed for pin A-10 (pwm channel 3, positive)

GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEEDR13 | // high speed for pin B-13 (pwm channel 1, negative)

GPIO_OSPEEDR_OSPEEDR14 | // high speed for pin B-14 (pwm channel 2, negative)

GPIO_OSPEEDR_OSPEEDR15; // high speed for pin B-15 (pwm channel 3, negative)

GPIOA->AFR[1] |= (0x02 << GPIO_AFRH_AFSEL8_Pos) | // for pin A-8 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL9_Pos) | // for pin A-9 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL10_Pos); // for pin A-10 alternative funciton 2

GPIOB->AFR[1] |= (0x02 << GPIO_AFRH_AFSEL13_Pos) | // for pin B-13 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL14_Pos) | // for pin B-14 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL15_Pos); // for pin B-15 alternative funciton 2

TIM1->CCR3 = 0xA; // duty cycle of tim1 channel 3

TIM1->CCR2 = 0xA; // duty cycle of tim1 channel 2

TIM1->CCR1 = 0xA; // duty cycle of tim1 channel 1

TIM1->CR1 |= (0x01 << TIM_CR1_CMS_Pos); // centre-aligned mode 1 - up&down

TIM1->RCR = 0x3; // repetition counter

TIM1->BDTR |= TIM_BDTR_MOE | // main output enable

TIM_BDTR_OSSR | // Off-state selection for Run mode

TIM_BDTR_OSSI | // Off-state selection for Idle mode

0x02; // 2-count dead-time

TIM1->CR1 |= TIM_AUTORELOAD_PRELOAD_ENABLE; // enable timer 1 preload

TIM1->CCER |= TIM_CCER_CC1E | // enable channel 1, positive

TIM_CCER_CC2E | // enable channel 2, positive

TIM_CCER_CC3E | // enable channel 3, positive

TIM_CCER_CC1NE | // enable channel 1, negative

TIM_CCER_CC2NE | // enable channel 2, negative

TIM_CCER_CC3NE; // enable channel 3, negative

TIM1->EGR |= TIM_EGR_UG; // force update event

TIM1->CR1 |= TIM_CR1_CEN; // enable timer 1

while (1)

{

}

}
Enrico Poli
ST Employee
Posted on August 31, 2017 at 09:57

Hi,

I see two issues:

  1. The OCTH_STBY1 (PF7) and the OCTH_STBY2 (PF6) lines of the embedded gate driver are not configured. In this condition the gate driver is in standby mode and then not operative. You can also verify this measuring the VREF12 voltage, it should be zero instead of 12 V.
  2. In the initialization code for the TIM1 the dead-time value is missing. When you are driving the power stage dead-time is a must. Without it a cross-conduction occurs at each commutation of the outputs.

    For the STEVAL-SPIN3201 a good dead-time value is about 800 ns. For your custom board, it depends on the power stage you designed.

P.S. Even if the STSPIN32F0 embeds an actual STM32F031C6 microcontroller, you can find more experts about it in the 'Motor Control' forum of the Community

Misha K
Associate III
Posted on September 01, 2017 at 15:28

Enrico, thank you very much! Your answer helped me to fix the problem. Here is my version that confirmed to work. It has 1uS dead-time.

void initPwm()

{

RCC->AHBENR |= RCC_AHBENR_GPIOAEN | // enable clock for GPIOA

RCC_AHBENR_GPIOBEN | // enable clock for GPIOB

RCC_AHBENR_GPIOFEN; // enable clock for GPIOF

RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // enable timer 1

TIM1->ARR = 0xA00; // tim1 period

// tim1 config channel

TIM1->CCMR1 |= TIM_CCMR1_OC1PE | // Output compare on channel 1 preload enable (for pin B-13, low-side 1)

(0x06 << TIM_CCMR1_OC1M_Pos) | // Output compare on channel 1 mode = 110 (PWM mode 1)

TIM_CCMR1_OC2PE | // Output compare on channel 2 preload enable (for pin B-14, low-side 2)

(0x06 << TIM_CCMR1_OC2M_Pos); // Output compare on channel 2 mode = 110 (PWM mode 1)

TIM1->CCMR2 |= TIM_CCMR2_OC3PE | // Output compare channel 3 preload enable (for pin A-10, high-side and pin B-15, low-side)

(0x06 << TIM_CCMR2_OC3M_Pos); // Output compare 3 mode = 110 (PWM mode 1)

// GPIOA

GPIOA->MODER |= (0x02 << GPIO_MODER_MODER8_Pos) | // alternative function for pin A-8 (pwm channel 1, positive)

(0x02 << GPIO_MODER_MODER9_Pos) | // alternative function for pin A-9 (pwm channel 2, positive)

(0x02 << GPIO_MODER_MODER10_Pos) | // alternative function for pin A-10 (pwm channel 3, positive)

(0x01 << GPIO_MODER_MODER11_Pos); // output for pin A-11 (overcurrent control)

GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEEDR8 | // high speed for pin A-8 (pwm channel 1, positive)

GPIO_OSPEEDR_OSPEEDR9 | // high speed for pin A-9 (pwm channel 2, positive)

GPIO_OSPEEDR_OSPEEDR10 | // high speed for pin A-10 (pwm channel 3, positive)

(0x01 << GPIO_OSPEEDR_OSPEEDR11_Pos); // medium speed for pin A-11 (overcurrent control)

GPIOA->AFR[1] |= (0x02 << GPIO_AFRH_AFSEL8_Pos) | // for pin A-8 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL9_Pos) | // for pin A-9 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL10_Pos); // for pin A-10 alternative funciton 2

GPIOA->PUPDR |= (0x01 << GPIO_PUPDR_PUPDR11_Pos); // pull-up for pin A-11 (overcurrent control)

// GPIOB

GPIOB->MODER |= (0x02 << GPIO_MODER_MODER13_Pos) | // alternate function for pin B-13 (PWM channel 1, negative)

(0x02 << GPIO_MODER_MODER14_Pos) | // alternate function for pin B-14 (PWM channel 2, negative)

(0x02 << GPIO_MODER_MODER15_Pos); // alternate function for pin B-15 (PWM channel 3, negative)

GPIOB->OSPEEDR |= GPIO_OSPEEDR_OSPEEDR13 | // high speed for pin B-13 (pwm channel 1, negative)

GPIO_OSPEEDR_OSPEEDR14 | // high speed for pin B-14 (pwm channel 2, negative)

GPIO_OSPEEDR_OSPEEDR15; // high speed for pin B-15 (pwm channel 3, negative)

GPIOB->AFR[1] |= (0x02 << GPIO_AFRH_AFSEL13_Pos) | // for pin B-13 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL14_Pos) | // for pin B-14 alternative funciton 2

(0x02 << GPIO_AFRH_AFSEL15_Pos); // for pin B-15 alternative funciton 2

// GPIOF

GPIOF->MODER |= (0x01 << GPIO_MODER_MODER6_Pos) | // output mode for pin F-6 (standby mode)

(0x01 << GPIO_MODER_MODER7_Pos); // output mode for pin F-7 (standby mode)

GPIOF->PUPDR |= (0x01 << GPIO_PUPDR_PUPDR6_Pos) | // pull-up for pin F-6

(0x01 << GPIO_PUPDR_PUPDR7_Pos); // pull-up for pin F-7

// over-current config (pin A-11)

GPIOA->BRR = (1 << 11); // reset pin 11 (overcurrent does not effect gate driver directly)

GPIOF->BSRR = (1 << 7); // disable stand-by mode

TIM1->CCR3 = 0x800; // duty cycle of tim1 channel 3

TIM1->CCR2 = 0x400; // duty cycle of tim1 channel 2

TIM1->CCR1 = 0x600; // duty cycle of tim1 channel 1

TIM1->CR1 |= (0x01 << TIM_CR1_CMS_Pos); // center-aligned mode 1 - up&down

TIM1->RCR = 0x3; //repetition counter

TIM1->BDTR |= TIM_BDTR_MOE | // main output enable

TIM_BDTR_OSSR | // Off-state selection for Run mode

TIM_BDTR_OSSI | // Off-state selection for Idle mode

0x08; // 1uS dead-time

TIM1->CR1 |= TIM_AUTORELOAD_PRELOAD_ENABLE; // enable timer 1

TIM1->CCER |= TIM_CCER_CC1E | // enable channel1, positive

TIM_CCER_CC2E | // enable channel2, positive

TIM_CCER_CC3E | // enable channel3, positive

TIM_CCER_CC1NE | // enable channel 1, negative

TIM_CCER_CC2NE | // enable channel 2, negative

TIM_CCER_CC3NE; // enable channel 3, negative

TIM1->CR1 |= TIM_CR1_CEN; // enable timer 1

}