Added PWM support to rp2040

This commit is contained in:
curuvar
2022-06-22 20:36:10 -04:00
committed by Alan Carvalho de Assis
parent 75facdee72
commit 412539e66c
5 changed files with 1032 additions and 0 deletions
+143
View File
@@ -0,0 +1,143 @@
/****************************************************************************
* arch/arm/src/rp2040/hardware/rp2040_pwm.h
*
* Generated from rp2040.svd originally provided by
* Raspberry Pi (Trading) Ltd.
*
* Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_PWM_H
#define __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_PWM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "hardware/rp2040_memorymap.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Register offsets *********************************************************/
#define RP2040_PWM_CSR_OFFSET(n) (0x000000 + (n) * 20) /* PWM control and status register */
#define RP2040_PWM_DIV_OFFSET(n) (0x000004 + (n) * 20) /* PWM clock divisor register */
#define RP2040_PWM_CTR_OFFSET(n) (0x000008 + (n) * 20) /* PWM counter register */
#define RP2040_PWM_CC_OFFSET(n) (0x00000C + (n) * 20) /* PWM compare register */
#define RP2040_PWM_TOP_OFFSET(n) (0x000010 + (n) * 20) /* PWM wrap value register */
#define RP2040_PWM_ENA_OFFSET 0x0000A0 /* PWM enable register */
#define RP2040_PWM_INTR_OFFSET 0x0000A4 /* PWM raw interrupt register */
#define RP2040_PWM_INTE_OFFSET 0x0000A8 /* PWM interrupt enable register */
#define RP2040_PWM_INTF_OFFSET 0x0000AC /* PWM interrupt force register */
#define RP2040_PWM_INTS_OFFSET 0x0000BO /* PWM interrupt status register */
/* Register definitions *****************************************************/
#define RP2040_PWM_CSR(n) (RP2040_PWM_BASE + RP2040_PWM_CSR_OFFSET(n))
#define RP2040_PWM_DIV(n) (RP2040_PWM_BASE + RP2040_PWM_DIV_OFFSET(n))
#define RP2040_PWM_CTR(n) (RP2040_PWM_BASE + RP2040_PWM_CTR_OFFSET(n))
#define RP2040_PWM_CC(n) (RP2040_PWM_BASE + RP2040_PWM_CC_OFFSET(n))
#define RP2040_PWM_TOP(n) (RP2040_PWM_BASE + RP2040_PWM_TOP_OFFSET(n))
#define RP2040_PWM_ENA (RP2040_PWM_BASE + RP2040_PWM_ENA_OFFSET)
#define RP2040_PWM_INTR (RP2040_PWM_BASE + RP2040_PWM_INTR_OFFSET)
#define RP2040_PWM_INTE (RP2040_PWM_BASE + RP2040_PWM_INTE_OFFSET)
#define RP2040_PWM_INTF (RP2040_PWM_BASE + RP2040_PWM_INTF_OFFSET)
#define RP2040_PWM_INTS (RP2040_PWM_BASE + RP2040_PWM_INTS_OFFSET)
/* Register bit definitions *************************************************/
#define RP2040_PWM_CSR_PH_ADV (1 << 7) /* advance phase of counter by one */
#define RP2040_PWM_CSR_PH_RET (1 << 5) /* retard phase of counter by one */
#define RP2040_PWM_CSR_DIVMODE_SHIFT (4) /* divisor mode */
#define RP2040_PWM_CSR_DIVMODE_MASK (0x03 << RP2040_PWM_CSR_DIVMODE_SHIFT)
#define RP2040_PWM_CSR_B_INV (1 << 3) /* invert output B */
#define RP2040_PWM_CSR_A_INV (1 << 2) /* invert output A */
#define RP2040_PWM_CSR_PH_CORRECT (1 << 1) /* enable phase correct modulation */
#define RP2040_PWM_CSR_EN (1 << 0) /* enable the PWM channel */
#define RP2040_PWN_CSR_DIVMODE_DIV 0x00
#define RP2040_PWN_CSR_DIVMODE_LEVEL 0x01
#define RP2040_PWN_CSR_DIVMODE_RISE 0x02
#define RP2040_PWN_CSR_DIVMODE_FALL 0x03
#define RP2040_PWM_DIV_INT_SHIFT (4) /* divisor integer part */
#define RP2040_PWM_DIV_INT_MASK (0xff << RP2040_PWM_DIV_INT_SHIFT)
#define RP2040_PWM_DIV_FRAC_SHIFT (0) /* divisor fraction part */
#define RP2040_PWM_DIV_FRAC_MASK (0x0f << RP2040_PWM_DIV_FRAC_SHIFT)
#define RP2040_PWM_CC_B_SHIFT (16) /* channel B compare register */
#define RP2040_PWM_CC_B_MASK (0xffff << RP2040_PWM_CC_B_SHIFT)
#define RP2040_PWM_CC_A_SHIFT (0) /* channel A compare register */
#define RP2040_PWM_CC_A_MASK (0xffff << RP2040_PWM_CC_A_SHIFT)
#define RP2040_PWM_TOP_SHIFT (0) /* channel A compare register */
#define RP2040_PWM_TOP_MASK (0xffff << RP2040_PWM_TOP_SHIFT)
/* Bit mask for ENA, INTR, INTE, INTF, and INTS registers */
#define RP2040_PWM_CH7 (1 << 7) /* PWM channel 7 */
#define RP2040_PWM_CH6 (1 << 6) /* PWM channel 6 */
#define RP2040_PWM_CH5 (1 << 5) /* PWM channel 5 */
#define RP2040_PWM_CH4 (1 << 4) /* PWM channel 4 */
#define RP2040_PWM_CH3 (1 << 3) /* PWM channel 3 */
#define RP2040_PWM_CH2 (1 << 2) /* PWM channel 2 */
#define RP2040_PWM_CH1 (1 << 1) /* PWM channel 1 */
#define RP2040_PWM_CH0 (1 << 0) /* PWM channel 0 */
/****************************************************************************
* The following IOCTL values set additional flags in the RP2040 PWM
* device.
****************************************************************************/
/****************************************************************************
* PWMIOC_RP2040_SETINVERTPULSE sets the pulse invert flag.
*
* The argument is an integer where:
* bit zero is set to invert channel A
* bit one is set to invert channel B
****************************************************************************/
#define PWMIOC_RP2040_SETINVERTPULSE _PWMIOC(0x80)
#define PWMIOC_RP2040_GETINVERTPULSE _PWMIOC(0x81)
/****************************************************************************
* PWMIOC_RP2040_SETPHASECORRECT sets phase correct flags.
*
* The argument is an integer which if non-zero sets the phase correct flag.
****************************************************************************/
#define PWMIOC_RP2040_SETPHASECORRECT _PWMIOC(0x82)
#define PWMIOC_RP2040_GETPHASECORRECT _PWMIOC(0x83)
#endif
File diff suppressed because it is too large Load Diff
+120
View File
@@ -0,0 +1,120 @@
/****************************************************************************
* arch/arm/src/rp2040/rp2040_pwm.h
*
* 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 __ARCH_ARM_SRC_RP2040_RP2040_PWM_H
#define __ARCH_ARM_SRC_RP2040_RP2040_PWM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "hardware/rp2040_pwm.h"
#include "nuttx/timers/pwm.h"
#ifndef __ASSEMBLY__
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/* This structure represents the state of one PWM timer */
struct rp2040_pwm_lowerhalf_s
{
const struct pwm_ops_s * ops; /* PWM operations */
uint32_t frequency; /* PWM current frequency */
uint32_t divisor; /* PWM current clock divisor */
uint32_t flags; /* PWM mode flags */
uint16_t top; /* PWM current top value */
#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2
uint16_t duty[2];
int8_t pin[2];
#else
uint16_t duty; /* Time duty value */
int8_t pin;
#endif
uint8_t num; /* Timer ID */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: rp2040_pwm_initialize
*
* Description:
* Initialize the selected PWM port. And return a unique instance of struct
* struct rp2040_pwm_lowerhalf_s. This function may be called to obtain
* multiple instances of the interface, each of which may be set up with a
* different frequency and address.
*
* Input Parameters:
* Port number (for hardware that has multiple PWM interfaces)
* GPIO pin number for pin A
* GPIO pin number for pin B (CONFIG_PWM_NCHANNELS == 2)
*
* Returned Value:
* Valid PWM device structure reference on success; a NULL on failure
*
****************************************************************************/
#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2
struct rp2040_pwm_lowerhalf_s *rp2040_pwm_initialize(int port,
int pin_a,
int pin_b,
uint32_t flags);
#else
struct rp2040_pwm_lowerhalf_s *rp2040_pwm_initialize(int port,
int pin,
uint32_t flags);
#endif
/****************************************************************************
* Name: rp2040_pwmdev_uninitialize
*
* Description:
* De-initialize the selected pwm port, and power down the device.
*
* Input Parameter:
* Device structure as returned by the rp2040_pwmdev_initialize()
*
* Returned Value:
* OK on success, ERROR when internal reference count mismatch or dev
* points to invalid hardware device.
*
****************************************************************************/
int rp2040_pwm_uninitialize(struct pwm_lowerhalf_s *dev);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_RP2040_RP2040_I2C_H */
@@ -0,0 +1,78 @@
/****************************************************************************
* boards/arm/rp2040/common/include/rp2040_pwmdev.h
*
* 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 __BOARDS_ARM_RP2040_RASPBERRYPI_PICO_INCLUDE_RP2040_PWMDEV_H
#define __BOARDS_ARM_RP2040_RASPBERRYPI_PICO_INCLUDE_RP2040_PWMDEV_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
/****************************************************************************
* Public Data
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: rp2040_pwmdev_initialize
*
* Description:
* Initialize pwm driver and register the /dev/pwm device.
*
****************************************************************************/
#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2
int rp2040_pwmdev_initialize(int slice,
int pin_a,
int pin_b,
uint32_t flags);
#else
int rp2040_pwmdev_initialize(int slice,
int pin,
uint32_t flags);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_RP2040_RASPBERRYPI_PICO_INCLUDE_RP2040_PWMDEV_H */
@@ -0,0 +1,95 @@
/****************************************************************************
* boards/arm/rp2040/common/src/rp2040_pwmdev.c
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <debug.h>
#include <errno.h>
#include "rp2040_pwm.h"
#ifdef CONFIG_RP2040_PWM
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_pwmdev_initialize
*
* Description:
* Initialize and register spi driver for the specified pwm port
*
****************************************************************************/
#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2
int rp2040_pwmdev_initialize(int slice,
int pin_a,
int pin_b,
uint32_t flags)
#else
int rp2040_pwmdev_initialize(int slice,
int pin,
uint32_t flags)
#endif
{
int ret;
struct rp2040_pwm_lowerhalf_s *pwm_lowerhalf;
pwminfo("Initializing /dev/pwm%d a %d b %d f 0x%08lX..\n",
slice,
pin_a,
pin_b,
flags);
/* Initialize spi device */
#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2
pwm_lowerhalf = rp2040_pwm_initialize(slice, pin_a, pin_b, flags);
#else
pwm_lowerhalf = rp2040_pwm_initialize(slice, pin, flags);
#endif
if (!pwm_lowerhalf)
{
pwmerr("ERROR: Failed to initialize pwm%d.\n", slice);
return -ENODEV;
}
char path[10] = "/dev/pwmN";
path[8] = '0' + slice; /* replace "N" with slice number. */
ret = pwm_register(path, (struct pwm_lowerhalf_s *) pwm_lowerhalf);
if (ret < 0)
{
pwmerr("ERROR: Failed to register pwm%d: %d\n", slice, ret);
return -ENODEV;
}
return OK;
}
#endif /* CONFIG_RP2040_PWM */