STM32F411: implement heater-stm32.c partially.

Like Traumflugs implementation at a fixed frequency of 1kHz and a fixed duty
cycle of 10%.
This commit is contained in:
Nico Tonnhofer 2016-03-22 19:53:59 +01:00
parent 8347b09c0f
commit df78b8d826
4 changed files with 308 additions and 4 deletions

View File

@ -37,18 +37,34 @@
#define PA_0_PIN 0
#define PA_0_PORT GPIOA
#define PA_0_ADC 0
#define PA_0_AF 1
#define PA_0_TIMER TIM2
#define PA_0_CHANNEL 1
#define PA_0_INVERT 0
#define PA_1_PIN 1
#define PA_1_PORT GPIOA
#define PA_1_ADC 1
#define PA_1_AF 1
#define PA_1_TIMER TIM2
#define PA_1_CHANNEL 2
#define PA_1_INVERT 0
#define PA_2_PIN 2
#define PA_2_PORT GPIOA
#define PA_2_ADC 2
// #define PA_2_ADC 2
// #define PA_2_AF 3
// #define PA_2_TIMER TIM9
// #define PA_2_CHANNEL 1
// #define PA_2_INVERT 0
#define PA_3_PIN 3
#define PA_3_PORT GPIOA
#define PA_3_ADC 3
// #define PA_3_ADC 3
// #define PA_3_AF 3
// #define PA_3_TIMER TIM9
// #define PA_3_CHANNEL 2
// #define PA_3_INVERT 0
#define PA_4_PIN 4
#define PA_4_PORT GPIOA
@ -57,26 +73,54 @@
#define PA_5_PIN 5
#define PA_5_PORT GPIOA
#define PA_5_ADC 5
#define PA_5_AF 1
#define PA_5_TIMER TIM2
#define PA_5_CHANNEL 1
#define PA_5_INVERT 0
#define PA_6_PIN 6
#define PA_6_PORT GPIOA
#define PA_6_ADC 6
// #define PA_6_AF 2
// #define PA_6_TIMER TIM3
// #define PA_6_CHANNEL 1
// #define PA_6_INVERT 0
#define PA_7_PIN 7
#define PA_7_PORT GPIOA
#define PA_7_ADC 7
// #define PA_7_AF 1
// #define PA_7_TIMER TIM1
// #define PA_7_CHANNEL 1
// #define PA_7_INVERT 1
#define PA_8_PIN 8
#define PA_8_PORT GPIOA
#define PA_8_AF 1
#define PA_8_TIMER TIM1
#define PA_8_CHANNEL 1
#define PA_8_INVERT 0
#define PA_9_PIN 9
#define PA_9_PORT GPIOA
#define PA_9_AF 1
#define PA_9_TIMER TIM1
#define PA_9_CHANNEL 2
#define PA_9_INVERT 0
#define PA_10_PIN 10
#define PA_10_PORT GPIOA
#define PA_10_AF 1
#define PA_10_TIMER TIM1
#define PA_10_CHANNEL 3
#define PA_10_INVERT 0
#define PA_11_PIN 11
#define PA_11_PORT GPIOA
#define PA_11_AF 1
#define PA_11_TIMER TIM1
#define PA_11_CHANNEL 4
#define PA_11_INVERT 0
#define PA_12_PIN 12
#define PA_12_PORT GPIOA
@ -89,53 +133,109 @@
#define PA_15_PIN 15
#define PA_15_PORT GPIOA
// #define PA_15_AF 1
// #define PA_15_TIMER TIM2
// #define PA_15_CHANNEL 1
// #define PA_15_INVERT 0
#define PB_0_PIN 0
#define PB_0_PORT GPIOB
#define PB_0_ADC 8
#define PB_0_AF 2
#define PB_0_TIMER TIM3
#define PB_0_CHANNEL 3
#define PB_0_INVERT 0
#define PB_1_PIN 1
#define PB_1_PORT GPIOB
#define PB_1_ADC 9
#define PB_1_AF 2
#define PB_1_TIMER TIM3
#define PB_1_CHANNEL 4
#define PB_1_INVERT 0
#define PB_2_PIN 2
#define PB_2_PORT GPIOB
#define PB_3_PIN 3
#define PB_3_PORT GPIOB
// #define PB_3_AF 1
// #define PB_3_TIMER TIM2
// #define PB_3_CHANNEL 2
// #define PB_3_INVERT 0
#define PB_4_PIN 4
#define PB_4_PORT GPIOB
#define PB_4_AF 2
#define PB_4_TIMER TIM3
#define PB_4_CHANNEL 1
#define PB_4_INVERT 0
#define PB_5_PIN 5
#define PB_5_PORT GPIOB
#define PB_5_AF 2
#define PB_5_TIMER TIM3
#define PB_5_CHANNEL 1
#define PB_5_INVERT 0
#define PB_6_PIN 6
#define PB_6_PORT GPIOB
#define PB_6_AF 2
#define PB_6_TIMER TIM4
#define PB_6_CHANNEL 1
#define PB_6_INVERT 0
#define PB_7_PIN 7
#define PB_7_PORT GPIOB
#define PB_7_AF 2
#define PB_7_TIMER TIM4
#define PB_7_CHANNEL 2
#define PB_7_INVERT 0
#define PB_8_PIN 8
#define PB_8_PORT GPIOB
#define PB_8_AF 2
#define PB_8_TIMER TIM4
#define PB_8_CHANNEL 3
#define PB_8_INVERT 0
#define PB_9_PIN 9
#define PB_9_PORT GPIOB
#define PB_9_AF 2
#define PB_9_TIMER TIM4
#define PB_9_CHANNEL 4
#define PB_9_INVERT 0
#define PB_10_PIN 10
#define PB_10_PORT GPIOB
#define PB_10_AF 1
#define PB_10_TIMER TIM2
#define PB_10_CHANNEL 3
#define PB_10_INVERT 0
#define PB_12_PIN 12
#define PB_12_PORT GPIOB
#define PB_13_PIN 13
#define PB_13_PORT GPIOB
// #define PB_13_AF 1
// #define PB_13_TIMER TIM1
// #define PB_13_CHANNEL 1
// #define PB_13_INVERT 1
#define PB_14_PIN 14
#define PB_14_PORT GPIOB
// #define PB_14_AF 1
// #define PB_14_TIMER TIM1
// #define PB_14_CHANNEL 2
// #define PB_14_INVERT 1
#define PB_15_PIN 15
#define PB_15_PORT GPIOB
// #define PB_15_AF 1
// #define PB_15_TIMER TIM1
// #define PB_15_CHANNEL 3
// #define PB_15_INVERT 1
#define PC_0_PIN 0
#define PC_0_PORT GPIOC
@ -163,15 +263,31 @@
#define PC_6_PIN 6
#define PC_6_PORT GPIOC
// #define PC_6_AF 2
// #define PC_6_TIMER TIM3
// #define PC_6_CHANNEL 1
// #define PC_6_INVERT 0
#define PC_7_PIN 7
#define PC_7_PORT GPIOC
// #define PC_7_AF 2
// #define PC_7_TIMER TIM3
// #define PC_7_CHANNEL 2
// #define PC_7_INVERT 0
#define PC_8_PIN 8
#define PC_8_PORT GPIOC
// #define PC_8_AF 2
// #define PC_8_TIMER TIM3
// #define PC_8_CHANNEL 3
// #define PC_8_INVERT 0
#define PC_9_PIN 9
#define PC_9_PORT GPIOC
// #define PC_9_AF 2
// #define PC_9_TIMER TIM3
// #define PC_9_CHANNEL 4
// #define PC_9_INVERT 0
#define PC_10_PIN 10
#define PC_10_PORT GPIOC

View File

@ -5,7 +5,7 @@
For test cases see the intro comment in heater.c.
*/
#if defined TEACUP_C_INCLUDE && defined __ARMEL__
#if defined TEACUP_C_INCLUDE && defined __ARM_LPC1114__
#include "cmsis-lpc11xx.h"
#include <stddef.h>
@ -216,4 +216,4 @@ void heater_set(heater_t index, uint8_t value) {
}
}
#endif /* defined TEACUP_C_INCLUDE && defined __ARMEL__ */
#endif /* defined TEACUP_C_INCLUDE && defined __ARM_LPC1114__ */

187
heater-stm32.c Normal file
View File

@ -0,0 +1,187 @@
/** \file
\brief Manage heaters, including PID and PWM, ARM specific part.
*/
#if defined TEACUP_C_INCLUDE && defined __ARM_STM32F411__
/**
Test configuration.
*/
#ifdef EECONFIG
#error EEPROM handling (EECONFIG) not yet supported on ARM.
#endif
#ifdef BANG_BANG
#error BANG_BANG not supported on ARM. You may set PWM frequency of one \
or all heater(s) to zero, which gives similar, better behaviour.
#endif
/** \def PWM_SCALE
G-code standard (if such a thing exists at all) gives a heater setting
range between 0 (off) and 255 (full on), so we let the PWM timers count up
to 255. Doing so allows to set the prescaler for these frequencies (all on
a 96 MHz CPU clock):
prescaler frequency prescaler frequency
0 367.5 kHz 4 75.3 kHz
1 188.2 kHz 5 62.7 kHz
2 125.5 kHz ... ...
3 94.1 kHz 65535 5.74 Hz
As one can see, frequency steps are rather coarse on the high end and
become finer grained the lower it gets.
If this range is generally too high for your purposes, you can set PWM_SCALE
to multiples of 255 to lower the range. Doubling it to 510 moves the
frequency range to 2.9 Hz...183.8 kHz, quadrupling it to 1020 moves the range
to 1.5 Hz...91.9 kHz and so on. The highest allowed number is 65535.
That said, code below calculates the best prescaler value for a configured
frequency, so you should bother about PWM_SCALE only of you need frequencies
below 6 Hz.
*/
#define PWM_SCALE 255
/** Initialise heater subsystem.
Initialise PWM timers, etc. Inspired by heater-arm_lpc11xx.c (pwm.c in LPC1343CodeBase):
https://github.com/microbuilder/LPC1343CodeBase
Note that PWM is inversed, pins start at Low by chip design. When the pin's
counter is reached, they're set to High. Reaching the timer reset counter is
programmed to reset everything and start over. Thus, having both counter
matches similar gives a low duty, having the pin counter match zero gives
full on.
For simplicity we reset all timer counters always on Match 3 and always
at PWM_SCALE (255 per default), so setting a pin match to PWM_SCALE / 2
gives 50% duty, setting it to PWM_SCALE gives full off. This choice disallows
using a pin connected to a Match 3, working around this would make code much
more complicated (and still not allow to use more than 3 pins per timer).
On ARM we can define a PWM frequency pretty fine grained, so we take the
'pwm' value of DEFINE_HEATER() not only wether to use PWM at all, but also
to define the PWM frequency. Float values are allowed.
If there's more than one pin on a timer, they share the same PWM frequency;
the frequency choosen is the one of the pin defined last.
*/
void heater_init() {
/**
Pins on the STM32F411RE are usable as following, N are negated pin (active low)
some pins are commented out (-) because they are shared. You can change this
in arduino_stm32f4xx. But take care! You could pwm two pins simultanious or disable
other important functions (serial connection).
PWM5 = TIM5 = Stepper timer.
pin timer/channel alt func for PWM other uses
PIOA_0 PWM2/1, 5/1 01, 02 AD0
PIOA_1 PWM2/2, 5/2 01, 02 MOSI4, AD1
- PIOA_2 PWM2/3, 5/3, 9/1 01, 02, 03 TX2, AD2, UART!
- PIOA_3 PWM2/4, 5/4, 9/2 01, 02, 03 RX2, AD3, UART!
- PIOA_5 PWM2/1 01 LED1, SCK1, AD5
- PIOA_6 PWM3/1 02 MISO1, AD6
- PIOA_7 PWM1/1N, 3/2 01, 02 MOSI1, AD7
PIOA_8 PWM1/1 01 SCL1
PIOA_9 PWM1/2 01 TX1
PIOA_10 PWM1/3 01 MOSI5, RX1
PIOA_11 PWM1/4 01 TX6, MISO4
- PIOA_15 PWM2/1 01 NSS1, TX1
PIOB_0 PWM1/2N, 3/3 01, 02 SCK5, CK5, AD8
PIOB_1 PWM1/3N, 3/4 01, 02 NSS4, WS5, AD9
- PIOB_3 PWM2/2 01 SDA2, SCK3
PIOB_4 PWM3/1 02 SDA3, MISO3
PIOB_5 PWM3/2 02 MOSI3
PIOB_6 PWM4/1 02 SCL1, TX1
PIOB_7 PWM4/2 02 SDA1, RX1
PIOB_8 PWM4/3, 10/1 02, 03 SCL1, MOSI5
PIOB_9 PWM4/4, 11/1 02, 03 SDA1, NSS2
PIOB_10 PWM2/3 01 SCL3
- PIOB_13 PWM1/1N 01 SCK2
- PIOB_14 PWM1/2N 01 MISO2
- PIOB_15 PWM1/3N 01 MOSI2
- PIOC_6 PWM3/1 02 MCK2, TX6
- PIOC_7 PWM3/2 02 SCK2, RX6
- PIOC_8 PWM3/3 02 SDA3
- PIOC_9 PWM3/4 02 SDA3
*/
if (NUM_HEATERS) { // At least one channel in use.
// For simplicity, turn on all timers, not only the used ones.
// TODO: turn on only the used ones. we know pin ## TIMER.
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
RCC->APB2ENR |= RCC_APB2ENR_TIM9EN;
RCC->APB2ENR |= RCC_APB2ENR_TIM10EN;
RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
// Auto-generate pin setup.
// some helper macros
#define _EXPANDER(pre, val, post) pre ## val ## post
#define EXPANDER(pre, val, post) _EXPANDER(pre, val, post)
#undef DEFINE_HEATER
uint8_t macro_mask;
#define DEFINE_HEATER(name, pin, pwm) \
pin ## _PORT->MODER &= ~(3 << (pin ## _PIN << 1)); /* reset pin mode */ \
pin ## _PORT->MODER |= (2 << (pin ## _PIN << 1)); /* pin mode to AF */ \
pin ## _PORT->OSPEEDR |= (3 << (pin ## _PIN << 1)); /* high speed */ \
pin ## _PORT->PUPDR &= ~(3 << ((pin ## _PIN) << 1)); /* no pullup-pulldown */ \
macro_mask = pin ## _PIN < 8 ? (pin ## _PIN) : (pin ## _PIN - 8); \
/* we have to registers for AFR. ARF[0] for the first 8, ARF[1] for the second 8*/ \
/* also we use this to keep the compiler happy and don't shift > 32 */ \
if (pin ## _PIN < 8) { \
pin ## _PORT->AFR[0] |= pin ## _AF << (macro_mask * 4); \
} else { \
pin ## _PORT->AFR[1] |= pin ## _AF << (macro_mask * 4); \
} \
/* AFR is a 64bit register, first half are for pin 0-7, second half 8-15 */ \
pin ## _TIMER->CR1 |= TIM_CR1_ARPE; /* auto-reload preload */ \
pin ## _TIMER->ARR = PWM_SCALE - 1; /* reset on auto reload at 254 */ \
/* PWM_SCALE - 1, so CCR = 255 is full off. */ \
pin ## _TIMER-> EXPANDER(CCR, pin ## _CHANNEL,) = PWM_SCALE * 0.1; /* testing*/ \
pin ## _TIMER->PSC = F_CPU / PWM_SCALE / 1000 - 1; /* 1kHz */ \
macro_mask = pin ## _CHANNEL > 2 ? 2 : 1; \
if (macro_mask == 1) { \
pin ## _TIMER->CCMR1 |= 0x0D << (3 + (8 * (pin ## _CHANNEL / macro_mask - 1))); \
/* ch 2 / mm 1 - 1 = 1, ch 1 / mm 1 - 1 = 0*/ \
} else { \
pin ## _TIMER->CCMR2 |= 0x0D << (3 + (8 * (pin ## _CHANNEL / macro_mask - 1))); \
/* ch 4 / mm 2 - 1 = 1, ch 3 / mm 2 - 1 = 0*/ \
} \
pin ## _TIMER->CCER |= EXPANDER(TIM_CCER_CC, pin ## _CHANNEL, E); \
/* output enable */ \
if (pin ## _INVERT) { \
pin ## _TIMER->CCER |= EXPANDER(TIM_CCER_CC, pin ## _CHANNEL, P); \
} else { \
pin ## _TIMER->CCER &= ~(EXPANDER(TIM_CCER_CC, pin ## _CHANNEL, P)); \
} \
/* invert the signal for negated timers*/ \
/* TODO: use this also with a XOR for inverted heaters later */ \
pin ## _TIMER->EGR |= TIM_EGR_UG; /* update generation */ \
pin ## _TIMER->CR1 |= TIM_CR1_CEN; /* enable counters */
#include "config_wrapper.h"
#undef DEFINE_HEATER
} /* NUM_HEATERS */
#if 0
pid_init(i);
#endif /* 0 */
}
#endif /* defined TEACUP_C_INCLUDE && defined __ARM_STM32F411__ */

View File

@ -26,6 +26,7 @@
#define TEACUP_C_INCLUDE
#include "heater-avr.c"
#include "heater-lpc.c"
#include "heater-stm32.c"
#undef TEACUP_C_INCLUDE
#include <stdlib.h>