From 64b906b7d7cca07d0f51030ca300cc2dc33f0ee4 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 1 Sep 2016 16:03:57 +0200 Subject: o A couple of stepper motor driver applications. --- apps/stepper2/CMakeLists.txt | 3 +- apps/stepper2/stepper2.cpp | 226 ++++++++++++++++++++++++++----------------- 2 files changed, 138 insertions(+), 91 deletions(-) diff --git a/apps/stepper2/CMakeLists.txt b/apps/stepper2/CMakeLists.txt index 67d76b0..928bbfd 100644 --- a/apps/stepper2/CMakeLists.txt +++ b/apps/stepper2/CMakeLists.txt @@ -2,6 +2,7 @@ add_executable(stepper2.elf stepper2.cpp ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport/core_cm3.c ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/misc.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_adc.c ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_rcc.c ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_spi.c ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c @@ -14,7 +15,7 @@ target_include_directories(stepper2.elf PUBLIC $ ) target_compile_definitions(stepper2.elf PUBLIC ${STM32F10X_STDPERIPH_DEFINES}) -target_link_libraries(stepper2.elf tinyprintf) +target_link_libraries(stepper2.elf tinyprintf m) set_target_properties(stepper2.elf PROPERTIES LINK_FLAGS "-nostartfiles -T${CMAKE_SOURCE_DIR}/cmake/stm32.ld") add_extra_commands(stepper2.elf) diff --git a/apps/stepper2/stepper2.cpp b/apps/stepper2/stepper2.cpp index 75603ac..dea3088 100644 --- a/apps/stepper2/stepper2.cpp +++ b/apps/stepper2/stepper2.cpp @@ -1,5 +1,7 @@ +#include #include #include +#include #include #include #include @@ -28,89 +30,66 @@ void HardFault_Handler_C(uint32_t *hardfault_args) { volatile bool dma_busy; -struct motor_t { +struct hbridge_t { GPIO_TypeDef *gpio_port; const uint16_t ah; const uint16_t al; }; -static struct motor_t motor_a = { - gpio_port: GPIOA, - ah : GPIO_Pin_0, - al : GPIO_Pin_1, -}; - -TIM_TypeDef *pwm_timer = TIM2; - -struct apb_bus_1 { -}; -struct apb_bus_2 { +struct motor_t { + TIM_TypeDef *pwm_timer; + ADC_TypeDef *adc; + uint8_t adc_channel; + GPIO_TypeDef *shunt_gpio_port; + uint16_t shunt_pin; + hbridge_t a; + hbridge_t b; }; -template -class apb_ctrl { -public: - static void RCC_PeriphClockCmd(uint32_t peripherals, FunctionalState functionalState) { - RCC_PeriphClockCmd(apb_bus{}, peripherals, functionalState); - } - -private: - static void RCC_PeriphClockCmd(apb_bus_1, uint32_t peripherals, FunctionalState functionalState) { - RCC_APB1PeriphClockCmd(peripherals, functionalState); - } - - static void RCC_PeriphClockCmd(apb_bus_2, uint32_t peripherals, FunctionalState functionalState) { - RCC_APB2PeriphClockCmd(functionalState, functionalState); - } - -public: - static void RCC_PeriphResetCmd(uint32_t peripherals, FunctionalState functionalState) { - RCC_PeriphResetCmd(apb_bus{}, peripherals, functionalState); - } - -private: - static void RCC_PeriphResetCmd(apb_bus_1, uint32_t peripherals, FunctionalState functionalState) { - RCC_APB1PeriphResetCmd(peripherals, functionalState); - } - - static void RCC_PeriphResetCmd(apb_bus_2, uint32_t peripherals, FunctionalState functionalState) { - RCC_APB2PeriphResetCmd(functionalState, functionalState); - } +static struct motor_t motor = { + pwm_timer: TIM2, + adc: ADC1, + adc_channel: ADC_Channel_4, + shunt_gpio_port: GPIOA, + shunt_pin: GPIO_Pin_4, // ADC12_IN4 + a: { + gpio_port: GPIOA, + ah : GPIO_Pin_0, + al : GPIO_Pin_1, + }, + b: { + gpio_port: GPIOA, + ah : GPIO_Pin_2, + al : GPIO_Pin_3, + }, }; -template -class apb_device { -public: - static void reset() { - apb_ctrl::RCC_PeriphResetCmd(peripheral, ENABLE); - apb_ctrl::RCC_PeriphResetCmd(peripheral, DISABLE); - } - - static void enable() { - apb_ctrl::RCC_PeriphClockCmd(peripheral, ENABLE); - } - - static void disable() { - apb_ctrl::RCC_PeriphClockCmd(peripheral, DISABLE); - } -}; +volatile bool adc_ready; +volatile uint16_t adc_current_sample; -template -class gpio_port : public apb_device { -public: -}; +void adc_init(const motor_t &motor) { -class gpio_port_a : public gpio_port { -}; + GPIO_InitTypeDef init; + GPIO_StructInit(&init); + init.GPIO_Mode = GPIO_Mode_AIN; + init.GPIO_Pin = motor.shunt_pin; + init.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(motor.shunt_gpio_port, &init); -class gpio_port_b : public gpio_port { -}; + adc_ready = false; -class gpio_port_c : public gpio_port { -}; + ADC_InitTypeDef adcInit = { + ADC_Mode: ADC_Mode_Independent, + ADC_ScanConvMode: DISABLE, + ADC_ContinuousConvMode: DISABLE, + ADC_ExternalTrigConv: ADC_ExternalTrigConv_None, + ADC_DataAlign: ADC_DataAlign_Right, + ADC_NbrOfChannel: 1 + }; + ADC_Init(motor.adc, &adcInit); -class tim2 : public apb_device { -}; + ADC_RegularChannelConfig(motor.adc, motor.adc_channel, 1, ADC_SampleTime_13Cycles5); +} void timer_init(TIM_TypeDef *tim, uint16_t period) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); @@ -141,7 +120,7 @@ void pwm_control(TIM_TypeDef *tim, uint16_t pulse) { TIM_OC2PreloadConfig(tim, TIM_OCPreload_Enable); } -void gpio_init(GPIO_TypeDef* gpio_port, uint16_t pins, bool use_af) { +void gpio_init(GPIO_TypeDef *gpio_port, uint16_t pins, bool use_af) { GPIO_InitTypeDef init; GPIO_StructInit(&init); init.GPIO_Mode = use_af ? GPIO_Mode_AF_PP : GPIO_Mode_Out_PP; @@ -154,6 +133,8 @@ volatile bool run = true; bool use_gpio = false; +volatile uint32_t millis = 0; + int main() { SystemInit(); @@ -161,15 +142,29 @@ int main() { dbg_printf("stepper2\n"); - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); - NVIC_InitTypeDef NVIC_InitStruct = { - NVIC_IRQChannel: DMA1_Channel3_IRQn, - NVIC_IRQChannelPreemptionPriority: 0, - NVIC_IRQChannelSubPriority: 0, - NVIC_IRQChannelCmd: ENABLE, - }; - NVIC_Init(&NVIC_InitStruct); - NVIC_EnableIRQ(DMA1_Channel3_IRQn); + { + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); + NVIC_InitTypeDef NVIC_InitStruct = { + NVIC_IRQChannel: DMA1_Channel3_IRQn, + NVIC_IRQChannelPreemptionPriority: 0, + NVIC_IRQChannelSubPriority: 0, + NVIC_IRQChannelCmd: ENABLE, + }; + NVIC_Init(&NVIC_InitStruct); + NVIC_EnableIRQ(DMA1_Channel3_IRQn); + } + + { + NVIC_InitTypeDef NVIC_InitStruct = { + NVIC_IRQChannel: ADC1_2_IRQn, + NVIC_IRQChannelPreemptionPriority: 0, + NVIC_IRQChannelSubPriority: 0, + NVIC_IRQChannelCmd: ENABLE, + }; + + NVIC_Init(&NVIC_InitStruct); + NVIC_EnableIRQ(ADC1_2_IRQn); + } RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA @@ -188,23 +183,41 @@ int main() { uint16_t pulse = 500; - gpio_init(motor_a.gpio_port, motor_a.ah | motor_a.al, !use_gpio); - timer_init(pwm_timer, period); - pwm_control(pwm_timer, pulse); + gpio_init(motor.a.gpio_port, motor.a.ah | motor.a.al, !use_gpio); + timer_init(motor.pwm_timer, period); + pwm_control(motor.pwm_timer, pulse); + + TIM_ARRPreloadConfig(motor.pwm_timer, ENABLE); + TIM_Cmd(motor.pwm_timer, ENABLE); + + adc_init(motor); + + ADC_Cmd(motor.adc, ENABLE); - TIM_ARRPreloadConfig(pwm_timer, ENABLE); - TIM_Cmd(pwm_timer, ENABLE); + dbg_printf("Starting calibration\n"); + ADC_ResetCalibration(motor.adc); + while (ADC_GetResetCalibrationStatus(motor.adc)); + ADC_StartCalibration(motor.adc); + while (ADC_GetCalibrationStatus(motor.adc)); + ADC_SoftwareStartConvCmd(motor.adc, ENABLE); + dbg_printf("ADC calibration done\n"); + + if (SysTick_Config(SystemCoreClock / 1000)) { + dbg_printf("SysTick_Config failed.\n"); + } + + ADC_ITConfig(motor.adc, ADC_IT_EOC, ENABLE); while (run) { static bool on = false; if (use_gpio) { if (on) { - GPIO_SetBits(motor_a.gpio_port, motor_a.ah); - GPIO_SetBits(motor_a.gpio_port, motor_a.al); + GPIO_SetBits(motor.a.gpio_port, motor.a.ah); + GPIO_SetBits(motor.a.gpio_port, motor.a.al); } else { - GPIO_ResetBits(motor_a.gpio_port, motor_a.ah); - GPIO_ResetBits(motor_a.gpio_port, motor_a.al); + GPIO_ResetBits(motor.a.gpio_port, motor.a.ah); + GPIO_ResetBits(motor.a.gpio_port, motor.a.al); } on = !on; } else { @@ -219,10 +232,30 @@ int main() { pulse = 0; } - pwm_timer->CCR1 = pulse; - pwm_timer->CCR2 = period - pulse; + motor.pwm_timer->CCR1 = pulse; + motor.pwm_timer->CCR2 = period - pulse; } } + + static int adc_count = 0; + if (adc_ready) { + adc_ready = false; + ADC_SoftwareStartConvCmd(motor.adc, ENABLE); + adc_count++; + } + + static uint32_t last_ms = 0; + if (millis > last_ms + 1000) { + // adc_current_sample = [0, 4096] + int a = adc_current_sample * 25; // [0, 102400). 3.3V = 102400 + int b = a * 33; // [0, 307200). 3.3V = 3379200 + int c = b / 1024; // [0, 3300] + int voltage_mv = c; + dbg_printf("adc_count=%d, value=%" PRIu16 "\n", adc_count, adc_current_sample); + dbg_printf("voltage=%d\n", voltage_mv); + adc_count = 0; + last_ms += 1000; + } } return 0; @@ -239,3 +272,16 @@ void DMA1_Channel3_IRQHandler() { dma_busy = false; } } + +extern "C" +void ADC1_2_IRQHandler() { + adc_ready = true; + adc_current_sample = ADC_GetConversionValue(motor.adc); + + ADC_ClearITPendingBit(motor.adc, ADC_IT_EOC | ADC_IT_AWD | ADC_IT_JEOC); +} + +extern "C" +void SysTick_Handler() { + millis++; +} -- cgit v1.2.3