diff --git a/stm32f103c8t6/build_number.txt b/stm32f103c8t6/build_number.txt index e01062f..9b5c454 100644 --- a/stm32f103c8t6/build_number.txt +++ b/stm32f103c8t6/build_number.txt @@ -1 +1 @@ -282 +319 diff --git a/stm32f103c8t6/src/pinning.h b/stm32f103c8t6/src/pinning.h index 11f3820..ec9b2de 100644 --- a/stm32f103c8t6/src/pinning.h +++ b/stm32f103c8t6/src/pinning.h @@ -8,7 +8,7 @@ // #define PIN_USB_PULLUP 15 // PA15 - 1.5 kΩ to D+ // Port B -#define PIN_PEN_STATE 6 // PB6 +#define PIN_PEN_STATE 6 // PB6 - TIM4_CH1 // Port C #define PIN_LED 13 // PC13 - Status LED diff --git a/stm32f103c8t6/src/pwm_output.c b/stm32f103c8t6/src/pwm_output.c index ae47f05..0cc1198 100644 --- a/stm32f103c8t6/src/pwm_output.c +++ b/stm32f103c8t6/src/pwm_output.c @@ -9,11 +9,13 @@ MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_X); MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_Y); MODULE_OWNS_PIN(GPIOB, PIN_PEN_STATE); MODULE_OWNS_PERIPHERAL(TIM1); +MODULE_OWNS_PERIPHERAL(TIM4); static HPGL_Movement_t Output_Buffer[CONFIG_BUFFER_MOVEMENTS]; static const HPGL_Movement_t *Output_BufferRead = Output_Buffer; static HPGL_Movement_t *Output_BufferWrite = Output_Buffer; -static bool Output_PenIsDown; +//static bool Output_PenIsDown; +static unsigned int Output_PenState = OUTPUT_PEN_UP; static unsigned int Output_DelayCounter = 0; typedef struct @@ -26,7 +28,7 @@ static Output_Coordinate_t Output_CurrentLineStart = {0, 0}; static Output_Coordinate_t Output_CurrentLineEnd = {0, 0}; static unsigned int Output_CurrentLineLength; static unsigned int Output_CurrentLinePosition; -static unsigned int Output_CurrentVelocity = OUTPUT_LENGTH_SCALE / 2; +static unsigned int Output_CurrentVelocity = OUTPUT_LENGTH_SCALE / 3; bool Output_EnqueueMovement(HPGL_Movement_t movement) { @@ -60,14 +62,14 @@ bool Output_EnqueueMovement(HPGL_Movement_t movement) static void Output_PenDown(void) { - GPIOB->BRR = (1 << PIN_PEN_STATE); - Output_PenIsDown = true; + Output_PenState = OUTPUT_PEN_START; + TIM4->CCR1 = Output_PenState; } static void Output_PenUp(void) { - GPIOB->BSRR = (1 << PIN_PEN_STATE); - Output_PenIsDown = false; + Output_PenState = OUTPUT_PEN_UP; + TIM4->CCR1 = Output_PenState; } static unsigned int Output_ApproximateLength(int dx, int dy) @@ -100,17 +102,18 @@ static bool Output_FetchNextPoint(void) } const HPGL_Movement_t *movement = Output_BufferRead; - if(movement->pen_down != Output_PenIsDown) + if(movement->pen_down != (Output_PenState == OUTPUT_PEN_DOWN)) { if(movement->pen_down) { Output_PenDown(); + Output_DelayCounter = OUTPUT_PEN_DOWN_DELAY; } else { Output_PenUp(); + Output_DelayCounter = OUTPUT_PEN_UP_DELAY; } - Output_DelayCounter = OUTPUT_PEN_DELAY; return false; } @@ -139,8 +142,38 @@ static void Output_Position(Output_Coordinate_t position) TIM1->CCR2 = compare_y; } +// Update the pen PWM output if the pen is currently moving, return false +// otherwise +static bool Output_UpdatePen(void) +{ + // Only the downwards motion of the pen is smoothed. Thus, the direction is + // implied within the state variable (intermediate values only occur while + // the pen is being lowered). + if((Output_PenState == OUTPUT_PEN_DOWN) + || (Output_PenState == OUTPUT_PEN_UP)) + { + return false; + } + + Output_PenState += OUTPUT_PEN_STEP; + if(Output_PenState >= OUTPUT_PEN_STOP) + { + Output_PenState = OUTPUT_PEN_DOWN; + } + TIM4->CCR1 = Output_PenState; + + return true; +} + void Output_Tick(void) { + // Do not move while pen is lowered + if(Output_UpdatePen()) + { + return; + } + + // Wait for a bit longer after each pen state change if(Output_DelayCounter > 0) { Output_DelayCounter--; @@ -188,6 +221,7 @@ void Output_Tick(void) void Output_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; @@ -202,7 +236,7 @@ void Output_Init(void) GPIOB->CRL = (GPIOB->CRL & ~(0xf << (4 * PIN_PEN_STATE))) - | (0x6 << (4 * PIN_PEN_STATE)) // OD output, 2 MHz + | (0xe << (4 * PIN_PEN_STATE)) // AF-OD output, 2 MHz ; TIM1->CCMR1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 @@ -213,6 +247,13 @@ void Output_Init(void) TIM1->DIER = TIM_DIER_UIE; TIM1->CR1 = TIM_CR1_CEN; NVIC_EnableIRQ(TIM1_UP_IRQn); + + TIM4->CCMR1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; + TIM4->CCER = TIM_CCER_CC1P | TIM_CCER_CC1E; + TIM4->PSC = OUTPUT_PEN_PRESCALER - 1; + TIM4->ARR = OUTPUT_PEN_RELOAD; + TIM4->CCR1 = OUTPUT_PEN_UP; + TIM4->CR1 = TIM_CR1_CEN; } void TIM1_UP_IRQHandler(void) diff --git a/stm32f103c8t6/src/pwm_output.h b/stm32f103c8t6/src/pwm_output.h index 745c62a..70896f6 100644 --- a/stm32f103c8t6/src/pwm_output.h +++ b/stm32f103c8t6/src/pwm_output.h @@ -1,8 +1,10 @@ #pragma once #include "hpgl.h" +#include "clock.h" -// PWM coordinate output settings +// PWM coordinate output settings (reoslution also determines the movement +// timer tick frequency) #define OUTPUT_PWM_RESOLUTION 15 // In bits #define OUTPUT_PWM_OFFSET 300 // Minimum value @@ -16,7 +18,24 @@ #define OUTPUT_LENGTH_SCALE (1 << 3) // Delay after initiating pen-up/-down before continuing movements -#define OUTPUT_PEN_DELAY 200 // In timer ticks +#define OUTPUT_PEN_UP_DELAY 200 // In movement timer ticks +#define OUTPUT_PEN_DOWN_DELAY 20 // In movement timer ticks + +// PWM frequency for the pen state output +#define OUTPUT_PEN_FREQUENCY 120 // In Hertz + +// Resulting timer settings for pen PWM output +#define OUTPUT_PEN_PRESCALER (CLOCK_APB1 / OUTPUT_PEN_FREQUENCY / 65535 + 1) +#define OUTPUT_PEN_RELOAD ((uint16_t)(CLOCK_APB1 / OUTPUT_PEN_FREQUENCY \ + / OUTPUT_PEN_PRESCALER - 1)) +#define OUTPUT_PEN_UP 0 +#define OUTPUT_PEN_DOWN (OUTPUT_PEN_RELOAD + 1) + +// Start and stop duty cycles and duty cycle step (per movement timer tick) for +// gracefully lowering the pen +#define OUTPUT_PEN_START ((unsigned int)(0.4 * OUTPUT_PEN_RELOAD)) +#define OUTPUT_PEN_STOP ((unsigned int)(0.43 * OUTPUT_PEN_RELOAD)) +#define OUTPUT_PEN_STEP ((unsigned int)(0.0001 * OUTPUT_PEN_RELOAD)) void Output_Init(void); bool Output_EnqueueMovement(HPGL_Movement_t movement);