Switch branches/tags
Nothing to show
Find file History
jsphuebner Added CAN throttle and IO control
Using RTC (unbuffered) for timestamping
Switching all PWM outputs to low when not requesting any voltage
Bugfix in CAN module when clearing all messages
Latest commit 96eea9c Aug 14, 2018
Permalink
..
Failed to load latest commit information.
test - Added active pulldown of PWM pins to bootloader and FW Init code Apr 20, 2018
.cproject eclipse project files Sep 28, 2011
.project eclipse project files Sep 28, 2011
Makefile - Refactoring and match to current libopencm3 API Jan 28, 2018
README.txt Added support for active low PWM signals Oct 16, 2014
TEST_INSTRUCTIONS.txt Updated to address Tom's comments Dec 16, 2010
anain.cpp - Added encoder SPI mode for AD2S resolver to digital chip Mar 22, 2018
anain.h - Refactoring Dec 20, 2016
anain_prj.h - Added build configuration for Damiens Tesla board Oct 17, 2017
digio.cpp - speedflt (for encoder filter) renamed to encflt Jul 12, 2015
digio.h - Moved STM32F1 define to Makefile Dec 22, 2015
digio_prj.h Added CAN throttle and IO control Aug 14, 2018
errormessage.cpp Do not print error messages in the same context they are posted. Nov 18, 2017
errormessage.h Do not print error messages in the same context they are posted. Nov 18, 2017
errormessage_prj.h Added CAN throttle and IO control Aug 14, 2018
foc.cpp - speedflt (for encoder filter) renamed to encflt Jul 12, 2015
foc.h - ADC samples faster and the extra values are used for interpolation. Jun 5, 2014
fu.cpp - Changed the fmax ramp to 20Hz because of oscillation Dec 13, 2016
fu.h - Split off PWM generation to new module (still needs refactoring) Dec 9, 2016
hwdefs.h - Dual channel throttle support May 14, 2018
hwinit.cpp Added CAN throttle and IO control Aug 14, 2018
hwinit.h Added CAN throttle and IO control Aug 14, 2018
inc_encoder.cpp - Added active pulldown of PWM pins to bootloader and FW Init code Apr 20, 2018
inc_encoder.h - Added encoder SPI mode for AD2S resolver to digital chip Mar 22, 2018
my_fp.c Refactored throttle control May 18, 2015
my_fp.h Refactored throttle control May 18, 2015
my_math.h - Added active pulldown of PWM pins to bootloader and FW Init code Apr 20, 2018
my_string.c - Dual channel throttle support May 14, 2018
my_string.h - Dual channel throttle support May 14, 2018
param_prj.h Added CAN throttle and IO control Aug 14, 2018
param_save.cpp - Refactoring and match to current libopencm3 API Jan 28, 2018
param_save.h - Module for ADC: uses DMA to continuously sample up to 18 inputs and Jan 20, 2013
params.cpp Added CAN throttle and IO control Aug 14, 2018
params.h Added CAN throttle and IO control Aug 14, 2018
printf.c - Module for ADC: uses DMA to continuously sample up to 18 inputs and Jan 20, 2013
printf.h - forgot some files Mar 19, 2014
pwmgeneration.cpp Added CAN throttle and IO control Aug 14, 2018
pwmgeneration.h - Split off PWM generation to new module (still needs refactoring) Dec 9, 2016
sine_core.cpp - Added encoder SPI mode for AD2S resolver to digital chip Mar 22, 2018
sine_core.h - Added encoder SPI mode for AD2S resolver to digital chip Mar 22, 2018
sintab.ods Added support for active low PWM signals Oct 16, 2014
sinus.cbp - Refactoring and match to current libopencm3 API Jan 28, 2018
stm32_can.cpp Added CAN throttle and IO control Aug 14, 2018
stm32_can.h Added CAN throttle and IO control Aug 14, 2018
stm32_sine.cpp Added CAN throttle and IO control Aug 14, 2018
stm32_sine.h - Added possibility to scale fweak and boost with voltage Nov 8, 2017
stm32_sine.ld - Module for ADC: uses DMA to continuously sample up to 18 inputs and Jan 20, 2013
stm32scheduler.cpp - Added encoder SPI mode for AD2S resolver to digital chip Mar 22, 2018
stm32scheduler.h - Added encoder SPI mode for AD2S resolver to digital chip Mar 22, 2018
temp_meas.cpp - Added build configuration for Damiens Tesla board Oct 17, 2017
temp_meas.h - Added build configuration for Damiens Tesla board Oct 17, 2017
temp_sensors.ods Added support for active low PWM signals Oct 16, 2014
terminal.c Added CAN throttle and IO control Aug 14, 2018
terminal.h - Dual channel throttle support May 14, 2018
terminal_prj.cpp - Dual channel throttle support May 14, 2018
throttle.cpp - Dual channel throttle support May 14, 2018
throttle.h - Added active pulldown of PWM pins to bootloader and FW Init code Apr 20, 2018

README.txt

stm32_sine
----------

Build instructions
-------------------
Two options:
a) Type 'make' to build standalone test app
b) or type 'make libopencm3_stm32.a' to build lib (to be used with Tumanako Vehicle Control)

1. Sine wave lookup
-------------------
stm32_sine.h contains a large define for the sine wave LUT. It has basically been
created using OpenOffice Calc.

The sine is scaled with 32767 and offset with 32767. Thus when a normal sine function is

-1	: LUT is 0
 0	: LUT is 32767
 1	: LUT is 65535

To address the table, we scale the signs argument so that 2xPi maps to 65535.
So, when the sine table has 256 entries, we devide the argument by 256 and
with the result do the lookup.

address = argument / 256

When using a u16 argument, it will wrap at 65535 and thus always stay within
the table boundaries.

We call the function SineLookup(Arg)

2. Space Vector modulation
--------------------------
Sine wave modulation can never use the full DC-bus voltage, because when one
of the three sine waves reaches its maximum, neither of the other two sine
waves reach their minimum. This wastes around 15% of the DC voltage.
To use the full voltage of the DC-bus, we allow amplitudes greater than 1,
namely amplitudes up to 1.15. Now, when one sine wave, say L1, reaches an
amplitude of 1, we start offsetting the virtual neutral potential in a way
that L1 never exceeds 1. Since we apply this offset to all three phases,
the phase-to-phase voltage stays the same.
It all comes down to the formular
Offset = 1/2 * (min{a,b,c} + max{a,b,c})
where a,b,c in [-1,1] represent the three phases.
In the source code it is explained how we apply this calculation to the
[0,65535] value range.

We call the function SVPWMOfs

3. Sine wave scaling
--------------------
to scale the result of our lookup, we use a simple integer mulitplication
We map zero amplitude to 0 and full amplitude to 32767. With values larger
than that we can generate a double humped or overmodulated SVM later on.

Scaling now works in 3 steps:

a) Multiply sine lookup value with amplitude with a u32 multiplication
b) Right shift the result 15 (meaning division by 32767)
c) Right shift the result to match the PWM resolution, e.g. by 4 (i.e. 16-12, if PWM resolution is 12 bits).

We call the Function MultAmp(amp, base)

3. Dutycycle calculation
------------------------
The 3 sine waves look like this (x=0..2Pi, a=0..1)

L1 = a * sin(x         )
L2 = a * sin(x +   Pi/3)
L3 = a * sin(x + 2xPi/3)

With SVPWM:
Ofs = SVPWMOfs(L1, L2, L3)

With the scaling introduced above this comes to (amp=0..37550, arg=0..65535)
Dutycycle L1 = MultAmp(amp, SineLookup( arg                        ) - Ofs)
Dutycycle L2 = MultAmp(amp, SineLookup((arg +     65535/3) & 0xFFFF) - Ofs)
Dutycycle L3 = MultAmp(amp, SineLookup((arg + 2 * 65535/3) & 0xFFFF) - Ofs)

The addition arg + 65535/3 is done in u32 and then masked to u16, because
you never know what the compiler does in case of overflow.

4. Frequency
------------
The frequency is increased by skipping over the lookup table faster. Thus, after
every calculation of the dutycycles we add a certain amount to the argument.
What frequency that comes down to depends on the PWM frequency.

In the program we add the result of the ADC (0..4095) offset by 2048 and 
divided by 8. That way we can skip over the sine wave table backward and
forward and thus spin the motor in both directions.

With the current setup, the PWM base frequency equal

36 MHz
------ = 8789 kHz
4096

Thus, when frq = 1 we yield an inverter frequency of 8789/65536 = 0.13411 Hz.
This gives us a scaling ratio of 7.4565 digit/Hz.

5. Timer ISR
------------
The timer interrupt handler calculates the new dutycycle as described above,
increases the argument and clears the interrupt pending flag

6. Timer setup
--------------
This is largely hardware dependendant, since the timer outputs map to fixed pins.
The best choice would be TIM1 or TIM8 since they allow for complementary
outputs with dead time generation.

Timer setup comes down to the following steps

a) Enable the APB clock, TIM4 is on APB1
b) Configure pins. TIM4 Ch1-3 is on GPIOB Pins PA6-PA8
c) Configure interrupt controller (nvic_enable_irq and nvic_set_priority)
d) Enable center aligned mode 1 (CMS_CENTER_1) and ARPE in TIMx_CR1
e) Set PWM mode 1 (OCxM_PWM1) and Preload enable (OCyPE) for channel 1 and 2 in TIMx_CCMR1
f) Set PWM mode 1 (OCxM_PWM1) and Preload enable (OCyPE) for channel 3 TIMx_CCMR2
g) enable the output for channels 1-3 with CCyE in TIMx_CCER
h) enable the update generation flag UG in TIMx_EGR
i) Enable the update interrupt UIE in TIMx_DIER
j) Set the prescaler TIMx_PSC (haven't yet understood, 1 looked allright)
k) set the maximum PWM value and thus the frequency in TIMx_ARR
l) Enable the timer with CEN in TIMx_CR1

7. Speed sensor
---------------
To get started I simply attached a photo sensor to the motor with a toothed wheel
running through it. This gives us 32 pulses/rev. The pulses are counted by a timer
(TIM1 in my case) with a heavily filtered trigger input. Without filtering, all
the EMI spikes are counted as well
I then created a task that polls the timer value every 100ms. So, when the motor
runs at 1.25 rotations per second (75 rotations per minute) this would give us
a counter value of 4 every 100ms.
This gives us a scaling ratio of 3.2 digit/rotation.
To get the electrical rotor frequency, we have to divide by the number of pole pairs.
More generally the formular to calculate rotor frequency out of the counter value is

          p * f_task * Cnt
f_rotor = ----------------
           n_pulses
		   
where p is the number of pole pairs, f_task the timer polling frequency, Cnt the polled
counter value and n_pulses the number of pulses per rotation.

8. Slip calculation and slip control
------------------------------------
With the values for inverter frequency and rotor frequency at hand it is now fairly easy
to calculate the motors current slip

     f_rotor
s = -----------
     f_inv
	 
To implement a simple (none-PID) slip control we simply rearrange the formular to

          f_rotor
f_inv = -----------
            s
			
I have setup the throttle pot to control the slip with values between 
0.7952 (accelerate) and 1.2048 (brake)
These values need a lot of fine tuning and also the motor flux should
somehow be affected by the pot I guess? Implementing U(f) would be a logical
next step.