Use PWM to slowly lower pen

This commit is contained in:
fruchti 2020-12-29 13:43:20 +01:00
parent ab5b2c61e6
commit c9a3535df9
4 changed files with 73 additions and 13 deletions

View file

@ -1 +1 @@
282 319

View file

@ -8,7 +8,7 @@
// #define PIN_USB_PULLUP 15 // PA15 - 1.5 kΩ to D+ // #define PIN_USB_PULLUP 15 // PA15 - 1.5 kΩ to D+
// Port B // Port B
#define PIN_PEN_STATE 6 // PB6 #define PIN_PEN_STATE 6 // PB6 - TIM4_CH1
// Port C // Port C
#define PIN_LED 13 // PC13 - Status LED #define PIN_LED 13 // PC13 - Status LED

View file

@ -9,11 +9,13 @@ MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_X);
MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_Y); MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_Y);
MODULE_OWNS_PIN(GPIOB, PIN_PEN_STATE); MODULE_OWNS_PIN(GPIOB, PIN_PEN_STATE);
MODULE_OWNS_PERIPHERAL(TIM1); MODULE_OWNS_PERIPHERAL(TIM1);
MODULE_OWNS_PERIPHERAL(TIM4);
static HPGL_Movement_t Output_Buffer[CONFIG_BUFFER_MOVEMENTS]; static HPGL_Movement_t Output_Buffer[CONFIG_BUFFER_MOVEMENTS];
static const HPGL_Movement_t *Output_BufferRead = Output_Buffer; static const HPGL_Movement_t *Output_BufferRead = Output_Buffer;
static HPGL_Movement_t *Output_BufferWrite = 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; static unsigned int Output_DelayCounter = 0;
typedef struct typedef struct
@ -26,7 +28,7 @@ static Output_Coordinate_t Output_CurrentLineStart = {0, 0};
static Output_Coordinate_t Output_CurrentLineEnd = {0, 0}; static Output_Coordinate_t Output_CurrentLineEnd = {0, 0};
static unsigned int Output_CurrentLineLength; static unsigned int Output_CurrentLineLength;
static unsigned int Output_CurrentLinePosition; 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) bool Output_EnqueueMovement(HPGL_Movement_t movement)
{ {
@ -60,14 +62,14 @@ bool Output_EnqueueMovement(HPGL_Movement_t movement)
static void Output_PenDown(void) static void Output_PenDown(void)
{ {
GPIOB->BRR = (1 << PIN_PEN_STATE); Output_PenState = OUTPUT_PEN_START;
Output_PenIsDown = true; TIM4->CCR1 = Output_PenState;
} }
static void Output_PenUp(void) static void Output_PenUp(void)
{ {
GPIOB->BSRR = (1 << PIN_PEN_STATE); Output_PenState = OUTPUT_PEN_UP;
Output_PenIsDown = false; TIM4->CCR1 = Output_PenState;
} }
static unsigned int Output_ApproximateLength(int dx, int dy) 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; 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) if(movement->pen_down)
{ {
Output_PenDown(); Output_PenDown();
Output_DelayCounter = OUTPUT_PEN_DOWN_DELAY;
} }
else else
{ {
Output_PenUp(); Output_PenUp();
Output_DelayCounter = OUTPUT_PEN_UP_DELAY;
} }
Output_DelayCounter = OUTPUT_PEN_DELAY;
return false; return false;
} }
@ -139,8 +142,38 @@ static void Output_Position(Output_Coordinate_t position)
TIM1->CCR2 = compare_y; 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) 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) if(Output_DelayCounter > 0)
{ {
Output_DelayCounter--; Output_DelayCounter--;
@ -188,6 +221,7 @@ void Output_Tick(void)
void Output_Init(void) void Output_Init(void)
{ {
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
@ -202,7 +236,7 @@ void Output_Init(void)
GPIOB->CRL = (GPIOB->CRL GPIOB->CRL = (GPIOB->CRL
& ~(0xf << (4 * PIN_PEN_STATE))) & ~(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 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->DIER = TIM_DIER_UIE;
TIM1->CR1 = TIM_CR1_CEN; TIM1->CR1 = TIM_CR1_CEN;
NVIC_EnableIRQ(TIM1_UP_IRQn); 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) void TIM1_UP_IRQHandler(void)

View file

@ -1,8 +1,10 @@
#pragma once #pragma once
#include "hpgl.h" #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_RESOLUTION 15 // In bits
#define OUTPUT_PWM_OFFSET 300 // Minimum value #define OUTPUT_PWM_OFFSET 300 // Minimum value
@ -16,7 +18,24 @@
#define OUTPUT_LENGTH_SCALE (1 << 3) #define OUTPUT_LENGTH_SCALE (1 << 3)
// Delay after initiating pen-up/-down before continuing movements // 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); void Output_Init(void);
bool Output_EnqueueMovement(HPGL_Movement_t movement); bool Output_EnqueueMovement(HPGL_Movement_t movement);