aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2016-08-31 16:30:35 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2016-08-31 16:30:35 +0200
commit07090d14e0dafc3b5b564a339cd615c2d9864125 (patch)
tree6d20c9168c3f059381981ff4cc8cb9774db4041d
parent7a3326e8687cd8c86750a2db8348ab34c261b426 (diff)
downloadstm32f103-playground-07090d14e0dafc3b5b564a339cd615c2d9864125.tar.gz
stm32f103-playground-07090d14e0dafc3b5b564a339cd615c2d9864125.tar.bz2
stm32f103-playground-07090d14e0dafc3b5b564a339cd615c2d9864125.tar.xz
stm32f103-playground-07090d14e0dafc3b5b564a339cd615c2d9864125.zip
o A couple of stepper motor driver applications.
-rw-r--r--apps/CMakeLists.txt2
-rw-r--r--apps/stepper1/CMakeLists.txt19
-rw-r--r--apps/stepper1/stepper1.cpp174
-rw-r--r--apps/stepper2/CMakeLists.txt20
-rw-r--r--apps/stepper2/stepper2.cpp241
-rw-r--r--gdb-start31
6 files changed, 487 insertions, 0 deletions
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index cbbbc65..f5fe450 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -4,4 +4,6 @@ add_subdirectory(os1)
add_subdirectory(os2)
add_subdirectory(serial1)
add_subdirectory(serial2)
+add_subdirectory(stepper1)
+add_subdirectory(stepper2)
add_subdirectory(test1)
diff --git a/apps/stepper1/CMakeLists.txt b/apps/stepper1/CMakeLists.txt
new file mode 100644
index 0000000..e09a093
--- /dev/null
+++ b/apps/stepper1/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_executable(stepper1.elf stepper1.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_rcc.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_spi.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_dma.c
+ $<TARGET_OBJECTS:playground>
+ )
+
+target_include_directories(stepper1.elf PUBLIC
+ $<TARGET_PROPERTY:playground,INTERFACE_INCLUDE_DIRECTORIES>
+ )
+target_compile_definitions(stepper1.elf PUBLIC ${STM32F10X_STDPERIPH_DEFINES})
+target_link_libraries(stepper1.elf tinyprintf)
+
+set_target_properties(stepper1.elf PROPERTIES LINK_FLAGS "-nostartfiles -T${CMAKE_SOURCE_DIR}/cmake/stm32.ld")
+add_extra_commands(stepper1.elf)
diff --git a/apps/stepper1/stepper1.cpp b/apps/stepper1/stepper1.cpp
new file mode 100644
index 0000000..4ee8d88
--- /dev/null
+++ b/apps/stepper1/stepper1.cpp
@@ -0,0 +1,174 @@
+#include <stdint.h>
+#include <stm32f10x.h>
+#include <stm32f10x_rcc.h>
+#include <stm32f10x_gpio.h>
+#include <stm32f10x_dma.h>
+#include <misc.h>
+
+#include "debug.h"
+#include "tinyprintf.h"
+#include "playground.h"
+
+extern "C"
+__attribute__((naked, used))
+void HardFault_Handler_C(uint32_t *hardfault_args) {
+ dbg_printf("r0 = 0x%08lx (%lu)\n", hardfault_args[0], hardfault_args[0]);
+ dbg_printf("r1 = 0x%08lx (%lu)\n", hardfault_args[1], hardfault_args[1]);
+ dbg_printf("r2 = 0x%08lx (%lu)\n", hardfault_args[2], hardfault_args[2]);
+ dbg_printf("r3 = 0x%08lx (%lu)\n", hardfault_args[3], hardfault_args[3]);
+ dbg_printf("r12 = 0x%08lx (%lu)\n", hardfault_args[4], hardfault_args[4]);
+ dbg_printf("lr = 0x%08lx (%lu)\n", hardfault_args[5], hardfault_args[5]);
+ dbg_printf("pc = 0x%08lx (%lu)\n", hardfault_args[6], hardfault_args[6]);
+ dbg_printf("psr = 0x%08lx (%lu)\n", hardfault_args[7], hardfault_args[7]);
+ dbg_printf("\n");
+
+ halt();
+}
+
+volatile bool dma_busy;
+
+static uint32_t pwm_buffer[128];
+
+static uint16_t pwm_gpio_pin_a = GPIO_Pin_2;
+static uint16_t pwm_gpio_pin_b = GPIO_Pin_3;
+
+static
+void pwm_init() {
+ int on = true;
+ for (size_t i = 0; i < SizeOfArray(pwm_buffer); i++) {
+ pwm_buffer[i] = on ? 0xffffffff : 0;
+ on=!on;
+ }
+
+// for (size_t i = 0; i < SizeOfArray(pwm_buffer) / 2; i++) {
+// pwm_buffer[i] = 0xffffffff;
+// }
+//
+// for (size_t i = SizeOfArray(pwm_buffer) / 2; i < SizeOfArray(pwm_buffer); i++) {
+// pwm_buffer[i] = 0;
+// }
+}
+
+static
+void pwm_transfer_setup() {
+ DMA_Cmd(DMA1_Channel3, DISABLE);
+ DMA_DeInit(DMA1_Channel3);
+
+ DMA_InitTypeDef dmaInit;
+ DMA_StructInit(&dmaInit);
+
+ dmaInit.DMA_M2M = DMA_M2M_Enable;
+ dmaInit.DMA_Mode = DMA_Mode_Normal;
+ dmaInit.DMA_Priority = DMA_Priority_VeryHigh;
+
+ dmaInit.DMA_DIR = DMA_DIR_PeripheralDST;
+
+ dmaInit.DMA_PeripheralBaseAddr = reinterpret_cast<uint32_t>(&GPIOA->ODR);
+ dmaInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
+ dmaInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+
+ dmaInit.DMA_MemoryBaseAddr = reinterpret_cast<uint32_t>(pwm_buffer);
+ dmaInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
+ dmaInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
+
+ dmaInit.DMA_BufferSize = SizeOfArray(pwm_buffer);
+ DMA_Init(DMA1_Channel3, &dmaInit);
+ DMA_ITConfig(DMA1_Channel3, DMA_IT_TC | DMA_IT_TE, ENABLE);
+
+ dma_busy = true;
+
+ DMA_Cmd(DMA1_Channel3, ENABLE);
+}
+
+void gpio_a_setup() {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, DISABLE);
+
+ GPIO_InitTypeDef init;
+ GPIO_StructInit(&init);
+ init.GPIO_Mode = GPIO_Mode_Out_PP;
+ init.GPIO_Pin = pwm_gpio_pin_a | pwm_gpio_pin_b;
+ GPIO_Init(GPIOA, &init);
+}
+
+void gpio_a_loop() {
+ static bool on = false;
+ if (on) {
+ GPIO_SetBits(GPIOA, pwm_gpio_pin_a);
+ GPIO_SetBits(GPIOA, pwm_gpio_pin_b);
+ } else {
+ GPIO_ResetBits(GPIOA, pwm_gpio_pin_a);
+ GPIO_ResetBits(GPIOA, pwm_gpio_pin_b);
+ }
+ on = !on;
+}
+
+volatile bool run = true;
+
+bool use_dma = true;
+
+int main() {
+ SystemInit();
+
+ init_printf(nullptr, dbg_putc);
+
+ dbg_printf("stepper1\n");
+
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
+
+ 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);
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO
+ | RCC_APB2Periph_GPIOA
+// | RCC_APB2Periph_GPIOB
+// | RCC_APB2Periph_GPIOC
+// | RCC_APB2Periph_ADC1
+// | RCC_APB2Periph_ADC2
+// | RCC_APB2Periph_ADC3,
+ , ENABLE);
+
+ /* ***************************************** */
+
+ gpio_a_setup();
+
+ pwm_init();
+
+ while (run) {
+ if (use_dma) {
+// dbg_printf("dma setup...");
+ pwm_transfer_setup();
+// dbg_printf("done\n");
+
+ int count = 0;
+ while (dma_busy) {
+ count++;
+ }
+
+// dbg_printf("dma tx done: count=%d\n", count);
+ } else {
+ gpio_a_loop();
+ }
+ }
+
+ return 0;
+}
+
+extern "C"
+void DMA1_Channel3_IRQHandler() {
+ ITStatus tc = DMA_GetITStatus(DMA1_IT_TC3);
+ ITStatus te = DMA_GetITStatus(DMA1_IT_TE3);
+ ITStatus ht = DMA_GetITStatus(DMA1_IT_HT3);
+
+ if (tc || te || ht) {
+ DMA_ClearITPendingBit(DMA1_IT_GL3);
+ dma_busy = false;
+ }
+}
diff --git a/apps/stepper2/CMakeLists.txt b/apps/stepper2/CMakeLists.txt
new file mode 100644
index 0000000..67d76b0
--- /dev/null
+++ b/apps/stepper2/CMakeLists.txt
@@ -0,0 +1,20 @@
+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_rcc.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_spi.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_tim.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_dma.c
+ $<TARGET_OBJECTS:playground>
+ )
+
+target_include_directories(stepper2.elf PUBLIC
+ $<TARGET_PROPERTY:playground,INTERFACE_INCLUDE_DIRECTORIES>
+ )
+target_compile_definitions(stepper2.elf PUBLIC ${STM32F10X_STDPERIPH_DEFINES})
+target_link_libraries(stepper2.elf tinyprintf)
+
+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
new file mode 100644
index 0000000..75603ac
--- /dev/null
+++ b/apps/stepper2/stepper2.cpp
@@ -0,0 +1,241 @@
+#include <stdint.h>
+#include <stm32f10x.h>
+#include <stm32f10x_rcc.h>
+#include <stm32f10x_gpio.h>
+#include <stm32f10x_dma.h>
+#include <stm32f10x_tim.h>
+#include <misc.h>
+
+#include "debug.h"
+#include "tinyprintf.h"
+#include "playground.h"
+
+extern "C"
+__attribute__((naked, used))
+void HardFault_Handler_C(uint32_t *hardfault_args) {
+ dbg_printf("r0 = 0x%08lx (%lu)\n", hardfault_args[0], hardfault_args[0]);
+ dbg_printf("r1 = 0x%08lx (%lu)\n", hardfault_args[1], hardfault_args[1]);
+ dbg_printf("r2 = 0x%08lx (%lu)\n", hardfault_args[2], hardfault_args[2]);
+ dbg_printf("r3 = 0x%08lx (%lu)\n", hardfault_args[3], hardfault_args[3]);
+ dbg_printf("r12 = 0x%08lx (%lu)\n", hardfault_args[4], hardfault_args[4]);
+ dbg_printf("lr = 0x%08lx (%lu)\n", hardfault_args[5], hardfault_args[5]);
+ dbg_printf("pc = 0x%08lx (%lu)\n", hardfault_args[6], hardfault_args[6]);
+ dbg_printf("psr = 0x%08lx (%lu)\n", hardfault_args[7], hardfault_args[7]);
+ dbg_printf("\n");
+
+ halt();
+}
+
+volatile bool dma_busy;
+
+struct motor_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 {
+};
+
+template<typename apb_bus>
+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);
+ }
+};
+
+template<typename apb_bus, uint32_t peripheral>
+class apb_device {
+public:
+ static void reset() {
+ apb_ctrl<apb_bus>::RCC_PeriphResetCmd(peripheral, ENABLE);
+ apb_ctrl<apb_bus>::RCC_PeriphResetCmd(peripheral, DISABLE);
+ }
+
+ static void enable() {
+ apb_ctrl<apb_bus>::RCC_PeriphClockCmd(peripheral, ENABLE);
+ }
+
+ static void disable() {
+ apb_ctrl<apb_bus>::RCC_PeriphClockCmd(peripheral, DISABLE);
+ }
+};
+
+template<typename apb_bus, uint32_t peripheral>
+class gpio_port : public apb_device<apb_bus, peripheral> {
+public:
+};
+
+class gpio_port_a : public gpio_port<apb_bus_2, RCC_APB2Periph_GPIOA> {
+};
+
+class gpio_port_b : public gpio_port<apb_bus_2, RCC_APB2Periph_GPIOB> {
+};
+
+class gpio_port_c : public gpio_port<apb_bus_2, RCC_APB2Periph_GPIOC> {
+};
+
+class tim2 : public apb_device<apb_bus_1, RCC_APB1Periph_TIM2> {
+};
+
+void timer_init(TIM_TypeDef *tim, uint16_t period) {
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+// tim2::reset();
+// tim2::enable();
+
+ TIM_TimeBaseInitTypeDef timerInitStructure;
+ TIM_TimeBaseStructInit(&timerInitStructure);
+ timerInitStructure.TIM_Prescaler = 0;
+ timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ timerInitStructure.TIM_Period = period;
+ timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
+ timerInitStructure.TIM_RepetitionCounter = 0;
+ TIM_TimeBaseInit(tim, &timerInitStructure);
+}
+
+void pwm_control(TIM_TypeDef *tim, uint16_t pulse) {
+ TIM_OCInitTypeDef outputChannelInit;
+ outputChannelInit.TIM_OCMode = TIM_OCMode_PWM1;
+ outputChannelInit.TIM_Pulse = pulse;
+ outputChannelInit.TIM_OutputState = TIM_OutputState_Enable;
+ outputChannelInit.TIM_OCPolarity = TIM_OCPolarity_High;
+
+ TIM_OC1Init(tim, &outputChannelInit);
+ TIM_OC1PreloadConfig(tim, TIM_OCPreload_Enable);
+
+ TIM_OC2Init(tim, &outputChannelInit);
+ TIM_OC2PreloadConfig(tim, TIM_OCPreload_Enable);
+}
+
+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;
+ init.GPIO_Pin = pins;
+ init.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(gpio_port, &init);
+}
+
+volatile bool run = true;
+
+bool use_gpio = false;
+
+int main() {
+ SystemInit();
+
+ init_printf(nullptr, dbg_putc);
+
+ 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);
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO
+ | RCC_APB2Periph_GPIOA
+ | RCC_APB2Periph_GPIOB
+ | RCC_APB2Periph_GPIOC
+ | RCC_APB2Periph_ADC1
+ | RCC_APB2Periph_ADC2
+ | RCC_APB2Periph_ADC3
+ | RCC_APB2Periph_TIM1,
+ ENABLE);
+
+ const uint16_t period = 1000;
+
+ const int count_max = 10000;
+ int count = count_max - 1;
+
+ 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);
+
+ TIM_ARRPreloadConfig(pwm_timer, ENABLE);
+ TIM_Cmd(pwm_timer, 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);
+ } else {
+ GPIO_ResetBits(motor_a.gpio_port, motor_a.ah);
+ GPIO_ResetBits(motor_a.gpio_port, motor_a.al);
+ }
+ on = !on;
+ } else {
+ count++;
+
+ if (count == count_max) {
+ count = 0;
+
+ pulse++;
+
+ if (pulse > period) {
+ pulse = 0;
+ }
+
+ pwm_timer->CCR1 = pulse;
+ pwm_timer->CCR2 = period - pulse;
+ }
+ }
+ }
+
+ return 0;
+}
+
+extern "C"
+void DMA1_Channel3_IRQHandler() {
+ ITStatus tc = DMA_GetITStatus(DMA1_IT_TC3);
+ ITStatus te = DMA_GetITStatus(DMA1_IT_TE3);
+ ITStatus ht = DMA_GetITStatus(DMA1_IT_HT3);
+
+ if (tc || te || ht) {
+ DMA_ClearITPendingBit(DMA1_IT_GL3);
+ dma_busy = false;
+ }
+}
diff --git a/gdb-start b/gdb-start
index de85932..fbd8789 100644
--- a/gdb-start
+++ b/gdb-start
@@ -1,5 +1,6 @@
target remote tcp:localhost:3333
monitor reset halt
+set remotetimeout 10
define flash_test1
shell cd build && make test1.elf
@@ -46,6 +47,36 @@ define flash_serial2
hbreak halt
end
+define flash_stepper1
+ shell cd build && make stepper1.elf
+
+ monitor arm semihosting enable
+ monitor reset halt
+
+ set confirm off
+ file build/apps/stepper1/stepper1.elf
+ load build/apps/stepper1/stepper1.elf
+ set confirm on
+
+ monitor stm32f1x.cpu mwb 0x20000000 0x5a 20480
+ hbreak halt
+end
+
+define flash_stepper2
+ shell cd build && make stepper2.elf
+
+ monitor arm semihosting enable
+ monitor reset halt
+
+ set confirm off
+ file build/apps/stepper2/stepper2.elf
+ load build/apps/stepper2/stepper2.elf
+ set confirm on
+
+ monitor stm32f1x.cpu mwb 0x20000000 0x5a 20480
+ hbreak halt
+end
+
define flash_os1
shell cd build && make os1.elf