aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/platforms/AT91SAM7/pwm_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/platforms/AT91SAM7/pwm_lld.c')
-rw-r--r--os/hal/platforms/AT91SAM7/pwm_lld.c467
1 files changed, 0 insertions, 467 deletions
diff --git a/os/hal/platforms/AT91SAM7/pwm_lld.c b/os/hal/platforms/AT91SAM7/pwm_lld.c
deleted file mode 100644
index 7d4060427..000000000
--- a/os/hal/platforms/AT91SAM7/pwm_lld.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
-
- Licensed 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.
-*/
-/*
- This file has been contributed by:
- Andrew Hannam aka inmarket.
-*/
-
-/**
- * @file AT91SAM7/pwm_lld.c
- * @brief AT91SAM7 PWM Driver subsystem low level driver source.
- *
- * @addtogroup PWM
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-
-#if HAL_USE_PWM || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#ifdef UNUSED
-#elif defined(__GNUC__)
-# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
-#elif defined(__LCLINT__)
-# define UNUSED(x) /*@unused@*/ x
-#else
-# define UNUSED(x) x
-#endif
-
-#define PWMC_M ((AT91S_PWMC *)AT91C_PWMC_MR)
-
-#define PWM_MCK_MASK 0x0F00
-#define PWM_MCK_SHIFT 8
-
-typedef struct pindef {
- uint32_t portpin; /* Set to 0 if this pin combination is invalid */
- AT91S_PIO *pio;
- AT91_REG *perab;
-} pindef_t;
-
-typedef struct pwmpindefs {
- pindef_t pin[3];
-} pwmpindefs_t;
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
-PWMDriver PWMD1;
-#endif
-
-#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
-PWMDriver PWMD2;
-#endif
-
-#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
-PWMDriver PWMD3;
-#endif
-
-#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
-PWMDriver PWMD4;
-#endif
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-#if (SAM7_PLATFORM == SAM7S64) || (SAM7_PLATFORM == SAM7S128) || \
- (SAM7_PLATFORM == SAM7S256) || (SAM7_PLATFORM == SAM7S512)
-
-#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP1 = {{
- { AT91C_PA0_PWM0 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_ASR },
- { AT91C_PA11_PWM0, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- { AT91C_PA23_PWM0, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- }};
-#endif
-#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP2 = {{
- { AT91C_PA1_PWM1 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_ASR },
- { AT91C_PA12_PWM1, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- { AT91C_PA24_PWM1, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- }};
-#endif
-#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP3 = {{
- { AT91C_PA2_PWM2 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_ASR },
- { AT91C_PA13_PWM2, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- { AT91C_PA25_PWM2, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- }};
-#endif
-#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP4 = {{
- { AT91C_PA7_PWM3 , AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- { AT91C_PA14_PWM3, AT91C_BASE_PIOA, &AT91C_BASE_PIOA->PIO_BSR },
- { 0, 0, 0 },
- }};
-#endif
-
-#elif (SAM7_PLATFORM == SAM7X128) || (SAM7_PLATFORM == SAM7X256) || \
- (SAM7_PLATFORM == SAM7X512)
-
-#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP1 = {{
- { AT91C_PB19_PWM0, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
- { AT91C_PB27_PWM0, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
- { 0, 0, 0 },
- }};
-#endif
-#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP2 = {{
- { AT91C_PB20_PWM1, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
- { AT91C_PB28_PWM1, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
- { 0, 0, 0 },
- }};
-#endif
-#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP3 = {{
- { AT91C_PB21_PWM2, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
- { AT91C_PB29_PWM2, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
- { 0, 0, 0 },
- }};
-#endif
-#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
-static const pwmpindefs_t PWMP4 = {{
- { AT91C_PB22_PWM3, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_ASR },
- { AT91C_PB30_PWM3, AT91C_BASE_PIOB, &AT91C_BASE_PIOB->PIO_BSR },
- { 0, 0, 0 },
- }};
-#endif
-
-#else
- #error "PWM pins not defined for this SAM7 version"
-#endif
-
-#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
-PWMDriver PWMD2;
-#endif
-
-#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
-PWMDriver PWMD3;
-#endif
-
-#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
-PWMDriver PWMD4;
-#endif
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-#if defined(__GNUC__)
-__attribute__((noinline))
-#endif
-/**
- * @brief Common IRQ handler.
- */
-static void pwm_lld_serve_interrupt(void) {
- uint32_t isr;
-
- isr = PWMC_M->PWMC_ISR;
-#if PWM_USE_PWM1
- if ((isr & 1) && PWMD1.config->channels[0].callback)
- PWMD1.config->channels[0].callback(&PWMD1);
-#endif
-#if PWM_USE_PWM2
- if ((isr & 2) && PWMD2.config->channels[0].callback)
- PWMD2.config->channels[0].callback(&PWMD2);
-#endif
-#if PWM_USE_PWM3
- if ((isr & 4) && PWMD3.config->channels[0].callback)
- PWMD3.config->channels[0].callback(&PWMD3);
-#endif
-#if PWM_USE_PWM4
- if ((isr & 8) && PWMD4.config->channels[0].callback)
- PWMD4.config->channels[0].callback(&PWMD4);
-#endif
-}
-
-CH_IRQ_HANDLER(PWMIrqHandler) {
- CH_IRQ_PROLOGUE();
- pwm_lld_serve_interrupt();
- AT91C_BASE_AIC->AIC_EOICR = 0;
- CH_IRQ_EPILOGUE();
-}
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Low level PWM driver initialization.
- *
- * @notapi
- */
-void pwm_lld_init(void) {
-
- /* Driver initialization.*/
-#if PWM_USE_PWM1 && !defined(__DOXYGEN__)
- pwmObjectInit(&PWMD1);
- PWMD1.chbit = 1;
- PWMD1.reg = AT91C_BASE_PWMC_CH0;
- PWMD1.pins = &PWMP1;
-#endif
-
-#if PWM_USE_PWM2 && !defined(__DOXYGEN__)
- pwmObjectInit(&PWMD2);
- PWMD2.chbit = 2;
- PWMD2.reg = AT91C_BASE_PWMC_CH1;
- PWMD2.pins = &PWMP2;
-#endif
-
-#if PWM_USE_PWM3 && !defined(__DOXYGEN__)
- pwmObjectInit(&PWMD3);
- PWMD3.chbit = 4;
- PWMD3.reg = AT91C_BASE_PWMC_CH2;
- PWMD3.pins = &PWMP3;
-#endif
-
-#if PWM_USE_PWM4 && !defined(__DOXYGEN__)
- pwmObjectInit(&PWMD4);
- PWMD4.chbit = 8;
- PWMD4.reg = AT91C_BASE_PWMC_CH3;
- PWMD4.pins = &PWMP4;
-#endif
-
- /* Turn on PWM in the power management controller */
- AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PWMC);
-
- /* Setup interrupt handler */
- PWMC_M->PWMC_IDR = 0xFFFFFFFF;
- AIC_ConfigureIT(AT91C_ID_PWMC,
- AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91SAM7_PWM_PRIORITY,
- PWMIrqHandler);
- AIC_EnableIT(AT91C_ID_PWMC);
-}
-
-/**
- * @brief Configures and activates the PWM peripheral.
- *
- * @param[in] pwmp pointer to the @p PWMDriver object
- *
- * @notapi
- */
-void pwm_lld_start(PWMDriver *pwmp) {
- uint32_t mode, mr, div, pre;
-
- /* Steps:
- 1. Turn the IO pin to a PWM output
- 2. Configuration of Clock if DIVA or DIVB used
- 3. Selection of the clock for each channel (CPRE field in the PWM_CMRx register)
- 4. Configuration of the waveform alignment for each channel (CALG field in the PWM_CMRx register)
- 5. Configuration of the output waveform polarity for each channel (CPOL in the PWM_CMRx register)
- 6. Configuration of the period for each channel (CPRD in the PWM_CPRDx register). Writing in
- PWM_CPRDx Register is possible while the channel is disabled. After validation of the
- channel, the user must use PWM_CUPDx Register to update PWM_CPRDx
- 7. Enable Interrupts (Writing CHIDx in the PWM_IER register)
- */
-
- /* Make sure it is off first */
- pwm_lld_disable_channel(pwmp, 0);
-
- /* Configuration.*/
- mode = pwmp->config->channels[0].mode;
-
- /* Step 1 */
- if (mode & PWM_OUTPUT_PIN1) {
- pwmp->pins->pin[0].perab[0] = pwmp->pins->pin[0].portpin; /* Select A or B peripheral */
- pwmp->pins->pin[0].pio->PIO_PDR = pwmp->pins->pin[0].portpin; /* Turn PIO into PWM output */
- pwmp->pins->pin[0].pio->PIO_MDDR = pwmp->pins->pin[0].portpin; /* Turn off PIO multi-drive */
- if (mode & PWM_DISABLEPULLUP_PIN1)
- pwmp->pins->pin[0].pio->PIO_PPUDR = pwmp->pins->pin[0].portpin; /* Turn off PIO pullup */
- else
- pwmp->pins->pin[0].pio->PIO_PPUER = pwmp->pins->pin[0].portpin; /* Turn on PIO pullup */
- }
- if (mode & PWM_OUTPUT_PIN2) {
- pwmp->pins->pin[1].perab[0] = pwmp->pins->pin[1].portpin;
- pwmp->pins->pin[1].pio->PIO_PDR = pwmp->pins->pin[1].portpin;
- pwmp->pins->pin[1].pio->PIO_MDDR = pwmp->pins->pin[1].portpin;
- if (mode & PWM_DISABLEPULLUP_PIN2)
- pwmp->pins->pin[1].pio->PIO_PPUDR = pwmp->pins->pin[1].portpin;
- else
- pwmp->pins->pin[1].pio->PIO_PPUER = pwmp->pins->pin[1].portpin;
- }
- if ((mode & PWM_OUTPUT_PIN3) && pwmp->pins->pin[2].portpin) {
- pwmp->pins->pin[2].perab[0] = pwmp->pins->pin[2].portpin;
- pwmp->pins->pin[2].pio->PIO_PDR = pwmp->pins->pin[2].portpin;
- pwmp->pins->pin[2].pio->PIO_MDDR = pwmp->pins->pin[2].portpin;
- if (mode & PWM_DISABLEPULLUP_PIN3)
- pwmp->pins->pin[2].pio->PIO_PPUDR = pwmp->pins->pin[2].portpin;
- else
- pwmp->pins->pin[2].pio->PIO_PPUER = pwmp->pins->pin[2].portpin;
- }
-
- /* Step 2 */
- if ((mode & PWM_MCK_MASK) == PWM_MCK_DIV_CLKA) {
- if (!pwmp->config->frequency) {
- /* As slow as we go */
- PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0xFFFF0000) | (10 << 8) | (255 << 0);
- } else if (pwmp->config->frequency > MCK) {
- /* Just use MCLK */
- mode &= ~PWM_MCK_MASK;
- } else {
- div = MCK / pwmp->config->frequency;
- if (mode & PWM_OUTPUT_CENTER) div >>= 1;
- for(pre = 0; div > 255 && pre < 10; pre++) div >>= 1;
- if (div > 255) div = 255;
- PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0xFFFF0000) | (pre << 8) | (div << 0);
- }
- } else if ((mode & PWM_MCK_MASK) == PWM_MCK_DIV_CLKB) {
- if (!pwmp->config->frequency) {
- /* As slow as we go */
- PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0x0000FFFF) | (10 << 24) | (255 << 16);
- } else if (pwmp->config->frequency > MCK) {
- /* Just use MCLK */
- mode &= ~PWM_MCK_MASK;
- } else {
- div = MCK / pwmp->config->frequency;
- if (mode & PWM_OUTPUT_CENTER) div >>= 1;
- for(pre = 0; div > 255 && pre < 10; pre++) div >>= 1;
- if (div > 255) div = 255;
- PWMC_M->PWMC_MR = (PWMC_M->PWMC_MR & 0x0000FFFF) | (pre << 24) | (div << 16);
- }
- }
-
- /* Step 3 -> 5 */
- mr = (mode & PWM_MCK_MASK) >> PWM_MCK_SHIFT;
- if (mode & PWM_OUTPUT_CENTER) mr |= AT91C_PWMC_CALG;
- if (mode & PWM_OUTPUT_ACTIVE_HIGH) mr |= AT91C_PWMC_CPOL;
- pwmp->reg->PWMC_CMR = mr;
-
- /* Step 6 */
- pwmp->reg->PWMC_CPRDR = pwmp->period;
-
- /* Step 7 */
- if (pwmp->config->channels[0].callback)
- PWMC_M->PWMC_IER = pwmp->chbit;
-}
-
-/**
- * @brief Deactivates the PWM peripheral.
- *
- * @param[in] pwmp pointer to the @p PWMDriver object
- *
- * @notapi
- */
-void pwm_lld_stop(PWMDriver *pwmp) {
- /* Make sure it is off */
- pwm_lld_disable_channel(pwmp, 0);
-
- /* Turn the pin back to a PIO pin - we have forgotten pull-up and multi-drive state for the pin though */
- if (pwmp->config->channels[0].mode & PWM_OUTPUT_PIN1)
- pwmp->pins->pin[0].pio->PIO_PER = pwmp->pins->pin[0].portpin;
- if (pwmp->config->channels[0].mode & PWM_OUTPUT_PIN2)
- pwmp->pins->pin[1].pio->PIO_PER = pwmp->pins->pin[1].portpin;
- if ((pwmp->config->channels[0].mode & PWM_OUTPUT_PIN3) && pwmp->pins->pin[2].portpin)
- pwmp->pins->pin[2].pio->PIO_PER = pwmp->pins->pin[2].portpin;
-}
-
-/**
- * @brief Changes the period the PWM peripheral.
- * @details This function changes the period of a PWM unit that has already
- * been activated using @p pwmStart().
- * @pre The PWM unit must have been activated using @p pwmStart().
- * @post The PWM unit period is changed to the new value.
- * @note The function has effect at the next cycle start.
- * @note If a period is specified that is shorter than the pulse width
- * programmed in one of the channels then the behavior is not
- * guaranteed.
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] period new cycle time in ticks
- *
- * @notapi
- */
-void pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period) {
- pwmp->period = period;
-
- if (PWMC_M->PWMC_SR & pwmp->chbit) {
- pwmp->reg->PWMC_CMR |= AT91C_PWMC_CPD;
- pwmp->reg->PWMC_CUPDR = period;
- } else {
- pwmp->reg->PWMC_CPRDR = period;
- }
-}
-
-/**
- * @brief Enables a PWM channel.
- * @pre The PWM unit must have been activated using @p pwmStart().
- * @post The channel is active using the specified configuration.
- * @note Depending on the hardware implementation this function has
- * effect starting on the next cycle (recommended implementation)
- * or immediately (fallback implementation).
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
- * @param[in] width PWM pulse width as clock pulses number
- *
- * @notapi
- */
-void pwm_lld_enable_channel(PWMDriver *pwmp,
- pwmchannel_t UNUSED(channel),
- pwmcnt_t width) {
- /*
- 6. Configuration of the duty cycle for each channel (CDTY in the PWM_CDTYx register).
- Writing in PWM_CDTYx Register is possible while the channel is disabled. After validation of
- the channel, the user must use PWM_CUPDx Register to update PWM_CDTYx.
- 7. Enable the PWM channel (Writing CHIDx in the PWM_ENA register)
- */
-
- /* Step 6 */
- if (PWMC_M->PWMC_SR & pwmp->chbit) {
- pwmp->reg->PWMC_CMR &= ~AT91C_PWMC_CPD;
- pwmp->reg->PWMC_CUPDR = width;
- } else {
- pwmp->reg->PWMC_CDTYR = width;
- PWMC_M->PWMC_ENA = pwmp->chbit;
- }
-
- /* Step 7 */
- PWMC_M->PWMC_ENA = pwmp->chbit;
-}
-
-/**
- * @brief Disables a PWM channel.
- * @pre The PWM unit must have been activated using @p pwmStart().
- * @post The channel is disabled and its output line returned to the
- * idle state.
- * @note Depending on the hardware implementation this function has
- * effect starting on the next cycle (recommended implementation)
- * or immediately (fallback implementation).
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
- *
- * @notapi
- */
-void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t UNUSED(channel)) {
- PWMC_M->PWMC_IDR = pwmp->chbit;
- PWMC_M->PWMC_DIS = pwmp->chbit;
-}
-
-#endif /* HAL_USE_PWM */
-
-/** @} */