From 045f533afae5ff12dd05a8a608a6f86a87b3a039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Thu, 18 Aug 2016 10:45:36 +0200 Subject: [PATCH] add generic way to get register addresses --- global.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++ global.h | 100 +++++++++++++++++------------------------ lib/usart_soft.c | 70 ++++++++++++++++++++++++----- lib/usart_soft.h | 15 ++++--- main.c | 62 ++++---------------------- 5 files changed, 233 insertions(+), 128 deletions(-) create mode 100644 global.c diff --git a/global.c b/global.c new file mode 100644 index 0000000..370a4f5 --- /dev/null +++ b/global.c @@ -0,0 +1,114 @@ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +/** global definitions and methods (code) + * @file global.c + * @author King Kévin + * @date 2016 + */ +/* standard libraries */ +#include // standard integer types +#include // general utilities + +/* STM32 (including CM3) libraries */ +#include // real-time control clock library +#include // general purpose input output library +#include // timer library +#include // interrupt handler +#include // external interrupt defines + +#include "global.h" // common methods + +volatile bool button_flag = false; + +const uint32_t GPIO[] = {GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,GPIOF,GPIOG}; +const uint32_t RCC_GPIO[] = {RCC_GPIOA,RCC_GPIOB,RCC_GPIOC,RCC_GPIOD,RCC_GPIOE,RCC_GPIOF,RCC_GPIOG}; +const uint32_t TIM[] = {~0,TIM1,TIM2,TIM3,TIM4,TIM5,TIM6,TIM7,TIM8,TIM9,TIM10,TIM11,TIM12,TIM13,TIM14,TIM15,TIM16,TIM17}; +const uint32_t RCC_TIM[] = {~0,RCC_TIM1,RCC_TIM2,RCC_TIM3,RCC_TIM4,RCC_TIM5,RCC_TIM6,RCC_TIM7,RCC_TIM8,RCC_TIM9,RCC_TIM10,RCC_TIM11,RCC_TIM12,RCC_TIM13,RCC_TIM14,RCC_TIM15,RCC_TIM16,RCC_TIM17}; +const uint32_t NVIC_TIM_IRQ[] = {~0,~0,NVIC_TIM2_IRQ,NVIC_TIM3_IRQ,NVIC_TIM4_IRQ,NVIC_TIM5_IRQ,NVIC_TIM6_IRQ,NVIC_TIM7_IRQ,~0,~0,~0,~0,~0,~0,~0,~0,~0,~0}; + +char* b2s(uint64_t binary, uint8_t rjust) +{ + static char string[64+1] = {0}; // the string representation to return + int8_t bit = LENGTH(string)-1; // the index of the bit to print + string[bit--] = 0; // terminate string + + while (binary) { + if (binary & 1) { + string[bit--] = '1'; + } else { + string[bit--] = '0'; + } + binary >>= 1; + } + + while (64-bit-1=0) { + string[bit--] = '0'; + } + + return &string[bit+1]; +} + +/** switch on board LED */ +void led_on(void) +{ +#if defined(SYSTEM_BOARD) || defined(BLUE_PILL) + gpio_clear(LED_PORT, LED_PIN); +#elif defined(MAPLE_MINI) + gpio_set(LED_PORT, LED_PIN); +#endif +} +/** switch off board LED */ +void led_off(void) +{ +#if defined(SYSTEM_BOARD) || defined(BLUE_PILL) + gpio_set(LED_PORT, LED_PIN); +#elif defined(MAPLE_MINI) + gpio_clear(LED_PORT, LED_PIN); +#endif +} +/** toggle board LED */ +void led_toggle(void) +{ + gpio_toggle(LED_PORT, LED_PIN); +} + +void board_setup(void) +{ + // setup LED + rcc_periph_clock_enable(LED_RCC); // enable clock for LED + gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); // set LED pin to 'output push-pull' + led_off(); // switch off LED per default + + // setup button +#if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ) + rcc_periph_clock_enable(BUTTON_RCC); // enable clock for button + gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, BUTTON_PIN); // set button pin to input + gpio_clear(BUTTON_PORT, BUTTON_PIN); // pull down to be able to detect button push (go high) + rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt + exti_select_source(BUTTON_EXTI, BUTTON_PORT); // mask external interrupt of this pin only for this port + exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_RISING); // trigger when button is pressed + exti_enable_request(BUTTON_EXTI); // enable external interrupt + nvic_enable_irq(BUTTON_IRQ); // enable interrupt +#endif +} + +#if defined(BUTTON_ISR) && defined(BUTTON_EXTI) +/** interrupt service routine called when button is pressed */ +void BUTTON_ISR(void) +{ + exti_reset_request(BUTTON_EXTI); // reset interrupt + button_flag = true; // perform button action +} +#endif diff --git a/global.h b/global.h index cb1e94c..d40d664 100644 --- a/global.h +++ b/global.h @@ -12,54 +12,44 @@ * along with this program. If not, see . * */ -/** global definitions and methods +/** global definitions and methods (API) * @file global.h * @author King Kévin * @date 2016 */ #pragma once -#include // GPIO defines -#include // interrupt defines -#include // external interrupt defines /** get the length of an array */ #define LENGTH(x) (sizeof(x) / sizeof((x)[0])) +/** concatenate 2 arguments (used to defer concatenation) */ +#define CAT2(x,y) x##y +/** concatenate 3 arguments (used to defer concatenation) */ +#define CAT3(x,y,z) x##y##z -/** @defgroup reg_macro macros to get define values based on other defines values +/** @defgroup reg_table get register address based on identifier + * @note used when the value is not calculated * @{ */ -/** get RCC for GPIO based on GPIO */ -#define RCC_GPIO(x) switch (x) { \ - case GPIOA: RCC_GPIOA; break; \ - case GPIOB: RCC_GPIOB; break; \ - case GPIOC: RCC_GPIOC; break; \ - case GPIOD: RCC_GPIOD; break; \ - case GPIOE: RCC_GPIOE; break; \ - case GPIOF: RCC_GPIOF; break; \ - case GPIOG: RCC_GPIOG; break; \ - default: 0; break; \ -} +/** get GPIO port based on port identifier (0=A, ...) */ +extern const uint32_t GPIO[]; +/** get RCC for GPIO based on GPIO identifier */ +extern const uint32_t RCC_GPIO[]; +/** get TIM based on TIM identifier */ +extern const uint32_t TIM[]; /** get RCC for timer based on TIM */ -#define RCC_TIM(x) switch (x) { \ - case TIM1: RCC_TIM1; break; \ - case TIM2: RCC_TIM2; break; \ - case TIM3: RCC_TIM3; break; \ - case TIM4: RCC_TIM4; break; \ - case TIM5: RCC_TIM5; break; \ - case TIM6: RCC_TIM6; break; \ - case TIM7: RCC_TIM7; break; \ - case TIM8: RCC_TIM8; break; \ - case TIM9: RCC_TIM9; break; \ - case TIM10: RCC_TIM10; break; \ - case TIM11: RCC_TIM11; break; \ - case TIM12: RCC_TIM12; break; \ - case TIM13: RCC_TIM13; break; \ - case TIM14: RCC_TIM14; break; \ - case TIM15: RCC_TIM15; break; \ - case TIM16: RCC_TIM16; break; \ - case TIM17: RCC_TIM17; break; \ - default: 0; break; \ -} +extern const uint32_t RCC_TIM[]; +/** get NVIC IRQ for timer base on TIM */ +extern const uint32_t NVIC_TIM_IRQ[]; +/** @} */ + +/** @defgroup reg_macro macros to get define values based on other defines values + * @note used when the value is calculated or isn't a value + * @{ + */ +/** get GPIO pin based on pin identifier */ +#define GPIO(x) (1< // general purpose input output library #include // timer library #include // interrupt handler +#include // interrupt handler #include "usart_soft.h" // software USART library API #include "global.h" // common methods @@ -35,29 +36,76 @@ /** @defgroup usart_soft_gpio GPIO used for the software USART ports * @{ */ -const static uint32_t usart_soft_rx_ports[USART_SOFT_PORTS] = {}; /**< GPIO ports for RX signals */ -const static uint32_t usart_soft_rx_pins[USART_SOFT_PORTS] = {}; /**< GPIO pins for RX signals */ +static const uint32_t usart_soft_rx_ports[USART_SOFT_RX_PORTS] = {0}; /**< GPIO ports for receive signals */ +static const uint32_t usart_soft_rx_pins[USART_SOFT_RX_PORTS] = {0}; /**< GPIO pins for receive signals */ +static const uint32_t usart_soft_tx_ports[USART_SOFT_TX_PORTS] = {0}; /**< GPIO ports for transmit signals */ +static const uint32_t usart_soft_tx_pins[USART_SOFT_TX_PORTS] = {0}; /**< GPIO pins for transmit signals */ /** @} */ /** @defgroup usart_soft_config USART configurations - * @note this implementation is designed for 8N1 configuration since this is the most common case + * @note this implementation is designed for 8 bits, no parity, any stop configuration since this is the most common case * @{ */ -const static uint32_t usart_soft_baudrate[USART_SOFT_PORTS] = {}; /**< baudrate for USART communication */ +static const uint32_t usart_soft_rx_baudrates[USART_SOFT_RX_PORTS] = {9600}; /**< receive signal baudrates (2400-115200) */ +static const uint32_t usart_soft_tx_baudrates[USART_SOFT_TX_PORTS] = {0}; /**< transmit signal baudrates (2400-115200) */ /** @} */ /** @defgroup usart_soft_timer timer used to same USART signals * @{ */ +#define USART_SOFT_RX_TIMER 3 /**< timer peripheral for receive signals */ +#define USART_SOFT_TX_TIMER 4 /**< timer peripheral for transmit signals */ /** @} */ -void usart_soft_setup(void) +bool usart_soft_setup(void) { - // setup GPIOs - for (uint8_t i = 0; i < USART_SOFT_PORTS; i++) { - rcc_periph_clock_enable(RCC_GPIO(usart_soft_rx_ports[i])); // enable clock for GPIO peripheral - gpio_set_mode(usart_soft_rx_ports[i], GPIO_MODE_INPUT, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, LED_WS2812B_CLK_PIN); // set pin as output - gpio_set_mode(usart_soft_rx_ports[i], GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, usart_soft_rx_pins[i]); // setup GPIO pin USART receive - gpio_set(usart_soft_rx_ports[i], usart_soft_rx_pins[i]); // pull up to avoid noise when not connected + // verify configuration + if ((USART_SOFT_RX_PORTS<0) || (USART_SOFT_RX_PORTS>4)) { + return false; } + if ((USART_SOFT_TX_PORTS<0) || (USART_SOFT_TX_PORTS>4)) { + return false; + } + for (uint8_t i = 0; i < USART_SOFT_RX_PORTS; i++) { + if ((usart_soft_rx_baudrates[i]<2400) || (usart_soft_rx_baudrates[i]>115200)) { + return false; + } + } + for (uint8_t i = 0; i < USART_SOFT_TX_PORTS; i++) { + if ((usart_soft_tx_baudrates[i]<2400) || (usart_soft_tx_baudrates[i]>115200)) { + return false; + } + } + + // setup GPIOs + for (uint8_t i = 0; i < USART_SOFT_RX_PORTS; i++) { + rcc_periph_clock_enable(RCC_GPIO[usart_soft_rx_ports[i]]); // enable clock for GPIO peripheral + gpio_set_mode(GPIO[usart_soft_rx_ports[i]], GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO(usart_soft_rx_pins[i])); // setup GPIO pin USART receive + gpio_set(GPIO[usart_soft_rx_ports[i]], GPIO(usart_soft_rx_pins[i])); // pull up to avoid noise when not connected + } + for (uint8_t i = 0; i < USART_SOFT_TX_PORTS; i++) { + rcc_periph_clock_enable(RCC_GPIO[usart_soft_tx_ports[i]]); // enable clock for GPIO peripheral + gpio_set_mode(GPIO[usart_soft_tx_ports[i]], GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(usart_soft_tx_pins[i])); // setup GPIO pin USART transmit + } + // setup timer + if (USART_SOFT_RX_PORTS>0) { + rcc_periph_clock_enable(RCC_TIM[USART_SOFT_RX_TIMER]); // enable clock for timer peripheral + timer_reset(TIM[USART_SOFT_RX_TIMER]); // reset timer state + timer_set_mode(TIM[USART_SOFT_RX_TIMER], TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up + timer_set_prescaler(TIM[USART_SOFT_RX_TIMER], 0); // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps) + nvic_enable_irq(NVIC_TIM_IRQ[USART_SOFT_RX_TIMER]); // allow interrupt for timer + } + if (USART_SOFT_TX_PORTS>0) { + rcc_periph_clock_enable(RCC_TIM[USART_SOFT_TX_TIMER]); // enable clock for timer peripheral + timer_reset(TIM[USART_SOFT_TX_TIMER]); // reset timer state + timer_set_mode(TIM[USART_SOFT_TX_TIMER], TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up + timer_set_prescaler(TIM[USART_SOFT_TX_TIMER], 0); // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps) + nvic_enable_irq(NVIC_TIM_IRQ[USART_SOFT_TX_TIMER]); // allow interrupt for timer + } + + return true; // setup completed +} + +void TIM_ISR(USART_SOFT_RX_TIMER)(void) +{ } diff --git a/lib/usart_soft.h b/lib/usart_soft.h index 0ab5635..70bdbd8 100644 --- a/lib/usart_soft.h +++ b/lib/usart_soft.h @@ -19,11 +19,16 @@ * @note peripherals used: GPIO @ref usart_soft_gpio, timer @ref usart_soft_timer */ -/** number of software USART ports +/** number of software USART receive ports (0-4) * @note the corresponding GPIOs need to be configured in @p usart_soft_gpio */ -#define USART_SOFT_PORTS 1 - -/** setup software USART ports */ -void usart_soft_setup(void); +#define USART_SOFT_RX_PORTS 1 +/** number of software USART transmit ports (0-4) + * @note the corresponding GPIOs need to be configured in @p usart_soft_gpio + */ +#define USART_SOFT_TX_PORTS 1 +/** setup software USART ports + * @return is setup succeeded, else the configuration is wrong + */ +bool usart_soft_setup(void); diff --git a/main.c b/main.c index 03330e2..d3aaec1 100644 --- a/main.c +++ b/main.c @@ -23,9 +23,9 @@ #include // standard I/O facilities #include // standard utilities #include // standard streams -#include // error number utilities #include // string utilities #include // mathematical utilities +#include // error number utilities /* STM32 (including CM3) libraries */ #include // real-time control clock library @@ -40,19 +40,14 @@ #include "global.h" // board definitions #include "usart.h" // USART utilities #include "usb_cdcacm.h" // USB CDC ACM utilities +#include "usart_soft.h" // software USART utilities /** @defgroup main_flags flag set in interrupts to be processed in main task * @{ */ -volatile bool button_flag = false; /**< flag set when board user button has been pressed/released */ volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */ /** @} */ -/** user input command */ -char command[32] = {0}; -/** user input command index */ -uint8_t command_i = 0; - int _write(int file, char *ptr, int len) { int i; // how much data has been sent @@ -83,27 +78,10 @@ int _write(int file, char *ptr, int len) return -1; } -char* b2s(uint64_t binary, uint8_t rjust) -{ - static char string[64+1] = {0}; // the string representation to return - int8_t bit = LENGTH(string)-1; // the index of the bit to print - string[bit--] = 0; // terminate string - - while (binary) { - if (binary & 1) { - string[bit--] = '1'; - } else { - string[bit--] = '0'; - } - binary >>= 1; - } - - while (64-bit-1=0) { - string[bit--] = '0'; - } - - return &string[bit+1]; -} +/** user input command */ +char command[32] = {0}; +/** user input command index */ +uint8_t command_i = 0; /** process user command * @param[in] str user command string (\0 ended) @@ -162,12 +140,10 @@ error: int main(void) { rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock - - // setup LED - rcc_periph_clock_enable(LED_RCC); // enable clock for LED - gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); // set LED pin to 'output push-pull' - led_off(); // switch off LED per default + // setup board + board_setup(); + // setup USART and USB for user communication usart_setup(); // setup USART (for printing) cdcacm_setup(); // setup USB CDC ACM (for printing) @@ -177,18 +153,6 @@ int main(void) // minimal setup ready printf("welcome to the STM32F1 CuVoodoo example code\n"); // print welcome message - // setup button -#if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ) - rcc_periph_clock_enable(BUTTON_RCC); // enable clock for button - gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, BUTTON_PIN); // set button pin to input - gpio_clear(BUTTON_PORT, BUTTON_PIN); // pull down to be able to detect button push (go high) - rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt - exti_select_source(BUTTON_EXTI, BUTTON_PORT); // mask external interrupt of this pin only for this port - exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_RISING); // trigger when button is pressed - exti_enable_request(BUTTON_EXTI); // enable external interrupt - nvic_enable_irq(BUTTON_IRQ); // enable interrupt -#endif - // setup RTC printf("setup internal RTC: "); rtc_auto_awake(RCC_LSE, 32768-1); // ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect) @@ -264,14 +228,6 @@ int main(void) return 0; } -#if defined(BUTTON_ISR) && defined(BUTTON_EXTI) -/** interrupt service routine called when button is pressed */ -void BUTTON_ISR(void) -{ - exti_reset_request(BUTTON_EXTI); // reset interrupt - button_flag = true; // perform button action -} -#endif /** @brief interrupt service routine called when tick passed on RTC */ void rtc_isr(void)