Skip to content

Commit

Permalink
Added/updated low-level ioports driver layer for analog output (PWM).
Browse files Browse the repository at this point in the history
NOTE: not yet used by any board map files.
Workaround for issue #121, settings write failure.
Improved frequency range for spindle PWM.
  • Loading branch information
terjeio committed May 27, 2023
1 parent 0bb6e32 commit b3f5ceb
Show file tree
Hide file tree
Showing 6 changed files with 730 additions and 271 deletions.
199 changes: 198 additions & 1 deletion Inc/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
#define timerCLKENA(t) timercken(t)
#define timercken(t) __HAL_RCC_TIM ## t ## _CLK_ENABLE
#define timerAPB2(t) (t == 1 || t == 8 || t == 9 || t == 10 || t == 11)
#define TIMER_CLOCK_MUL(d) (d == RCC_HCLK_DIV1 ? 1 : 2)

#define usart(t) usartN(t)
#define usartN(t) USART ## t
Expand Down Expand Up @@ -274,6 +275,199 @@
#endif
#endif

#ifdef AUXOUTPUT0_PWM_PORT_BASE

#if AUXOUTPUT0_PWM_PORT_BASE == GPIOA_BASE
#if AUXOUTPUT0_PWM_PIN == 5 // PA5 - TIM2_CH1
#define AUXOUTPUT0_PWM_TIMER_N 2
#define AUXOUTPUT0_PWM_TIMER_CH 1
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 1
#elif AUXOUTPUT0_PWM_PIN == 7 // PA7 - TIM1_CH1N
#define AUXOUTPUT0_PWM_TIMER_N 1
#define AUXOUTPUT0_PWM_TIMER_CH 1
#define AUXOUTPUT0_PWM_TIMER_INV 1
#define AUXOUTPUT0_PWM_TIMER_AF 1
#elif AUXOUTPUT0_PWM_PIN == 8 // PA8 - TIM1_CH1
#define AUXOUTPUT0_PWM_TIMER_N 1
#define AUXOUTPUT0_PWM_TIMER_CH 1
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 1
#endif
#elif AUXOUTPUT0_PWM_PORT_BASE == GPIOB_BASE
#if AUXOUTPUT0_PWM_PIN == 0 // PB0 - TIM1_CH2N
#define AUXOUTPUT0_PWM_TIMER_N 1
#define AUXOUTPUT0_PWM_TIMER_CH 2
#define AUXOUTPUT0_PWM_TIMER_INV 1
#define AUXOUTPUT0_PWM_TIMER_AF 1
#elif AUXOUTPUT0_PWM_PIN == 2 // PB2 - TIM2_CH4
#define AUXOUTPUT0_PWM_TIMER_N 2
#define AUXOUTPUT0_PWM_TIMER_CH 4
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 1
#elif AUXOUTPUT0_PWM_PIN == 3 // PB3 - TIM2_CH2
#define AUXOUTPUT0_PWM_TIMER_N 2
#define AUXOUTPUT0_PWM_TIMER_CH 2
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 1
#elif AUXOUTPUT0_PWM_PIN == 4 // PB4 - TIM3_CH1
#define AUXOUTPUT0_PWM_TIMER_N 3
#define AUXOUTPUT0_PWM_TIMER_CH 1
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 2
#elif AUXOUTPUT0_PWM_PIN == 9 // PB9 - TIM11_CH1
#define AUXOUTPUT0_PWM_TIMER_N 11
#define AUXOUTPUT0_PWM_TIMER_CH 1
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 3
#endif
#elif AUXOUTPUT0_PWM_PORT_BASE == GPIOC_BASE
#if AUXOUTPUT0_PWM_PIN == 8 // PC8 - TIM3_CH3
#define AUXOUTPUT0_PWM_TIMER_N 3
#define AUXOUTPUT0_PWM_TIMER_CH 3
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 2
#endif
#elif AUXOUTPUT0_PWM_PORT_BASE == GPIOE_BASE
#if AUXOUTPUT0_PWM_PIN == 5 // PE5 - TIM9_CH1
#define AUXOUTPUT0_PWM_TIMER_N 9
#define AUXOUTPUT0_PWM_TIMER_CH 1
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 3
#elif AUXOUTPUT0_PWM_PIN == 6 // PE6 - TIM9_CH2
#define AUXOUTPUT0_PWM_TIMER_N 9
#define AUXOUTPUT0_PWM_TIMER_CH 2
#define AUXOUTPUT0_PWM_TIMER_INV 0
#define AUXOUTPUT0_PWM_TIMER_AF 3
#endif
#endif

#if AUXOUTPUT0_PWM_TIMER_CH == 1 || AUXOUTPUT0_PWM_TIMER_CH == 2
#define AUXOUTPUT0_PWM_CCR 1
#else
#define AUXOUTPUT0_PWM_CCR 2
#endif
#define AUXOUTPUT0_PWM_TIMER timer(AUXOUTPUT0_PWM_TIMER_N)
#define AUXOUTPUT0_PWM_TIMER_CCR timerCCR(AUXOUTPUT0_PWM_TIMER_N, AUXOUTPUT0_PWM_TIMER_CH)
#define AUXOUTPUT0_PWM_TIMER_CCMR timerCCMR(AUXOUTPUT0_PWM_TIMER_N, AUXOUTPUT0_PWM_CCR)
#define AUXOUTPUT0_PWM_CCMR_OCM_SET timerOCM(AUXOUTPUT0_PWM_CCR, AUXOUTPUT0_PWM_TIMER_CH)
#define AUXOUTPUT0_PWM_CCMR_OCM_CLR timerOCMC(AUXOUTPUT0_PWM_CCR, AUXOUTPUT0_PWM_TIMER_CH)
#if AUXOUTPUT0_PWM_TIMER_INV
#define AUXOUTPUT0_PWM_CCER_EN timerCCEN(AUXOUTPUT0_PWM_TIMER_CH, N)
#define AUXOUTPUT0_PWM_CCER_POL timerCCP(AUXOUTPUT0_PWM_TIMER_CH, N)
#define AUXOUTPUT0_PWM_CR2_OIS timerCR2OIS(AUXOUTPUT0_PWM_TIMER_CH, N)
#else
#define AUXOUTPUT0_PWM_CCER_EN timerCCEN(AUXOUTPUT0_PWM_TIMER_CH, )
#define AUXOUTPUT0_PWM_CCER_POL timerCCP(AUXOUTPUT0_PWM_TIMER_CH, )
#define AUXOUTPUT0_PWM_CR2_OIS timerCR2OIS(AUXOUTPUT0_PWM_TIMER_CH, )
#endif

#define AUXOUTPUT0_PWM_PORT ((GPIO_TypeDef *)AUXOUTPUT0_PWM_PORT_BASE)
#define AUXOUTPUT0_PWM_AF timerAF(AUXOUTPUT0_PWM_TIMER_N, AUXOUTPUT0_PWM_TIMER_AF)
#define AUXOUTPUT0_PWM_CLOCK_ENA timerCLKENA(AUXOUTPUT0_PWM_TIMER_N)

#endif // AUXOUTPUT0_PWM_PORT_BASE

#ifdef AUXOUTPUT1_PWM_PORT_BASE

#if AUXOUTPUT1_PWM_PORT_BASE == GPIOA_BASE
#if AUXOUTPUT1_PWM_PIN == 5 // PA5 - TIM2_CH1
#define AUXOUTPUT1_PWM_TIMER_N 2
#define AUXOUTPUT1_PWM_TIMER_CH 1
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 1
#elif AUXOUTPUT1_PWM_PIN == 7 // PA7 - TIM1_CH1N
#define AUXOUTPUT1_PWM_TIMER_N 1
#define AUXOUTPUT1_PWM_TIMER_CH 1
#define AUXOUTPUT1_PWM_TIMER_INV 1
#define AUXOUTPUT1_PWM_TIMER_AF 1
#elif AUXOUTPUT1_PWM_PIN == 8 // PA8 - TIM1_CH1
#define AUXOUTPUT1_PWM_TIMER_N 1
#define AUXOUTPUT1_PWM_TIMER_CH 1
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 1
#endif
#elif AUXOUTPUT1_PWM_PORT_BASE == GPIOB_BASE
#if AUXOUTPUT1_PWM_PIN == 0 // PB0 - TIM1_CH2N
#define AUXOUTPUT1_PWM_TIMER_N 1
#define AUXOUTPUT1_PWM_TIMER_CH 2
#define AUXOUTPUT1_PWM_TIMER_INV 1
#define AUXOUTPUT1_PWM_TIMER_AF 1
#elif AUXOUTPUT1_PWM_PIN == 2 // PB2 - TIM2_CH4
#define AUXOUTPUT1_PWM_TIMER_N 2
#define AUXOUTPUT1_PWM_TIMER_CH 4
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 1
#elif AUXOUTPUT1_PWM_PIN == 3 // PB3 - TIM2_CH2
#define AUXOUTPUT1_PWM_TIMER_N 2
#define AUXOUTPUT1_PWM_TIMER_CH 2
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 1
#elif AUXOUTPUT1_PWM_PIN == 4 // PB4 - TIM3_CH1
#define AUXOUTPUT1_PWM_TIMER_N 3
#define AUXOUTPUT1_PWM_TIMER_CH 1
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 2
#elif AUXOUTPUT1_PWM_PIN == 9 // PB9 - TIM11_CH1
#define AUXOUTPUT1_PWM_TIMER_N 11
#define AUXOUTPUT1_PWM_TIMER_CH 1
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 3
#endif
#elif AUXOUTPUT1_PWM_PORT_BASE == GPIOC_BASE
#if AUXOUTPUT1_PWM_PIN == 8 // PC8 - TIM3_CH3
#define AUXOUTPUT1_PWM_TIMER_N 3
#define AUXOUTPUT1_PWM_TIMER_CH 3
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 2
#endif
#elif AUXOUTPUT1_PWM_PORT_BASE == GPIOE_BASE
#if AUXOUTPUT1_PWM_PIN == 5 // PE5 - TIM9_CH1
#define AUXOUTPUT1_PWM_TIMER_N 9
#define AUXOUTPUT1_PWM_TIMER_CH 1
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 3
#elif AUXOUTPUT1_PWM_PIN == 6 // PE6 - TIM9_CH2
#define AUXOUTPUT1_PWM_TIMER_N 9
#define AUXOUTPUT1_PWM_TIMER_CH 2
#define AUXOUTPUT1_PWM_TIMER_INV 0
#define AUXOUTPUT1_PWM_TIMER_AF 3
#endif
#endif

#if AUXOUTPUT1_PWM_TIMER_CH == 1 || AUXOUTPUT1_PWM_TIMER_CH == 2
#define AUXOUTPUT1_PWM_CCR 1
#else
#define AUXOUTPUT1_PWM_CCR 2
#endif
#define AUXOUTPUT1_PWM_TIMER timer(AUXOUTPUT1_PWM_TIMER_N)
#define AUXOUTPUT1_PWM_TIMER_CCR timerCCR(AUXOUTPUT1_PWM_TIMER_N, AUXOUTPUT1_PWM_TIMER_CH)
#define AUXOUTPUT1_PWM_TIMER_CCMR timerCCMR(AUXOUTPUT1_PWM_TIMER_N, AUXOUTPUT1_PWM_CCR)
#define AUXOUTPUT1_PWM_CCMR_OCM_SET timerOCM(AUXOUTPUT1_PWM_CCR, AUXOUTPUT1_PWM_TIMER_CH)
#define AUXOUTPUT1_PWM_CCMR_OCM_CLR timerOCMC(AUXOUTPUT1_PWM_CCR, AUXOUTPUT1_PWM_TIMER_CH)
#if AUXOUTPUT1_PWM_TIMER_INV
#define AUXOUTPUT1_PWM_CCER_EN timerCCEN(AUXOUTPUT1_PWM_TIMER_CH, N)
#define AUXOUTPUT1_PWM_CCER_POL timerCCP(AUXOUTPUT1_PWM_TIMER_CH, N)
#define AUXOUTPUT1_PWM_CR2_OIS timerCR2OIS(AUXOUTPUT1_PWM_TIMER_CH, N)
#else
#define AUXOUTPUT1_PWM_CCER_EN timerCCEN(AUXOUTPUT1_PWM_TIMER_CH, )
#define AUXOUTPUT1_PWM_CCER_POL timerCCP(AUXOUTPUT1_PWM_TIMER_CH, )
#define AUXOUTPUT1_PWM_CR2_OIS timerCR2OIS(AUXOUTPUT1_PWM_TIMER_CH, )
#endif

#define AUXOUTPUT1_PWM_PORT ((GPIO_TypeDef *)AUXOUTPUT1_PWM_PORT_BASE)
#define AUXOUTPUT1_PWM_AF timerAF(AUXOUTPUT1_PWM_TIMER_N, AUXOUTPUT1_PWM_TIMER_AF)
#define AUXOUTPUT1_PWM_CLOCK_ENA timerCLKENA(AUXOUTPUT1_PWM_TIMER_N)

#endif // AUXOUTPUT1_PWM_PORT_BASE

#if defined(AUXOUTPUT0_PWM_PORT_BASE) || defined(AUXOUTPUT1_PWM_PORT_BASE)
#define AUX_ANALOG 1
#else
#define AUX_ANALOG 0
#endif


#if SPINDLE_PWM_TIMER_N == 9
#define DEBOUNCE_TIMER_N 13
#define DEBOUNCE_TIMER_IRQn TIM8_UP_TIM13_IRQn // !
Expand Down Expand Up @@ -364,7 +558,7 @@
#define KEYPAD_TEST 0
#endif

#if MODBUS_TEST + KEYPAD_TEST + MPG_TEST + TRINAMIC_TEST + BLUETOOTH_ENABLE > 1
#if MODBUS_TEST + KEYPAD_TEST + MPG_TEST + TRINAMIC_TEST + (BLUETOOTH_ENABLE ? 1 : 0) > 1
#error "Only one option that uses the serial port can be enabled!"
#endif

Expand Down Expand Up @@ -464,6 +658,9 @@ void board_init (void);
#endif
#ifdef HAS_IOPORTS
void ioports_init(pin_group_pins_t *aux_inputs, pin_group_pins_t *aux_outputs);
#if AUX_ANALOG
void ioports_init_analog (pin_group_pins_t *aux_inputs, pin_group_pins_t *aux_outputs);
#endif
void ioports_event (uint32_t bit);
#endif

Expand Down
53 changes: 41 additions & 12 deletions Src/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@
#endif

#define STEPPER_TIMER_DIV 4
#define TIMER_CLOCK_MUL(d) (d == RCC_HCLK_DIV1 ? 1 : 2)

typedef union {
uint8_t mask;
Expand Down Expand Up @@ -444,7 +443,19 @@ static output_signal_t outputpin[] = {
{ .id = Output_Aux6, .port = AUXOUTPUT6_PORT, .pin = AUXOUTPUT6_PIN, .group = PinGroup_AuxOutput },
#endif
#ifdef AUXOUTPUT7_PORT
{ .id = Output_Aux7, .port = AUXOUTPUT7_PORT, .pin = AUXOUTPUT7_PIN, .group = PinGroup_AuxOutput }
{ .id = Output_Aux7, .port = AUXOUTPUT7_PORT, .pin = AUXOUTPUT7_PIN, .group = PinGroup_AuxOutput },
#endif
#ifdef AUXOUTPUT0_PWM_PORT
{ .id = Output_Analog_Aux0, .port = AUXOUTPUT0_PWM_PORT, .pin = AUXOUTPUT0_PWM_PIN, .group = PinGroup_AuxOutputAnalog, .mode = { PINMODE_PWM } },
#endif
#ifdef AUXOUTPUT0_ANALOG_PORT
{ .id = Output_Analog_Aux0, .port = AUXOUTPUT0_ANALOG_PORT, .pin = AUXOUTPUT0_ANALOG_PIN, .group = PinGroup_AuxOutputAnalog },
#endif
#ifdef AUXOUTPUT1_PWM_PORT
{ .id = Output_Analog_Aux1, .port = AUXOUTPUT1_PWM_PORT, .pin = AUXOUTPUT1_PWM_PIN, .group = PinGroup_AuxOutputAnalog, .mode = { PINMODE_PWM } },
#endif
#ifdef AUXOUTPUT1_ANALOG_PORT
{ .id = Output_Analog_Aux1, .port = AUXOUTPUT1_ANALOG_PORT, .pin = AUXOUTPUT1_ANALOG_PIN, .group = PinGroup_AuxOutputAnalog }
#endif
};

Expand Down Expand Up @@ -1234,7 +1245,7 @@ static bool spindleConfig (spindle_ptrs_t *spindle)
return false;

RCC_ClkInitTypeDef clock;
uint32_t latency, prescaler = settings.spindle.pwm_freq > 4000.0f ? 1 : (settings.spindle.pwm_freq > 200.0f ? 12 : 25);
uint32_t latency, prescaler = 1;

HAL_RCC_GetClockConfig(&clock, &latency);

Expand All @@ -1244,6 +1255,15 @@ static bool spindleConfig (spindle_ptrs_t *spindle)
if((spindle->cap.variable = !settings.spindle.flags.pwm_disable && spindle_precompute_pwm_values(spindle, &spindle_pwm, (HAL_RCC_GetPCLK1Freq() * TIMER_CLOCK_MUL(clock.APB1CLKDivider)) / prescaler))) {
#endif

while(spindle_pwm.period > 65534) {
prescaler++;
#if SPINDLE_PWM_TIMER_N == 1
spindle_precompute_pwm_values(spindle, &spindle_pwm, (HAL_RCC_GetPCLK2Freq() * TIMER_CLOCK_MUL(clock.APB2CLKDivider)) / prescaler);
#else
ispindle_precompute_pwm_values(spindle, &spindle_pwm, (HAL_RCC_GetPCLK1Freq() * TIMER_CLOCK_MUL(clock.APB1CLKDivider)) / prescaler);
#endif
}

spindle->set_state = spindleSetStateVariable;

SPINDLE_PWM_TIMER->CR1 &= ~TIM_CR1_CEN;
Expand Down Expand Up @@ -1999,7 +2019,7 @@ static bool driver_setup (settings_t *settings)
hal.delay_ms(100, NULL);

for(i = 0 ; i < sizeof(outputpin) / sizeof(output_signal_t); i++) {
if(outputpin[i].group != PinGroup_StepperPower) {
if(!(outputpin[i].group == PinGroup_StepperPower || outputpin[i].group == PinGroup_AuxOutputAnalog)) {
GPIO_Init.Pin = 1 << outputpin[i].pin;
GPIO_Init.Mode = outputpin[i].mode.open_drain ? GPIO_MODE_OUTPUT_OD : GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(outputpin[i].port, &GPIO_Init);
Expand Down Expand Up @@ -2432,14 +2452,14 @@ bool driver_init (void)

uint32_t i;
input_signal_t *input;
static pin_group_pins_t aux_inputs = {0}, aux_outputs = {0};
static pin_group_pins_t aux_digital_in = {0}, aux_digital_out = {0}, aux_analog_out = {0};

for(i = 0 ; i < sizeof(inputpin) / sizeof(input_signal_t); i++) {
input = &inputpin[i];
if(input->group == PinGroup_AuxInput) {
if(aux_inputs.pins.inputs == NULL)
aux_inputs.pins.inputs = input;
input->id = (pin_function_t)(Input_Aux0 + aux_inputs.n_pins++);
if(aux_digital_in.pins.inputs == NULL)
aux_digital_in.pins.inputs = input;
input->id = (pin_function_t)(Input_Aux0 + aux_digital_in.n_pins++);
input->bit = 1 << input->pin;
input->cap.pull_mode = PullMode_UpDown;
input->cap.irq_mode = (DRIVER_IRQMASK & input->bit) ? IRQ_Mode_None : IRQ_Mode_Edges;
Expand All @@ -2450,14 +2470,23 @@ bool driver_init (void)
for(i = 0 ; i < sizeof(outputpin) / sizeof(output_signal_t); i++) {
output = &outputpin[i];
if(output->group == PinGroup_AuxOutput) {
if(aux_outputs.pins.outputs == NULL)
aux_outputs.pins.outputs = output;
output->id = (pin_function_t)(Output_Aux0 + aux_outputs.n_pins++);
if(aux_digital_out.pins.outputs == NULL)
aux_digital_out.pins.outputs = output;
output->id = (pin_function_t)(Output_Aux0 + aux_digital_out.n_pins++);
} else if(output->group == PinGroup_AuxOutputAnalog) {
if(aux_analog_out.pins.outputs == NULL)
aux_analog_out.pins.outputs = output;
output->id = (pin_function_t)(Output_Analog_Aux0 + aux_analog_out.n_pins++);
}
}

#ifdef HAS_IOPORTS
ioports_init(&aux_inputs, &aux_outputs);
if(aux_digital_in.n_pins || aux_digital_out.n_pins)
ioports_init(&aux_digital_in, &aux_digital_out);
#if AUX_ANALOG
if(aux_analog_out.n_pins)
ioports_init_analog(NULL, &aux_analog_out);
#endif
#endif

#ifdef HAS_BOARD_INIT
Expand Down
10 changes: 6 additions & 4 deletions Src/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Part of grblHAL
Copyright (c) 2019-2021 Terje Io
Copyright (c) 2019-2023 Terje Io
This code reads/writes the whole RAM-based emulated EPROM contents from/to flash
Expand Down Expand Up @@ -57,14 +57,16 @@ bool memcpy_to_flash (uint8_t *source)

uint32_t error;

status = HAL_FLASHEx_Erase(&erase, &error);
// Retry erase once if it fails (ref issue #121)
if((status = HAL_FLASHEx_Erase(&erase, &error)) != HAL_OK)
status = HAL_FLASHEx_Erase(&erase, &error);

uint16_t *data = (uint16_t *)source;
uint32_t address = (uint32_t)&_EEPROM_Emul_Start, remaining = (uint32_t)hal.nvs.size;

while(remaining && status == HAL_OK) {
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, *data++);
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address + 2, *data++);
if((status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, *data++)) == HAL_OK)
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address + 2, *data++);
address += 4;
remaining -= 4;
}
Expand Down
Loading

0 comments on commit b3f5ceb

Please sign in to comment.