diff --git a/src/stm32f1/Makefile b/src/stm32f1/Makefile index 44643e5e..a4074263 100644 --- a/src/stm32f1/Makefile +++ b/src/stm32f1/Makefile @@ -17,6 +17,8 @@ CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs # Add source files src-y += stm32f1/main.c stm32f1/timer.c stm32f1/gpio.c +src-$(CONFIG_HAVE_GPIO_ADC) += stm32f1/adc.c +src-$(CONFIG_HAVE_GPIO_SPI) += stm32f1/spi.c src-y += $(addprefix ../, $(wildcard lib/hal-stm32f1/source/stm32f1xx_ll_*.c)) src-y += generic/crc16_ccitt.c generic/armcm_irq.c generic/timer_irq.c src-y += ../lib/cmsis-stm32f1/source/system_stm32f1xx.c diff --git a/src/stm32f1/adc.c b/src/stm32f1/adc.c new file mode 100644 index 00000000..2fe4977e --- /dev/null +++ b/src/stm32f1/adc.c @@ -0,0 +1,109 @@ +// ADC functions on STM32F1 +// +// Copyright (C) 2018 Grigori Goronzy +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include // bool +#include "board/io.h" // readb +#include "command.h" // shutdown +#include "compiler.h" // ARRAY_SIZE +#include "gpio.h" // gpio_adc_setup +#include "internal.h" // GPIO +#include "stm32f1xx_ll_adc.h" // LL_ADC_REG_ReadConversionData12 +#include "stm32f1xx_ll_gpio.h" // LL_GPIO_SetPinMode +#include "sched.h" // sched_shutdown + +DECL_CONSTANT(ADC_MAX, 4095); + +#define ADC_DELAY (240 * 8) + +static bool adc_busy; +static uint32_t adc_current_channel; + +static const uint8_t adc_pins[] = { + GPIO('A', 0), GPIO('A', 1), GPIO('A', 2), GPIO('A', 3), + GPIO('A', 4), GPIO('A', 5), GPIO('A', 6), GPIO('A', 7), + GPIO('B', 0), GPIO('B', 1), GPIO('C', 0), GPIO('C', 1), + GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), GPIO('C', 5) +}; + +static const uint32_t adc_channels[] = { + LL_ADC_CHANNEL_0, + LL_ADC_CHANNEL_1, + LL_ADC_CHANNEL_2, + LL_ADC_CHANNEL_3, + LL_ADC_CHANNEL_4, + LL_ADC_CHANNEL_5, + LL_ADC_CHANNEL_6, + LL_ADC_CHANNEL_7, + LL_ADC_CHANNEL_8, + LL_ADC_CHANNEL_9, + LL_ADC_CHANNEL_10, + LL_ADC_CHANNEL_11, + LL_ADC_CHANNEL_12, + LL_ADC_CHANNEL_13, + LL_ADC_CHANNEL_14, + LL_ADC_CHANNEL_15, +}; + +struct gpio_adc +gpio_adc_setup(uint8_t pin) +{ + // Find pin in adc_pins table + int chan; + for (chan=0; ; chan++) { + if (chan >= ARRAY_SIZE(adc_pins)) + shutdown("Not a valid ADC pin"); + if (adc_pins[chan] == pin) + break; + } + + GPIO_TypeDef *regs = digital_regs[GPIO2PORT(pin)]; + uint32_t bit = digital_pins[pin % 16]; + LL_GPIO_SetPinMode(regs, bit, LL_GPIO_MODE_ANALOG); + + return (struct gpio_adc){ .bit = adc_channels[chan] }; +} + +// Try to sample a value. Returns zero if sample ready, otherwise +// returns the number of clock ticks the caller should wait before +// retrying this function. +uint32_t +gpio_adc_sample(struct gpio_adc g) +{ + /* ADC not busy, start conversion */ + if (!readb(&adc_busy)) { + LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, g.bit); + LL_ADC_SetChannelSamplingTime(ADC1, g.bit, LL_ADC_SAMPLINGTIME_239CYCLES_5); + LL_ADC_REG_StartConversionSWStart(ADC1); + adc_busy = true; + adc_current_channel = g.bit; + return ADC_DELAY; + /* ADC finished conversion for this channel */ + } else if (LL_ADC_IsActiveFlag_EOS(ADC1) && + readl(&adc_current_channel) == g.bit) { + LL_ADC_ClearFlag_EOS(ADC1); + adc_busy = false; + return 0; + } + /* Wants to sample another channel, or not finished yet */ + return ADC_DELAY; +} + +// Read a value; use only after gpio_adc_sample() returns zero +uint16_t +gpio_adc_read(struct gpio_adc g) +{ + return LL_ADC_REG_ReadConversionData12(ADC1); +} + +// Cancel a sample that may have been started with gpio_adc_sample() +void +gpio_adc_cancel_sample(struct gpio_adc g) +{ + if (readb(&adc_busy) && readl(&adc_current_channel) == g.bit) { + adc_busy = false; + LL_ADC_ClearFlag_EOS(ADC1); + } +} diff --git a/src/stm32f1/gpio.c b/src/stm32f1/gpio.c index 5deb752b..e6df3888 100644 --- a/src/stm32f1/gpio.c +++ b/src/stm32f1/gpio.c @@ -4,34 +4,24 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include // uint32_t -#include -#include "autoconf.h" // CONFIG_CLOCK_FREQ +#include "board/irq.h" // irq_save #include "command.h" // shutdown #include "compiler.h" // ARRAY_SIZE #include "gpio.h" // gpio_out_setup -#include "stm32f1xx.h" -#include "stm32f1xx_ll_rcc.h" -#include "stm32f1xx_ll_gpio.h" -#include "stm32f1xx_ll_adc.h" -#include "stm32f1xx_ll_spi.h" +#include "internal.h" // GPIO +#include "stm32f1xx_ll_gpio.h" // LL_GPIO_SetPinMode #include "sched.h" // sched_shutdown -#include "board/irq.h" -#include "board/io.h" /**************************************************************** * Pin mappings ****************************************************************/ -#define GPIO(PORT, NUM) (((PORT)-'A') * 16 + (NUM)) -#define GPIO2PORT(PIN) ((PIN) / 16) - -static GPIO_TypeDef *const digital_regs[] = { +GPIO_TypeDef *const digital_regs[] = { GPIOA, GPIOB, GPIOC, GPIOD, GPIOE }; -static uint32_t const digital_pins[] = { +uint32_t const digital_pins[] = { LL_GPIO_PIN_0, LL_GPIO_PIN_1, LL_GPIO_PIN_2, @@ -136,205 +126,3 @@ gpio_in_read(struct gpio_in g) { return LL_GPIO_IsInputPinSet(g.regs, g.bit); } - - -/**************************************************************** - * Analog to Digital Converter (ADC) pins - ****************************************************************/ - -DECL_CONSTANT(ADC_MAX, 4095); - -#define ADC_DELAY (240 * 8) - -static bool adc_busy; -static uint32_t adc_current_channel; - -static const uint8_t adc_pins[] = { - GPIO('A', 0), GPIO('A', 1), GPIO('A', 2), GPIO('A', 3), - GPIO('A', 4), GPIO('A', 5), GPIO('A', 6), GPIO('A', 7), - GPIO('B', 0), GPIO('B', 1), GPIO('C', 0), GPIO('C', 1), - GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), GPIO('C', 5) -}; - -static const uint32_t adc_channels[] = { - LL_ADC_CHANNEL_0, - LL_ADC_CHANNEL_1, - LL_ADC_CHANNEL_2, - LL_ADC_CHANNEL_3, - LL_ADC_CHANNEL_4, - LL_ADC_CHANNEL_5, - LL_ADC_CHANNEL_6, - LL_ADC_CHANNEL_7, - LL_ADC_CHANNEL_8, - LL_ADC_CHANNEL_9, - LL_ADC_CHANNEL_10, - LL_ADC_CHANNEL_11, - LL_ADC_CHANNEL_12, - LL_ADC_CHANNEL_13, - LL_ADC_CHANNEL_14, - LL_ADC_CHANNEL_15, -}; - -struct gpio_adc -gpio_adc_setup(uint8_t pin) -{ - // Find pin in adc_pins table - int chan; - for (chan=0; ; chan++) { - if (chan >= ARRAY_SIZE(adc_pins)) - shutdown("Not a valid ADC pin"); - if (adc_pins[chan] == pin) - break; - } - - GPIO_TypeDef *regs = digital_regs[GPIO2PORT(pin)]; - uint32_t bit = digital_pins[pin % 16]; - LL_GPIO_SetPinMode(regs, bit, LL_GPIO_MODE_ANALOG); - - return (struct gpio_adc){ .bit = adc_channels[chan] }; -} - -// Try to sample a value. Returns zero if sample ready, otherwise -// returns the number of clock ticks the caller should wait before -// retrying this function. -uint32_t -gpio_adc_sample(struct gpio_adc g) -{ - /* ADC not busy, start conversion */ - if (!readb(&adc_busy)) { - LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, g.bit); - LL_ADC_SetChannelSamplingTime(ADC1, g.bit, LL_ADC_SAMPLINGTIME_239CYCLES_5); - LL_ADC_REG_StartConversionSWStart(ADC1); - adc_busy = true; - adc_current_channel = g.bit; - return ADC_DELAY; - /* ADC finished conversion for this channel */ - } else if (LL_ADC_IsActiveFlag_EOS(ADC1) && - readl(&adc_current_channel) == g.bit) { - LL_ADC_ClearFlag_EOS(ADC1); - adc_busy = false; - return 0; - } - /* Wants to sample another channel, or not finished yet */ - return ADC_DELAY; -} - -// Read a value; use only after gpio_adc_sample() returns zero -uint16_t -gpio_adc_read(struct gpio_adc g) -{ - return LL_ADC_REG_ReadConversionData12(ADC1); -} - -// Cancel a sample that may have been started with gpio_adc_sample() -void -gpio_adc_cancel_sample(struct gpio_adc g) -{ - if (readb(&adc_busy) && readl(&adc_current_channel) == g.bit) { - adc_busy = false; - LL_ADC_ClearFlag_EOS(ADC1); - } -} - -/**************************************************************** - * Serial Peripheral Interface (SPI) pins - ****************************************************************/ - -void spi_set_mode(SPI_TypeDef *spi, uint8_t mode) -{ - switch (mode) { - case 0: - LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_LOW); - LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_1EDGE); - break; - case 1: - LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_LOW); - LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_2EDGE); - break; - case 2: - LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_HIGH); - LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_1EDGE); - break; - case 3: - LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_HIGH); - LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_2EDGE); - break; - default: - shutdown("Invalid SPI mode"); - } -} - -void spi_set_baudrate(SPI_TypeDef *spi, uint32_t rate) -{ - const uint32_t pclk = __LL_RCC_CALC_PCLK1_FREQ(SystemCoreClock, LL_RCC_GetAPB1Prescaler()); - const uint32_t prescaler = pclk / rate; - - uint32_t setting = LL_SPI_BAUDRATEPRESCALER_DIV256; - if (prescaler <= 2) - setting = LL_SPI_BAUDRATEPRESCALER_DIV2; - else if (prescaler <= 4) - setting = LL_SPI_BAUDRATEPRESCALER_DIV4; - else if (prescaler <= 8) - setting = LL_SPI_BAUDRATEPRESCALER_DIV8; - else if (prescaler <= 16) - setting = LL_SPI_BAUDRATEPRESCALER_DIV16; - else if (prescaler <= 32) - setting = LL_SPI_BAUDRATEPRESCALER_DIV32; - else if (prescaler <= 64) - setting = LL_SPI_BAUDRATEPRESCALER_DIV64; - else if (prescaler <= 128) - setting = LL_SPI_BAUDRATEPRESCALER_DIV128; - - LL_SPI_SetBaudRatePrescaler(spi, setting); -} - -void spi_init_pins(void) -{ - LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_14, LL_GPIO_MODE_INPUT); - LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_15, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_PUSHPULL); - LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_14, LL_GPIO_PULL_UP); - LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_15, LL_GPIO_OUTPUT_PUSHPULL); -} - -struct spi_config -spi_setup(uint32_t bus, uint8_t mode, uint32_t rate) -{ - struct spi_config config; - config.config = *SPI2; - - if (bus > 0 || !rate) - shutdown("Invalid spi_setup parameters"); - - spi_init_pins(); - spi_set_mode(&config.config, mode); - spi_set_baudrate(&config.config, rate); - - return config; -} - -void -spi_prepare(struct spi_config config) -{ - *SPI2 = config.config; - LL_SPI_Enable(SPI2); -} - -void -spi_transfer(struct spi_config config, uint8_t receive_data, - uint8_t len, uint8_t *data) -{ - while (len--) { - LL_SPI_TransmitData8(SPI2, *data); - while (!LL_SPI_IsActiveFlag_TXE(SPI2)); - if (receive_data) { - while (!LL_SPI_IsActiveFlag_RXNE(SPI2)); - *data = LL_SPI_ReceiveData8(SPI2); - } - data++; - } - - while (LL_SPI_IsActiveFlag_BSY(SPI2)); - LL_SPI_Disable(SPI2); -} diff --git a/src/stm32f1/internal.h b/src/stm32f1/internal.h new file mode 100644 index 00000000..be9ea4d0 --- /dev/null +++ b/src/stm32f1/internal.h @@ -0,0 +1,11 @@ +#ifndef __STM32F1_INTERNAL_H +#define __STM32F1_INTERNAL_H +// Local definitions for STM32F1 code + +#define GPIO(PORT, NUM) (((PORT)-'A') * 16 + (NUM)) +#define GPIO2PORT(PIN) ((PIN) / 16) + +extern GPIO_TypeDef *const digital_regs[]; +extern uint32_t const digital_pins[]; + +#endif // internal.h diff --git a/src/stm32f1/spi.c b/src/stm32f1/spi.c new file mode 100644 index 00000000..ab3a4589 --- /dev/null +++ b/src/stm32f1/spi.c @@ -0,0 +1,111 @@ +// SPI functions on STM32F1 +// +// Copyright (C) 2018 Grigori Goronzy +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "command.h" // shutdown +#include "gpio.h" // spi_setup +#include "sched.h" // sched_shutdown +#include "stm32f1xx_ll_gpio.h" // LL_GPIO_SetPinMode +#include "stm32f1xx_ll_rcc.h" // __LL_RCC_CALC_PCLK1_FREQ +#include "stm32f1xx_ll_spi.h" // LL_SPI_Enable + +static void spi_set_mode(SPI_TypeDef *spi, uint8_t mode) +{ + switch (mode) { + case 0: + LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_LOW); + LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_1EDGE); + break; + case 1: + LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_LOW); + LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_2EDGE); + break; + case 2: + LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_HIGH); + LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_1EDGE); + break; + case 3: + LL_SPI_SetClockPolarity(spi, LL_SPI_POLARITY_HIGH); + LL_SPI_SetClockPhase(spi, LL_SPI_PHASE_2EDGE); + break; + default: + shutdown("Invalid SPI mode"); + } +} + +static void spi_set_baudrate(SPI_TypeDef *spi, uint32_t rate) +{ + const uint32_t pclk = __LL_RCC_CALC_PCLK1_FREQ(SystemCoreClock, LL_RCC_GetAPB1Prescaler()); + const uint32_t prescaler = pclk / rate; + + uint32_t setting = LL_SPI_BAUDRATEPRESCALER_DIV256; + if (prescaler <= 2) + setting = LL_SPI_BAUDRATEPRESCALER_DIV2; + else if (prescaler <= 4) + setting = LL_SPI_BAUDRATEPRESCALER_DIV4; + else if (prescaler <= 8) + setting = LL_SPI_BAUDRATEPRESCALER_DIV8; + else if (prescaler <= 16) + setting = LL_SPI_BAUDRATEPRESCALER_DIV16; + else if (prescaler <= 32) + setting = LL_SPI_BAUDRATEPRESCALER_DIV32; + else if (prescaler <= 64) + setting = LL_SPI_BAUDRATEPRESCALER_DIV64; + else if (prescaler <= 128) + setting = LL_SPI_BAUDRATEPRESCALER_DIV128; + + LL_SPI_SetBaudRatePrescaler(spi, setting); +} + +static void spi_init_pins(void) +{ + LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_14, LL_GPIO_MODE_INPUT); + LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_15, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_PUSHPULL); + LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_14, LL_GPIO_PULL_UP); + LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_15, LL_GPIO_OUTPUT_PUSHPULL); +} + +struct spi_config +spi_setup(uint32_t bus, uint8_t mode, uint32_t rate) +{ + struct spi_config config; + config.config = *SPI2; + + if (bus > 0 || !rate) + shutdown("Invalid spi_setup parameters"); + + spi_init_pins(); + spi_set_mode(&config.config, mode); + spi_set_baudrate(&config.config, rate); + + return config; +} + +void +spi_prepare(struct spi_config config) +{ + *SPI2 = config.config; + LL_SPI_Enable(SPI2); +} + +void +spi_transfer(struct spi_config config, uint8_t receive_data, + uint8_t len, uint8_t *data) +{ + while (len--) { + LL_SPI_TransmitData8(SPI2, *data); + while (!LL_SPI_IsActiveFlag_TXE(SPI2)); + if (receive_data) { + while (!LL_SPI_IsActiveFlag_RXNE(SPI2)); + *data = LL_SPI_ReceiveData8(SPI2); + } + data++; + } + + while (LL_SPI_IsActiveFlag_BSY(SPI2)); + LL_SPI_Disable(SPI2); +}