You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/06/06 08:17:21 UTC
[GitHub] mkiiskila closed pull request #1102: Feature/stm32 pwm enabled
mkiiskila closed pull request #1102: Feature/stm32 pwm enabled
URL: https://github.com/apache/mynewt-core/pull/1102
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/apps/pwm_test/src/main.c b/apps/pwm_test/src/main.c
index 1fc0efec58..495e471fe8 100644
--- a/apps/pwm_test/src/main.c
+++ b/apps/pwm_test/src/main.c
@@ -23,6 +23,34 @@
#include <easing/easing.h>
#include <console/console.h>
+#if (defined NUCLEO_F767ZI)
+# define PWM_TEST_CH_CFG_PIN MCU_AFIO_GPIO(LED_BLINK_PIN, 2)
+# define PWM_TEST_CH_CFG_INV false
+# define PWM_TEST_CH_NUM 2
+# define PWM_TEST_IRQ_PRIO 0
+#elif (defined NUCLEO_F303RE)
+# define PWM_TEST_CH_CFG_PIN MCU_AFIO_GPIO(LED_BLINK_PIN, 1)
+# define PWM_TEST_CH_CFG_INV false
+# define PWM_TEST_CH_NUM 0
+# define PWM_TEST_IRQ_PRIO 0
+#elif (defined NUCLEO_F303K8)
+# define PWM_TEST_CH_CFG_PIN MCU_AFIO_GPIO(LED_BLINK_PIN, 1)
+# define PWM_TEST_CH_CFG_INV false
+# define PWM_TEST_CH_NUM 1
+# define PWM_TEST_IRQ_PRIO 0
+#else
+# define PWM_TEST_CH_CFG_PIN LED_BLINK_PIN
+# define PWM_TEST_CH_CFG_INV true
+# define PWM_TEST_CH_NUM 0
+# define PWM_TEST_IRQ_PRIO 3
+#endif
+
+#if MYNEWT_VAL(SOFT_PWM)
+# define PWM_TEST_DEV "spwm0"
+#else
+# define PWM_TEST_DEV "pwm0"
+#endif
+
struct pwm_dev *pwm;
static uint32_t pwm_freq = 200;
static uint32_t max_steps = 200; /* two seconds motion up/down */
@@ -37,7 +65,7 @@ pwm_cycle_handler(void* unused)
{
int16_t eased;
eased = easing_funct(step, max_steps, top_val);
- pwm_set_duty_cycle(pwm, 0, eased);
+ pwm_set_duty_cycle(pwm, PWM_TEST_CH_NUM, eased);
if (step >= max_steps || step <= 0) {
up = !up;
}
@@ -96,13 +124,13 @@ int
pwm_init(void)
{
struct pwm_chan_cfg chan_conf = {
- .pin = LED_BLINK_PIN,
- .inverted = true,
+ .pin = PWM_TEST_CH_CFG_PIN,
+ .inverted = PWM_TEST_CH_CFG_INV,
.data = NULL,
};
struct pwm_dev_cfg dev_conf = {
.n_cycles = pwm_freq * 6, /* 6 seconds cycles */
- .int_prio = 3,
+ .int_prio = PWM_TEST_IRQ_PRIO,
.cycle_handler = pwm_cycle_handler, /* this won't work on soft_pwm */
.seq_end_handler = pwm_end_seq_handler, /* this won't work on soft_pwm */
.cycle_data = NULL,
@@ -111,11 +139,7 @@ pwm_init(void)
};
int rc;
-#if MYNEWT_VAL(SOFT_PWM)
- pwm = (struct pwm_dev *) os_dev_open("spwm0", 0, NULL);
-#else
- pwm = (struct pwm_dev *) os_dev_open("pwm0", 0, NULL);
-#endif
+ pwm = (struct pwm_dev *) os_dev_open(PWM_TEST_DEV, 0, NULL);
pwm_configure_device(pwm, &dev_conf);
@@ -123,12 +147,12 @@ pwm_init(void)
pwm_set_frequency(pwm, pwm_freq);
top_val = (uint16_t) pwm_get_top_value(pwm);
- /* setup led 1 */
- rc = pwm_configure_channel(pwm, 0, &chan_conf);
+ /* setup led */
+ rc = pwm_configure_channel(pwm, PWM_TEST_CH_NUM, &chan_conf);
assert(rc == 0);
/* console_printf ("Easing: sine io\n"); */
- rc = pwm_set_duty_cycle(pwm, 0, top_val);
+ rc = pwm_set_duty_cycle(pwm, PWM_TEST_CH_NUM, top_val);
rc = pwm_enable(pwm);
assert(rc == 0);
diff --git a/hw/bsp/nucleo-f303k8/include/bsp/bsp.h b/hw/bsp/nucleo-f303k8/include/bsp/bsp.h
index 5964dd2f4f..d2db90c15c 100644
--- a/hw/bsp/nucleo-f303k8/include/bsp/bsp.h
+++ b/hw/bsp/nucleo-f303k8/include/bsp/bsp.h
@@ -6,7 +6,7 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
@@ -48,25 +48,17 @@ extern uint8_t _ccram_start;
#define LED_BLINK_PIN_1 MCU_GPIO_PORTB(3)
#define LED_BLINK_PIN LED_BLINK_PIN_1
-
-
+
/* UART ports */
-#if (MYNEWT_VAL(UART_0) && MYNEWT_VAL(UART_1))
-# define UART_CNT 2
-# define UART_0_DEV_ID 0
-# define UART_1_DEV_ID 1
-#elif MYNEWT_VAL(UART_0)
-# define UART_CNT 1
-# define UART_0_DEV_ID 0
-#elif MYNEWT_VAL(UART_1)
-# define UART_CNT 1
-# define UART_1_DEV_ID 0
-#else
-# define UART_CNT 0
-#endif
+#define UART_CNT (MYNEWT_VAL(UART_0) + MYNEWT_VAL(UART_1))
+#define UART_0_DEV_ID 0
+#define UART_1_DEV_ID (UART_0_DEV_ID + MYNEWT_VAL(UART_0))
-#define _UART_DEV_NAME(id) ("uart" #id)
-#define UART_DEV_NAME(id) _UART_DEV_NAME(id)
+/* PWM */
+#define PWM_CNT (MYNEWT_VAL(PWM_0) + MYNEWT_VAL(PWM_1) + MYNEWT_VAL(PWM_2))
+#define PWM_0_DEV_ID 0
+#define PWM_1_DEV_ID (PWM_0_DEV_ID + MYNEWT_VAL(PWM_0))
+#define PWM_2_DEV_ID (PWM_1_DEV_ID + MYNEWT_VAL(PWM_1))
#ifdef __cplusplus
}
diff --git a/hw/bsp/nucleo-f303k8/pkg.yml b/hw/bsp/nucleo-f303k8/pkg.yml
index 736de64784..3be47b4b4e 100644
--- a/hw/bsp/nucleo-f303k8/pkg.yml
+++ b/hw/bsp/nucleo-f303k8/pkg.yml
@@ -27,7 +27,7 @@ pkg.keywords:
- stm32f3
- nucleo
-pkg.cflags: -DSTM32F303x8
+pkg.cflags: -DSTM32F303x8 -DNUCLEO_F303K8
pkg.cflags.HARDFLOAT:
- -mfloat-abi=hard -mfpu=fpv4-sp-d16
@@ -42,3 +42,12 @@ pkg.deps.UART_0:
pkg.deps.UART_1:
- hw/drivers/uart/uart_hal
+pkg.deps.PWM_0:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_1:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_2:
+ - hw/drivers/pwm/pwm_stm32
+
diff --git a/hw/bsp/nucleo-f303k8/src/hal_bsp.c b/hw/bsp/nucleo-f303k8/src/hal_bsp.c
index 24f3daa716..28e6cf61b9 100644
--- a/hw/bsp/nucleo-f303k8/src/hal_bsp.c
+++ b/hw/bsp/nucleo-f303k8/src/hal_bsp.c
@@ -43,7 +43,7 @@
#include "stm32f3xx_hal_rcc.h"
#if MYNEWT_VAL(UART_0) || MYNEWT_VAL(UART_1)
-static struct uart_dev hal_uart[2];
+static struct uart_dev hal_uart[UART_CNT];
static const struct stm32_uart_cfg uart_cfg[UART_CNT] = {
#if MYNEWT_VAL(UART_0)
@@ -80,7 +80,50 @@ bsp_uart_config(int port)
assert(port < UART_CNT);
return &uart_cfg[port];
}
+
+static char *stm32_uart_dev_name[UART_CNT] = {
+#if UART_CNT > 0
+ "uart0",
+#endif
+#if UART_CNT > 1
+ "uart1",
+#endif
+};
+
+#endif
+
+
+#if PWM_CNT
+#include <pwm_stm32/pwm_stm32.h>
+static struct pwm_dev stm32_pwm_dev_driver[PWM_CNT];
+static const char *stm32_pwm_dev_name[PWM_CNT] = {
+#if PWM_CNT > 0
+ "pwm0",
#endif
+#if PWM_CNT > 1
+ "pwm1",
+#endif
+#if PWM_CNT > 2
+ "pwm2",
+#endif
+};
+
+static struct stm32_pwm_conf stm32_pwm_config[PWM_CNT] = {
+#if MYNEWT_VAL(PWM_0)
+ { TIM2, TIM2_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_1)
+ { TIM15, TIM1_BRK_TIM15_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_2)
+ { TIM3, TIM3_IRQn },
+#endif
+};
+
+
+#endif
+
+
static const struct hal_bsp_mem_dump dump_cfg[] = {
[0] = {
@@ -139,7 +182,7 @@ hal_bsp_init(void)
#if MYNEWT_VAL(UART_0)
rc = os_dev_create((struct os_dev *)&hal_uart[UART_0_DEV_ID],
- UART_DEV_NAME(UART_0_DEV_ID),
+ stm32_uart_dev_name[UART_0_DEV_ID],
OS_DEV_INIT_PRIMARY, 0, uart_hal_init,
(void *)&uart_cfg[UART_0_DEV_ID]);
assert(rc == 0);
@@ -147,7 +190,7 @@ hal_bsp_init(void)
#if MYNEWT_VAL(UART_1)
rc = os_dev_create((struct os_dev *)&hal_uart[UART_1_DEV_ID],
- UART_DEV_NAME(UART_1_DEV_ID),
+ stm32_uart_dev_name[UART_1_DEV_ID],
OS_DEV_INIT_PRIMARY, 0, uart_hal_init,
(void *)&uart_cfg[UART_1_DEV_ID]);
assert(rc == 0);
@@ -162,4 +205,35 @@ hal_bsp_init(void)
rc = os_cputime_init(MYNEWT_VAL(OS_CPUTIME_FREQ));
assert(rc == 0);
#endif
+
+#if MYNEWT_VAL(PWM_0)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_0_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_0_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_0_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_1_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_1_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_1_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_2_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_2_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_2_DEV_ID]);
+ assert(rc == 0);
+#endif
+
}
diff --git a/hw/bsp/nucleo-f303k8/syscfg.yml b/hw/bsp/nucleo-f303k8/syscfg.yml
index 2c75a58383..427947867c 100644
--- a/hw/bsp/nucleo-f303k8/syscfg.yml
+++ b/hw/bsp/nucleo-f303k8/syscfg.yml
@@ -21,7 +21,6 @@ syscfg.defs:
UART_0:
description: 'Whether to enable UART0'
value: 1
-
UART_1:
description: 'Whether to enable UART1'
value: 0
@@ -30,6 +29,16 @@ syscfg.defs:
description: 'Support for timer 0'
value: 1
+ PWM_0:
+ description: 'Support for PWM 0'
+ value: 0
+ PWM_1:
+ description: 'Support for PWM 1'
+ value: 0
+ PWM_2:
+ description: 'Support for PWM 2'
+ value: 0
+
syscfg.vals:
REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG
CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS
diff --git a/hw/bsp/nucleo-f303re/include/bsp/bsp.h b/hw/bsp/nucleo-f303re/include/bsp/bsp.h
index 5a8bedda69..4e2fb7984e 100644
--- a/hw/bsp/nucleo-f303re/include/bsp/bsp.h
+++ b/hw/bsp/nucleo-f303re/include/bsp/bsp.h
@@ -6,7 +6,7 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
@@ -53,23 +53,15 @@ extern uint8_t _ccram_start;
#define BTN_USER_1 MCU_GPIO_PORTC(13)
/* UART ports */
-#if (MYNEWT_VAL(UART_0) && MYNEWT_VAL(UART_1))
-# define UART_CNT 2
-# define UART_0_DEV_ID 0
-# define UART_1_DEV_ID 1
-#elif MYNEWT_VAL(UART_0)
-# define UART_CNT 1
-# define UART_0_DEV_ID 0
-#elif MYNEWT_VAL(UART_1)
-# define UART_CNT 1
-# define UART_1_DEV_ID 0
-#else
-# define UART_CNT 0
-#endif
-
-#define _UART_DEV_NAME(id) ("uart" #id)
-#define UART_DEV_NAME(id) _UART_DEV_NAME(id)
+#define UART_CNT (MYNEWT_VAL(UART_0) + MYNEWT_VAL(UART_1))
+#define UART_0_DEV_ID 0
+#define UART_1_DEV_ID (UART_0_DEV_ID + MYNEWT_VAL(UART_0))
+/* PWM */
+#define PWM_CNT (MYNEWT_VAL(PWM_0) + MYNEWT_VAL(PWM_1) + MYNEWT_VAL(PWM_2))
+#define PWM_0_DEV_ID 0
+#define PWM_1_DEV_ID (PWM_0_DEV_ID + MYNEWT_VAL(PWM_0))
+#define PWM_2_DEV_ID (PWM_1_DEV_ID + MYNEWT_VAL(PWM_1))
/* This defines the maximum NFFS areas (block) are in the BSPs NFS file
* system space. This in conjunction with flash map determines how
diff --git a/hw/bsp/nucleo-f303re/pkg.yml b/hw/bsp/nucleo-f303re/pkg.yml
index c71a4f802c..ca6f7ea014 100644
--- a/hw/bsp/nucleo-f303re/pkg.yml
+++ b/hw/bsp/nucleo-f303re/pkg.yml
@@ -42,3 +42,11 @@ pkg.deps.UART_0:
pkg.deps.UART_1:
- hw/drivers/uart/uart_hal
+pkg.deps.PWM_0:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_1:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_2:
+ - hw/drivers/pwm/pwm_stm32
diff --git a/hw/bsp/nucleo-f303re/src/hal_bsp.c b/hw/bsp/nucleo-f303re/src/hal_bsp.c
index 42c50fd53e..f667c57f3c 100644
--- a/hw/bsp/nucleo-f303re/src/hal_bsp.c
+++ b/hw/bsp/nucleo-f303re/src/hal_bsp.c
@@ -43,7 +43,7 @@
#include "stm32f3xx_hal_rcc.h"
#if MYNEWT_VAL(UART_0) || MYNEWT_VAL(UART_1)
-static struct uart_dev hal_uart[2];
+static struct uart_dev hal_uart[UART_CNT];
static const struct stm32_uart_cfg uart_cfg[UART_CNT] = {
#if MYNEWT_VAL(UART_0)
@@ -80,7 +80,50 @@ bsp_uart_config(int port)
assert(port < UART_CNT);
return &uart_cfg[port];
}
+
+static char *stm32_uart_dev_name[UART_CNT] = {
+#if UART_CNT > 0
+ "uart0",
+#endif
+#if UART_CNT > 1
+ "uart1",
+#endif
+};
+
+#endif
+
+
+#if PWM_CNT
+#include <pwm_stm32/pwm_stm32.h>
+static struct pwm_dev stm32_pwm_dev_driver[PWM_CNT];
+static const char *stm32_pwm_dev_name[PWM_CNT] = {
+#if PWM_CNT > 0
+ "pwm0",
#endif
+#if PWM_CNT > 1
+ "pwm1",
+#endif
+#if PWM_CNT > 2
+ "pwm2",
+#endif
+};
+
+static struct stm32_pwm_conf stm32_pwm_config[PWM_CNT] = {
+#if MYNEWT_VAL(PWM_0)
+ { TIM2, TIM2_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_1)
+ { TIM4, TIM4_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_2)
+ { TIM3, TIM3_IRQn },
+#endif
+};
+
+
+#endif
+
+
static const struct hal_bsp_mem_dump dump_cfg[] = {
[0] = {
@@ -139,7 +182,7 @@ hal_bsp_init(void)
#if MYNEWT_VAL(UART_0)
rc = os_dev_create((struct os_dev *)&hal_uart[UART_0_DEV_ID],
- UART_DEV_NAME(UART_0_DEV_ID),
+ stm32_uart_dev_name[UART_0_DEV_ID],
OS_DEV_INIT_PRIMARY, 0, uart_hal_init,
(void *)&uart_cfg[UART_0_DEV_ID]);
assert(rc == 0);
@@ -147,7 +190,7 @@ hal_bsp_init(void)
#if MYNEWT_VAL(UART_1)
rc = os_dev_create((struct os_dev *)&hal_uart[UART_1_DEV_ID],
- UART_DEV_NAME(UART_1_DEV_ID),
+ stm32_uart_dev_name[UART_1_DEV_ID],
OS_DEV_INIT_PRIMARY, 0, uart_hal_init,
(void *)&uart_cfg[UART_1_DEV_ID]);
assert(rc == 0);
@@ -162,4 +205,35 @@ hal_bsp_init(void)
rc = os_cputime_init(MYNEWT_VAL(OS_CPUTIME_FREQ));
assert(rc == 0);
#endif
+
+#if MYNEWT_VAL(PWM_0)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_0_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_0_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_0_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_1_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_1_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_1_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_2_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_2_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_2_DEV_ID]);
+ assert(rc == 0);
+#endif
+
}
diff --git a/hw/bsp/nucleo-f303re/syscfg.yml b/hw/bsp/nucleo-f303re/syscfg.yml
index 2c75a58383..427947867c 100644
--- a/hw/bsp/nucleo-f303re/syscfg.yml
+++ b/hw/bsp/nucleo-f303re/syscfg.yml
@@ -21,7 +21,6 @@ syscfg.defs:
UART_0:
description: 'Whether to enable UART0'
value: 1
-
UART_1:
description: 'Whether to enable UART1'
value: 0
@@ -30,6 +29,16 @@ syscfg.defs:
description: 'Support for timer 0'
value: 1
+ PWM_0:
+ description: 'Support for PWM 0'
+ value: 0
+ PWM_1:
+ description: 'Support for PWM 1'
+ value: 0
+ PWM_2:
+ description: 'Support for PWM 2'
+ value: 0
+
syscfg.vals:
REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG
CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS
diff --git a/hw/bsp/nucleo-f767zi/include/bsp/bsp.h b/hw/bsp/nucleo-f767zi/include/bsp/bsp.h
index 3b06ad8c8b..aa5656d1d3 100644
--- a/hw/bsp/nucleo-f767zi/include/bsp/bsp.h
+++ b/hw/bsp/nucleo-f767zi/include/bsp/bsp.h
@@ -61,6 +61,11 @@ extern uint8_t _ram2_start;
/* UART */
#define UART_CNT 1
+#define PWM_CNT (MYNEWT_VAL(PWM_0) + MYNEWT_VAL(PWM_1) + MYNEWT_VAL(PWM_2))
+#define PWM_0_DEV_ID 0
+#define PWM_1_DEV_ID (PWM_0_DEV_ID + MYNEWT_VAL(PWM_0))
+#define PWM_2_DEV_ID (PWM_1_DEV_ID + MYNEWT_VAL(PWM_1))
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/nucleo-f767zi/pkg.yml b/hw/bsp/nucleo-f767zi/pkg.yml
index c246547f3a..71fc4e1c11 100644
--- a/hw/bsp/nucleo-f767zi/pkg.yml
+++ b/hw/bsp/nucleo-f767zi/pkg.yml
@@ -6,7 +6,7 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
@@ -41,3 +41,12 @@ pkg.deps.UART_0:
pkg.deps.ETH_0:
- hw/drivers/lwip/stm32_eth
+
+pkg.deps.PWM_0:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_1:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_2:
+ - hw/drivers/pwm/pwm_stm32
diff --git a/hw/bsp/nucleo-f767zi/src/hal_bsp.c b/hw/bsp/nucleo-f767zi/src/hal_bsp.c
index b7e0d1e9d9..d202630dd4 100644
--- a/hw/bsp/nucleo-f767zi/src/hal_bsp.c
+++ b/hw/bsp/nucleo-f767zi/src/hal_bsp.c
@@ -18,6 +18,7 @@
*/
#include <assert.h>
+#include "bsp/bsp.h"
#include "os/mynewt.h"
#if MYNEWT_VAL(TRNG)
@@ -52,7 +53,35 @@
#include <stm32_eth/stm32_eth_cfg.h>
#endif
-#include "bsp/bsp.h"
+#if PWM_CNT
+#include <pwm_stm32/pwm_stm32.h>
+static struct pwm_dev stm32_pwm_dev_driver[PWM_CNT];
+static const char *stm32_pwm_dev_name[PWM_CNT] = {
+#if PWM_CNT > 0
+ "pwm0",
+#endif
+#if PWM_CNT > 1
+ "pwm1",
+#endif
+#if PWM_CNT > 2
+ "pwm2",
+#endif
+};
+
+static struct stm32_pwm_conf stm32_pwm_config[PWM_CNT] = {
+#if MYNEWT_VAL(PWM_0)
+ { TIM3, TIM3_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_1)
+ { TIM4, TIM4_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_2)
+ { TIM11, TIM1_TRG_COM_TIM11_IRQn },
+#endif
+};
+
+
+#endif
#if MYNEWT_VAL(TRNG)
static struct trng_dev os_bsp_trng;
@@ -179,7 +208,6 @@ void
hal_bsp_init(void)
{
int rc;
-
(void)rc;
hal_system_clock_start();
@@ -231,6 +259,36 @@ hal_bsp_init(void)
#if MYNEWT_VAL(ETH_0)
stm32_eth_init(ð_cfg);
#endif
+
+#if MYNEWT_VAL(PWM_0)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_0_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_0_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_0_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_1_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_1_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_1_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_2_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_2_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_2_DEV_ID]);
+ assert(rc == 0);
+#endif
}
/**
diff --git a/hw/bsp/nucleo-f767zi/syscfg.yml b/hw/bsp/nucleo-f767zi/syscfg.yml
index 2069d494d2..5fe108d830 100644
--- a/hw/bsp/nucleo-f767zi/syscfg.yml
+++ b/hw/bsp/nucleo-f767zi/syscfg.yml
@@ -6,7 +6,7 @@
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
@@ -25,11 +25,9 @@ syscfg.defs:
TIMER_0:
description: 'Timer 0'
value: 1
-
TIMER_1:
description: 'Timer 1'
value: 1
-
TIMER_2:
description: 'Timer 2'
value: 1
@@ -38,6 +36,16 @@ syscfg.defs:
description: 'Ethernet driver for LwIP'
value: 0
+ PWM_0:
+ description: 'Support for PWM 0'
+ value: 0
+ PWM_1:
+ description: 'Support for PWM 1'
+ value: 0
+ PWM_2:
+ description: 'Support for PWM 2'
+ value: 0
+
syscfg.vals:
REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG
CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS
diff --git a/hw/bsp/stm32f7discovery/include/bsp/bsp.h b/hw/bsp/stm32f7discovery/include/bsp/bsp.h
index b92e19c3cc..386be65533 100644
--- a/hw/bsp/stm32f7discovery/include/bsp/bsp.h
+++ b/hw/bsp/stm32f7discovery/include/bsp/bsp.h
@@ -48,6 +48,11 @@ extern uint8_t _itcmram_start;
/* UART */
#define UART_CNT 1
+#define PWM_CNT (MYNEWT_VAL(PWM_0) + MYNEWT_VAL(PWM_1) + MYNEWT_VAL(PWM_2))
+#define PWM_0_DEV_ID 0
+#define PWM_1_DEV_ID (PWM_0_DEV_ID + MYNEWT_VAL(PWM_0))
+#define PWM_2_DEV_ID (PWM_1_DEV_ID + MYNEWT_VAL(PWM_1))
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/stm32f7discovery/pkg.yml b/hw/bsp/stm32f7discovery/pkg.yml
index c6f4c14511..a880e3cc38 100644
--- a/hw/bsp/stm32f7discovery/pkg.yml
+++ b/hw/bsp/stm32f7discovery/pkg.yml
@@ -41,3 +41,12 @@ pkg.deps.UART_0:
pkg.deps.ETH_0:
- hw/drivers/lwip/stm32_eth
+
+pkg.deps.PWM_0:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_1:
+ - hw/drivers/pwm/pwm_stm32
+
+pkg.deps.PWM_2:
+ - hw/drivers/pwm/pwm_stm32
diff --git a/hw/bsp/stm32f7discovery/src/hal_bsp.c b/hw/bsp/stm32f7discovery/src/hal_bsp.c
index 4d9ec4a9ef..d521574532 100644
--- a/hw/bsp/stm32f7discovery/src/hal_bsp.c
+++ b/hw/bsp/stm32f7discovery/src/hal_bsp.c
@@ -42,6 +42,36 @@
#include "bsp/bsp.h"
+#if PWM_CNT
+#include <pwm_stm32/pwm_stm32.h>
+static struct pwm_dev stm32_pwm_dev_driver[PWM_CNT];
+static const char *stm32_pwm_dev_name[PWM_CNT] = {
+#if PWM_CNT > 0
+ "pwm0",
+#endif
+#if PWM_CNT > 1
+ "pwm1",
+#endif
+#if PWM_CNT > 2
+ "pwm2",
+#endif
+};
+
+static struct stm32_pwm_conf stm32_pwm_config[PWM_CNT] = {
+#if MYNEWT_VAL(PWM_0)
+ { TIM3, TIM3_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_1)
+ { TIM4, TIM4_IRQn },
+#endif
+#if MYNEWT_VAL(PWM_2)
+ { TIM11, TIM1_TRG_COM_TIM11_IRQn },
+#endif
+};
+
+
+#endif
+
#if MYNEWT_VAL(UART_0)
static struct uart_dev hal_uart0;
@@ -160,6 +190,36 @@ hal_bsp_init(void)
#if MYNEWT_VAL(ETH_0)
stm32_eth_init(ð_cfg);
#endif
+
+#if MYNEWT_VAL(PWM_0)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_0_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_0_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_0_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_1)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_1_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_1_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_1_DEV_ID]);
+ assert(rc == 0);
+#endif
+
+#if MYNEWT_VAL(PWM_2)
+ rc = os_dev_create((struct os_dev *) &stm32_pwm_dev_driver[PWM_2_DEV_ID],
+ (char*)stm32_pwm_dev_name[PWM_2_DEV_ID],
+ OS_DEV_INIT_KERNEL,
+ OS_DEV_INIT_PRIO_DEFAULT,
+ stm32_pwm_dev_init,
+ &stm32_pwm_config[PWM_2_DEV_ID]);
+ assert(rc == 0);
+#endif
}
/**
diff --git a/hw/bsp/stm32f7discovery/syscfg.yml b/hw/bsp/stm32f7discovery/syscfg.yml
index d3698109fb..5fe108d830 100644
--- a/hw/bsp/stm32f7discovery/syscfg.yml
+++ b/hw/bsp/stm32f7discovery/syscfg.yml
@@ -21,6 +21,7 @@ syscfg.defs:
UART_0:
description: 'Uart 0'
value: 1
+
TIMER_0:
description: 'Timer 0'
value: 1
@@ -35,8 +36,19 @@ syscfg.defs:
description: 'Ethernet driver for LwIP'
value: 0
+ PWM_0:
+ description: 'Support for PWM 0'
+ value: 0
+ PWM_1:
+ description: 'Support for PWM 1'
+ value: 0
+ PWM_2:
+ description: 'Support for PWM 2'
+ value: 0
+
syscfg.vals:
REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG
CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS
NFFS_FLASH_AREA: FLASH_AREA_NFFS
COREDUMP_FLASH_AREA: FLASH_AREA_IMAGE_1
+ MCU_SYSCLK_PLL_HSI: 0
diff --git a/hw/drivers/pwm/pwm_stm32/include/pwm_stm32/pwm_stm32.h b/hw/drivers/pwm/pwm_stm32/include/pwm_stm32/pwm_stm32.h
new file mode 100644
index 0000000000..f45f987bab
--- /dev/null
+++ b/hw/drivers/pwm/pwm_stm32/include/pwm_stm32/pwm_stm32.h
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __PWM_STM32_H__
+#define __PWM_STM32_H__
+
+#include <pwm/pwm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * All HW timers capable of PWM are supported. A maximum of 4 channels per
+ * timer can be configured, depending on the HW timer being used.
+ *
+ * Currently there is no support for complementary outputs.
+ *
+ * MCU_AFIO_PIN_NONE can be used in pwm_configure_channel in order
+ * 'unconfigure' a previously configured PWM IO pin.
+ *
+ * The driver can return one of several error codes in order to aid issue
+ * tracking.
+ *
+ * STM32_PWM_ERR_OK ... no error
+ * STM32_PWM_ERR_NODEV ... no devices available, depending on configuration
+ * up to 3 devices are supported
+ * STM32_PWM_ERR_NOTIM ... no hw timer was specified for initialization
+ * STM32_PWM_ERR_CHAN ... specified channel is not valid for device
+ * STM32_PWM_ERR_FREQ ... either no frequency was specified, or the specified
+ * frequency is higher than the clock frequency
+ * STM32_PWM_ERR_GPIO ... an error occured during IO pin configuration
+ * STM32_PWM_ERR_NOIRQ ... the device was registered without IRQ support but
+ * later cycle and/or sequence support was requested
+ */
+
+#define STM32_PWM_ERR_OK 0
+#define STM32_PWM_ERR_NODEV -1
+#define STM32_PWM_ERR_NOTIM -2
+#define STM32_PWM_ERR_CHAN -3
+#define STM32_PWM_ERR_FREQ -4
+#define STM32_PWM_ERR_GPIO -5
+#define STM32_PWM_ERR_NOIRQ -6
+
+typedef struct stm32_pwm_conf {
+ TIM_TypeDef *tim;
+ uint16_t irq;
+} stm32_pwm_conf_t;
+
+int stm32_pwm_dev_init(struct os_dev *dev, void *struct_stm32_pwm_conf_pointer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PWM_STM32_H__ */
diff --git a/hw/drivers/pwm/pwm_stm32/pkg.yml b/hw/drivers/pwm/pwm_stm32/pkg.yml
new file mode 100644
index 0000000000..85544ad9da
--- /dev/null
+++ b/hw/drivers/pwm/pwm_stm32/pkg.yml
@@ -0,0 +1,36 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: hw/drivers/pwm/pwm_stm32
+pkg.description: PWM driver for the STM32
+pkg.author: "Apache Mynewt <de...@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.apis:
+ - PWM_HW_IMPL
+
+pkg.deps:
+ - hw/drivers/pwm
+
+pkg.deps.MCU_STM32F3:
+ - hw/mcu/stm/stm32f3xx
+
+pkg.deps.MCU_STM32F7:
+ - hw/mcu/stm/stm32f7xx
diff --git a/hw/drivers/pwm/pwm_stm32/src/pwm_stm32.c b/hw/drivers/pwm/pwm_stm32/src/pwm_stm32.c
new file mode 100644
index 0000000000..f9aeef4c2c
--- /dev/null
+++ b/hw/drivers/pwm/pwm_stm32/src/pwm_stm32.c
@@ -0,0 +1,606 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "pwm_stm32/pwm_stm32.h"
+
+#include <bsp.h>
+#include <hal/hal_bsp.h>
+#include <mcu/cmsis_nvic.h>
+#include <os/os.h>
+#include <pwm/pwm.h>
+#include <stm32_common/stm32_hal.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#define STM32_PWM_CH_MAX 4
+#define STM32_PWM_CH_IDLE 0x0000
+#define STM32_PWM_CH_MODE_ENA LL_TIM_OCMODE_PWM2
+#define STM32_PWM_CH_MODE_DIS LL_TIM_OCMODE_ACTIVE
+
+
+typedef struct {
+ uint32_t n_cycles;
+ user_handler_t cycle_handler;
+ user_handler_t seq_end_handler;
+ void *cycle_data;
+ void *seq_end_data;
+} stm32_pwm_dev_cfg_t;
+
+typedef struct {
+ TIM_TypeDef *timx;
+ uint32_t cycle;
+ uint16_t pin[STM32_PWM_CH_MAX];
+ uint16_t irq;
+ stm32_pwm_dev_cfg_t cfg;
+} stm32_pwm_dev_t;
+
+static stm32_pwm_dev_t stm32_pwm_dev[PWM_CNT];
+
+static inline bool
+stm32_pwm_ch_is_active(const stm32_pwm_dev_t *pwm, int ch)
+{
+ return MCU_AFIO_PIN_NONE != pwm->pin[ch];
+}
+
+static uint32_t
+stm32_pwm_ch(int ch)
+{
+ switch (ch) {
+ case 0: return LL_TIM_CHANNEL_CH1;
+ case 1: return LL_TIM_CHANNEL_CH2;
+ case 2: return LL_TIM_CHANNEL_CH3;
+ case 3: return LL_TIM_CHANNEL_CH4;
+ }
+ assert(0);
+ return 0;
+}
+
+static void
+stm32_pwm_active_ch_set_mode(stm32_pwm_dev_t *pwm, uint32_t mode)
+{
+ for (int i=0; i < STM32_PWM_CH_MAX; ++i) {
+ if (stm32_pwm_ch_is_active(pwm, i)) {
+ LL_TIM_OC_SetMode(pwm->timx, stm32_pwm_ch(i), mode);
+ }
+ }
+}
+
+static void
+stm32_pwm_ch_set_compare(TIM_TypeDef *tim, int ch, uint32_t value)
+{
+ switch (ch) {
+ case 0:
+ LL_TIM_OC_SetCompareCH1(tim, value);
+ break;
+ case 1:
+ LL_TIM_OC_SetCompareCH2(tim, value);
+ break;
+ case 2:
+ LL_TIM_OC_SetCompareCH3(tim, value);
+ break;
+ case 3:
+ LL_TIM_OC_SetCompareCH4(tim, value);
+ break;
+ }
+}
+
+static void
+stm32_pwm_ch_unconfigure(const stm32_pwm_dev_t *pwm, uint32_t id)
+{
+ uint32_t ch = stm32_pwm_ch(id);
+
+ LL_TIM_CC_DisableChannel(pwm->timx, ch);
+ LL_TIM_OC_SetMode(pwm->timx, ch, 0);
+ LL_TIM_OC_SetPolarity(pwm->timx, ch, 0);
+ LL_TIM_OC_DisablePreload(pwm->timx, ch);
+}
+
+static void
+stm32_pwm_isr(stm32_pwm_dev_t *pwm)
+{
+ uint32_t sr = pwm->timx->SR;
+ pwm->timx->SR = ~sr;
+
+ if (pwm->cfg.cycle_handler) {
+ pwm->cfg.cycle_handler(pwm->cfg.cycle_data);
+ }
+
+ if (pwm->cfg.n_cycles) {
+ if (!pwm->cycle) {
+
+ LL_TIM_DisableCounter(pwm->timx);
+ LL_TIM_SetCounter(pwm->timx, 0);
+
+ if (pwm->cfg.seq_end_handler) {
+ pwm->cfg.seq_end_handler(pwm->cfg.seq_end_data);
+ }
+ } else {
+ if (1 == pwm->cycle) {
+ /* prep output pins for shutdown */
+ stm32_pwm_active_ch_set_mode(pwm, STM32_PWM_CH_MODE_DIS);
+ }
+ --pwm->cycle;
+ }
+ }
+}
+
+static void
+stm32_pwm_isr_0(void)
+{
+ stm32_pwm_isr(&stm32_pwm_dev[0]);
+}
+
+static void
+stm32_pwm_isr_1(void)
+{
+ stm32_pwm_isr(&stm32_pwm_dev[1]);
+}
+
+static void
+stm32_pwm_isr_2(void)
+{
+ stm32_pwm_isr(&stm32_pwm_dev[2]);
+}
+
+static int
+stm32_pwm_enable(struct pwm_dev *dev)
+{
+ stm32_pwm_dev_t *pwm;
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+ pwm->cycle = pwm->cfg.n_cycles;
+
+ stm32_pwm_active_ch_set_mode(pwm, STM32_PWM_CH_MODE_ENA);
+
+ LL_TIM_GenerateEvent_UPDATE(pwm->timx);
+ LL_TIM_EnableCounter(pwm->timx);
+
+ return STM32_PWM_ERR_OK;
+}
+
+static int
+stm32_pwm_disable(struct pwm_dev *dev)
+{
+ stm32_pwm_dev_t *pwm;
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+
+ LL_TIM_DisableCounter(pwm->timx);
+ LL_TIM_SetCounter(pwm->timx, 0);
+
+ return STM32_PWM_ERR_OK;
+}
+
+static bool
+stm32_pwm_is_enabled(struct pwm_dev *dev)
+{
+ stm32_pwm_dev_t *pwm;
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+
+ return LL_TIM_IsEnabledCounter(pwm->timx);
+}
+
+static int
+stm32_pwm_open(struct os_dev *odev, uint32_t wait, void *arg)
+{
+ struct pwm_dev *dev;
+ int rc;
+
+ dev = (struct pwm_dev *)odev;
+
+ if (os_started()) {
+ rc = os_mutex_pend(&dev->pwm_lock, wait);
+ if (OS_OK != rc) {
+ return rc;
+ }
+ }
+
+ if (odev->od_flags & OS_DEV_F_STATUS_OPEN) {
+ os_mutex_release(&dev->pwm_lock);
+ rc = OS_EBUSY;
+ return rc;
+ }
+
+ return STM32_PWM_ERR_OK;
+}
+
+static int
+stm32_pwm_close(struct os_dev *odev)
+{
+ struct pwm_dev *dev;
+ stm32_pwm_dev_t *pwm;
+
+ dev = (struct pwm_dev *)odev;
+
+ stm32_pwm_disable(dev);
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+
+ for (int i=0; i < STM32_PWM_CH_MAX; ++i) {
+ stm32_pwm_ch_set_compare(pwm->timx, i, STM32_PWM_CH_IDLE);
+ if (stm32_pwm_ch_is_active(pwm, i)) {
+ hal_gpio_init_af(MCU_AFIO_PIN_PAD(pwm->pin[i]), 0, HAL_GPIO_PULL_NONE, 0);
+ }
+ pwm->pin[i] = MCU_AFIO_PIN_NONE;
+ stm32_pwm_ch_unconfigure(pwm, i);
+ }
+
+ if (os_started()) {
+ os_mutex_release(&dev->pwm_lock);
+ }
+
+ return STM32_PWM_ERR_OK;
+}
+
+static int
+stm32_pwm_ch_configure(struct pwm_dev *dev, uint8_t cnum, struct pwm_chan_cfg *cfg)
+{
+ stm32_pwm_dev_t *pwm;
+ uint32_t ch;
+
+ assert(cnum < STM32_PWM_CH_MAX);
+ if (cnum >= dev->pwm_chan_count) {
+ return STM32_PWM_ERR_CHAN;
+ }
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+ ch = stm32_pwm_ch(cnum);
+
+ LL_TIM_CC_DisableChannel(pwm->timx, ch);
+
+ if (stm32_pwm_ch_is_active(pwm, cnum)) {
+ if (hal_gpio_init_af(MCU_AFIO_PIN_PAD(pwm->pin[cnum]), 0, HAL_GPIO_PULL_NONE, 0)) {
+ return STM32_PWM_ERR_GPIO;
+ }
+ pwm->pin[cnum] = MCU_AFIO_PIN_NONE;
+ }
+
+ if (cfg && MCU_AFIO_PIN_NONE != cfg->pin ) {
+ LL_TIM_OC_SetMode(pwm->timx, ch, STM32_PWM_CH_MODE_ENA);
+ LL_TIM_OC_SetPolarity(pwm->timx, ch, cfg->inverted ? LL_TIM_OCPOLARITY_HIGH : LL_TIM_OCPOLARITY_LOW);
+ LL_TIM_OC_EnablePreload(pwm->timx, ch);
+
+ if (hal_gpio_init_af(MCU_AFIO_PIN_PAD(cfg->pin), MCU_AFIO_PIN_AF(cfg->pin), HAL_GPIO_PULL_NONE, 0)) {
+ return STM32_PWM_ERR_GPIO;
+ }
+ pwm->pin[cnum] = cfg->pin;
+
+ LL_TIM_CC_EnableChannel(pwm->timx, ch);
+ } else {
+ stm32_pwm_ch_unconfigure(pwm, cnum);
+ pwm->pin[cnum] = MCU_AFIO_PIN_NONE;
+ }
+
+ return STM32_PWM_ERR_OK;
+}
+
+
+static int
+stm32_pwm_ch_set_duty_cycle(struct pwm_dev *dev, uint8_t cnum, uint16_t fraction)
+{
+ stm32_pwm_dev_t *pwm;
+
+ assert(cnum < STM32_PWM_CH_MAX);
+ if (cnum >= dev->pwm_chan_count) {
+ return STM32_PWM_ERR_CHAN;
+ }
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+
+ stm32_pwm_ch_set_compare(pwm->timx, cnum, fraction);
+
+ return STM32_PWM_ERR_OK;
+}
+
+static int
+stm32_pwm_set_frequency(struct pwm_dev *dev, uint32_t freq_hz)
+{
+ stm32_pwm_dev_t *pwm;
+ uint32_t id;
+ uint32_t timer_clock;
+ uint32_t div, div1, div2;
+
+ if (!freq_hz) {
+ return STM32_PWM_ERR_FREQ;
+ }
+
+ id = dev->pwm_instance_id;
+ pwm = &stm32_pwm_dev[id];
+
+ timer_clock = stm32_hal_timer_get_freq(pwm->timx);
+ assert(timer_clock);
+
+ div = timer_clock / freq_hz;
+ if (!div) {
+ return STM32_PWM_ERR_FREQ;
+ }
+
+ div1 = div >> 16;
+ div2 = div / (div1 + 1);
+
+ if (div1 > div2) {
+ uint32_t tmp = div1;
+ div1 = div2;
+ div2 = tmp;
+ }
+ div2 -= 1;
+
+ LL_TIM_SetPrescaler(pwm->timx, div1);
+ LL_TIM_SetAutoReload(pwm->timx, div2);
+
+ return STM32_PWM_ERR_OK;
+}
+
+static int
+stm32_pwm_configure(struct pwm_dev *dev, struct pwm_dev_cfg *cfg)
+{
+ stm32_pwm_dev_t *pwm;
+ uint32_t prio;
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+
+ if (!pwm->irq) {
+ return STM32_PWM_ERR_NOIRQ;
+ }
+
+ NVIC_DisableIRQ(pwm->irq);
+
+ if (cfg) {
+ prio = cfg->int_prio;
+ if (!prio) {
+ prio = (1 << __NVIC_PRIO_BITS) - 1;
+ }
+
+ LL_TIM_EnableIT_UPDATE(pwm->timx);
+ NVIC_SetPriority(pwm->irq, prio);
+ switch (dev->pwm_instance_id) {
+ case 0:
+ NVIC_SetVector(pwm->irq, (uintptr_t)stm32_pwm_isr_0);
+ break;
+ case 1:
+ NVIC_SetVector(pwm->irq, (uintptr_t)stm32_pwm_isr_1);
+ break;
+ case 2:
+ NVIC_SetVector(pwm->irq, (uintptr_t)stm32_pwm_isr_2);
+ break;
+ default:
+ return STM32_PWM_ERR_NODEV;
+ }
+
+ pwm->cfg.n_cycles = cfg->n_cycles;
+ pwm->cfg.cycle_handler = cfg->cycle_handler;
+ pwm->cfg.seq_end_handler = cfg->seq_end_handler;
+ pwm->cfg.cycle_data = cfg->cycle_data;
+ pwm->cfg.seq_end_data = cfg->seq_end_data;
+
+ NVIC_EnableIRQ(pwm->irq);
+ } else {
+ LL_TIM_DisableIT_UPDATE(pwm->timx);
+ }
+
+ return STM32_PWM_ERR_OK;
+}
+
+static int
+stm32_pwm_get_clock_freq(struct pwm_dev *dev)
+{
+ stm32_pwm_dev_t *pwm;
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+ return stm32_hal_timer_get_freq(pwm->timx) / (LL_TIM_GetPrescaler(pwm->timx) + 1);
+}
+
+static int
+stm32_pwm_get_top_value(struct pwm_dev *dev)
+{
+ stm32_pwm_dev_t *pwm;
+
+ pwm = &stm32_pwm_dev[dev->pwm_instance_id];
+ return LL_TIM_GetAutoReload(pwm->timx) + 1;
+}
+
+static int
+stm32_pwm_get_resolution_bits(struct pwm_dev *dev)
+{
+ uint32_t period = stm32_pwm_get_top_value(dev) - 1;
+
+ for (int bit=15; bit; --bit) {
+ if (period & (0x01 << bit)) {
+ return bit + 1;
+ }
+ }
+
+ return period ? 1 : 0;
+}
+
+
+int
+stm32_pwm_dev_init(struct os_dev *odev, void *arg)
+{
+ stm32_pwm_conf_t *cfg;
+ stm32_pwm_dev_t *pwm;
+ struct pwm_dev *dev;
+ uint32_t id;
+
+ for (id=0; id < PWM_CNT; ++id) {
+ pwm = &stm32_pwm_dev[id];
+ if (!pwm->timx) {
+ break;
+ }
+ }
+ if (PWM_CNT <= id) {
+ return STM32_PWM_ERR_NODEV;
+ }
+ memset(pwm, 0, sizeof(stm32_pwm_dev_t));
+
+ if (NULL == arg) {
+ return STM32_PWM_ERR_NOTIM;
+ }
+
+ cfg = (stm32_pwm_conf_t*)arg;
+
+ pwm->timx = cfg->tim;
+ pwm->irq = cfg->irq;
+
+ LL_TIM_SetPrescaler(cfg->tim, 0xffff);
+ LL_TIM_SetAutoReload(cfg->tim, 0);
+
+ dev = (struct pwm_dev *)odev;
+ dev->pwm_instance_id = id;
+
+ switch ((uintptr_t)cfg->tim) {
+#ifdef TIM1
+ case (uintptr_t)TIM1:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+#ifdef TIM2
+ case (uintptr_t)TIM2:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+#ifdef TIM3
+ case (uintptr_t)TIM3:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+#ifdef TIM4
+ case (uintptr_t)TIM4:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+#ifdef TIM5
+ case (uintptr_t)TIM5:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM5);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+
+ /* basic timers TIM6 and TIM7 have no PWM capabilities */
+
+#ifdef TIM8
+ case (uintptr_t)TIM8:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM8);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+#ifdef TIM9
+ case (uintptr_t)TIM9:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM9);
+ dev->pwm_chan_count = 2;
+ break;
+#endif
+#ifdef TIM10
+ case (uintptr_t)TIM10:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM10);
+ dev->pwm_chan_count = 1;
+ break;
+#endif
+#ifdef TIM11
+ case (uintptr_t)TIM11:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM11);
+ dev->pwm_chan_count = 1;
+ break;
+#endif
+#ifdef TIM12
+ case (uintptr_t)TIM12:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM12);
+ dev->pwm_chan_count = 2;
+ break;
+#endif
+#ifdef TIM13
+ case (uintptr_t)TIM13:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM13);
+ dev->pwm_chan_count = 1;
+ break;
+#endif
+#ifdef TIM14
+ case (uintptr_t)TIM14:
+ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM14);
+ dev->pwm_chan_count = 1;
+ break;
+#endif
+#ifdef TIM15
+ case (uintptr_t)TIM15:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM15);
+ dev->pwm_chan_count = 2;
+ break;
+#endif
+#ifdef TIM16
+ case (uintptr_t)TIM16:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM16);
+ dev->pwm_chan_count = 1;
+ break;
+#endif
+#ifdef TIM17
+ case (uintptr_t)TIM17:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM17);
+ dev->pwm_chan_count = 1;
+ break;
+#endif
+
+ /* basic timer TIM18 has no PWM capabilities */
+
+#ifdef TIM19
+ case (uintptr_t)TIM19:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM19);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+#ifdef TIM20
+ case (uintptr_t)TIM20:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM20);
+ dev->pwm_chan_count = 4;
+ break;
+#endif
+
+ default:
+ assert(0);
+ }
+
+ for (int i=0; i < STM32_PWM_CH_MAX; ++i) {
+ stm32_pwm_ch_set_compare(pwm->timx, i, STM32_PWM_CH_IDLE);
+ pwm->pin[i] = MCU_AFIO_PIN_NONE;
+ }
+
+ dev->pwm_funcs.pwm_configure_channel = stm32_pwm_ch_configure;
+ dev->pwm_funcs.pwm_configure_device = stm32_pwm_configure;
+ dev->pwm_funcs.pwm_disable = stm32_pwm_disable;
+ dev->pwm_funcs.pwm_enable = stm32_pwm_enable;
+ dev->pwm_funcs.pwm_get_clock_freq = stm32_pwm_get_clock_freq;
+ dev->pwm_funcs.pwm_get_resolution_bits = stm32_pwm_get_resolution_bits;
+ dev->pwm_funcs.pwm_get_top_value = stm32_pwm_get_top_value;
+ dev->pwm_funcs.pwm_is_enabled = stm32_pwm_is_enabled;
+ dev->pwm_funcs.pwm_set_duty_cycle = stm32_pwm_ch_set_duty_cycle;
+ dev->pwm_funcs.pwm_set_frequency = stm32_pwm_set_frequency;
+
+ os_mutex_init(&dev->pwm_lock);
+ OS_DEV_SETHANDLERS(odev, stm32_pwm_open, stm32_pwm_close);
+
+ LL_TIM_EnableARRPreload(cfg->tim);
+ LL_TIM_CC_EnablePreload(cfg->tim);
+ LL_TIM_SetCounter(pwm->timx, 0);
+
+ return STM32_PWM_ERR_OK;
+}
diff --git a/hw/mcu/stm/stm32_common/include/stm32_common/stm32_hal.h b/hw/mcu/stm/stm32_common/include/stm32_common/stm32_hal.h
new file mode 100644
index 0000000000..80ef158390
--- /dev/null
+++ b/hw/mcu/stm/stm32_common/include/stm32_common/stm32_hal.h
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef STM32_COMMON_HAL_H
+#define STM32_COMMON_HAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <mcu/stm32_hal.h>
+
+uint32_t
+stm32_hal_timer_get_freq(void *timx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/mcu/stm/stm32_common/src/hal_timer.c b/hw/mcu/stm/stm32_common/src/hal_timer.c
index c80f7b2b7f..4446c009e6 100644
--- a/hw/mcu/stm/stm32_common/src/hal_timer.c
+++ b/hw/mcu/stm/stm32_common/src/hal_timer.c
@@ -26,6 +26,7 @@
#include <mcu/cmsis_nvic.h>
#include <hal/hal_timer.h>
#include "mcu/stm32_hal.h"
+#include "stm32_common/stm32_hal.h"
#define STM32_OFLOW_VALUE (0x10000UL)
#define STM32_NSEC_PER_SEC (1000000000UL)
@@ -160,69 +161,6 @@ stm32_tmr_reg_irq(IRQn_Type irqn, uint32_t func)
NVIC_EnableIRQ(irqn);
}
-static uint32_t
-stm32_base_freq(TIM_TypeDef *regs)
-{
- RCC_ClkInitTypeDef clocks;
- uint32_t fl;
- uint32_t freq;
-
- HAL_RCC_GetClockConfig(&clocks, &fl);
-
- /*
- * Assuming RCC_DCKCFGR->TIMPRE is 0.
- * There's just APB2 timers here.
- */
- switch ((uint32_t)regs) {
-#ifdef TIM1
- case (uint32_t)TIM1:
-#endif
-#ifdef TIM8
- case (uint32_t)TIM8:
-#endif
-#ifdef TIM9
- case (uint32_t)TIM9:
-#endif
-#ifdef TIM10
- case (uint32_t)TIM10:
-#endif
-#ifdef TIM11
- case (uint32_t)TIM11:
-#endif
-#ifdef TIM15
- case (uint32_t)TIM15:
-#endif
-#ifdef TIM16
- case (uint32_t)TIM16:
-#endif
-#ifdef TIM17
- case (uint32_t)TIM17:
-#endif
- freq = HAL_RCC_GetPCLK2Freq();
- if (clocks.APB2CLKDivider) {
- freq *= 2;
- }
- break;
-#ifdef TIM2
- case (uint32_t)TIM2:
-#endif
-#ifdef TIM3
- case (uint32_t)TIM3:
-#endif
-#ifdef TIM4
- case (uint32_t)TIM4:
-#endif
- freq = HAL_RCC_GetPCLK1Freq();
- if (clocks.APB1CLKDivider) {
- freq *= 2;
- }
- break;
- default:
- return 0;
- }
- return freq;
-}
-
static void
stm32_hw_setup(int num, TIM_TypeDef *regs)
{
@@ -514,7 +452,7 @@ hal_timer_config(int num, uint32_t freq_hz)
return -1;
}
- prescaler = stm32_base_freq(tmr->sht_regs) / freq_hz;
+ prescaler = stm32_hal_timer_get_freq(tmr->sht_regs) / freq_hz;
if (prescaler > 0xffff) {
return -1;
}
diff --git a/hw/mcu/stm/stm32f1xx/include/mcu/stm32_hal.h b/hw/mcu/stm/stm32f1xx/include/mcu/stm32_hal.h
index 9753547957..dc99bb97fe 100644
--- a/hw/mcu/stm/stm32f1xx/include/mcu/stm32_hal.h
+++ b/hw/mcu/stm/stm32f1xx/include/mcu/stm32_hal.h
@@ -64,6 +64,8 @@ struct stm32_hal_spi_cfg {
/* hal_timer */
#include "stm32f1xx_hal_tim.h"
+#include "stm32f1xx_ll_bus.h"
+#include "stm32f1xx_ll_tim.h"
#define STM32_HAL_TIMER_MAX (3)
diff --git a/hw/mcu/stm/stm32f1xx/src/hal_timer_freq.c b/hw/mcu/stm/stm32f1xx/src/hal_timer_freq.c
new file mode 100644
index 0000000000..1e48d793b6
--- /dev/null
+++ b/hw/mcu/stm/stm32f1xx/src/hal_timer_freq.c
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+
+#include "os/mynewt.h"
+
+#include <hal/hal_timer.h>
+#include "mcu/stm32_hal.h"
+#include "stm32_common/stm32_hal.h"
+
+
+/*
+ * Generic implementation for determining the frequency
+ * of a timer.
+ */
+
+uint32_t
+stm32_hal_timer_get_freq(void *regs)
+{
+ RCC_ClkInitTypeDef clocks;
+ uint32_t fl;
+ uint32_t freq;
+
+ HAL_RCC_GetClockConfig(&clocks, &fl);
+
+ /*
+ * Assuming RCC_DCKCFGR->TIMPRE is 0.
+ * There's just APB2 timers here.
+ */
+ switch ((uintptr_t)regs) {
+#ifdef TIM1
+ case (uintptr_t)TIM1:
+#endif
+#ifdef TIM8
+ case (uintptr_t)TIM8:
+#endif
+#ifdef TIM9
+ case (uuintptr_t)TIM9:
+#endif
+#ifdef TIM10
+ case (uintptr_t)TIM10:
+#endif
+#ifdef TIM11
+ case (uintptr_t)TIM11:
+#endif
+#ifdef TIM15
+ case (uintptr_t)TIM15:
+#endif
+#ifdef TIM16
+ case (uintptr_t)TIM16:
+#endif
+#ifdef TIM17
+ case (uintptr_t)TIM17:
+#endif
+ freq = HAL_RCC_GetPCLK2Freq();
+ if (clocks.APB2CLKDivider) {
+ freq *= 2;
+ }
+ break;
+#ifdef TIM2
+ case (uintptr_t)TIM2:
+#endif
+#ifdef TIM3
+ case (uintptr_t)TIM3:
+#endif
+#ifdef TIM4
+ case (uintptr_t)TIM4:
+#endif
+ freq = HAL_RCC_GetPCLK1Freq();
+ if (clocks.APB1CLKDivider) {
+ freq *= 2;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return freq;
+}
diff --git a/hw/mcu/stm/stm32f3xx/include/mcu/mcu.h b/hw/mcu/stm/stm32f3xx/include/mcu/mcu.h
index eb947399fd..bd5a29e14b 100644
--- a/hw/mcu/stm/stm32f3xx/include/mcu/mcu.h
+++ b/hw/mcu/stm/stm32f3xx/include/mcu/mcu.h
@@ -37,10 +37,42 @@ extern "C" {
#define MCU_GPIO_PORTH(pin) ((7 * 16) + (pin))
#define MCU_GPIO_PORTI(pin) ((8 * 16) + (pin))
#define MCU_GPIO_PORTJ(pin) ((9 * 16) + (pin))
-
/* NOTE: PORTK only have pins 0, 1, 3, 4, 5, 6, 7 available */
#define MCU_GPIO_PORTK(pin) ((10 * 16) + (pin))
+/*
+ * Mapping of a GPIO pin to an alternate function.
+ */
+#define MCU_AFIO_GPIO(pin,af) (((0x0F & af) << 12) | (0x00FF & pin))
+
+/*
+ * Mapping of alternate function pin descriptors.
+ */
+#define MCU_AFIO_PORTA(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTA(pin))
+#define MCU_AFIO_PORTB(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTB(pin))
+#define MCU_AFIO_PORTC(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTC(pin))
+#define MCU_AFIO_PORTD(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTD(pin))
+#define MCU_AFIO_PORTE(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTE(pin))
+#define MCU_AFIO_PORTF(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTF(pin))
+#define MCU_AFIO_PORTG(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTG(pin))
+#define MCU_AFIO_PORTH(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTH(pin))
+#define MCU_AFIO_PORTI(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTI(pin))
+#define MCU_AFIO_PORTJ(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTJ(pin))
+#define MCU_AFIO_PORTK(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTK(pin))
+
+/*
+ * Helper macros to extract components from a pin descriptor.
+ */
+#define MCU_AFIO_PIN_NUM(pin) (0x000F & pin)
+#define MCU_AFIO_PIN_PORT(pin) ((0x00F0 & pin) >> 4)
+#define MCU_AFIO_PIN_PAD(pin) (0x00FF & pin)
+#define MCU_AFIO_PIN_AF(pin) ((0xF000 & pin) >> 12)
+
+/*
+ * Use this value for pins that should not be used.
+ */
+#define MCU_AFIO_PIN_NONE (0xFFFF)
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/mcu/stm/stm32f3xx/include/mcu/stm32_hal.h b/hw/mcu/stm/stm32f3xx/include/mcu/stm32_hal.h
index 18edb52a61..1eddd45ade 100644
--- a/hw/mcu/stm/stm32f3xx/include/mcu/stm32_hal.h
+++ b/hw/mcu/stm/stm32f3xx/include/mcu/stm32_hal.h
@@ -70,6 +70,8 @@ struct stm32_hal_spi_cfg {
/* hal_timer */
#include "stm32f3xx_hal_tim.h"
+#include "stm32f3xx_ll_bus.h"
+#include "stm32f3xx_ll_tim.h"
#define STM32_HAL_TIMER_MAX (3)
diff --git a/hw/mcu/stm/stm32f3xx/src/hal_timer_freq.c b/hw/mcu/stm/stm32f3xx/src/hal_timer_freq.c
new file mode 100644
index 0000000000..cff66cfa21
--- /dev/null
+++ b/hw/mcu/stm/stm32f3xx/src/hal_timer_freq.c
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+
+#include "os/mynewt.h"
+#include "stm32f3xx_hal_rcc.h"
+
+static uint32_t
+stm32_hal_timer_get_freq_ahb1(RCC_ClkInitTypeDef *clk) {
+ uint32_t freq = HAL_RCC_GetPCLK1Freq();
+
+ if (clk->APB1CLKDivider != RCC_HCLK_DIV1) {
+ return 2 * freq;
+ }
+
+ return freq;
+}
+
+static uint32_t
+stm32_hal_timer_get_freq_ahb2(RCC_ClkInitTypeDef *clk, bool pll2source)
+{
+ uint32_t freq = HAL_RCC_GetPCLK2Freq();
+
+ if (pll2source && RCC_HCLK_DIV1 == clk->APB2CLKDivider && RCC_SYSCLK_DIV1 == clk->AHBCLKDivider) {
+ return 2 * freq;
+ }
+
+ if (clk->APB2CLKDivider != RCC_HCLK_DIV1) {
+ return 2 * freq;
+ }
+
+ return freq;
+}
+
+uint32_t
+stm32_hal_timer_get_freq(void *timx)
+{
+ uintptr_t regs = (uintptr_t)timx;
+ RCC_ClkInitTypeDef clk;
+ uint32_t flashLatency;
+
+ HAL_RCC_GetClockConfig(&clk, &flashLatency);
+
+ switch (regs) {
+#ifdef TIM1
+ case (uintptr_t)TIM1:
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM1_SOURCE());
+#endif
+#ifdef TIM8
+ case (uintptr_t)TIM8:
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM8_SOURCE());
+#endif
+#ifdef TIM9
+ case (uintptr_t)TIM9:
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM9_SOURCE());
+#endif
+#ifdef TIM10
+ case (uintptr_t)TIM10:
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM10_SOURCE());
+#endif
+#ifdef TIM11
+ case (uintptr_t)TIM11:
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM11_SOURCE());
+#endif
+#ifdef TIM15
+ case (uintptr_t)TIM15:
+# ifdef __HAL_RCC_GET_TIM15_SOURCE
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM15_SOURCE());
+# else
+ return stm32_hal_timer_get_freq_ahb2(&clk, false);
+# endif
+#endif
+#ifdef TIM16
+ case (uintptr_t)TIM16:
+# ifdef __HAL_RCC_GET_TIM16_SOURCE
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM16_SOURCE());
+# else
+ return stm32_hal_timer_get_freq_ahb2(&clk, false);
+# endif
+#endif
+#ifdef TIM17
+ case (uintptr_t)TIM17:
+# ifdef __HAL_RCC_GET_TIM17_SOURCE
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM17_SOURCE());
+# else
+ return stm32_hal_timer_get_freq_ahb2(&clk, false);
+# endif
+#endif
+#ifdef TIM20
+ case (uintptr_t)TIM20:
+# ifdef __HAL_RCC_GET_TIM20_SOURCE
+ return stm32_hal_timer_get_freq_ahb2(&clk, __HAL_RCC_GET_TIM20_SOURCE());
+# else
+ return stm32_hal_timer_get_freq_ahb2(&clk, false);
+# endif
+#endif
+ /* AHB1 timers ... */
+#ifdef TIM2
+ case (uintptr_t)TIM2:
+#endif
+#ifdef TIM3
+ case (uintptr_t)TIM3:
+#endif
+#ifdef TIM4
+ case (uintptr_t)TIM4:
+#endif
+#ifdef TIM5
+ case (uintptr_t)TIM5:
+#endif
+#ifdef TIM6
+ case (uintptr_t)TIM6:
+#endif
+#ifdef TIM7
+ case (uintptr_t)TIM7:
+#endif
+
+#ifdef TIM12
+ case (uintptr_t)TIM12:
+#endif
+#ifdef TIM13
+ case (uintptr_t)TIM13:
+#endif
+#ifdef TIM14
+ case (uintptr_t)TIM14:
+#endif
+ return stm32_hal_timer_get_freq_ahb1(&clk);
+ }
+
+ assert(0);
+ return 0;
+}
+
diff --git a/hw/mcu/stm/stm32f4xx/include/mcu/stm32_hal.h b/hw/mcu/stm/stm32f4xx/include/mcu/stm32_hal.h
index 37f49fe963..aec79d9d1d 100644
--- a/hw/mcu/stm/stm32f4xx/include/mcu/stm32_hal.h
+++ b/hw/mcu/stm/stm32f4xx/include/mcu/stm32_hal.h
@@ -68,6 +68,8 @@ struct stm32_hal_spi_cfg {
/* hal_timer */
#include "stm32f4xx_hal_tim.h"
+#include "stm32f4xx_ll_bus.h"
+#include "stm32f4xx_ll_tim.h"
#define STM32_HAL_TIMER_MAX (3)
diff --git a/hw/mcu/stm/stm32f4xx/src/hal_timer_freq.c b/hw/mcu/stm/stm32f4xx/src/hal_timer_freq.c
new file mode 100644
index 0000000000..0cdb3b7147
--- /dev/null
+++ b/hw/mcu/stm/stm32f4xx/src/hal_timer_freq.c
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+
+#include "os/mynewt.h"
+
+#include <hal/hal_timer.h>
+#include "mcu/stm32_hal.h"
+#include "stm32_common/stm32_hal.h"
+
+
+/*
+ * Generic implementation for determining the frequency
+ * of a timer.
+ */
+
+uint32_t
+stm32_hal_timer_get_freq(void *regs)
+{
+ RCC_ClkInitTypeDef clocks;
+ uint32_t fl;
+ uint32_t freq;
+
+ HAL_RCC_GetClockConfig(&clocks, &fl);
+
+ /*
+ * Assuming RCC_DCKCFGR->TIMPRE is 0.
+ * There's just APB2 timers here.
+ */
+ switch ((uintptr_t)regs) {
+#ifdef TIM1
+ case (uintptr_t)TIM1:
+#endif
+#ifdef TIM8
+ case (uintptr_t)TIM8:
+#endif
+#ifdef TIM9
+ case (uintptr_t)TIM9:
+#endif
+#ifdef TIM10
+ case (uintptr_t)TIM10:
+#endif
+#ifdef TIM11
+ case (uintptr_t)TIM11:
+#endif
+#ifdef TIM15
+ case (uintptr_t)TIM15:
+#endif
+#ifdef TIM16
+ case (uintptr_t)TIM16:
+#endif
+#ifdef TIM17
+ case (uintptr_t)TIM17:
+#endif
+ freq = HAL_RCC_GetPCLK2Freq();
+ if (clocks.APB2CLKDivider) {
+ freq *= 2;
+ }
+ break;
+#ifdef TIM2
+ case (uintptr_t)TIM2:
+#endif
+#ifdef TIM3
+ case (uintptr_t)TIM3:
+#endif
+#ifdef TIM4
+ case (uintptr_t)TIM4:
+#endif
+ freq = HAL_RCC_GetPCLK1Freq();
+ if (clocks.APB1CLKDivider) {
+ freq *= 2;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return freq;
+}
diff --git a/hw/mcu/stm/stm32f7xx/include/mcu/mcu.h b/hw/mcu/stm/stm32f7xx/include/mcu/mcu.h
index eb947399fd..bd5a29e14b 100644
--- a/hw/mcu/stm/stm32f7xx/include/mcu/mcu.h
+++ b/hw/mcu/stm/stm32f7xx/include/mcu/mcu.h
@@ -37,10 +37,42 @@ extern "C" {
#define MCU_GPIO_PORTH(pin) ((7 * 16) + (pin))
#define MCU_GPIO_PORTI(pin) ((8 * 16) + (pin))
#define MCU_GPIO_PORTJ(pin) ((9 * 16) + (pin))
-
/* NOTE: PORTK only have pins 0, 1, 3, 4, 5, 6, 7 available */
#define MCU_GPIO_PORTK(pin) ((10 * 16) + (pin))
+/*
+ * Mapping of a GPIO pin to an alternate function.
+ */
+#define MCU_AFIO_GPIO(pin,af) (((0x0F & af) << 12) | (0x00FF & pin))
+
+/*
+ * Mapping of alternate function pin descriptors.
+ */
+#define MCU_AFIO_PORTA(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTA(pin))
+#define MCU_AFIO_PORTB(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTB(pin))
+#define MCU_AFIO_PORTC(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTC(pin))
+#define MCU_AFIO_PORTD(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTD(pin))
+#define MCU_AFIO_PORTE(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTE(pin))
+#define MCU_AFIO_PORTF(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTF(pin))
+#define MCU_AFIO_PORTG(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTG(pin))
+#define MCU_AFIO_PORTH(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTH(pin))
+#define MCU_AFIO_PORTI(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTI(pin))
+#define MCU_AFIO_PORTJ(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTJ(pin))
+#define MCU_AFIO_PORTK(pin, af) MCU_AFIO_GPIO(af, MCU_GPIO_PORTK(pin))
+
+/*
+ * Helper macros to extract components from a pin descriptor.
+ */
+#define MCU_AFIO_PIN_NUM(pin) (0x000F & pin)
+#define MCU_AFIO_PIN_PORT(pin) ((0x00F0 & pin) >> 4)
+#define MCU_AFIO_PIN_PAD(pin) (0x00FF & pin)
+#define MCU_AFIO_PIN_AF(pin) ((0xF000 & pin) >> 12)
+
+/*
+ * Use this value for pins that should not be used.
+ */
+#define MCU_AFIO_PIN_NONE (0xFFFF)
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/mcu/stm/stm32f7xx/include/mcu/stm32_hal.h b/hw/mcu/stm/stm32f7xx/include/mcu/stm32_hal.h
index 10241d44c7..8cdd6b414e 100644
--- a/hw/mcu/stm/stm32f7xx/include/mcu/stm32_hal.h
+++ b/hw/mcu/stm/stm32f7xx/include/mcu/stm32_hal.h
@@ -72,6 +72,8 @@ struct stm32_hal_spi_cfg {
/* hal_timer */
#include "stm32f7xx_hal_tim.h"
+#include "stm32f7xx_ll_bus.h"
+#include "stm32f7xx_ll_tim.h"
#define STM32_HAL_TIMER_MAX (3)
diff --git a/hw/mcu/stm/stm32f7xx/src/hal_timer_freq.c b/hw/mcu/stm/stm32f7xx/src/hal_timer_freq.c
new file mode 100644
index 0000000000..45c2add500
--- /dev/null
+++ b/hw/mcu/stm/stm32f7xx/src/hal_timer_freq.c
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "os/mynewt.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include "stm32f7xx_hal_rcc.h"
+
+static uint32_t
+stm32_hal_timer_abp_clk_div(uint32_t divider)
+{
+ switch (divider) {
+ case RCC_HCLK_DIV1:
+ return 1;
+ case RCC_HCLK_DIV2:
+ return 2;
+ case RCC_HCLK_DIV4:
+ return 4;
+ case RCC_HCLK_DIV8:
+ return 8;
+ case RCC_HCLK_DIV16:
+ return 16;
+ }
+ return 0;
+}
+
+uint32_t
+stm32_hal_timer_get_freq(void *timx)
+{
+ uintptr_t regs = (uintptr_t)timx;
+ RCC_ClkInitTypeDef clocks;
+ uint32_t flashLatency;
+ uint32_t freq = 0;
+ uint32_t div = 0;
+
+ HAL_RCC_GetClockConfig(&clocks, &flashLatency);
+
+ switch (regs) {
+#ifdef TIM1
+ case (uintptr_t)TIM1:
+#endif
+#ifdef TIM8
+ case (uintptr_t)TIM8:
+#endif
+#ifdef TIM9
+ case (uintptr_t)TIM9:
+#endif
+#ifdef TIM10
+ case (uintptr_t)TIM10:
+#endif
+#ifdef TIM11
+ case (uintptr_t)TIM11:
+#endif
+#ifdef TIM15
+ case (uintptr_t)TIM15:
+#endif
+#ifdef TIM16
+ case (uintptr_t)TIM16:
+#endif
+#ifdef TIM17
+ case (uintptr_t)TIM17:
+#endif
+#ifdef TIM20
+ case (uintptr_t)TIM20:
+#endif
+ freq = HAL_RCC_GetPCLK2Freq();
+ div = stm32_hal_timer_abp_clk_div(clocks.APB2CLKDivider);
+ break;
+
+#ifdef TIM2
+ case (uintptr_t)TIM2:
+#endif
+#ifdef TIM3
+ case (uintptr_t)TIM3:
+#endif
+#ifdef TIM4
+ case (uintptr_t)TIM4:
+#endif
+#ifdef TIM5
+ case (uintptr_t)TIM5:
+#endif
+#ifdef TIM6
+ case (uintptr_t)TIM6:
+#endif
+#ifdef TIM7
+ case (uintptr_t)TIM7:
+#endif
+
+#ifdef TIM12
+ case (uintptr_t)TIM12:
+#endif
+#ifdef TIM13
+ case (uintptr_t)TIM13:
+#endif
+#ifdef TIM14
+ case (uintptr_t)TIM14:
+#endif
+ freq = HAL_RCC_GetPCLK1Freq();
+ div = stm32_hal_timer_abp_clk_div(clocks.APB1CLKDivider);
+ break;
+
+ default:
+ assert(0);
+ return 0;
+ }
+
+ if (RCC_TIMPRES_ACTIVATED == READ_BIT(RCC->DCKCFGR1, RCC_DCKCFGR1_TIMPRE)) {
+ if (div > 2) {
+ return freq * 4;
+ }
+ return freq * div;
+ }
+
+ if (div > 1) {
+ return freq * 2;
+ }
+ return freq;
+}
diff --git a/hw/mcu/stm/stm32l1xx/include/mcu/stm32_hal.h b/hw/mcu/stm/stm32l1xx/include/mcu/stm32_hal.h
index d618d4d0e2..1b95ad9ef6 100644
--- a/hw/mcu/stm/stm32l1xx/include/mcu/stm32_hal.h
+++ b/hw/mcu/stm/stm32l1xx/include/mcu/stm32_hal.h
@@ -68,6 +68,8 @@ struct stm32_hal_spi_cfg {
/* hal_timer */
#include "stm32l1xx_hal_tim.h"
+#include "stm32l1xx_ll_bus.h"
+#include "stm32l1xx_ll_tim.h"
#define STM32_HAL_TIMER_MAX (3)
diff --git a/hw/mcu/stm/stm32l1xx/src/hal_timer_freq.c b/hw/mcu/stm/stm32l1xx/src/hal_timer_freq.c
new file mode 100644
index 0000000000..0cdb3b7147
--- /dev/null
+++ b/hw/mcu/stm/stm32l1xx/src/hal_timer_freq.c
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <inttypes.h>
+#include <assert.h>
+
+#include "os/mynewt.h"
+
+#include <hal/hal_timer.h>
+#include "mcu/stm32_hal.h"
+#include "stm32_common/stm32_hal.h"
+
+
+/*
+ * Generic implementation for determining the frequency
+ * of a timer.
+ */
+
+uint32_t
+stm32_hal_timer_get_freq(void *regs)
+{
+ RCC_ClkInitTypeDef clocks;
+ uint32_t fl;
+ uint32_t freq;
+
+ HAL_RCC_GetClockConfig(&clocks, &fl);
+
+ /*
+ * Assuming RCC_DCKCFGR->TIMPRE is 0.
+ * There's just APB2 timers here.
+ */
+ switch ((uintptr_t)regs) {
+#ifdef TIM1
+ case (uintptr_t)TIM1:
+#endif
+#ifdef TIM8
+ case (uintptr_t)TIM8:
+#endif
+#ifdef TIM9
+ case (uintptr_t)TIM9:
+#endif
+#ifdef TIM10
+ case (uintptr_t)TIM10:
+#endif
+#ifdef TIM11
+ case (uintptr_t)TIM11:
+#endif
+#ifdef TIM15
+ case (uintptr_t)TIM15:
+#endif
+#ifdef TIM16
+ case (uintptr_t)TIM16:
+#endif
+#ifdef TIM17
+ case (uintptr_t)TIM17:
+#endif
+ freq = HAL_RCC_GetPCLK2Freq();
+ if (clocks.APB2CLKDivider) {
+ freq *= 2;
+ }
+ break;
+#ifdef TIM2
+ case (uintptr_t)TIM2:
+#endif
+#ifdef TIM3
+ case (uintptr_t)TIM3:
+#endif
+#ifdef TIM4
+ case (uintptr_t)TIM4:
+#endif
+ freq = HAL_RCC_GetPCLK1Freq();
+ if (clocks.APB1CLKDivider) {
+ freq *= 2;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return freq;
+}
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services