From 58b05abc91b28f2e523c8c9e9cf8ff4940c0b4b4 Mon Sep 17 00:00:00 2001 From: supperthomas <78900636@qq.com> Date: Sat, 1 Aug 2020 15:54:31 +0800 Subject: [PATCH] [bsp/nrf5x]: add the driver of pwm --- bsp/nrf5x/libraries/drivers/SConscript | 4 + bsp/nrf5x/libraries/drivers/drv_pwm.c | 432 +++++++++++++++++++++++++ bsp/nrf5x/nrf52840/board/Kconfig | 146 +++++++-- 3 files changed, 564 insertions(+), 18 deletions(-) create mode 100644 bsp/nrf5x/libraries/drivers/drv_pwm.c diff --git a/bsp/nrf5x/libraries/drivers/SConscript b/bsp/nrf5x/libraries/drivers/SConscript index 6bbdffce07..b446b7c3b4 100644 --- a/bsp/nrf5x/libraries/drivers/SConscript +++ b/bsp/nrf5x/libraries/drivers/SConscript @@ -19,8 +19,12 @@ if GetDepend(['BSP_USING_QSPI_FLASH']): if GetDepend(['BSP_USING_SPI']): src += ['drv_spi.c'] + if GetDepend(['BSP_USING_GPIO']): src += ['drv_gpio.c'] + +if GetDepend(['BSP_USING_PWM']): + src += ['drv_pwm.c'] path = [cwd] diff --git a/bsp/nrf5x/libraries/drivers/drv_pwm.c b/bsp/nrf5x/libraries/drivers/drv_pwm.c new file mode 100644 index 0000000000..4d7c036ce5 --- /dev/null +++ b/bsp/nrf5x/libraries/drivers/drv_pwm.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-07-26 supperthomas first version + * + */ + + +#include +#include "rtdevice.h" +#include "rtservice.h" + +#ifdef RT_USING_PWM + +#include + +struct mcu_pwm +{ + struct rt_device_pwm pwm_device; + + nrfx_pwm_t *pwm_handle; + nrf_pwm_values_individual_t m_demo1_seq_values; + nrf_pwm_sequence_t m_demo1_seq; + + rt_uint8_t channel; + char *name; + rt_uint64_t pwm_src_clk; + uint8_t channel_0_pin; + uint8_t channel_1_pin; + uint8_t channel_2_pin; + uint8_t channel_3_pin; +}; + +enum +{ +#ifdef BSP_USING_PWM0 + PWM0_INDEX, +#endif +#ifdef BSP_USING_PWM1 + PWM1_INDEX, +#endif +#ifdef BSP_USING_PWM2 + PWM2_INDEX, +#endif +#ifdef BSP_USING_PWM3 + PWM3_INDEX, +#endif +}; +#ifdef BSP_USING_PWM0 +static nrfx_pwm_t m_pwm0 = NRFX_PWM_INSTANCE(0); +#define PWM0_CONFIG \ + { \ + .pwm_handle = &m_pwm0, \ + .name = "pwm0", \ + .pwm_src_clk = 1000000, \ + } +#endif + +#ifdef BSP_USING_PWM1 +static nrfx_pwm_t m_pwm1 = NRFX_PWM_INSTANCE(1); +#define PWM1_CONFIG \ + { \ + .pwm_handle = &m_pwm1, \ + .name = "pwm1", \ + .pwm_src_clk = 1000000, \ + } +#endif + +#ifdef BSP_USING_PWM2 +static nrfx_pwm_t m_pwm2 = NRFX_PWM_INSTANCE(2); +#define PWM2_CONFIG \ + { \ + .pwm_handle = &m_pwm2, \ + .name = "pwm2", \ + .pwm_src_clk = 1000000, \ + } +#endif + +#ifdef BSP_USING_PWM3 +static nrfx_pwm_t m_pwm3 = NRFX_PWM_INSTANCE(3); +#define PWM3_CONFIG \ + { \ + .pwm_handle = &m_pwm3, \ + .name = "pwm3", \ + .pwm_src_clk = 1000000, \ + } +#endif + +static struct mcu_pwm mcu_pwm_obj[] = +{ +#ifdef BSP_USING_PWM0 + PWM0_CONFIG, +#endif +#ifdef BSP_USING_PWM1 + PWM1_CONFIG, +#endif + +#ifdef BSP_USING_PWM2 + PWM2_CONFIG, +#endif + +#ifdef BSP_USING_PWM3 + PWM3_CONFIG, +#endif +}; + +static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg); +static struct rt_pwm_ops drv_ops = +{ + drv_pwm_control +}; + +static rt_err_t drv_pwm_enable(struct mcu_pwm *p_mcu, struct rt_pwm_configuration *configuration, rt_bool_t enable) +{ + if (!enable) + { + nrfx_pwm_stop(p_mcu->pwm_handle, true); + } + else + { + (void)nrfx_pwm_simple_playback(p_mcu->pwm_handle, &p_mcu->m_demo1_seq, 1, NRFX_PWM_FLAG_LOOP); + } + + return RT_EOK; +} + +uint8_t mcu_get_channel_number(uint8_t channel) +{ + if (channel & 0x01) + { + return 0; + } + else if (channel & 0x02) + { + return 1; + } + else if (channel & 0x04) + { + return 2; + } + else if (channel & 0x08) + { + return 3; + } + return 0; +} + +static rt_err_t drv_pwm_get(struct mcu_pwm *pwm_handle, struct rt_pwm_configuration *configuration) +{ + rt_uint8_t channel_number = mcu_get_channel_number(configuration->channel); + uint8_t tick_pscond; + + tick_pscond = pwm_handle->pwm_src_clk / 1000000UL; + configuration->period = pwm_handle->pwm_handle->p_registers->COUNTERTOP * 1000UL / tick_pscond; + configuration->pulse = pwm_handle->pwm_handle->p_registers->SEQ[channel_number].PTR / tick_pscond; + + return RT_EOK; +} + +static void nrfx_set_prioid(nrfx_pwm_t *pwm_handle, uint32_t perioid) +{ + pwm_handle->p_registers->COUNTERTOP = perioid; +} + +static rt_err_t drv_pwm_set(struct mcu_pwm *p_mcu, struct rt_pwm_configuration *configuration) +{ + rt_uint32_t period, pulse; + uint8_t tick_pscond; + tick_pscond = p_mcu->pwm_src_clk / 1000000UL; + + p_mcu->pwm_handle->p_registers->COUNTERTOP = (unsigned long long)configuration->period * tick_pscond; + if (configuration->channel & 0x01) + { + p_mcu->m_demo1_seq_values.channel_0 = configuration->pulse; + } + + if (configuration->channel & 0x02) + { + p_mcu->m_demo1_seq_values.channel_1 = configuration->pulse; + } + + if (configuration->channel & 0x04) + { + p_mcu->m_demo1_seq_values.channel_2 = configuration->pulse; + } + + if (configuration->channel & 0x08) + { + p_mcu->m_demo1_seq_values.channel_3 = configuration->pulse; + } + return RT_EOK; +} + +static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg) +{ + struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg; + void *pwm_handle = (void *)device->parent.user_data; + nrfx_pwm_t *p_handle = (nrfx_pwm_t *)pwm_handle; + struct mcu_pwm *p_mcu = rt_container_of(p_handle, struct mcu_pwm, pwm_handle); + switch (cmd) + { + case PWM_CMD_ENABLE: + return drv_pwm_enable(p_mcu, configuration, RT_TRUE); + case PWM_CMD_DISABLE: + return drv_pwm_enable(p_mcu, configuration, RT_FALSE); + case PWM_CMD_SET: + return drv_pwm_set(p_mcu, configuration); + case PWM_CMD_GET: + return drv_pwm_get(p_mcu, configuration); + default: + return RT_EINVAL; + } +} + +static rt_err_t mcu_hw_pwm_init(struct mcu_pwm *device) +{ +#define NRFX_PWM_PIN_INVERTED 0x80 +#define _PRIO_APP_LOWEST 7 + nrfx_pwm_config_t config0 = + { + .irq_priority = _PRIO_APP_LOWEST, + .base_clock = NRF_PWM_CLK_1MHz, //default value + .count_mode = NRF_PWM_MODE_UP, + .top_value = 5000, //default vaule + .load_mode = NRF_PWM_LOAD_INDIVIDUAL, + .step_mode = NRF_PWM_STEP_AUTO + }; + rt_err_t result = RT_EOK; + if (device->pwm_src_clk == 1000000) + { + config0.base_clock = NRF_PWM_CLK_1MHz; + } + else if (device->pwm_src_clk == 2000000) + { + config0.base_clock = NRF_PWM_CLK_2MHz; + } + else if (device->pwm_src_clk == 8000000) + { + config0.base_clock = NRF_PWM_CLK_8MHz; + } + else + { + config0.base_clock = NRF_PWM_CLK_1MHz; + } + + if (device->channel & 0x01) + { + config0.output_pins[0] = device->channel_0_pin | NRFX_PWM_PIN_INVERTED; + } + + if (device->channel & 0x02) + { + config0.output_pins[1] = device->channel_1_pin | NRFX_PWM_PIN_INVERTED; + } + + if (device->channel & 0x04) + { + config0.output_pins[2] = device->channel_2_pin | NRFX_PWM_PIN_INVERTED; + } + + if (device->channel & 0x08) + { + config0.output_pins[3] = device->channel_3_pin | NRFX_PWM_PIN_INVERTED; + } + device->m_demo1_seq.values.p_individual = &device->m_demo1_seq_values; + device->m_demo1_seq.length = NRF_PWM_VALUES_LENGTH(device->m_demo1_seq_values), + nrfx_pwm_init(device->pwm_handle, &config0, NULL, NULL); + return result; +} + +static void pwm_get_channel(void) +{ +#ifdef BSP_USING_PWM0_CH0 + mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 0; + mcu_pwm_obj[PWM0_INDEX].channel_0_pin = BSP_USING_PWM0_CH0; +#endif +#ifdef BSP_USING_PWM0_CH1 + mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 1; + mcu_pwm_obj[PWM0_INDEX].channel_1_pin = BSP_USING_PWM0_CH1; +#endif +#ifdef BSP_USING_PWM0_CH2 + mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 2; + mcu_pwm_obj[PWM0_INDEX].channel_2_pin = BSP_USING_PWM0_CH2; +#endif +#ifdef BSP_USING_PWM0_CH3 + mcu_pwm_obj[PWM0_INDEX].channel |= 1 << 3; + mcu_pwm_obj[PWM0_INDEX].channel_3_pin = BSP_USING_PWM0_CH3; +#endif +#ifdef BSP_USING_PWM1_CH0 + mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 0; + mcu_pwm_obj[PWM1_INDEX].channel_0_pin = BSP_USING_PWM1_CH0; +#endif +#ifdef BSP_USING_PWM1_CH1 + mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 1; + mcu_pwm_obj[PWM1_INDEX].channel_1_pin = BSP_USING_PWM1_CH1; +#endif +#ifdef BSP_USING_PWM1_CH2 + mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 2; + mcu_pwm_obj[PWM1_INDEX].channel_2_pin = BSP_USING_PWM1_CH2; +#endif +#ifdef BSP_USING_PWM1_CH3 + mcu_pwm_obj[PWM1_INDEX].channel |= 1 << 3; + mcu_pwm_obj[PWM1_INDEX].channel_3_pin = BSP_USING_PWM1_CH3; +#endif +#ifdef BSP_USING_PWM2_CH0 + mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 0; + mcu_pwm_obj[PWM2_INDEX].channel_0_pin = BSP_USING_PWM2_CH0; +#endif +#ifdef BSP_USING_PWM2_CH1 + mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 1; + mcu_pwm_obj[PWM2_INDEX].channel_1_pin = BSP_USING_PWM2_CH1; +#endif +#ifdef BSP_USING_PWM2_CH2 + mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 2; + mcu_pwm_obj[PWM2_INDEX].channel_2_pin = BSP_USING_PWM2_CH2; +#endif +#ifdef BSP_USING_PWM2_CH3 + mcu_pwm_obj[PWM2_INDEX].channel |= 1 << 3; + mcu_pwm_obj[PWM2_INDEX].channel_3_pin = BSP_USING_PWM2_CH3; +#endif +#ifdef BSP_USING_PWM3_CH0 + mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 0; + mcu_pwm_obj[PWM3_INDEX].channel_0_pin = BSP_USING_PWM3_CH0; +#endif +#ifdef BSP_USING_PWM3_CH1 + mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 1; + mcu_pwm_obj[PWM3_INDEX].channel_1_pin = BSP_USING_PWM3_CH1; +#endif +#ifdef BSP_USING_PWM3_CH2 + mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 2; + mcu_pwm_obj[PWM3_INDEX].channel_2_pin = BSP_USING_PWM3_CH2; +#endif +#ifdef BSP_USING_PWM3_CH3 + mcu_pwm_obj[PWM3_INDEX].channel |= 1 << 3; + mcu_pwm_obj[PWM3_INDEX].channel_3_pin = BSP_USING_PWM3_CH3; +#endif +} + +static int mcu_pwm_init(void) +{ + int i = 0; + int result = RT_EOK; + + pwm_get_channel(); + for (i = 0; i < sizeof(mcu_pwm_obj) / sizeof(mcu_pwm_obj[0]); i++) + { + /* pwm init */ + if (mcu_hw_pwm_init(&mcu_pwm_obj[i]) != RT_EOK) + { + rt_kprintf("\r\n %s init failed", mcu_pwm_obj[i].name); + result = -RT_ERROR; + goto __exit; + } + else + { + rt_kprintf("\r\n %s init success", mcu_pwm_obj[i].name); + + /* register pwm device */ + if (rt_device_pwm_register(&mcu_pwm_obj[i].pwm_device, mcu_pwm_obj[i].name, &drv_ops, &mcu_pwm_obj[i].pwm_handle) == RT_EOK) + { + rt_kprintf("\r\n %s register success", mcu_pwm_obj[i].name); + } + else + { + rt_kprintf("\r\n %s register failed", mcu_pwm_obj[i].name); + result = -RT_ERROR; + } + } + } +__exit: + return result; +} +INIT_DEVICE_EXPORT(mcu_pwm_init); + + + +/* test example */ +#define PWM_DEV_NAME "pwm0" /* PWM name*/ +#define PWM_DEV_CHANNEL 15 /* PWM channel */ + +struct rt_device_pwm *pwm_dev; + +static int pwm_led_sample(int argc, char *argv[]) +{ + rt_uint32_t period, pulse, dir; + + period = 50000; /* 50ms*/ + dir = 1; + pulse = 0; + + + pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME); + if (pwm_dev == RT_NULL) + { + rt_kprintf("pwm sample run failed! can't find %s device!\n", PWM_DEV_NAME); + return RT_ERROR; + } + + rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse); + rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL); + + while (1) + { + rt_thread_mdelay(50); + if (dir) + { + pulse += 500; + } + else + { + pulse -= 500; + } + if (pulse >= period) + { + dir = 0; + } + if (0 == pulse) + { + dir = 1; + } + + + rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse); + } +} +MSH_CMD_EXPORT(pwm_led_sample, pwm sample); + +#endif \ No newline at end of file diff --git a/bsp/nrf5x/nrf52840/board/Kconfig b/bsp/nrf5x/nrf52840/board/Kconfig index 9f95a9177e..1bf97f6e4d 100644 --- a/bsp/nrf5x/nrf52840/board/Kconfig +++ b/bsp/nrf5x/nrf52840/board/Kconfig @@ -7,6 +7,12 @@ config SOC_NRF52840 select RT_USING_USER_MAIN default y +config SOC_NORDIC + bool + config SOC_NORDIC + default y + + menu "Onboard Peripheral Drivers" config BSP_USING_JLINK_TO_USART bool "Enable JLINK TO USART (uart0|RX_PIN:8|TX_PIN:6)" @@ -55,38 +61,142 @@ menu "On-chip Peripheral Drivers" bool "Enable GPIO" select RT_USING_PIN default y + menuconfig BSP_USING_PWM + bool "Enable PWM" + select RT_USING_PWM + default n + if BSP_USING_PWM + config NRFX_PWM_ENABLED + int + default 1 + config BSP_USING_PWM0 + bool "Enable PWM0 bus" + default y + if BSP_USING_PWM0 + config NRFX_PWM0_ENABLED + int + default 1 + config BSP_USING_PWM0_CH0 + int "PWM0 channel 0 pin number set" + range 0 47 + default 13 + config BSP_USING_PWM0_CH1 + int "PWM0 channel 1 pin number set" + range 0 47 + default 14 + config BSP_USING_PWM0_CH2 + int "PWM0 channel 2 pin number set" + range 0 47 + default 15 + config BSP_USING_PWM0_CH3 + int "PWM0 channel 3 pin number set" + range 0 47 + default 16 + endif + config BSP_USING_PWM1 + bool "Enable PWM1 bus" + default n + if BSP_USING_PWM1 + config NRFX_PWM1_ENABLED + int + default 1 + config BSP_USING_PWM1_CH0 + int "PWM1 channel 0 pin number set" + range 0 47 + default 13 + config BSP_USING_PWM1_CH1 + int "PWM1 channel 1 pin number set" + range 0 47 + default 14 + config BSP_USING_PWM1_CH2 + int "PWM1 channel 2 pin number set" + range 0 47 + default 15 + config BSP_USING_PWM1_CH3 + int "PWM1 channel 3 pin number set" + range 0 47 + default 16 + endif + config BSP_USING_PWM2 + bool "Enable PWM2 bus" + default n + if BSP_USING_PWM2 + config NRFX_PWM2_ENABLED + int + default 1 + config BSP_USING_PWM2_CH0 + int "PWM2 channel 0 pin number set" + range 0 47 + default 13 + config BSP_USING_PWM2_CH1 + int "PWM2 channel 1 pin number set" + range 0 47 + default 14 + config BSP_USING_PWM2_CH2 + int "PWM2 channel 2 pin number set" + range 0 47 + default 15 + config BSP_USING_PWM2_CH3 + int "PWM2 channel 3 pin number set" + range 0 47 + default 16 + endif + config BSP_USING_PWM3 + bool "Enable PWM3 bus" + default n + if BSP_USING_PWM3 + config NRFX_PWM3_ENABLED + int + default 1 + config BSP_USING_PWM3_CH0 + int "PWM3 channel 0 pin number set" + range 0 47 + default 13 + config BSP_USING_PWM3_CH1 + int "PWM3 channel 1 pin number set" + range 0 47 + default 14 + config BSP_USING_PWM3_CH2 + int "PWM3 channel 2 pin number set" + range 0 47 + default 15 + config BSP_USING_PWM3_CH3 + int "PWM3 channel 3 pin number set" + range 0 47 + default 16 + endif + endif menuconfig BSP_USING_SOFTDEVICE bool "Enable NRF SOFTDEVICE" select PKG_USING_NRF5X_SDK + select NRFX_CLOCK_ENABLED default n if BSP_USING_SOFTDEVICE config NRFX_CLOCK_ENABLED - int "NRFX_CLOCK_ENABLED" + int default 1 - config NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY - int "NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY" + config NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY + int default 7 - config NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY - int "NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY" - default 7 - config NRFX_RTC_ENABLED - int "NRFX_RTC_ENABLED" + config NRFX_RTC_ENABLED + int default 1 - config NRF_CLOCK_ENABLED - int "NRF_CLOCK_ENABLED" + config NRFX_RTC1_ENABLED + int default 1 - config NRF_SDH_BLE_ENABLED - int "NRF_SDH_BLE_ENABLED" + config NRF_CLOCK_ENABLED + int default 1 - config NRF_SDH_ENABLED - int "NRF_SDH_ENABLED" + config NRF_SDH_BLE_ENABLED + int default 1 - config NRF_SDH_SOC_ENABLED - int "NRF_SDH_SOC_ENABLED" + config NRF_SDH_ENABLED + int + default 1 + config NRF_SDH_SOC_ENABLED + int default 1 - endif - menuconfig BSP_USING_UART bool "Enable UART" default y