From 91281015ab24fbcf341224e46b74ffab5540297e Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 18 May 2016 16:04:10 +0200 Subject: [PATCH] allow use of GPIOTE/PPI to drive gpio pin (without callback) changed value of PAL_NOLINE to -1 --- os/hal/ports/NRF51/NRF51822/hal_pal_lld.h | 2 +- os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c | 77 ++++++++++++++++++++--- os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h | 49 +++++++++++++-- testhal/NRF51/NRF51822/PWM/main.c | 13 +++- testhal/NRF51/NRF51822/PWM/mcuconf.h | 1 + 5 files changed, 125 insertions(+), 17 deletions(-) diff --git a/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h b/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h index e5b62eee..5032916a 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h @@ -80,7 +80,7 @@ /** * @brief Value identifying an invalid line. */ -#define PAL_NOLINE FFU +#define PAL_NOLINE ((ioline_t)-1) /** @} */ /** diff --git a/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c index 76bc5726..456dcffc 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c @@ -68,25 +68,27 @@ PWMDriver PWMD3; /*===========================================================================*/ static void pwm_lld_serve_interrupt(PWMDriver *pwmp) { - // Deal with PWM period - if (pwmp->timer->EVENTS_COMPARE[pwmp->channels]) { - pwmp->timer->EVENTS_COMPARE[pwmp->channels] = 0; - - if (pwmp->config->callback != NULL) { - pwmp->config->callback(pwmp); - } - } - // Deal with PWM channels uint8_t n; for (n = 0 ; n < pwmp->channels ; n++) { if (pwmp->timer->EVENTS_COMPARE[n]) { pwmp->timer->EVENTS_COMPARE[n] = 0; + if (pwmp->config->channels[n].callback != NULL) { pwmp->config->channels[n].callback(pwmp); } } } + + // Deal with PWM period + if (pwmp->timer->EVENTS_COMPARE[pwmp->channels]) { + pwmp->timer->EVENTS_COMPARE[pwmp->channels] = 0; + + if (pwmp->config->callback != NULL) { + pwmp->config->callback(pwmp); + } + } + } /*===========================================================================*/ @@ -280,6 +282,47 @@ void pwm_lld_stop(PWMDriver *pwmp) { void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width) { +#if NRF51_PWM_USE_GPIOTE_PPI + const PWMChannelConfig *cfg_channel = &pwmp->config->channels[channel]; + + uint32_t outinit; + switch(cfg_channel->mode & PWM_OUTPUT_MASK) { + case PWM_OUTPUT_ACTIVE_LOW: + outinit = GPIOTE_CONFIG_OUTINIT_Low; + break; + case PWM_OUTPUT_ACTIVE_HIGH: + outinit = GPIOTE_CONFIG_OUTINIT_High; + break; + case PWM_OUTPUT_DISABLED: + default: + goto no_output_config; + } + + const uint32_t gpio_pin = PAL_PAD(cfg_channel->ioline); + const uint8_t gpiote_channel = cfg_channel->gpiote_channel; + const uint8_t *ppi_channel = cfg_channel->ppi_channel; + const uint32_t polarity = GPIOTE_CONFIG_POLARITY_Toggle; + + // Create GPIO Task + NRF_GPIOTE->CONFIG[gpiote_channel] = GPIOTE_CONFIG_MODE_Task | + ((gpio_pin << GPIOTE_CONFIG_PSEL_Pos ) & GPIOTE_CONFIG_PSEL_Msk) | + ((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk) | + ((outinit << GPIOTE_CONFIG_OUTINIT_Pos ) & GPIOTE_CONFIG_OUTINIT_Msk); + + // Program tasks (one for duty cycle, one for periode) + NRF_PPI->CH[ppi_channel[0]].EEP = + (uint32_t)&pwmp->timer->EVENTS_COMPARE[channel]; + NRF_PPI->CH[ppi_channel[0]].TEP = + (uint32_t)&NRF_GPIOTE->TASKS_OUT[gpiote_channel]; + NRF_PPI->CH[ppi_channel[1]].EEP = + (uint32_t)&pwmp->timer->EVENTS_COMPARE[pwmp->channels]; + NRF_PPI->CH[ppi_channel[1]].TEP = + (uint32_t)&NRF_GPIOTE->TASKS_OUT[gpiote_channel]; + NRF_PPI->CHENSET = ((1 << ppi_channel[0]) | (1 << ppi_channel[1])); + + no_output_config: +#endif + pwmp->timer->CC[channel] = width; } @@ -297,6 +340,22 @@ void pwm_lld_enable_channel(PWMDriver *pwmp, */ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { pwmp->timer->CC[channel] = 0; +#if NRF51_PWM_USE_GPIOTE_PPI + const PWMChannelConfig *cfg_channel = &pwmp->config->channels[channel]; + switch(cfg_channel->mode & PWM_OUTPUT_MASK) { + case PWM_OUTPUT_ACTIVE_LOW: + case PWM_OUTPUT_ACTIVE_HIGH: { + const uint8_t gpiote_channel = cfg_channel->gpiote_channel; + const uint8_t *ppi_channel = cfg_channel->ppi_channel; + NRF_PPI->CHENCLR = ((1 << ppi_channel[0]) | (1 << ppi_channel[1])); + NRF_GPIOTE->CONFIG[gpiote_channel] = GPIOTE_CONFIG_MODE_Disabled; + break; + } + case PWM_OUTPUT_DISABLED: + default: + break; + } +#endif } /** diff --git a/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h index 0ddd65cf..3cb0a894 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.h @@ -52,14 +52,28 @@ /* Driver pre-compile time settings. */ /*===========================================================================*/ +/** + * @name Configuration options + * @{ + */ + +/** + * @brief TIMER0 as driver implementation + */ #if !defined(NRF51_PWM_USE_TIMER0) #define NRF51_PWM_USE_TIMER0 FALSE #endif +/** + * @brief TIMER1 as driver implementation + */ #if !defined(NRF51_PWM_USE_TIMER1) #define NRF51_PWM_USE_TIMER1 FALSE #endif +/** + * @brief TIMER2 as driver implementation + */ #if !defined(NRF51_PWM_USE_TIMER2) #define NRF51_PWM_USE_TIMER2 FALSE #endif @@ -85,12 +99,13 @@ #define NRF51_PWM_TIMER2_PRIORITY 12 #endif -/** @} */ - /** - * @name Configuration options - * @{ + * @brief Allow driver to use GPIOTE/PPI to control PAL line */ +#if !defined(NRF51_PWM_USE_GPIOTE_PPI) +#define NRF51_PWM_USE_GPIOTE_PPI FALSE +#endif + /** @} */ /*===========================================================================*/ @@ -145,6 +160,32 @@ typedef struct { */ pwmcallback_t callback; /* End of the mandatory fields.*/ + + /** + * @brief PAL line to toggle. + * @note Only used if mode is PWM_OUTPUT_HIGH or PWM_OUTPUT_LOW. + * @note When NRF51_PWM_USE_GPIOTE_PPI is used and channel enabled, + * it wont be possible to access this PAL line using the PAL + * driver. + */ + ioline_t ioline; + +#if NRF51_PWM_USE_GPIOTE_PPI || defined(__DOXYGEN__) + /** + * @brief Unique GPIOTE channel to use. (1 channel) + * @note Only used if mode is PWM_OUTPUT_HIGH or PWM_OUTPUT_LOW. + * @note Only 4 GPIOTE channels are available on nRF51. + */ + uint8_t gpiote_channel; + + /** + * @brief Unique PPI channels to use. (2 channels) + * @note Only used if mode is PWM_OUTPUT_HIGH or PWM_OUTPUT_LOW. + * @note Only 16 PPI channels are available on nRF51 + * (When Softdevice is enabled, only channels 0-7 are available) + */ + uint8_t ppi_channel[2]; +#endif } PWMChannelConfig; /** diff --git a/testhal/NRF51/NRF51822/PWM/main.c b/testhal/NRF51/NRF51822/PWM/main.c index b93c3b20..51179d8e 100644 --- a/testhal/NRF51/NRF51822/PWM/main.c +++ b/testhal/NRF51/NRF51822/PWM/main.c @@ -39,9 +39,15 @@ int main(void) { .frequency = PWM_FREQUENCY_31250HZ, .period = 31250, .callback = pwm_cb_period, - { {PWM_OUTPUT_ACTIVE_HIGH, pwm_cb_channel0}, - {PWM_OUTPUT_DISABLED, NULL}, - {PWM_OUTPUT_DISABLED, NULL} + { { .mode = PWM_OUTPUT_DISABLED, + .callback = pwm_cb_channel0, }, + { .mode = PWM_OUTPUT_ACTIVE_HIGH, + .callback = NULL, + .ioline = LINE_LED2, + .gpiote_channel = 0, + .ppi_channel = { 0, 1 } }, + { .mode = PWM_OUTPUT_DISABLED, + .callback = NULL, }, }, }; @@ -62,6 +68,7 @@ int main(void) { pwmEnablePeriodicNotification(&PWMD1); pwmEnableChannel(&PWMD1, 0, PWM_FRACTION_TO_WIDTH(&PWMD1, 2, 1)); pwmEnableChannelNotification(&PWMD1, 0); + pwmEnableChannel(&PWMD1, 1, PWM_FRACTION_TO_WIDTH(&PWMD1, 4, 3)); while (1) { chThdSleepMilliseconds(500); diff --git a/testhal/NRF51/NRF51822/PWM/mcuconf.h b/testhal/NRF51/NRF51822/PWM/mcuconf.h index 1694678d..374340bb 100644 --- a/testhal/NRF51/NRF51822/PWM/mcuconf.h +++ b/testhal/NRF51/NRF51822/PWM/mcuconf.h @@ -25,5 +25,6 @@ #define NRF51_ST_USE_RTC1 FALSE #define NRF51_ST_USE_TIMER0 FALSE #define NRF51_PWM_USE_TIMER0 TRUE +#define NRF51_PWM_USE_GPIOTE_PPI TRUE #endif /* _MCUCONF_H_ */