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)