From 91281015ab24fbcf341224e46b74ffab5540297e Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 18 May 2016 16:04:10 +0200 Subject: 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 ++++++++++++++++++-- 3 files changed, 114 insertions(+), 14 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h b/os/hal/ports/NRF51/NRF51822/hal_pal_lld.h index e5b62ee..5032916 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 76bc572..456dcff 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 0ddd65c..3cb0a89 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; /** -- cgit v1.2.3