From 4758aa5bc468331e417ae338be381f811b3dcbae Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Thu, 11 Jan 2018 21:00:33 -0800 Subject: [PATCH 01/44] SAMD External Interrupt Controller (EIC) support --- arch/arm/include/samdl/samd21_irq.h | 4 +- arch/arm/src/samdl/Kconfig | 4 + arch/arm/src/samdl/Make.defs | 4 + arch/arm/src/samdl/chip/samd_eic.h | 191 +++++++++++++++++++++++++ arch/arm/src/samdl/sam_eic.c | 211 ++++++++++++++++++++++++++++ arch/arm/src/samdl/sam_eic.h | 109 ++++++++++++++ arch/arm/src/samdl/sam_port.c | 26 +++- 7 files changed, 545 insertions(+), 4 deletions(-) create mode 100644 arch/arm/src/samdl/chip/samd_eic.h create mode 100644 arch/arm/src/samdl/sam_eic.c create mode 100644 arch/arm/src/samdl/sam_eic.h diff --git a/arch/arm/include/samdl/samd21_irq.h b/arch/arm/include/samdl/samd21_irq.h index e0b26bf962a..8c44ed256d8 100644 --- a/arch/arm/include/samdl/samd21_irq.h +++ b/arch/arm/include/samdl/samd21_irq.h @@ -86,9 +86,9 @@ #define SAM_IRQ_NINTS (28) /* Total number of interrupts */ #define SAM_IRQ_NIRQS (SAM_IRQ_INTERRUPT+28) /* The number of real interrupts */ -/* GPIO interrupts. Up to 16 pins may be configured to support interrupts */ +/* EIC interrupts. Up to 16 pins may be configured to support interrupts */ -#ifdef CONFIG_SAMDL_GPIOIRQ +#ifdef CONFIG_SAMDL_EIC # define SAM_IRQ_EXTINT0 (SAM_IRQ_NIRQS+0) /* External interrupt 0 */ # define SAM_IRQ_EXTINT1 (SAM_IRQ_NIRQS+1) /* External interrupt 1 */ # define SAM_IRQ_EXTINT2 (SAM_IRQ_NIRQS+2) /* External interrupt 2 */ diff --git a/arch/arm/src/samdl/Kconfig b/arch/arm/src/samdl/Kconfig index ec8507a048b..9813e7192dc 100644 --- a/arch/arm/src/samdl/Kconfig +++ b/arch/arm/src/samdl/Kconfig @@ -572,6 +572,10 @@ config SAMDL_USB default n depends on SAMDL_HAVE_USB +config SAMDL_EIC + bool "External Interrupt Controller" + default n + config SAMDL_WDT bool "Watchdog Timer" default n diff --git a/arch/arm/src/samdl/Make.defs b/arch/arm/src/samdl/Make.defs index 71b156c6c77..1ce9c0e5b8e 100644 --- a/arch/arm/src/samdl/Make.defs +++ b/arch/arm/src/samdl/Make.defs @@ -102,3 +102,7 @@ endif ifeq ($(CONFIG_SAMDL_USB),y) CHIP_CSRCS += sam_usb.c endif + +ifeq ($(CONFIG_SAMDL_EIC),y) +CHIP_CSRCS += sam_eic.c +endif diff --git a/arch/arm/src/samdl/chip/samd_eic.h b/arch/arm/src/samdl/chip/samd_eic.h new file mode 100644 index 00000000000..9bbd0dc4feb --- /dev/null +++ b/arch/arm/src/samdl/chip/samd_eic.h @@ -0,0 +1,191 @@ +/******************************************************************************************** + * arch/arm/src/samdl/chip/samd_eic.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * Matt Thompson + * + * References: + * "Microchip SAMD21 datasheet" + * + * 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 NuttX 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 OWNER 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_SAMDL_CHIP_SAMD_EIC_H +#define __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_EIC_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_ARCH_FAMILY_SAMD21 + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ +/* EIC register offsets *********************************************************************/ + +#define SAM_EIC_CTRLA_OFFSET 0x0000 /* Control A register */ +#define SAM_EIC_STATUS_OFFSET 0x0001 /* Status register */ +#define SAM_EIC_NMICTRL_OFFSET 0x0002 /* Non-maskable interrupt control register */ +#define SAM_EIC_NMIFLAG_OFFSET 0x0003 /* Non-maskable interrupt flag register */ +#define SAM_EIC_EVCTRL_OFFSET 0x0004 /* Event control register */ +#define SAM_EIC_INTENCLR_OFFSET 0x0008 /* Interrupt enable clear register */ +#define SAM_EIC_INTENSET_OFFSET 0x000c /* Interrupt enable set register */ +#define SAM_EIC_INTFLAG_OFFSET 0x0010 /* Interrupt flag and status clear register */ +#define SAM_EIC_WAKEUP_OFFSET 0x0014 /* Wakeup register */ +#define SAM_EIC_CONFIG0_OFFSET 0x0018 /* Configuration 0 register */ +#define SAM_EIC_CONFIG1_OFFSET 0x001c /* Configuration 1 register */ +#define SAM_EIC_CONFIG2_OFFSET 0x0020 /* Configuration 2 register */ + +/* EIC register addresses *******************************************************************/ + +#define SAM_EIC_CTRLA (SAM_EIC_BASE+SAM_EIC_CTRLA_OFFSET) +#define SAM_EIC_STATUS (SAM_EIC_BASE+SAM_EIC_STATUS_OFFSET) +#define SAM_EIC_NMICTRL (SAM_EIC_BASE+SAM_EIC_NMICTRL_OFFSET) +#define SAM_EIC_NMIFLAG (SAM_EIC_BASE+SAM_EIC_NMIFLAG_OFFSET) +#define SAM_EIC_EVCTRL (SAM_EIC_BASE+SAM_EIC_EVCTRL_OFFSET) +#define SAM_EIC_INTENCLR (SAM_EIC_BASE+SAM_EIC_INTENCLR_OFFSET) +#define SAM_EIC_INTENSET (SAM_EIC_BASE+SAM_EIC_INTENSET_OFFSET) +#define SAM_EIC_INTFLAG (SAM_EIC_BASE+SAM_EIC_INTFLAG_OFFSET) +#define SAM_EIC_WAKEUP (SAM_EIC_BASE+SAM_EIC_WAKEUP_OFFSET) +#define SAM_EIC_CONFIG0 (SAM_EIC_BASE+SAM_EIC_CONFIG0_OFFSET) +#define SAM_EIC_CONFIG1 (SAM_EIC_BASE+SAM_EIC_CONFIG1_OFFSET) +#define SAM_EIC_CONFIG2 (SAM_EIC_BASE+SAM_EIC_CONFIG2_OFFSET) + +/* EIC register bit definitions *************************************************************/ + +/* Control A register */ + +#define EIC_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */ +#define EIC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */ + +/* Status register */ + +#define EIC_STATUS_SYNCBUSY (1 << 7) /* Bit 7: Syncronization busy */ + +/* Non-maskable interrupt control register */ + +#define EIC_NMICTRL_NMISENSE_SHIFT (0) /* Bits 0-2: Non-maskable interrupt sense */ +#define EIC_NMICTRL_NMISENSE_MASK (7 << EIC_NVMICTRL_NMISENSE_SHIFT) +# define EIC_NMICTRL_NMISENSE_NONE (0 << EIC_NVMICTRL_NMISENSE_SHIFT) /* No detection */ +# define EIC_NMICTRL_NMISENSE_RISE (1 << EIC_NVMICTRL_NMISENSE_SHIFT) /* Rising edge detection */ +# define EIC_NMICTRL_NMISENSE_FALL (2 << EIC_NVMICTRL_NMISENSE_SHIFT) /* Falling edge detection */ +# define EIC_NMICTRL_NMISENSE_BOTH (3 << EIC_NVMICTRL_NMISENSE_SHIFT) /* Both edge detection */ +# define EIC_NMICTRL_NMISENSE_HIGH (4 << EIC_NVMICTRL_NMISENSE_SHIFT) /* High level detection */ +# define EIC_NMICTRL_NMISENSE_LOW (5 << EIC_NVMICTRL_NMISENSE_SHIFT) /* Low level detection */ +#define EIC_NMICTRL_NMIFLTEN (1 << 3) /* Bit 3: Non-maskable interrupt filter enable */ + +/* Non-maskable interrupt flas status and clear register */ + +#define EIC_NMIFLAG_NMI (1 << 0) /* Non-maskable interrupt */ + +/* Event control, Interrupt enable clear, interrupt enable set register, interrupt flag + * status and clear, and external interrupt wakeup registers. + */ + +#define EIC_EXTINT_SHIFT (0) /* Bits 0-15: External interrupt n */ +#define EIC_EXTINT_MASK (0x3ffff << EIC_EXTINT_SHIFT) +//# define EIC_EXTINT(n) ((uint32_t)(n) << EIC_EXTINT_SHIFT) +# define EIC_EXTINT(n) (1 << (n)) +# define EIC_EXTINT_0 (1 << 0) /* Bit 0: External interrupt 0 */ +# define EIC_EXTINT_1 (1 << 1) /* Bit 1: External interrupt 1 */ +# define EIC_EXTINT_2 (1 << 2) /* Bit 2: External interrupt 2 */ +# define EIC_EXTINT_3 (1 << 3) /* Bit 3: External interrupt 3 */ +# define EIC_EXTINT_4 (1 << 4) /* Bit 4: External interrupt 4 */ +# define EIC_EXTINT_5 (1 << 5) /* Bit 5: External interrupt 5 */ +# define EIC_EXTINT_6 (1 << 6) /* Bit 6: External interrupt 6 */ +# define EIC_EXTINT_7 (1 << 7) /* Bit 7: External interrupt 7 */ +# define EIC_EXTINT_8 (1 << 8) /* Bit 8: External interrupt 8 */ +# define EIC_EXTINT_9 (1 << 9) /* Bit 9: External interrupt 9 */ +# define EIC_EXTINT_10 (1 << 10) /* Bit 10: External interrupt 10 */ +# define EIC_EXTINT_11 (1 << 11) /* Bit 11: External interrupt 11 */ +# define EIC_EXTINT_12 (1 << 12) /* Bit 12: External interrupt 12 */ +# define EIC_EXTINT_13 (1 << 13) /* Bit 13: External interrupt 13 */ +# define EIC_EXTINT_14 (1 << 14) /* Bit 14: External interrupt 14 */ +# define EIC_EXTINT_15 (1 << 15) /* Bit 15: External interrupt 15 */ +# define EIC_EXTINT_16 (1 << 16) /* Bit 16: External interrupt 16 */ +# define EIC_EXTINT_17 (1 << 17) /* Bit 17: External interrupt 17 */ + +#define EIC_EXTINT_ALL EIC_EXTINT_MASK + +/* Configuration 0 register */ + +#define EIC_CONFIG0_FILTEN(n) (0x8 << ((n) << 2)) /* Filter n enable, n=0-7 */ +#define EIC_CONFIG0_SENSE_SHIFT(n) ((n) << 2) /* Filter n input sense, n=0-7 */ +#define EIC_CONFIG0_SENSE_MASK(n) (7 << EIC_CONFIG0_SENSE_SHIFT(n)) +# define EIC_CONFIG0_SENSE_NONE(n) (0 << EIC_CONFIG0_SENSE_SHIFT(n)) /* No detection */ +# define EIC_CONFIG0_SENSE_RISE(n) (1 << EIC_CONFIG0_SENSE_SHIFT(n)) /* Rising edge detection */ +# define EIC_CONFIG0_SENSE_FALL(n) (2 << EIC_CONFIG0_SENSE_SHIFT(n)) /* Falling edge detection */ +# define EIC_CONFIG0_SENSE_BOTH(n) (3 << EIC_CONFIG0_SENSE_SHIFT(n)) /* Both edge detection */ +# define EIC_CONFIG0_SENSE_HIGH(n) (4 << EIC_CONFIG0_SENSE_SHIFT(n)) /* High level detection */ +# define EIC_CONFIG0_SENSE_LOW(n) (5 << EIC_CONFIG0_SENSE_SHIFT(n)) /* Low level detection */ + +/* Configuration 1 register */ + +#define EIC_CONFIG1_FILTEN(n) (0x8 << (((n) - 8) << 2)) /* Filter n enable, n=8-15 */ +#define EIC_CONFIG1_SENSE_SHIFT(n) (((n) - 8) << 2) /* Filter n input sense, n=8-17 */ +#define EIC_CONFIG1_SENSE_MASK(n) (7 << EIC_CONFIG1_SENSE_SHIFT(n)) +# define EIC_CONFIG1_SENSE_NONE(n) (0 << EIC_CONFIG1_SENSE_SHIFT(n)) /* No detection */ +# define EIC_CONFIG1_SENSE_RISE(n) (1 << EIC_CONFIG1_SENSE_SHIFT(n)) /* Rising edge detection */ +# define EIC_CONFIG1_SENSE_FALL(n) (2 << EIC_CONFIG1_SENSE_SHIFT(n)) /* Falling edge detection */ +# define EIC_CONFIG1_SENSE_BOTH(n) (3 << EIC_CONFIG1_SENSE_SHIFT(n)) /* Both edge detection */ +# define EIC_CONFIG1_SENSE_HIGH(n) (4 << EIC_CONFIG1_SENSE_SHIFT(n)) /* High level detection */ +# define EIC_CONFIG1_SENSE_LOW(n) (5 << EIC_CONFIG1_SENSE_SHIFT(n)) /* Low level detection */ + +/* Configuration 2 register */ + +#define EIC_CONFIG2_FILTEN(n) (0x8 << (((n) - 16) << 2)) /* Filter n enable, n=16-23 */ +#define EIC_CONFIG2_SENSE_SHIFT(n) (((n) - 16) << 2) /* Filter n input sense, n=16-23 */ +#define EIC_CONFIG2_SENSE_MASK(n) (7 << EIC_CONFIG2_SENSE_SHIFT(n)) +# define EIC_CONFIG2_SENSE_NONE(n) (0 << EIC_CONFIG2_SENSE_SHIFT(n)) /* No detection */ +# define EIC_CONFIG2_SENSE_RISE(n) (1 << EIC_CONFIG2_SENSE_SHIFT(n)) /* Rising edge detection */ +# define EIC_CONFIG2_SENSE_FALL(n) (2 << EIC_CONFIG2_SENSE_SHIFT(n)) /* Falling edge detection */ +# define EIC_CONFIG2_SENSE_BOTH(n) (3 << EIC_CONFIG2_SENSE_SHIFT(n)) /* Both edge detection */ +# define EIC_CONFIG2_SENSE_HIGH(n) (4 << EIC_CONFIG2_SENSE_SHIFT(n)) /* High level detection */ +# define EIC_CONFIG2_SENSE_LOW(n) (5 << EIC_CONFIG2_SENSE_SHIFT(n)) /* Low level detection */ + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* CONFIG_ARCH_FAMILY_SAMD21 */ +#endif /* __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_EIC_H */ diff --git a/arch/arm/src/samdl/sam_eic.c b/arch/arm/src/samdl/sam_eic.c new file mode 100644 index 00000000000..e6661548384 --- /dev/null +++ b/arch/arm/src/samdl/sam_eic.c @@ -0,0 +1,211 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_eic.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * References: + * 1. "Microchip SAM D21E / SAM D21G / SAM D21J Datasheet" + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "up_arch.h" + +#include "sam_config.h" + +#include "sam_pm.h" +#include "sam_gclk.h" +#include "sam_periphclks.h" +#include "sam_eic.h" +#include "sam_port.h" + +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int sam_eic_isr(int irq, FAR void *context, FAR void *arg) +{ + uint32_t intflag; + int bit; + + /* Get the pending interrupt flag register */ + + intflag = getreg32(SAM_EIC_INTFLAG); + + /* Dispatch the IRQ to the SAM_IRQ_EXTINTn handlers */ + + for(bit=0;bit> bit & 0x1) + { + irq_dispatch(SAM_IRQ_EXTINT0 + bit, context); + } + } + + /* Clear the pending interrupt flags */ + + putreg32(EIC_EXTINT_ALL, SAM_EIC_INTFLAG); + + return 0; +} + +static void sam_eic_syncwait(void) +{ + while ((getreg8(SAM_EIC_STATUS) & EIC_STATUS_SYNCBUSY) != 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void sam_eic_dumpregs(void) +{ + irqinfo("EIC:\n"); + irqinfo(" CTRLA: %02x\n", getreg8(SAM_EIC_CTRLA)); + irqinfo(" STATUS: %02x\n", getreg8(SAM_EIC_STATUS)); + irqinfo(" NMICTRL: %02x\n", getreg8(SAM_EIC_NMICTRL)); + irqinfo(" NMIFLAG: %02x\n", getreg8(SAM_EIC_NMIFLAG)); + irqinfo(" EVCTRL: %08x\n", getreg32(SAM_EIC_EVCTRL)); + irqinfo(" INTENCLR: %08x\n", getreg32(SAM_EIC_INTENCLR)); + irqinfo(" INTENSET: %08x\n", getreg32(SAM_EIC_INTENSET)); + irqinfo(" INTFLAG: %08x\n", getreg32(SAM_EIC_INTFLAG)); + irqinfo(" WAKEUP: %08x\n", getreg32(SAM_EIC_WAKEUP)); + irqinfo(" CONFIG0: %08x\n", getreg32(SAM_EIC_CONFIG0)); + irqinfo(" CONFIG1: %08x\n", getreg32(SAM_EIC_CONFIG1)); + irqinfo(" CONFIG2: %08x\n", getreg32(SAM_EIC_CONFIG2)); +} + +/**************************************************************************** + * Name: sam_eic_initialize + * + * Description: + * Configure the external interrupt controller. + * + ****************************************************************************/ + +int sam_eic_initialize(uint8_t gclkgen) +{ + uint16_t regval; + + sam_eic_enableperiph(); + + regval = GCLK_CLKCTRL_ID_EIC | GCLK_CLKCTRL_GEN(gclkgen) | GCLK_CLKCTRL_CLKEN; + putreg16(regval, SAM_GCLK_CLKCTRL); + + putreg8(EIC_CTRLA_ENABLE, SAM_EIC_CTRLA); + sam_eic_syncwait(); + + irq_attach(SAM_IRQ_EIC, sam_eic_isr, NULL); + + sam_eic_dumpregs(); + + up_enable_irq(SAM_IRQ_EIC); + + return OK; +} + +int sam_eic_irq_enable(int irq) +{ + uint32_t config; + int eirq = irq - SAM_IRQ_EXTINT0; + + config = getreg32(SAM_EIC_CONFIG0); + config |= EIC_CONFIG0_FILTEN(eirq) | EIC_CONFIG0_SENSE_FALL(eirq); + putreg32(config, SAM_EIC_CONFIG0); + + putreg32(EIC_EXTINT(eirq), SAM_EIC_INTENSET); + sam_eic_dumpregs(); + return OK; +} + +int sam_eic_config(uint8_t eirq, port_pinset_t pinset) +{ + uint32_t reg; + uint32_t val; + uint32_t config; + + /* Determine which of the CONFIG[0:2] registers to write to */ + + if(eirq < 8) + { + reg = SAM_EIC_CONFIG0; + + val = EIC_CONFIG0_SENSE_BOTH(eirq); + if(pinset & PORT_INT_RISING) + val = EIC_CONFIG0_SENSE_RISE(eirq); + if(pinset & PORT_INT_FALLING) + val = EIC_CONFIG0_SENSE_FALL(eirq); + val |= EIC_CONFIG0_FILTEN(eirq); + } + else if(eirq < 16) + { + reg = SAM_EIC_CONFIG1; + val = EIC_CONFIG1_FILTEN(eirq) | EIC_CONFIG1_SENSE_FALL(eirq); + } + else + { + reg = SAM_EIC_CONFIG2; + val = EIC_CONFIG2_FILTEN(eirq) | EIC_CONFIG2_SENSE_FALL(eirq); + } + + /* Write the new config to the CONFIGn register */ + + config = getreg32(reg); + config |= val; + putreg32(config, reg); + + /* Enable interrupt generation for this pin */ + + putreg32(EIC_EXTINT(eirq), SAM_EIC_INTENSET); + + sam_eic_dumpregs(); + + return OK; +} diff --git a/arch/arm/src/samdl/sam_eic.h b/arch/arm/src/samdl/sam_eic.h new file mode 100644 index 00000000000..b149d182ea2 --- /dev/null +++ b/arch/arm/src/samdl/sam_eic.h @@ -0,0 +1,109 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_eic.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * 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 NuttX 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 OWNER 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_SAMDL_SAM_EIC_H +#define __ARCH_ARM_SRC_SAMDL_SAM_EIC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_config.h" +#include "sam_port.h" + +#if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) +# include "chip/samd_eic.h" +#elif defined(CONFIG_ARCH_FAMILY_SAML21) +# include "chip/saml_eic.h" +#else +# error Unrecognized SAMD/L architecture +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_eic_configure + * + * Description: + * Configure the EIC + * + * Input Parameters: + * gclkgen - GCLK Generator + * + * Returned Value: + * None + * + ****************************************************************************/ + +int sam_eic_initialize(uint8_t gclkgen); +int sam_eic_config(uint8_t eirq, port_pinset_t pinset); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM_SRC_SAMDL_SAM_EIC_H */ diff --git a/arch/arm/src/samdl/sam_port.c b/arch/arm/src/samdl/sam_port.c index b757de5c581..534ecef49cd 100644 --- a/arch/arm/src/samdl/sam_port.c +++ b/arch/arm/src/samdl/sam_port.c @@ -57,6 +57,7 @@ #include "chip.h" #include "sam_port.h" +#include "sam_eic.h" /**************************************************************************** * Private Data @@ -189,7 +190,27 @@ static inline void sam_configinput(uintptr_t base, port_pinset_t pinset) static inline void sam_configinterrupt(uintptr_t base, port_pinset_t pinset) { -#warning Missing logic + uint32_t func; + uint32_t regval; + int pin; + + pin = (pinset & PORT_PIN_MASK) >> PORT_PIN_SHIFT; + + regval = (PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_PMUXEN | PORT_WRCONFIG_INEN); + regval |= PORT_WRCONFIG_PINMASK(pin); + + func = (pinset & PORT_FUNC_MASK) >> PORT_FUNC_SHIFT; + regval |= (func << PORT_WRCONFIG_PMUX_SHIFT); + + putreg32(regval, base + SAM_PORT_WRCONFIG_OFFSET); + + /* Configure the interrupt edge sensitivity in CONFIGn register of the EIC */ + + sam_eic_config(pin, pinset); + +#ifdef CONFIG_DEBUG_GPIO_INFO + sam_dumpport(pinset, "extint"); +#endif } /**************************************************************************** @@ -531,7 +552,8 @@ int sam_dumpport(uint32_t pinset, const char *msg) /* Get the base address associated with the PIO port */ - pin = sam_portpin(pinset); + //pin = sam_portpin(pinset); + pin = (pinset & PORT_PIN_MASK) >> PORT_PIN_SHIFT; port = (pinset & PORT_MASK) >> PORT_SHIFT; base = SAM_PORTN_BASE(port); From 7ded6d5fd7b53f67e9f7f20e660194976f988775 Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Thu, 11 Jan 2018 21:12:40 -0800 Subject: [PATCH 02/44] removed comment --- arch/arm/src/samdl/sam_port.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/src/samdl/sam_port.c b/arch/arm/src/samdl/sam_port.c index 534ecef49cd..19be6f030fd 100644 --- a/arch/arm/src/samdl/sam_port.c +++ b/arch/arm/src/samdl/sam_port.c @@ -552,7 +552,6 @@ int sam_dumpport(uint32_t pinset, const char *msg) /* Get the base address associated with the PIO port */ - //pin = sam_portpin(pinset); pin = (pinset & PORT_PIN_MASK) >> PORT_PIN_SHIFT; port = (pinset & PORT_MASK) >> PORT_SHIFT; base = SAM_PORTN_BASE(port); From d7cc0c73685eaad76086b77f551087c27952c952 Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Wed, 17 Jan 2018 17:23:05 -0800 Subject: [PATCH 03/44] SAMDL: SPI must be disabled before changing the mode bits in CTRLA register --- arch/arm/src/samdl/sam_spi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/samdl/sam_spi.c b/arch/arm/src/samdl/sam_spi.c index 0596d9e84c3..dbecb7e09bb 100644 --- a/arch/arm/src/samdl/sam_spi.c +++ b/arch/arm/src/samdl/sam_spi.c @@ -944,7 +944,12 @@ static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) { /* Yes... Set the mode appropriately */ + /* First we need to disable SPI while we change the mode */ + regval = spi_getreg32(priv, SAM_SPI_CTRLA_OFFSET); + spi_putreg32(priv, regval & ~SPI_CTRLA_ENABLE, SAM_SPI_CTRLA_OFFSET); + spi_wait_synchronization(priv); + regval &= ~(SPI_CTRLA_CPOL | SPI_CTRLA_CPHA); switch (mode) @@ -969,7 +974,7 @@ static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) return; } - spi_putreg32(priv, regval, SAM_SPI_CTRLA_OFFSET); + spi_putreg32(priv, regval | SPI_CTRLA_ENABLE, SAM_SPI_CTRLA_OFFSET); /* Save the mode so that subsequent re-configurations will be faster */ From c70df0960d1f275a0186279ca6cd033471a4e76b Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Thu, 18 Jan 2018 12:30:43 +0900 Subject: [PATCH 04/44] arch/arm/src/lc823450: Assign I2S IRQ handling to CPU0 Previous commit assumed that the caller is running on CPU0. However, the caller sometimes runs at CPU1. This patch will assign the caller to CPU0 explicitly. Signed-off-by: Masayuki Ishikawa --- arch/arm/src/lc823450/lc823450_i2s.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm/src/lc823450/lc823450_i2s.c b/arch/arm/src/lc823450/lc823450_i2s.c index 3eced5cb4f2..fb9efa28df1 100644 --- a/arch/arm/src/lc823450/lc823450_i2s.c +++ b/arch/arm/src/lc823450/lc823450_i2s.c @@ -51,6 +51,10 @@ #include #include +#ifdef CONFIG_SMP +# include +#endif + #include "up_arch.h" #include "lc823450_dma.h" #include "lc823450_i2s.h" @@ -460,8 +464,32 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void) nxsem_init(&_sem_txdma, 0, 0); nxsem_init(&_sem_buf_under, 0, 0); +#ifdef CONFIG_SMP + cpu_set_t cpuset0; + cpu_set_t cpuset1; + + CPU_ZERO(&cpuset1); + CPU_SET(0, &cpuset1); + + /* Backup the current affinity */ + + sched_getaffinity(getpid(), sizeof(cpuset0), &cpuset0); + + /* Set the new affinity which assigns to CPU0 */ + + sched_setaffinity(getpid(), sizeof(cpuset1), &cpuset1); + nxsig_usleep(10 * 1000); +#endif + irq_attach(LC823450_IRQ_AUDIOBUF0, _i2s_isr, NULL); +#ifdef CONFIG_SMP + /* Restore the original affinity */ + + sched_setaffinity(getpid(), sizeof(cpuset0), &cpuset0); + nxsig_usleep(10 * 1000); +#endif + /* Enable IRQ for Audio Buffer */ up_enable_irq(LC823450_IRQ_AUDIOBUF0); From c93bbdcbc853bc4fff0738d9b92f4435459a2d63 Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Thu, 18 Jan 2018 12:48:07 +0900 Subject: [PATCH 05/44] arch/arm/src/lc823450: Change irqwarn() to ASSERT() in up_ack_irq() Signed-off-by: Masayuki Ishikawa --- arch/arm/src/lc823450/lc823450_irq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/lc823450/lc823450_irq.c b/arch/arm/src/lc823450/lc823450_irq.c index 9339f7cd632..bd159ef545e 100644 --- a/arch/arm/src/lc823450/lc823450_irq.c +++ b/arch/arm/src/lc823450/lc823450_irq.c @@ -711,7 +711,9 @@ void up_ack_irq(int irq) #ifdef CONFIG_SMP if (irq > LC823450_IRQ_LPDSP0 && 1 == up_cpu_index()) { - irqwarn("*** warning irq(%d) handled on CPU1."); + /* IRQ should be handled on CPU0 */ + + ASSERT(false); } #endif From c48a6a78fb34a858e08423b047ddfce15673dd88 Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Thu, 18 Jan 2018 12:49:46 +0900 Subject: [PATCH 06/44] configs/lc823450-xgevk: Update README.txt and defconfigs Update comments on SMP in README.txt Enable SYSTEM_TIME64 in defconfigs. Enable INSTRUMENTATION in rndis configuration. Signed-off-by: Masayuki Ishikawa --- configs/lc823450-xgevk/README.txt | 30 +++++++++++++++++++++----- configs/lc823450-xgevk/audio/defconfig | 1 + configs/lc823450-xgevk/nsh/defconfig | 1 + configs/lc823450-xgevk/rndis/defconfig | 4 ++++ configs/lc823450-xgevk/usb/defconfig | 1 + 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/configs/lc823450-xgevk/README.txt b/configs/lc823450-xgevk/README.txt index 63db6a0a308..a152c893e1f 100644 --- a/configs/lc823450-xgevk/README.txt +++ b/configs/lc823450-xgevk/README.txt @@ -45,13 +45,33 @@ to set MSP (main stack pointer) as follows. SMP related Status ^^^^^^^^^^^^^^^^^^ -Currently all applications except for ostest work in SMP mode but might stop -due to deadlocks or ASSERT(). - CPU activities are shown at D9 (CPU0) and D10 (CPU1) respectively. -1. "nsh> smp" works but the result will be corrupted. -2. "nsh> ostest" works but might cause a deadlock or assertion. +Currently all applications except for ostest work in SMP mode but might stop +due to deadlocks or ASSERT(). For a workaround, please try + +$ cd apps; git diff +diff --git a/examples/ostest/waitpid.c b/examples/ostest/waitpid.c +index 687f50ca..8418eff8 100644 +--- a/examples/ostest/waitpid.c ++++ b/examples/ostest/waitpid.c +@@ -54,7 +54,7 @@ + ****************************************************************************/ + + #define RETURN_STATUS 14 +-#define NCHILDREN 3 ++#define NCHILDREN 2 + #define PRIORITY 100 + + /**************************************************************************** + +If other deadlocks or ASSERT() still happen, please try the following. + +$ cd nuttx; git revert e238c8b0904988b966c3b33e7df2ba3faba52e2b + +This will revert the changes for clock_systimer() for 64bit so that it can +use spinlock to protect the internal data. We think that there still exist +race conditions somewhere in SMP logic but the revert might relax the conditions. Other Status ^^^^^^^^^^^^ diff --git a/configs/lc823450-xgevk/audio/defconfig b/configs/lc823450-xgevk/audio/defconfig index ae8ef0ad376..e06f30abc50 100644 --- a/configs/lc823450-xgevk/audio/defconfig +++ b/configs/lc823450-xgevk/audio/defconfig @@ -127,6 +127,7 @@ CONFIG_START_MONTH=10 CONFIG_START_YEAR=2013 CONFIG_SYSTEM_I2CTOOL=y CONFIG_SYSTEM_NXPLAYER=y +CONFIG_SYSTEM_TIME64=y CONFIG_SYSTEM_USBMSC_CMD_STACKSIZE=2048 CONFIG_SYSTEM_USBMSC_DEVPATH1="/dev/mtdblock0p10" CONFIG_SYSTEM_USBMSC_DEVPATH2="/dev/mtdblock1" diff --git a/configs/lc823450-xgevk/nsh/defconfig b/configs/lc823450-xgevk/nsh/defconfig index 74040a67398..91b32fbe49b 100644 --- a/configs/lc823450-xgevk/nsh/defconfig +++ b/configs/lc823450-xgevk/nsh/defconfig @@ -124,6 +124,7 @@ CONFIG_START_DAY=3 CONFIG_START_MONTH=10 CONFIG_START_YEAR=2013 CONFIG_SYSTEM_I2CTOOL=y +CONFIG_SYSTEM_TIME64=y CONFIG_TASK_NAME_SIZE=24 CONFIG_UART0_RXBUFSIZE=512 CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/configs/lc823450-xgevk/rndis/defconfig b/configs/lc823450-xgevk/rndis/defconfig index c07e826ca66..32a899edd9d 100644 --- a/configs/lc823450-xgevk/rndis/defconfig +++ b/configs/lc823450-xgevk/rndis/defconfig @@ -150,6 +150,9 @@ CONFIG_SCHED_HAVE_PARENT=y CONFIG_SCHED_HPWORKPERIOD=50000 CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_INSTRUMENTATION_BUFFER=y +CONFIG_SCHED_INSTRUMENTATION_PREEMPTION=y +CONFIG_SCHED_INSTRUMENTATION=y CONFIG_SCHED_LPWORK=y CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_ONEXIT=y @@ -169,6 +172,7 @@ CONFIG_START_YEAR=2013 CONFIG_SYSTEM_I2CTOOL=y CONFIG_SYSTEM_NXPLAYER=y CONFIG_SYSTEM_PING=y +CONFIG_SYSTEM_TIME64=y CONFIG_TASK_NAME_SIZE=24 CONFIG_TELNET_CHARACTER_MODE=y CONFIG_UART0_RXBUFSIZE=512 diff --git a/configs/lc823450-xgevk/usb/defconfig b/configs/lc823450-xgevk/usb/defconfig index 4b680dbd510..3ca1889d1bf 100644 --- a/configs/lc823450-xgevk/usb/defconfig +++ b/configs/lc823450-xgevk/usb/defconfig @@ -126,6 +126,7 @@ CONFIG_START_DAY=3 CONFIG_START_MONTH=10 CONFIG_START_YEAR=2013 CONFIG_SYSTEM_I2CTOOL=y +CONFIG_SYSTEM_TIME64=y CONFIG_SYSTEM_USBMSC_CMD_STACKSIZE=2048 CONFIG_SYSTEM_USBMSC_DEVPATH1="/dev/mtdblock0p10" CONFIG_SYSTEM_USBMSC_DEVPATH2="/dev/mtdblock1" From 9776a32e264021d15c5563cb402e309a3a007ef1 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 18 Jan 2018 06:57:13 -0600 Subject: [PATCH 07/44] configst/stm3240g-eval: Remove only bogus logic to start the NX server. That was there only to support the knxwm configuration and was implemented priorit to boardctl(BOARCIOC_NX_START). --- configs/lpcxpresso-lpc54628/README.txt | 1 - configs/stm3240g-eval/src/stm32_boot.c | 111 +--------------------- configs/stm3240g-eval/src/stm32_bringup.c | 22 ++--- configs/stm32f429i-disco/src/stm32_boot.c | 37 -------- 4 files changed, 10 insertions(+), 161 deletions(-) diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt index 2cb8625a859..e7b195ef41f 100644 --- a/configs/lpcxpresso-lpc54628/README.txt +++ b/configs/lpcxpresso-lpc54628/README.txt @@ -475,4 +475,3 @@ Configurations $ cd ~//nuttx $ make - diff --git a/configs/stm3240g-eval/src/stm32_boot.c b/configs/stm3240g-eval/src/stm32_boot.c index 2309fc50bba..2861a30b1d3 100644 --- a/configs/stm3240g-eval/src/stm32_boot.c +++ b/configs/stm3240g-eval/src/stm32_boot.c @@ -45,108 +45,10 @@ #include "stm3240g-eval.h" -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ -/* Configuration ********************************************************************/ -/* Should we initialize the NX server using nx_start? This is done for NxWidgets - * (CONFIG_NXWIDGETS=y) and if the NxWidget::CNxServer class expects the RTOS do the - * the NX initialization (CONFIG_NXWIDGET_SERVERINIT=n). This combination of - * settings is normally only used in the kernel build mode* (CONFIG_BUILD_PROTECTED) - * when NxWidgets is unable to initialize NX from user-space. - */ - -#undef HAVE_NXSTART - -#if defined(CONFIG_NXWIDGETS) && !defined(CONFIG_NXWIDGET_SERVERINIT) -# define HAVE_NXSTART -# include -#endif - -/* Should we initialize the touchscreen for the NxWM (CONFIG_NXWM=y)? This - * is done if we have a touchscreen (CONFIG_INPUT_STMPE811=y) and NxWM uses the - * touchscreen (CONFIG_NXWM_TOUCHSCREEN=y). - */ - -#undef HAVE_TCINIT - -#if defined(CONFIG_NXWM_TOUCHSCREEN) -# if !defined(CONFIG_NXWM_TOUCHSCREEN_DEVNO) -# error CONFIG_NXWM_TOUCHSCREEN_DEVNO is not defined -# elif defined(CONFIG_INPUT_STMPE811) -# define HAVE_TCINIT 1 -# include -# else -# error CONFIG_INPUT_STMPE811=y is needed -# endif -#endif - -/* Check if we will need to support the initialization kernel thread */ - -#undef HAVE_INITTHREAD - -#ifdef CONFIG_BOARD_INITIALIZE -# if defined(CONFIG_NSH_LIBRARY) && !defined(CONFIG_LIB_BOARDCTL) -# define HAVE_INITTHREAD 1 -# elif defined(HAVE_NXSTART) -# define HAVE_INITTHREAD 1 -# elif defined(HAVE_TCINIT) -# define HAVE_INITTHREAD 1 -# endif -#endif - -#ifdef HAVE_INITTHREAD -# include -# include -# include -# ifndef CONFIG_STM3240G_BOARDINIT_PRIO -# define CONFIG_STM3240G_BOARDINIT_PRIO 196 -# endif -# ifndef CONFIG_STM3240G_BOARDINIT_STACK -# define CONFIG_STM3240G_BOARDINIT_STACK 2048 -# endif -#endif - /************************************************************************************ * Private Functions ************************************************************************************/ -/************************************************************************************ - * Name: board_initthread - * - * Description: - * Board initialization kernel thread. This thread exists to support - * initialization when CONFIG_BOARD_INITIALIZE is defined. It is started by - * board_initialize() which runs on the IDLE thread. - * - * This function thread exists because some initialization steps may require - * waiting for events. Such waiting is not possible on the IDLE thread. - * - * Input Parameters: - * Standard task start-up parameters (none of which are used) - * - * Returned Value: - * Always returns EXIT_SUCCESS. - * - ************************************************************************************/ - -#ifdef HAVE_INITTHREAD -static int board_initthread(int argc, char *argv[]) -{ - int ret; - - /* Perform the board initialization on an initialization thread */ - - ret = stm32_bringup(); - if (ret < 0) - { - gerr("ERROR: stm32_bringup failed: %d\n", ret); - } - - return EXIT_SUCCESS; -} -#endif - /************************************************************************************ * Public Functions ************************************************************************************/ @@ -184,7 +86,7 @@ void stm32_boardinitialize(void) /* Initialize USB if the 1) OTG FS controller is in the configuration and 2) * disabled, and 3) the weak function stm32_usbinitialize() has been brought * the weak function stm32_usbinitialize() has been brought into the build. - * Presumeably either CONFIG_USBDEV or CONFIG_USBHOST is also selected. + * Presumably either CONFIG_USBDEV or CONFIG_USBHOST is also selected. */ if (stm32_usbinitialize) @@ -216,22 +118,11 @@ void stm32_boardinitialize(void) #ifdef CONFIG_BOARD_INITIALIZE void board_initialize(void) { -#ifdef HAVE_INITTHREAD - pid_t server; - - /* Start the board initialization kernel thread */ - - server = kthread_create("Board Init", CONFIG_STM3240G_BOARDINIT_PRIO, - CONFIG_STM3240G_BOARDINIT_STACK, board_initthread, - NULL); - ASSERT(server > 0); -#else /* Perform the board initialization on the start-up thread. Some * initializations may fail in this case due to the limited capability of * the start-up thread. */ (void)stm32_bringup(); -#endif } #endif diff --git a/configs/stm3240g-eval/src/stm32_bringup.c b/configs/stm3240g-eval/src/stm32_bringup.c index 61d3f4a69c9..7f78ccb8f30 100644 --- a/configs/stm3240g-eval/src/stm32_bringup.c +++ b/configs/stm3240g-eval/src/stm32_bringup.c @@ -71,6 +71,10 @@ # include #endif +#ifdef CONFIG_INPUT_STMPE811 +# include +#endif + #include "stm32.h" #include "stm32_i2c.h" #include "stm3240g-eval.h" @@ -354,20 +358,12 @@ int stm32_bringup(void) } #endif -#ifdef HAVE_NXSTART - /* Initialize the NX server */ +#ifdef CONFIG_INPUT_STMPE811 + /* Initialize the touchscreen. + * WARNING: stm32_tsc_setup() cannot be called from the IDLE thread. + */ - ret = nx_start(); - if (ret < 0) - { - syslog(LOG_ERR, "ERROR: nx_start failed: %d\n", ret); - } -#endif - -#ifdef HAVE_TCINIT - /* Initialize the touchscreen */ - - ret = stm32_tsc_setup(CONFIG_NXWM_TOUCHSCREEN_DEVNO); + ret = stm32_tsc_setup(0); if (ret < 0) { syslog(LOG_ERR, "ERROR: stm32_tsc_setup failed: %d\n", ret); diff --git a/configs/stm32f429i-disco/src/stm32_boot.c b/configs/stm32f429i-disco/src/stm32_boot.c index 9dda08d1de8..d76f3122fac 100644 --- a/configs/stm32f429i-disco/src/stm32_boot.c +++ b/configs/stm32f429i-disco/src/stm32_boot.c @@ -48,43 +48,6 @@ #include "stm32f429i-disco.h" #include "stm32_ccm.h" -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -/* Configuration ********************************************************************/ -/* Should we initialize the NX server using nx_start? This is done for NxWidgets - * (CONFIG_NXWIDGETS=y) and if the NxWidget::CNxServer class expects the RTOS do the - * the NX initialization (CONFIG_NXWIDGET_SERVERINIT=n). This combination of - * settings is normally only used in the kernel build mode* (CONFIG_BUILD_PROTECTED) - * when NxWidgets is unable to initialize NX from user-space. - */ - -#undef HAVE_NXSTART - -#if defined(CONFIG_NXWIDGETS) && !defined(CONFIG_NXWIDGET_SERVERINIT) -# define HAVE_NXSTART -# include -#endif - -/* Should we initialize the touchscreen for the NxWM (CONFIG_NXWM=y)? This - * is done if we have a touchscreen (CONFIG_INPUT_STMPE811=y) and NxWM uses the - * touchscreen (CONFIG_NXWM_TOUCHSCREEN=y). - */ - -#undef HAVE_TCINIT - -#if defined(CONFIG_NXWM_TOUCHSCREEN) -# if !defined(CONFIG_NXWM_TOUCHSCREEN_DEVNO) -# error CONFIG_NXWM_TOUCHSCREEN_DEVNO is not defined -# elif defined(CONFIG_INPUT_STMPE811) -# define HAVE_TCINIT -# include -# else -# error CONFIG_INPUT_STMPE811=y is needed -# endif -#endif - /************************************************************************************ * Public Functions ************************************************************************************/ From a65ebeeb2c98fd1e829bead8bc9a1a98a98d3cce Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 18 Jan 2018 09:59:31 -0600 Subject: [PATCH 08/44] drivers/input/ft5x06.c: Remove cool logic to disable polling when there there is no client waiting for read data. That was a great idea to save CPU cycles when there is nothing reading from the touchscrren but, unfortunately, does not work with readers that open the driver in non-blocking mode. So I think we just have to eat the CPUs even when there is nothing waiting for touchscreen input. --- drivers/input/ft5x06.c | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/drivers/input/ft5x06.c b/drivers/input/ft5x06.c index 25bd5f15514..de23742fba8 100644 --- a/drivers/input/ft5x06.c +++ b/drivers/input/ft5x06.c @@ -364,15 +364,9 @@ static void ft5x06_data_worker(FAR void *arg) } #ifdef CONFIG_FT5X06_POLLMODE - /* Exit, re-starting the poll (unless there is no longer any task waiting - * for touch data). - */ + /* Exit, re-starting the poll. */ - if (priv->nwaiters > 0) - { - (void)wd_start(priv->polltimer, priv->delay, ft5x06_poll_timeout, 1, - priv); - } + (void)wd_start(priv->polltimer, priv->delay, ft5x06_poll_timeout, 1, priv); #else /* Exit, re-enabling FT5x06 interrupts */ @@ -398,14 +392,11 @@ static void ft5x06_poll_timeout(int argc, wdparm_t arg1, ...) * required to protected the work queue. */ - if (priv->nwaiters > 0) + DEBUGASSERT(priv->work.worker == NULL); + ret = work_queue(HPWORK, &priv->work, ft5x06_data_worker, priv, 0); + if (ret != 0) { - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, ft5x06_data_worker, priv, 0); - if (ret != 0) - { - ierr("ERROR: Failed to queue work: %d\n", ret); - } + ierr("ERROR: Failed to queue work: %d\n", ret); } } #endif @@ -682,25 +673,6 @@ static ssize_t ft5x06_waitsample(FAR struct ft5x06_dev_s *priv, priv->nwaiters++; -#ifdef CONFIG_FT5X06_POLLMODE - /* The poll timer is stopped when there are no waiters. So we may - * need to restart with at the maximum rate. - */ - - if (priv->nwaiters == 1) - { - priv->delay = POLL_MINDELAY; - - ret = wd_start(priv->polltimer, priv->delay, ft5x06_poll_timeout, - 1, priv); - if (ret < 0) - { - ierr("ERROR: nxsem_wait failed: %d\n", ret); - goto errout; - } - } -#endif - /* Wait for a change in the FT5x06 state */ ret = nxsem_wait(&priv->waitsem); From af2ac8063f5e18a1f1b4c258807f2f9bc1fbb3d5 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 18 Jan 2018 10:00:27 -0600 Subject: [PATCH 09/44] configs/lpcxpresso-lpc54628/lvgl: Add LittlevGL graphics demo configuration. --- configs/lpcxpresso-lpc54628/README.txt | 21 +++++++ configs/lpcxpresso-lpc54628/lvgl/defconfig | 71 ++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 configs/lpcxpresso-lpc54628/lvgl/defconfig diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt index e7b195ef41f..ff1597cc4a8 100644 --- a/configs/lpcxpresso-lpc54628/README.txt +++ b/configs/lpcxpresso-lpc54628/README.txt @@ -229,6 +229,27 @@ Configurations interrupts are not supported on P4. So polled mode only for this puppy. + lvgl + ---- + This is a demonstration of the LittlevGL graphics library running on + the NuttX frame buffer driver (as in the fb configuration). You can + find LittlevGL here: + + https://littlevgl.com/ + https://github.com/littlevgl + + This configuration uses the LittlevGL demonstration at apps/examples/lvgldemo. + + NOTES: + + 1. The LittlevGL demonstration is quit large, due mostly to some large + graphic images. So memory is tight in the LPC54628's 512Kb FLASH. In + fact, if you disable optimization, the demo will not fit into FLASH + memory (at least not with debug output also enabled). + + A longer term solution might load the large images into the abundant + SDRAM at runtime instead of linking it statically in FLASH. + netnsh: ------ This is a special version of the NuttShell (nsh) configuration that is diff --git a/configs/lpcxpresso-lpc54628/lvgl/defconfig b/configs/lpcxpresso-lpc54628/lvgl/defconfig new file mode 100644 index 00000000000..69faf20696f --- /dev/null +++ b/configs/lpcxpresso-lpc54628/lvgl/defconfig @@ -0,0 +1,71 @@ +# CONFIG_ARCH_FPU is not set +# CONFIG_LV_FONT_ANTIALIAS is not set +CONFIG_ARCH_BOARD_LPCXPRESSO_LPC54628=y +CONFIG_ARCH_BOARD="lpcxpresso-lpc54628" +CONFIG_ARCH_CHIP_LPC54628=y +CONFIG_ARCH_CHIP_LPC54XX=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_STDARG_H=y +CONFIG_ARCH="arm" +CONFIG_BOARD_LOOPSPERMSEC=21082 +CONFIG_BUILTIN=y +CONFIG_DRIVERS_VIDEO=y +CONFIG_EXAMPLES_LVGLDEMO=y +CONFIG_FS_PROCFS=y +CONFIG_FT5X06_POLLMODE=y +CONFIG_FT5X06_SINGLEPOINT=y +CONFIG_FT5X06_SWAPXY=y +CONFIG_GRAPHICS_LVGL=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_HOST_WINDOWS=y +CONFIG_INPUT_FT5X06=y +CONFIG_INPUT=y +CONFIG_INTELHEX_BINARY=y +CONFIG_LIB_BOARDCTL=y +CONFIG_LPC54_EMC_DYNAMIC_CS0_OFFSET=0x00080000 +CONFIG_LPC54_EMC_DYNAMIC_CS0_SIZE=0x00f80000 +CONFIG_LPC54_EMC_DYNAMIC_CS0=y +CONFIG_LPC54_EMC=y +CONFIG_LPC54_GPIOIRQ=y +CONFIG_LPC54_I2C2_MASTER=y +CONFIG_LPC54_LCD_BGR=y +CONFIG_LPC54_LCD_BPP16_565=y +CONFIG_LPC54_LCD_HBACKPORCH=43 +CONFIG_LPC54_LCD_HFRONTPORCH=8 +CONFIG_LPC54_LCD_VBACKPORCH=12 +CONFIG_LPC54_LCD_VFRONTPORCH=4 +CONFIG_LPC54_LCD_VPULSE=10 +CONFIG_LPC54_LCD_VRAMBASE=0xa0000000 +CONFIG_LPC54_LCD=y +CONFIG_LPC54_USART0=y +CONFIG_LV_HOR_RES=480 +CONFIG_LV_VER_RES=272 +CONFIG_MAX_TASKS=16 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_MM_REGIONS=2 +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PREALLOC_WDOGS=4 +CONFIG_RAM_SIZE=163840 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_TASK_NAME_SIZE=32 +CONFIG_USART0_SERIAL_CONSOLE=y +CONFIG_USE_LV_FONT_DEJAVU_40_CYRILLIC=y +CONFIG_USE_LV_FONT_DEJAVU_40_LATIN_EXT_A=y +CONFIG_USE_LV_FONT_DEJAVU_40_LATIN_EXT_B=y +CONFIG_USE_LV_FONT_DEJAVU_40_SUP=y +CONFIG_USE_LV_FONT_SYMBOL_40_BASIC=y +CONFIG_USE_LV_FONT_SYMBOL_40_FEEDBACK=y +CONFIG_USE_LV_FONT_SYMBOL_40_FILE=y +CONFIG_USER_ENTRYPOINT="lvgldemo_main" +CONFIG_VIDEO_FB=y +CONFIG_WDOG_INTRESERVE=0 From 5350d7efa20915217c4789a6b19efc903ea8fc17 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 18 Jan 2018 11:14:54 -0600 Subject: [PATCH 10/44] configs/lpcxpresso-lpc54628: Update README --- configs/lpcxpresso-lpc54628/README.txt | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt index ff1597cc4a8..c9b3cbb5248 100644 --- a/configs/lpcxpresso-lpc54628/README.txt +++ b/configs/lpcxpresso-lpc54628/README.txt @@ -95,10 +95,12 @@ STATUS more testing is certainly needed. 2018-01-14: The basic SPI driver is code complete but still untested. It is "basic" in the sense that it supports only polled mode (no DMA). + 2018-01-18: Added the lvgl configuration. See notes under "Configuration + Sub-directories" for additional status. - There is still no support for the Accelerometer, SPIFI, or USB. There are - complete but not-yet-functional SD card and SPI drivers. There are no - on-board devices to support SPI testing. + There is still no support for the Accelerometer, SPIFI, or USB. There is + a complete but not-yet-functional SD card driver and and tested SPI + driver. There are no on-board devices to support SPI testing. Configurations ============== @@ -156,7 +158,7 @@ Configurations System Type -> Toolchain: CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIW=y : GNU ARM EABI toolchain - Configuration sub-directories + Configuration Sub-directories ----------------------------- fb: @@ -250,6 +252,18 @@ Configurations A longer term solution might load the large images into the abundant SDRAM at runtime instead of linking it statically in FLASH. + STATUS: + + 2018-01-18: The demo is basically function but has some issues: + + a) The font is too big on the "Write" screen. They don't fit in on + the keyboard. + b) The "List" display is filled with a big box that says "Click a + button to copy its text to Text area." There are no buttons and + nothing to click on (maybe they are behind the big box?). This + may also be a font size issue. + c) The "Chart" display looks okay. + netnsh: ------ This is a special version of the NuttShell (nsh) configuration that is From 75b1844b7bbf9784112b3cc7c2a30d894a7bd44c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 18 Jan 2018 12:51:07 -0600 Subject: [PATCH 11/44] include/termios.h: Update comments; fix long lines. --- include/termios.h | 70 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/include/termios.h b/include/termios.h index 8427cbf5991..10e88d7e000 100644 --- a/include/termios.h +++ b/include/termios.h @@ -58,7 +58,8 @@ #define INLCR (1 << 5) /* Bit 5: Map NL to CR on input */ #define INPCK (1 << 6) /* Bit 6: Enable input parity check */ #define ISTRIP (1 << 7) /* Bit 7: Strip character */ -#define IUCLC (1 << 8) /* Bit 8: Map upper-case to lower-case on input (LEGACY) */ +#define IUCLC (1 << 8) /* Bit 8: Map upper-case to lower-case on input + * (LEGACY) */ #define IXANY (1 << 9) /* Bit 9: Enable any character to restart output */ #define IXOFF (1 << 10) /* Bit 10: Enable start/stop input control */ #define IXON (1 << 11) /* Bit 11: Enable start/stop output control */ @@ -67,7 +68,8 @@ /* Terminal output modes (c_oflag in the termios structure) */ #define OPOST (1 << 0) /* Bit 0: Post-process output */ -#define OLCUC (1 << 1) /* Bit 1: Map lower-case to upper-case on output (LEGACY) */ +#define OLCUC (1 << 1) /* Bit 1: Map lower-case to upper-case on +* * output (LEGACY) */ #define ONLCR (1 << 2) /* Bit 2: Map NL to CR-NL on output */ #define OCRNL (1 << 3) /* Bit 3: Map CR to NL on output */ #define ONOCR (1 << 4) /* Bit 4: No CR output at column 0 */ @@ -116,22 +118,47 @@ /* Local Modes (c_lflag in the termios structure) */ #define ECHO (1 << 0) /* Bit 0: Enable echo */ -#define ECHOE (1 << 1) /* Bit 1: Echo erase character as error-correcting backspace */ +#define ECHOE (1 << 1) /* Bit 1: Echo erase character as error- + * correcting backspace */ #define ECHOK (1 << 2) /* Bit 2: Echo KILL */ #define ECHONL (1 << 3) /* Bit 3: Echo NL */ -#define ICANON (1 << 4) /* Bit 4: Canonical input (erase and kill processing) */ -#define IEXTEN (1 << 5) /* Bit 5: Enable extended input character processing */ +#define ICANON (1 << 4) /* Bit 4: Canonical input (erase and kill + * processing) */ +#define IEXTEN (1 << 5) /* Bit 5: Enable extended input character + * processing */ #define ISIG (1 << 6) /* Bit 6: Enable signals */ #define NOFLSH (1 << 7) /* Bit 7: Disable flush after interrupt or quit */ #define TOSTOP (1 << 8) /* Bit 8: Send SIGTTOU for background output */ -#define XCASE (1 << 9) /* Bit 9: Canonical upper/lower presentation (LEGACY) */ +#define XCASE (1 << 9) /* Bit 9: Canonical upper/lower presentation + * (LEGACY) */ -/* The following are subscript names for the termios c_cc array */ +/* The following are subscript names for the termios c_cc array. + * + * Common characters: VINTR, VQUIT, VSTART, VSTOP, VSUSP + * + * VINTR: Interrupt character (Default ETX, Control-C) + * VQUIT: Quit character (Default FS, Control-\) + * VSTART: Start character (Default DC1, Control-Q) + * VSTOP: Stop character (Default DC3, Control-S) + * VSUSP: Suspend character (Default SUB, Control-Z) + * + * Canonical mode: Adds VEOF, VEOL, VERASE, VKILL + * + * VEOL: End-of-file character (Default SUB, Control-Z) + * VEOF: End-of-line character (Default NUL) + * VERASE: Erase character (Default DEL or BS, Control-H) + * VKILL: Kill character (Default NAK or BS, Control-U) + * + * Non-canonical mode: Adds VMIN, VTIME + * + * VMIN: Minimum number of characters for non-canonical read + * VTIME: Timeout in deciseconds for non-canonical read + */ #define VEOF 0 /* Bit 0: EOF character (canonical mode) */ -#define VMIN VEOF /* Bit 0: MIN value (Non-canonical mode) */ +#define VMIN VEOF /* Bit 0: MIN value (non-canonical mode) */ #define VEOL 1 /* Bit 1: EOL character (canonical mode) */ -#define VTIME VEOL /* Bit 1: TIME value (Non-canonical mode) */ +#define VTIME VEOL /* Bit 1: TIME value (non-canonical mode) */ #define VERASE 2 /* Bit 2: ERASE character (canonical mode) */ #define VINTR 3 /* Bit 3: INTR character */ #define VKILL 4 /* Bit 4: KILL character (canonical mode) */ @@ -139,11 +166,13 @@ #define VSTART 6 /* Bit 6: START character */ #define VSTOP 7 /* Bit 7: STOP character */ #define VSUSP 8 /* Bit 8: SUSP character */ -#define NCCS 9 /* Bit 9: Size of the array c_cc for control characters */ +#define NCCS 9 /* Bit 9: Size of the array c_cc for control + * characters */ -/* Baud Rate Selection. These are instances of type speed_t. Values of 38400 - * and below are specified by POSIX; values above 38400 are sometimes referred - * to as extended values and most values appear in most termios.h implementations. +/* Baud Rate Selection. These are instances of type speed_t. Values of + * 38400 and below are specified by POSIX; values above 38400 are sometimes + * referred to as extended values and most values appear in most termios.h + * implementations. * * NOTE that is NuttX that the encoding of the speed_t values is simply the * value of the baud itself. So this opens a window for non-portable abuse @@ -188,18 +217,23 @@ #define TCSANOW 0 /* Change attributes immediately */ #define TCSADRAIN 1 /* Change attributes when output has drained */ -#define TCSAFLUSH 2 /* Change attributes when output has drained; also flush pending input */ +#define TCSAFLUSH 2 /* Change attributes when output has drained; + * also flush pending input */ /* Line Control (used with tcflush()) */ -#define TCIFLUSH 0 /* Flush pending input. Flush untransmitted output */ -#define TCIOFLUSH 1 /* Flush both pending input and untransmitted output */ +#define TCIFLUSH 0 /* Flush pending input. Flush untransmitted + * output */ +#define TCIOFLUSH 1 /* Flush both pending input and untransmitte + * output */ #define TCOFLUSH 2 /* Flush untransmitted output */ /* Constants for use with tcflow() */ -#define TCIOFF 0 /* Transmit a STOP character, intended to suspend input data */ -#define TCION 1 /* Transmit a START character, intended to restart input data */ +#define TCIOFF 0 /* Transmit a STOP character, intended to + * suspend input data */ +#define TCION 1 /* Transmit a START character, intended to + * restart input data */ #define TCOOFF 2 /* Suspend output */ #define TCOON 3 /* Restart output */ From cd1641305a5d7b9d5c5b44874b2b5a484324abb8 Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Fri, 19 Jan 2018 22:11:09 +0900 Subject: [PATCH 12/44] sched/semaphore: Add ASSERT(false) in nxsem_post() if no waiting task is found. Signed-off-by: Masayuki Ishikawa --- sched/semaphore/sem_post.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sched/semaphore/sem_post.c b/sched/semaphore/sem_post.c index 08a399b9166..a550c0aab4d 100644 --- a/sched/semaphore/sem_post.c +++ b/sched/semaphore/sem_post.c @@ -165,6 +165,12 @@ int nxsem_post(FAR sem_t *sem) up_unblock_task(stcb); } + else + { + /* This should not happen. */ + + ASSERT(false); + } } /* Check if we need to drop the priority of any threads holding From 1f54842c1e67c2ed9151efe4343e871a4859233c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 19 Jan 2018 08:49:55 -0600 Subject: [PATCH 13/44] sched/sched/sched_sporadic.c: fix compiler error when priority inheritance is enabled. Noted by eunb.song@samsung.com --- sched/sched/sched_sporadic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sched/sched/sched_sporadic.c b/sched/sched/sched_sporadic.c index 666416cf7dd..dda7a355b83 100644 --- a/sched/sched/sched_sporadic.c +++ b/sched/sched/sched_sporadic.c @@ -138,7 +138,7 @@ static int sporadic_set_lowpriority(FAR struct tcb_s *tcb) * state. */ - tcb->base_priority = sporadic->low_priority; + tcb->base_priority = tcb->low_priority; } #endif @@ -194,7 +194,7 @@ static int sporadic_set_hipriority(FAR struct tcb_s *tcb) { /* Boosted... Do we still need to reprioritize? */ - if (sporadic->hi_priority < sporadic->base_priority) + if (sporadic->hi_priority < tcb->base_priority) { /* No.. the current execution priority is lower than the * boosted priority. Just reset the base priority. @@ -322,7 +322,7 @@ static int sporadic_interval_start(FAR struct replenishment_s *mrepl) /* Start the timer that will terminate the low priority cycle. This timer * expiration is independent of what else may occur (except that it must - * be cancelled if the thread exits. + * be canceled if the thread exits. */ DEBUGVERIFY(wd_start(&mrepl->timer, remainder, sporadic_interval_expire, From 5a102fb227c7deab27c28ced95d56206946dca15 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 19 Jan 2018 09:07:19 -0600 Subject: [PATCH 14/44] Change ASSERT(false) to DEBUGPANIC(). --- sched/semaphore/sem_post.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sched/semaphore/sem_post.c b/sched/semaphore/sem_post.c index a550c0aab4d..f20cb68c774 100644 --- a/sched/semaphore/sem_post.c +++ b/sched/semaphore/sem_post.c @@ -169,7 +169,7 @@ int nxsem_post(FAR sem_t *sem) { /* This should not happen. */ - ASSERT(false); + DEBUGPANIC(); } } From c7f293d38823e74286b9442e941f6be43e1e9f02 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 20 Jan 2018 07:11:33 -0600 Subject: [PATCH 15/44] Documentation: Fix copy/paste error in NX graphics document. Noted by Henjiu Kang. --- Documentation/NXGraphicsSubsystem.html | 4 ++-- configs/flipnclick-pic32mz/README.txt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/NXGraphicsSubsystem.html b/Documentation/NXGraphicsSubsystem.html index 3a58de35fc3..efb8cbf1fe4 100644 --- a/Documentation/NXGraphicsSubsystem.html +++ b/Documentation/NXGraphicsSubsystem.html @@ -12,7 +12,7 @@

NX Graphics Subsystem

-

Last Updated: October 17, 2017

+

Last Updated: January 21, 2018

@@ -542,7 +542,7 @@ void nxgl_yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8

Description: - Convert 8-bit RGB triplet to 8-bit YUV triplet. + Convert 8-bit YUV triplet to 8-bit RGB triplet.

2.2.3 nxgl_rectcopy()

diff --git a/configs/flipnclick-pic32mz/README.txt b/configs/flipnclick-pic32mz/README.txt index 000cda2fcc0..3a1c3575d6d 100644 --- a/configs/flipnclick-pic32mz/README.txt +++ b/configs/flipnclick-pic32mz/README.txt @@ -46,7 +46,8 @@ On Board Debug Support There is a simple application available at Mikroe that will allow you to write .hex files via the USB HID bootloader. However, in order to use the bootloader, you will have to control the memory map so that the - downloaded code does not clobber the bootloader. + downloaded code does not clobber the bootloader code FLASH, data + memory, exception vectors, etc. At this point, I have found no documentation describing how to build the code outside of the Mikroe toolchain for use with the Mikroe From 414c449cf9c2b5a03e5ce8d6eb343bbb4bced95d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 20 Jan 2018 07:44:35 -0600 Subject: [PATCH 16/44] sched/sched: Fix some priority inheritance related issues noted during review of logic. Also add some REVISIT comments for some issues noted in the design. --- sched/sched/sched_sporadic.c | 55 ++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/sched/sched/sched_sporadic.c b/sched/sched/sched_sporadic.c index dda7a355b83..35984b72421 100644 --- a/sched/sched/sched_sporadic.c +++ b/sched/sched/sched_sporadic.c @@ -129,7 +129,19 @@ static int sporadic_set_lowpriority(FAR struct tcb_s *tcb) #ifdef CONFIG_PRIORITY_INHERITANCE /* If the priority was boosted above the higher priority, than just - * reset the base priority. + * reset the base priority and continue to run at the boosted priority. + * + * REVISIT: There is a logic flaw here... If the priority was NOT + * boosted above the hi_priority, then it still may still need to + * boosted with respect to the lo_priority. If the highest priority + * thread waiting on a semaphore held by the sporadic thread is greater + * than the low priority (but less than the hi_priority), the new + * sched_priority should be set to that priority, not to the lo_priority + * + * In order to do this we would need a list of all semaphores held by + * the thread. We would need to select the highest priority from among + * all tasks waiting for the semaphores. Unfortunately, at present we + * know nothing about the semaphores held by the sporadic thread. */ if (tcb->sched_priority > tcb->base_priority) @@ -140,18 +152,20 @@ static int sporadic_set_lowpriority(FAR struct tcb_s *tcb) tcb->base_priority = tcb->low_priority; } + else #endif - - /* Otherwise drop the priority of thread, possible causing a context - * switch. - */ - - ret = sched_reprioritize(tcb, sporadic->low_priority); - if (ret < 0) { - int errcode = get_errno(); - serr("ERROR: sched_reprioritize failed: %d\n", errcode); - return -errcode; + /* Otherwise drop the priority of thread, possible causing a context + * switch. + */ + + ret = sched_reprioritize(tcb, sporadic->low_priority); + if (ret < 0) + { + int errcode = get_errno(); + serr("ERROR: sched_reprioritize failed: %d\n", errcode); + return -errcode; + } } return OK; @@ -188,16 +202,27 @@ static int sporadic_set_hipriority(FAR struct tcb_s *tcb) #ifdef CONFIG_PRIORITY_INHERITANCE /* If the priority was boosted above the higher priority, than just * reset the base priority. + * + * First, was the priority boosted above the lo_priority which should be + * the same as the base_priority here? (This is an unnecessary test. + * sched_priority > hi_priority would be sufficient). */ if (tcb->sched_priority > tcb->base_priority) { - /* Boosted... Do we still need to reprioritize? */ + /* Boosted... Do we still need to reprioritize? If we were boosted to + * a priority above the hi_priority then we do not need to do anything + * except to adjust the base_priority + * + * REVISIT: This logic is probably okay. But may lead to problems + * when the hi_priority is resumed. See REVISIT comments in + * sporadic_set_lowpriority(). + */ - if (sporadic->hi_priority < tcb->base_priority) + if (tcb->sched_priority > sporadic->hi_priority) { - /* No.. the current execution priority is lower than the - * boosted priority. Just reset the base priority. + /* No.. the new execution priority is lower than the boosted + * priority. Just reset the base priority. */ tcb->base_priority = sporadic->hi_priority; From 2f0bc1907b9252f141cf3d2ac36ed71872bacc6a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 20 Jan 2018 12:59:56 -0600 Subject: [PATCH 17/44] Update README and some comments --- README.txt | 19 +++++++++++++++++++ sched/sched/sched_sporadic.c | 8 ++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/README.txt b/README.txt index 4dfd513a7f3..719fe60d177 100644 --- a/README.txt +++ b/README.txt @@ -1422,6 +1422,22 @@ Installing GNUWin32 CYGWIN BUILD PROBLEMS ^^^^^^^^^^^^^^^^^^^^^ +Performance +----------- + + Build performance under Cygwin is really not so bad, certainly not as good + as a Linux build. However, often you will find that the performance is + not just bad but terrible. If you are seeing awful performance.. like two + or three compilations per second.. the culprit is usually your Windows + Anti-Virus protection interfering with the build tool program execution. + + I use Cygwin quite often and I use Windows Defender. In order to get good + build performance, I routinely keep the Windows Defender "Virus & Threat + Protections Settings" screen up: I disable "Real-Time Protection" just + before entering 'make' then turn "Real-Time Protection" back on when the + build completes. With this additional nuisance step, I find that build + performance under Cygwin is completely acceptable. + Strange Path Problems --------------------- @@ -1475,6 +1491,7 @@ Window Native Toolchain Issues if you are using a native Windows toolchain. That bring us to #3: General Pre-built Toolchain Issues +---------------------------------- To continue with the list of "Window Native Toolchain Issues" we can add the following. These, however, are really just issues that you will have @@ -1528,6 +1545,7 @@ General Pre-built Toolchain Issues binutils and possibly different ABIs. Building Original Linux Boards in Cygwin +---------------------------------------- Some default board configurations are set to build under Linux and others to build under Windows with Cygwin. Various default toolchains may also @@ -1546,6 +1564,7 @@ Building Original Linux Boards in Cygwin ("Run As" option, right button) you find errors like "Permission denied". Recovering from Bad Configurations +---------------------------------- Many people make the mistake of configuring NuttX with the "canned" configuration and then just typing 'make' with disastrous consequences; diff --git a/sched/sched/sched_sporadic.c b/sched/sched/sched_sporadic.c index 35984b72421..90206c486e6 100644 --- a/sched/sched/sched_sporadic.c +++ b/sched/sched/sched_sporadic.c @@ -138,10 +138,10 @@ static int sporadic_set_lowpriority(FAR struct tcb_s *tcb) * than the low priority (but less than the hi_priority), the new * sched_priority should be set to that priority, not to the lo_priority * - * In order to do this we would need a list of all semaphores held by - * the thread. We would need to select the highest priority from among - * all tasks waiting for the semaphores. Unfortunately, at present we - * know nothing about the semaphores held by the sporadic thread. + * In order to do this we would need to know the highest priority from + * among all tasks waiting for the all semaphores held by the sporadic + * task. Perhaps that information could be retained by the priority + * inheritance logic for use here? */ if (tcb->sched_priority > tcb->base_priority) From c4e8dbbe6e6038602484e0d4d53a635f9069fb82 Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sat, 20 Jan 2018 23:00:47 +0100 Subject: [PATCH 18/44] Issue #85: /dev/userleds is not working for nucleo-l432kc fixed --- configs/nucleo-l432kc/README.txt | 2 +- configs/nucleo-l432kc/include/board.h | 4 ++-- configs/nucleo-l432kc/src/nucleo-l432kc.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configs/nucleo-l432kc/README.txt b/configs/nucleo-l432kc/README.txt index 33ebc530cdb..b68e68ebbdc 100644 --- a/configs/nucleo-l432kc/README.txt +++ b/configs/nucleo-l432kc/README.txt @@ -324,7 +324,7 @@ Hardware ---- The Nucleo F401RE and Nucleo F411RE provide a single user LED, LD2. LD2 is the green LED connected to Arduino signal D13 corresponding to MCU I/O - PA5 (pin 21) or PB13 (pin 34) depending on the STM32target. + PB3 (pin 26). - When the I/O is HIGH value, the LED is on. - When the I/O is LOW, the LED is off. diff --git a/configs/nucleo-l432kc/include/board.h b/configs/nucleo-l432kc/include/board.h index dbe6dbe48fa..529accb653a 100644 --- a/configs/nucleo-l432kc/include/board.h +++ b/configs/nucleo-l432kc/include/board.h @@ -147,8 +147,8 @@ /* LEDs * * The Nucleo l476RG board provides a single user LED, LD2. LD2 - * is the green LED connected to Arduino signal D13 corresponding to MCU I/O - * PA5 (pin 21) or PB13 (pin 34) depending on the STM32 target. + * is the green LED connected to Arduino signal D13 corresponding to + * MCU I/O PB3 (pin 26). * * - When the I/O is HIGH value, the LED is on. * - When the I/O is LOW, the LED is off. diff --git a/configs/nucleo-l432kc/src/nucleo-l432kc.h b/configs/nucleo-l432kc/src/nucleo-l432kc.h index 9ce05bc83d3..e5c34816bb9 100644 --- a/configs/nucleo-l432kc/src/nucleo-l432kc.h +++ b/configs/nucleo-l432kc/src/nucleo-l432kc.h @@ -77,7 +77,7 @@ #endif /* LED. User LD2: the green LED is a user LED connected to Arduino signal D13 - * corresponding to MCU I/O PA5 (pin 21) or PB13 (pin 34) depending on the STM32 + * corresponding to MCU I/O PB3 (pin 26) * target. * * - When the I/O is HIGH value, the LED is on. @@ -85,7 +85,7 @@ */ #define GPIO_LD2 \ - (GPIO_PORTA | GPIO_PIN5 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | GPIO_PULLUP | \ + (GPIO_PORTB | GPIO_PIN3 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | GPIO_PULLUP | \ GPIO_SPEED_50MHz) #define LED_DRIVER_PATH "/dev/userleds" From 1c502d4f726fd7df5ae73f62d7773e00f46240ad Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 20 Jan 2018 16:16:35 -0600 Subject: [PATCH 19/44] configs/nucleo-l432kc: Fix numerous cloning errors/typos. --- TODO | 4 ++-- configs/nucleo-l432kc/README.txt | 19 ++++++++----------- configs/nucleo-l432kc/include/board.h | 4 ++-- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/TODO b/TODO index 3d92fd7ee2c..19b328e54df 100644 --- a/TODO +++ b/TODO @@ -745,7 +745,7 @@ o Kernel/Protected Build Title: USER MODE TASKS CAN MODIFY PRIVILEGED TASKS Description: Certain interfaces, such as sched_setparam(), sched_setscheduler(), etc. can be used by user mode tasks to - modify the behavior of priviledged kernel threads. + modify the behavior of privileged kernel threads. For a truly secure system. Privileges need to be checked in every interface that permits one thread to modify the properties of another thread. @@ -1282,7 +1282,7 @@ o Network (net/, drivers/net) however, because its priority is low and so it is blocked from execution. - In the mean time, the remote host sends a - packet which is presumeably caught in the read-ahead buffer. + packet which is presumably caught in the read-ahead buffer. - Then the remote host closes the socket. Nothing happens on the target side because net_start_monitor() has not yet been called. diff --git a/configs/nucleo-l432kc/README.txt b/configs/nucleo-l432kc/README.txt index b68e68ebbdc..43eacb43913 100644 --- a/configs/nucleo-l432kc/README.txt +++ b/configs/nucleo-l432kc/README.txt @@ -230,12 +230,10 @@ NuttX EABI "buildroot" Toolchain 1. You must have already configured Nuttx in /nuttx. - $ (cd tools; ./configure.sh nucleo-f4x1re/f401-nsh) + $ tools/configure.sh nucleo-f432kc/nsh $ make qconfig $ V=1 make context all 2>&1 | tee mout - Use the f411-nsh configuration if you have the Nucleo-F411RE board. - 2. Download the latest buildroot package into 3. unpack the buildroot tarball. The resulting directory may @@ -298,14 +296,13 @@ NXFLAT Toolchain mbed ==== - The Nucleo-F401RE includes boot loader from mbed: + The Nucleo-F432KC includes boot loader from mbed: - https://mbed.org/platforms/ST-Nucleo-F401RE/ https://mbed.org/handbook/Homepage Using the mbed loader: - 1. Connect the Nucleo-F4x1RE to the host PC using the USB connector. + 1. Connect the Nucleo-F432kc to the host PC using the USB connector. 2. A new file system will appear called NUCLEO; open it with Windows Explorer (assuming that you are using Windows). 3. Drag and drop nuttx.bin into the MBED window. This will load the @@ -322,7 +319,7 @@ Hardware LEDs ---- - The Nucleo F401RE and Nucleo F411RE provide a single user LED, LD2. LD2 + The Nucleo F401RE and Nucleo F432KC provide a single user LED, LD2. LD2 is the green LED connected to Arduino signal D13 corresponding to MCU I/O PB3 (pin 26). @@ -367,7 +364,7 @@ Serial Consoles TTL to RS-232 converter connection: - Nucleo CN10 STM32F4x1RE + Nucleo CN10 STM32F432KC ----------- ------------ Pin 21 PA9 USART1_RX *Warning you make need to reverse RX/TX on Pin 33 PA10 USART1_TX some RS-232 converters @@ -399,7 +396,7 @@ Serial Consoles TTL to RS-232 converter connection: - Nucleo CN9 STM32F4x1RE + Nucleo CN9 STM32F432KC ----------- ------------ Pin 1 PA3 USART2_RX *Warning you make need to reverse RX/TX on Pin 2 PA2 USART2_TX some RS-232 converters @@ -457,7 +454,7 @@ Configurations nsh: --------- Configures the NuttShell (nsh) located at apps/examples/nsh for the - Nucleo-F401RE board. The Configuration enables the serial interfaces + Nucleo-F432KC board. The Configuration enables the serial interfaces on UART2. Support for builtin applications is enabled, but in the base configuration no builtin applications are selected (see NOTES below). @@ -484,7 +481,7 @@ Configurations Consoles). I have been using a TTL-to-RS-232 converter connected as shown below: - Nucleo CN10 STM32F4x1RE + Nucleo CN10 STM32F432KC ----------- ------------ Pin 21 PA9 USART1_RX *Warning you make need to reverse RX/TX on Pin 33 PA10 USART1_TX some RS-232 converters diff --git a/configs/nucleo-l432kc/include/board.h b/configs/nucleo-l432kc/include/board.h index 529accb653a..3e7e90c4537 100644 --- a/configs/nucleo-l432kc/include/board.h +++ b/configs/nucleo-l432kc/include/board.h @@ -146,7 +146,7 @@ /* LEDs * - * The Nucleo l476RG board provides a single user LED, LD2. LD2 + * The Nucleo l432kc board provides a single user LED, LD2. LD2 * is the green LED connected to Arduino signal D13 corresponding to * MCU I/O PB3 (pin 26). * @@ -266,4 +266,4 @@ void stm32l4_board_initialize(void); #endif #endif /* __ASSEMBLY__ */ -#endif /* __CONFIGS_NUCLEO_F476RG_INCLUDE_BOARD_H */ +#endif /* __CONFIGS_NUCLEO_F432KC_INCLUDE_BOARD_H */ From ef54d16116e8313d9b60ef29ddbce3ea120355be Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 21 Jan 2018 07:47:13 -0600 Subject: [PATCH 20/44] Update TODO list --- TODO | 81 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/TODO b/TODO index 19b328e54df..4d46a3e5b0b 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,15 @@ -NuttX TODO List (Last updated January 3, 2018) +NuttX TODO List (Last updated January 21, 2018) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with standards, things that could be improved, and ideas for enhancements. This -TODO list does not include issues associated with individual boar ports. See +TODO list does not include issues associated with individual board ports. See also the individual README.txt files in the configs/ sub-directories for issues related to each board port. nuttx/: - (12) Task/Scheduler (sched/) + (14) Task/Scheduler (sched/) (1) SMP (1) Memory Management (mm/) (0) Power Management (drivers/pm) @@ -47,7 +47,7 @@ o Task/Scheduler (sched/) Status: Closed. No, this behavior will not be implemented. Priority: Medium, required for good emulation of process/pthread model. The current behavior allows for the main thread of a task to - exit() and any child pthreads will perist. That does raise + exit() and any child pthreads will persist. That does raise some issues: The main thread is treated much like just-another- pthread but must follow the semantics of a task or a process. That results in some inconsistencies (for example, with robust @@ -124,7 +124,7 @@ o Task/Scheduler (sched/) The fix for all of these issues it to have the callbacks run on the caller's thread as is currently done with signal handlers. Signals are delivered differently in - PROTECTED and KERNEL modes: The deliver is involes a + PROTECTED and KERNEL modes: The delivery involves a signal handling trampoline function in the user address space and two signal handlers: One to call the signal handler trampoline in user mode (SYS_signal_handler) and @@ -198,7 +198,7 @@ o Task/Scheduler (sched/) Description: The internal NuttX logic uses the same interfaces as does the application. That sometime produces a problem because there is "overloaded" functionality in those user interfaces - that are not desireable. + that are not desirable. For example, having cancellation points hidden inside of the OS can cause non-cancellation point interfaces to behave @@ -327,6 +327,59 @@ o Task/Scheduler (sched/) Status: Open Priority: Low, only needed for more complete debug. + Title: PRIORITY INHERITANCE WITH SPORADIC SCHEDULER + Description: The sporadic scheduler manages CPU utilization by a task by + alternating between a high and a low priority. In either + state, it may have its priority boosted. However, under + some circumstances, it is impossible in the current design to + switch to the correct correct priority if a semaphore is + participating in priority inheritance: + + There is an when switching from the high to the low priority + state. If the priority was NOT boosted above the higher + priority, it still may still need to boosted with respect to + the lower priority. If the highest priority thread waiting + on a semaphore held by the sporadic thread is higher in + priority than the low priority but less than the higher + priority, then new thread priority should be set to that + middle priority, not to the lower priority + + In order to do this we would need to know the highest + priority from among all tasks waiting for the all semaphores + held by the sporadic task. That information could be + retained by the priority inheritance logic for use by the + sporadic scheduler. The boost priority could be retained in + a new field of the TCB (say, pend_priority). That + pend_priority could then be used when switching from the + higher to the lower priority. + Status: Open + Priority: Low. Does anyone actually use the sporadic scheduler? + + Title: SIMPLIFY SPORADIC SCHEDULER DESIGN + Description: I have been planning to re-implement sporadic scheduling for + some time. I believe that the current implementation is + unnecessarily complex. There is no clear statement for the + requirements of sporadic scheduling that I could find, so I + based the design on some behaviors of another OS that I saw + published (QNX as I recall). + + But I think that the bottom line requirement for sporadic + scheduling is that is it should make a best attempt to + control a fixed percentage of CPU bandwidth for a task in + during an interval only by modifying it is priority between + a low and a high priority. The current design involves + several timers: A "budget" timer plus a variable number of + "replenishment" timers and a lot of nonsense to duplicate QNX + behavior that I think I not necessary. + + It think that the sporadic scheduler could be re-implemented + with only the single "budget" timer. Instead of starting a + new "replenishment" timer when the task is resumed, that + single timer could just be extended. + Status: Open + Priority: Low. This is an enhancement. And does anyone actually use + the sporadic scheduler? + o SMP ^^^ @@ -572,7 +625,7 @@ o pthreads (sched/pthreads) group structure. I am, however, hesitant to make this change: In the FLAT build model, there is nothing that prevents people from accessing the inter-thread controls from threads in - differnt task groups. Making this change, while correct, + different task groups. Making this change, while correct, might introduce subtle bugs in code by people who are not using NuttX correctly. Status: Open @@ -1838,7 +1891,7 @@ o File system / Generic drivers (fs/, drivers/) (using pctl() instead sysctl()). My objective was to be able to control the number of available file descriptors on a task- by-task basis. The complexity due to the partitioning of - desciptor space in a range for file descriptors and a range + descriptor space in a range for file descriptors and a range for socket descriptors made this feature nearly impossible to implement. Status: Open @@ -1920,8 +1973,8 @@ o File system / Generic drivers (fs/, drivers/) 4) When comparing the checksum in the long file name entry with the checksum of the short file name, the checksum fails and the entire directory sequence is - ignored by readder() logic. This the file does not - appear in the 'ls'. + ignored by readdir() logic. This is why the file does + not appear in the 'ls'. o Graphics Subsystem (graphics/) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -2014,7 +2067,7 @@ o Graphics Subsystem (graphics/) Title: LOW-RES FRAMEBUFFER RENDERERING Description: There are obvious issues in the low-res, < 8 BPP, implemenation of - the framebuffer rendereing logic of graphics/nxglib/fb. I see two + the framebuffer rendering logic of graphics/nxglib/fb. I see two obvious problems in reviewing nxglib_copyrectangle(): 1. The masking logic might work 1 BPP, but is insufficient for other @@ -2026,7 +2079,7 @@ o Graphics Subsystem (graphics/) derives from nxglib_copyrectangle() and all of those issues have been resolved in that file. - Other frambuffer rendering functions probably have similary issues. + Other frambuffer rendering functions probably have similar issues. Status: Open Priority: Low. It is not surprising that there would be bugs in this logic: I have never encountered a hardware framebuffer with sub-byte pixel @@ -2279,11 +2332,11 @@ o Modbus (apps/modbus) Title: MODBUS NOT USABLE WITH USB SERIAL Description: Modbus can be used with USB serial, however, if the USB - serial connectiont is lost, Modbus will hang in an infinite + serial connection is lost, Modbus will hang in an infinite loop. This is a problem in the handling of select() and read() - and could probabaly resolved by studying the Modbus error + and could probably resolved by studying the Modbus error handling. A more USB-friendly solution would be to: (1) Re-connect and From e02a46f1d5e1ecea0de8709ad0647963c71a69ce Mon Sep 17 00:00:00 2001 From: Fanda Vacek Date: Sun, 21 Jan 2018 19:06:22 +0100 Subject: [PATCH 21/44] NUCLEO F432KC typo fixed, correct name is L432KC Just README.txt and comments affected, no changes in the code --- configs/nucleo-l432kc/README.txt | 16 ++++++++-------- configs/nucleo-l432kc/include/board.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/configs/nucleo-l432kc/README.txt b/configs/nucleo-l432kc/README.txt index 43eacb43913..a922e176386 100644 --- a/configs/nucleo-l432kc/README.txt +++ b/configs/nucleo-l432kc/README.txt @@ -230,7 +230,7 @@ NuttX EABI "buildroot" Toolchain 1. You must have already configured Nuttx in /nuttx. - $ tools/configure.sh nucleo-f432kc/nsh + $ tools/configure.sh nucleo-l432kc/nsh $ make qconfig $ V=1 make context all 2>&1 | tee mout @@ -296,13 +296,13 @@ NXFLAT Toolchain mbed ==== - The Nucleo-F432KC includes boot loader from mbed: + The Nucleo-L432KC includes boot loader from mbed: https://mbed.org/handbook/Homepage Using the mbed loader: - 1. Connect the Nucleo-F432kc to the host PC using the USB connector. + 1. Connect the Nucleo-L432kc to the host PC using the USB connector. 2. A new file system will appear called NUCLEO; open it with Windows Explorer (assuming that you are using Windows). 3. Drag and drop nuttx.bin into the MBED window. This will load the @@ -319,7 +319,7 @@ Hardware LEDs ---- - The Nucleo F401RE and Nucleo F432KC provide a single user LED, LD2. LD2 + The Nucleo L432KC provides a single user LED, LD2. LD2 is the green LED connected to Arduino signal D13 corresponding to MCU I/O PB3 (pin 26). @@ -364,7 +364,7 @@ Serial Consoles TTL to RS-232 converter connection: - Nucleo CN10 STM32F432KC + Nucleo CN10 STM32L432KC ----------- ------------ Pin 21 PA9 USART1_RX *Warning you make need to reverse RX/TX on Pin 33 PA10 USART1_TX some RS-232 converters @@ -396,7 +396,7 @@ Serial Consoles TTL to RS-232 converter connection: - Nucleo CN9 STM32F432KC + Nucleo CN9 STM32L432KC ----------- ------------ Pin 1 PA3 USART2_RX *Warning you make need to reverse RX/TX on Pin 2 PA2 USART2_TX some RS-232 converters @@ -454,7 +454,7 @@ Configurations nsh: --------- Configures the NuttShell (nsh) located at apps/examples/nsh for the - Nucleo-F432KC board. The Configuration enables the serial interfaces + Nucleo-L432KC board. The Configuration enables the serial interfaces on UART2. Support for builtin applications is enabled, but in the base configuration no builtin applications are selected (see NOTES below). @@ -481,7 +481,7 @@ Configurations Consoles). I have been using a TTL-to-RS-232 converter connected as shown below: - Nucleo CN10 STM32F432KC + Nucleo CN10 STM32L432KC ----------- ------------ Pin 21 PA9 USART1_RX *Warning you make need to reverse RX/TX on Pin 33 PA10 USART1_TX some RS-232 converters diff --git a/configs/nucleo-l432kc/include/board.h b/configs/nucleo-l432kc/include/board.h index 3e7e90c4537..041a755787c 100644 --- a/configs/nucleo-l432kc/include/board.h +++ b/configs/nucleo-l432kc/include/board.h @@ -266,4 +266,4 @@ void stm32l4_board_initialize(void); #endif #endif /* __ASSEMBLY__ */ -#endif /* __CONFIGS_NUCLEO_F432KC_INCLUDE_BOARD_H */ +#endif /* __CONFIGS_NUCLEO_L432KC_INCLUDE_BOARD_H */ From 6fd85ff0761a1f229d6657177dc7042573e21c51 Mon Sep 17 00:00:00 2001 From: Mateusz Szafoni Date: Sun, 21 Jan 2018 18:28:09 +0000 Subject: [PATCH 22/44] Merged in raiden00/nuttx (pull request #579) Master * stm32_hritm: add interface to get timer clock frequency stm32_hrtim: fix timer freq calculation stm32_hrtim: add compar/capture registers significant bits checking stm32_hrtim: minor changes * stm32f334-disco: add buck converter and boost converter logic Approved-by: Gregory Nutt --- arch/arm/src/stm32/stm32_hrtim.c | 415 +++++++++++++------ arch/arm/src/stm32/stm32_hrtim.h | 38 +- configs/stm32f334-disco/include/board.h | 34 +- configs/stm32f334-disco/src/stm32_smps.c | 493 ++++++++++++++++++++--- 4 files changed, 790 insertions(+), 190 deletions(-) diff --git a/arch/arm/src/stm32/stm32_hrtim.c b/arch/arm/src/stm32/stm32_hrtim.c index 44f78bff6f6..121b0e2e4f1 100644 --- a/arch/arm/src/stm32/stm32_hrtim.c +++ b/arch/arm/src/stm32/stm32_hrtim.c @@ -375,12 +375,13 @@ struct stm32_hrtim_capture_s struct stm32_hrtim_timcmn_s { uint32_t base; /* The base adress of the timer */ - uint32_t pclk; /* The frequency of the peripheral clock + uint64_t fclk; /* The frequency of the peripheral clock * that drives the timer module. */ + uint8_t prescaler:3; /* Prescaler */ uint8_t mode; /* Timer mode */ uint8_t dac:2; /* DAC triggering */ - uint8_t reserved:6; + uint8_t reserved:3; #ifdef CONFIG_STM32_HRTIM_INTERRUPTS uint16_t irq; /* interrupts configuration */ #endif @@ -623,6 +624,8 @@ static uint32_t hrtim_tim_getreg(FAR struct stm32_hrtim_s *priv, uint8_t timer, uint32_t offset); static FAR struct stm32_hrtim_tim_s *hrtim_tim_get(FAR struct stm32_hrtim_s *priv, uint8_t timer); +static FAR struct stm32_hrtim_slave_priv_s *hrtim_slave_get(FAR struct stm32_hrtim_s *priv, + uint8_t timer); static uint32_t hrtim_base_get(FAR struct stm32_hrtim_s *priv, uint8_t timer); /* Configuration */ @@ -665,7 +668,8 @@ static int hrtim_tim_dma_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer, #ifdef CONFIG_STM32_HRTIM_DEADTIME static int hrtim_deadtime_update(FAR struct hrtim_dev_s *dev, uint8_t timer, uint8_t dt, uint16_t value); -static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t dt); +static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t timer, + uint8_t dt); static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer); static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv); #endif @@ -705,6 +709,7 @@ static int hrtim_per_update(FAR struct hrtim_dev_s *dev, uint8_t timer, static uint16_t hrtim_per_get(FAR struct hrtim_dev_s *dev, uint8_t timer); static uint16_t hrtim_cmp_get(FAR struct hrtim_dev_s *dev, uint8_t timer, uint8_t index); +static uint64_t hrtim_fclk_get(FAR struct hrtim_dev_s *dev, uint8_t timer); static int hrtim_tim_reset_set(FAR struct stm32_hrtim_s *priv, uint8_t timer, uint32_t reset); static int hrtim_reset_config(FAR struct stm32_hrtim_s *priv); @@ -753,20 +758,21 @@ static struct stm32_hrtim_tim_s g_master = /* If MASTER is disabled, we need only MASTER base */ #ifdef CONFIG_STM32_HRTIM_MASTER - .pclk = HRTIM_CLOCK/(HRTIM_MASTER_PRESCALER+1), - .mode = HRTIM_MASTER_MODE, + .fclk = HRTIM_CLOCK/(1<priv; + +errout: + return slave; +} + /**************************************************************************** * Name: hrtim_base_get * @@ -2049,7 +2108,7 @@ static void hrtim_dumpregs(FAR struct stm32_hrtim_s *priv, uint8_t timer, * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2093,7 +2152,7 @@ static int hrtim_dll_cal(FAR struct stm32_hrtim_s *priv) * timer - An HRTIM Timer index * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2182,7 +2241,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2264,7 +2323,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2467,7 +2526,7 @@ static int hrtim_gpios_config(FAR struct stm32_hrtim_s *priv) * capture - capture trigers configuration * * Returned Value: - * None + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2478,7 +2537,9 @@ static int hrtim_tim_capture_cfg(FAR struct stm32_hrtim_s *priv, int ret = OK; uint32_t offset = 0; - if (timer == HRTIM_TIMER_MASTER) + /* Sanity checking */ + + if (timer == HRTIM_TIMER_MASTER || timer == HRTIM_TIMER_COMMON) { ret = -EINVAL; goto errout; @@ -2521,7 +2582,7 @@ errout: * priv - A reference to the HRTIM block * * Returned Value: - * None + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2574,7 +2635,7 @@ static int hrtim_capture_config(FAR struct stm32_hrtim_s *priv) * index - Capture register index * * Returned Value: - * None + * Timer Capture value on success, 0 on failure * ****************************************************************************/ @@ -2623,7 +2684,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2645,37 +2706,26 @@ static int hrtim_synch_config(FAR struct stm32_hrtim_s *priv) * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ #if defined(CONFIG_STM32_HRTIM_PWM) static int hrtim_tim_outputs_config(FAR struct stm32_hrtim_s *priv, uint8_t timer) { - FAR struct stm32_hrtim_tim_s* tim; FAR struct stm32_hrtim_slave_priv_s* slave; uint32_t regval = 0; int ret = OK; - /* Master Timer has no outputs */ + /* Get Slave Timer data structure */ - if (timer == HRTIM_TIMER_MASTER) + slave = hrtim_slave_get(priv, timer); + if (slave == NULL) { ret = -EINVAL; goto errout; } - /* Get Timer data strucutre */ - - tim = hrtim_tim_get(priv, timer); - if (tim == NULL) - { - ret = -EINVAL; - goto errout; - } - - slave = (struct stm32_hrtim_slave_priv_s*)tim->priv; - /* Configure CH1 SET events */ regval = slave->pwm.ch1.set; @@ -2773,7 +2823,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -2848,7 +2898,7 @@ errout: * state - Enable/disable operation * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -3009,7 +3059,6 @@ static int hrtim_output_set_set(FAR struct hrtim_dev_s *dev, uint16_t output, uint32_t set) { FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; - FAR struct stm32_hrtim_tim_s* tim; FAR struct stm32_hrtim_slave_priv_s* slave; uint8_t timer = 0; int ret = OK; @@ -3018,17 +3067,15 @@ static int hrtim_output_set_set(FAR struct hrtim_dev_s *dev, uint16_t output, timer = output_tim_index_get(output); - /* Get Timer data strucutre */ + /* Get Slave Timer data strucutre */ - tim = hrtim_tim_get(priv, timer); - if (tim == NULL) + slave = hrtim_slave_get(priv, timer); + if (slave == NULL) { ret = -EINVAL; goto errout; } - slave = (struct stm32_hrtim_slave_priv_s*)tim->priv; - /* Set new SET value */ switch (output_tim_ch_get(output)) @@ -3065,7 +3112,6 @@ static int hrtim_output_rst_set(FAR struct hrtim_dev_s *dev, uint16_t output, uint32_t rst) { FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; - FAR struct stm32_hrtim_tim_s* tim; FAR struct stm32_hrtim_slave_priv_s* slave; uint8_t timer = 0; int ret = OK; @@ -3074,17 +3120,15 @@ static int hrtim_output_rst_set(FAR struct hrtim_dev_s *dev, uint16_t output, timer = output_tim_index_get(output); - /* Get Timer data strucutre */ + /* Get Salve Timer data strucutre */ - tim = hrtim_tim_get(priv, timer); - if (tim == NULL) + slave = hrtim_slave_get(priv, timer); + if (slave == NULL) { ret = -EINVAL; goto errout; } - slave = (struct stm32_hrtim_slave_priv_s*)tim->priv; - /* Set new RST value */ switch (output_tim_ch_get(output)) @@ -3124,7 +3168,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -3172,7 +3216,7 @@ static int hrtim_adc_config(FAR struct stm32_hrtim_s *priv) * dac - DAC synchronisation event configuration * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -3203,7 +3247,7 @@ static int hrtim_tim_dac_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer, * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -3268,6 +3312,14 @@ static int hrtim_tim_dma_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer, int ret = OK; uint32_t regval = 0; + /* Sanity checking */ + + if (timer == HRTIM_TIMER_COMMON) + { + ret = -EINVAL; + goto errout; + } + if (timer == HRTIM_TIMER_MASTER) { /* Master support first 7 DMA requests */ @@ -3397,7 +3449,8 @@ errout: * Name: hrtim_deadtime_get ****************************************************************************/ -static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t dt) +static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t timer, + uint8_t dt) { #warning missing logic } @@ -3408,30 +3461,27 @@ static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t dt) static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer) { - FAR struct stm32_hrtim_tim_s* tim; FAR struct stm32_hrtim_slave_priv_s* slave; uint32_t regval = 0; int ret = OK; - /* Master Timer has no outputs */ + /* Sanity checking */ - if (timer == HRTIM_TIMER_MASTER) + if (timer == HRTIM_TIMER_MASTER || timer == HRTIM_TIMER_COMMON) { ret = -EINVAL; goto errout; } - /* Get Timer data strucutre */ + /* Get Slave Timer data strucutre */ - tim = hrtim_tim_get(priv, timer); - if (tim == NULL) + slave = hrtim_slave_get(priv, timer); + if (slave == NULL) { ret = -EINVAL; goto errout; } - slave = (struct stm32_hrtim_slave_priv_s*)tim->priv; - /* Configure deadtime prescaler */ regval |= slave->pwm.dt.prescaler << HRTIM_TIMDT_DTPRSC_SHIFT; @@ -3550,7 +3600,7 @@ static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv) * state - Enable/disable operation * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -3610,31 +3660,28 @@ errout: static int hrtim_tim_chopper_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer) { - FAR struct stm32_hrtim_tim_s* tim; FAR struct stm32_hrtim_slave_priv_s* slave; int ret = OK; uint32_t regval = 0; - /* Master Timer has no outputs */ + /* Sanity checking */ - if (timer == HRTIM_TIMER_MASTER) + if (timer == HRTIM_TIMER_MASTER || timer == HRTIM_TIMER_COMMON) { ret = -EINVAL; goto errout; } - /* Get Timer data strucutre */ + /* Get Slave Timer data strucutre */ - tim = hrtim_tim_get(priv, timer); - if (tim == NULL) + slave = hrtim_slave_get(priv, timer); + if (slave == NULL) { ret = -EINVAL; goto errout; } - slave = (struct stm32_hrtim_slave_priv_s*)tim->priv; - /* Configure start pulsewidth */ regval |= slave->pwm.chp.start_pulse << HRTIM_TIMCHP_STRTPW_SHIFT; @@ -3891,19 +3938,22 @@ static int hrtim_burst_config(FAR struct stm32_hrtim_s *priv) * timer - timer index * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ static int hrtim_tim_faults_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer) { - FAR struct stm32_hrtim_tim_s *tim; FAR struct stm32_hrtim_slave_priv_s *slave; uint32_t regval = 0; + int ret = OK; - tim = hrtim_tim_get(priv, timer); - - slave = tim->priv; + slave = hrtim_slave_get(priv, timer); + if (slave == NULL) + { + ret = -EINVAL; + goto errout; + } /* Get lock configuration */ @@ -3917,7 +3967,8 @@ static int hrtim_tim_faults_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer) hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_FLTR_OFFSET, regval); - return OK; +errout: + return ret; } /**************************************************************************** @@ -3931,7 +3982,7 @@ static int hrtim_tim_faults_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer) * index - Fault index * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -4073,7 +4124,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -4147,7 +4198,7 @@ static int hrtim_faults_config(FAR struct stm32_hrtim_s *priv) * index - External Event index * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -4322,7 +4373,7 @@ errout: * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -4392,7 +4443,7 @@ static int hrtim_events_config(FAR struct stm32_hrtim_s *priv) * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -4483,7 +4534,7 @@ static void hrtim_tim_mode_set(FAR struct stm32_hrtim_s *priv, uint8_t timer, * priv - A reference to the HRTIM structure * * Returned Value: - * None + * None * ****************************************************************************/ @@ -4514,6 +4565,77 @@ static void hrtim_mode_config(FAR struct stm32_hrtim_s *priv) #endif } +/**************************************************************************** + * Name: hrtim_cmpcap_mask_get + * + * Description: + * This function returns not significant bits in counter/capture + * regsiters for given HRTIM Timer index. + * + * Input Parameters: + * priv - A reference to the HRTIM structure + * timer - HRTIM Timer index + * + * Returned Value: + * Not significant bits for counter/capture registers + * + ****************************************************************************/ + +static uint8_t hrtim_cmpcap_mask_get(FAR struct stm32_hrtim_s *priv, + uint8_t timer) +{ + FAR struct stm32_hrtim_tim_s* tim; + uint8_t mask = 0; + + /* Get Timer data strucutre */ + + tim = hrtim_tim_get(priv, timer); + if (tim == NULL) + { + mask = 0; + goto errout; + } + + /* Not significant bits depens on timer prescaler */ + + switch(tim->tim.prescaler) + { + case HRTIM_PRESCALER_1: + { + mask = 0b11111; + break; + } + case HRTIM_PRESCALER_2: + { + mask = 0b1111; + break; + } + case HRTIM_PRESCALER_4: + { + mask = 0b111; + break; + } + case HRTIM_PRESCALER_8: + { + mask = 0b11; + break; + } + case HRTIM_PRESCALER_16: + { + mask = 0b1; + break; + } + default: + { + mask = 0; + break; + } + } + +errout: + return mask; +} + /**************************************************************************** * Name: hrtim_cmp_update * @@ -4527,7 +4649,7 @@ static void hrtim_mode_config(FAR struct stm32_hrtim_s *priv) * cmp - New compare register value * * Returned Value: - * Zero on success; a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -4537,6 +4659,7 @@ static int hrtim_cmp_update(FAR struct hrtim_dev_s *dev, uint8_t timer, FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; int ret = OK; uint32_t offset = 0; + uint8_t mask = 0; switch (index) { @@ -4571,6 +4694,16 @@ static int hrtim_cmp_update(FAR struct hrtim_dev_s *dev, uint8_t timer, } } + /* REVISIT: what should we do if cmp value is not significant ? + * At this moment we set compare register to the nearest significant value. + */ + + mask = hrtim_cmpcap_mask_get(priv, timer); + if (cmp <= mask) + { + cmp = mask + 1; + } + hrtim_tim_putreg(priv, timer, offset, cmp); errout: @@ -4589,7 +4722,7 @@ errout: * per - New period register value * * Returned Value: - * Zero on success; a negated errno value on failure + * 0 on success; a negated errno value on failure * ****************************************************************************/ @@ -4613,7 +4746,7 @@ static int hrtim_per_update(FAR struct hrtim_dev_s *dev, uint8_t timer, * timer - HRTIM Timer index * * Returned Value: - * Zero on success; a negated errno value on failure + * Timer period value * ****************************************************************************/ @@ -4636,7 +4769,7 @@ static uint16_t hrtim_per_get(FAR struct hrtim_dev_s *dev, uint8_t timer) * index - Compare register timer * * Returned Value: - * Zero on success; a negated errno value on failure + * Timer compare value * ****************************************************************************/ @@ -4686,6 +4819,42 @@ errout: return cmpx; } +/**************************************************************************** + * Name: hrtim_fclk_get + * + * Description: + * Get HRTIM Timer clock value + * + * Input parameters: + * dev - HRTIM device structure + * timer - HRTIM Timer index + * + * Returned Value: + * Timer clock value + * + ****************************************************************************/ + +static uint64_t hrtim_fclk_get(FAR struct hrtim_dev_s *dev, uint8_t timer) +{ + FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; + FAR struct stm32_hrtim_tim_s *tim; + uint64_t fclk = 0; + + /* Get Slave Timer data structure */ + + tim = hrtim_tim_get(priv, timer); + if (tim == NULL) + { + fclk = 0; + goto errout; + } + + fclk = tim->tim.fclk; + +errout: + return fclk; +} + /**************************************************************************** * Name: hrtim_tim_reset_set * @@ -4707,7 +4876,9 @@ static int hrtim_tim_reset_set(FAR struct stm32_hrtim_s *priv, uint8_t timer, { int ret = OK; - if (timer == HRTIM_TIMER_MASTER) + /* Sanity checking */ + + if (timer == HRTIM_TIMER_MASTER || timer == HRTIM_TIMER_COMMON) { ret = -EINVAL; goto errout; @@ -4811,7 +4982,7 @@ static int hrtim_update_config(FAR struct stm32_hrtim_s *priv) * priv - A reference to the HRTIM structure * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ diff --git a/arch/arm/src/stm32/stm32_hrtim.h b/arch/arm/src/stm32/stm32_hrtim.h index 40ffe37b8dc..da02364460f 100644 --- a/arch/arm/src/stm32/stm32_hrtim.h +++ b/arch/arm/src/stm32/stm32_hrtim.h @@ -187,7 +187,7 @@ # error "APB2 prescaler factor can not be greater than 2" # else # define HRTIM_HAVE_CLK_FROM_PLL 1 -# define HRTIM_CLOCK 2*STM32_PLL_FREQUENCY +# define HRTIM_MAIN_CLOCK 2*STM32_PLL_FREQUENCY # endif # else # error "Clock system must be set to PLL" @@ -195,19 +195,27 @@ #else # error "Not supported yet: system freezes when no PLL selected." # define HRTIM_HAVE_CLK_FROM_APB2 1 -# if STM32_RCC_CFGR_PPRE2 == RCC_CFGR_PPRE2_HCLK -# define HRTIM_CLOCK STM32_PCLK2_FREQUENCY +# if STM32_RCC_CFGR_PPRE2 == RCC_CFGR_PPRE2_HCLK +# define HRTIM_MAIN_CLOCK STM32_PCLK2_FREQUENCY # else -# define HRTIM_CLOCK 2*STM32_PCLK2_FREQUENCY +# define HRTIM_MAIN_CLOCK 2*STM32_PCLK2_FREQUENCY # endif #endif +/* High-resolution equivalent clock */ + +#define HRTIM_CLOCK (HRTIM_MAIN_CLOCK*32ull) + /* Helpers **************************************************************************/ #define HRTIM_CMP_SET(hrtim, tim, index, cmp) \ (hrtim)->hd_ops->cmp_update(hrtim, tim, index, cmp) #define HRTIM_PER_SET(hrtim, tim, per) \ (hrtim)->hd_ops->per_update(hrtim, tim, per) +#define HRTIM_PER_GET(hrtim, tim) \ + (hrtim)->hd_ops->per_get(hrtim, tim) +#define HRTIM_FCLK_GET(hrtim, tim) \ + (hrtim)->hd_ops->fclk_get(hrtim, tim) #define HRTIM_OUTPUTS_ENABLE(hrtim, outputs, state) \ (hrtim)->hd_ops->outputs_enable(hrtim, outputs, state) #define HRTIM_OUTPUT_SET_SET(hrtim, output, set) \ @@ -225,6 +233,11 @@ #define HRTIM_DEADTIME_UPDATE(hrtim, tim, dt, val) \ (hrtim)->hd_ops->deadtime_update(hrtim, tim, dt, val) +#define HRTIM_PER_MAX 0xFFFF +#define HRTIM_CMP_MAX 0xFFFF +#define HRTIM_CPT_MAX 0xFFFF +#define HRTIM_REP_MAX 0xFF + /************************************************************************************ * Public Types ************************************************************************************/ @@ -384,14 +397,14 @@ enum stm32_hrtim_tim_rst_e enum stm32_hrtim_tim_prescaler_e { - HRTIM_PRESCALER_1, - HRTIM_PRESCALER_2, - HRTIM_PRESCALER_4, - HRTIM_PRESCALER_8, - HRTIM_PRESCALER_16, - HRTIM_PRESCALER_32, - HRTIM_PRESCALER_64, - HRTIM_PRESCALER_128 + HRTIM_PRESCALER_1, /* CKPSC = 0 */ + HRTIM_PRESCALER_2, /* CKPSC = 1 */ + HRTIM_PRESCALER_4, /* CKPSC = 2 */ + HRTIM_PRESCALER_8, /* CKPSC = 3 */ + HRTIM_PRESCALER_16, /* CKPSC = 4 */ + HRTIM_PRESCALER_32, /* CKPSC = 5 */ + HRTIM_PRESCALER_64, /* CKPSC = 6 */ + HRTIM_PRESCALER_128 /* CKPSC = 7 */ }; /* HRTIM Timer Master/Slave mode */ @@ -971,6 +984,7 @@ struct stm32_hrtim_ops_s uint16_t (*per_get)(FAR struct hrtim_dev_s *dev, uint8_t timer); uint16_t (*cmp_get)(FAR struct hrtim_dev_s *dev, uint8_t timer, uint8_t index); + uint64_t (*fclk_get)(FAR struct hrtim_dev_s *dev, uint8_t timer); #ifdef CONFIG_STM32_HRTIM_INTERRUPTS void (*irq_ack)(FAR struct hrtim_dev_s *dev, uint8_t timer, int source); #endif diff --git a/configs/stm32f334-disco/include/board.h b/configs/stm32f334-disco/include/board.h index 115b02abd48..c138e01cabf 100644 --- a/configs/stm32f334-disco/include/board.h +++ b/configs/stm32f334-disco/include/board.h @@ -277,12 +277,42 @@ /* HRTIM configuration ******************************************************/ -#define HRTIM_TIMA_PRESCALER HRTIM_PRESCALER_32 +/* Timer A configuration - Buck operations */ + +#define HRTIM_TIMA_PRESCALER HRTIM_PRESCALER_1 #define HRTIM_TIMA_MODE HRTIM_MODE_CONT -#define HRTIM_TIMB_PRESCALER HRTIM_PRESCALER_32 +#define HRTIM_TIMA_CH1_SET HRTIM_OUT_SET_NONE +#define HRTIM_TIMA_CH1_RST HRTIM_OUT_RST_NONE +#define HRTIM_TIMA_CH2_SET HRTIM_OUT_SET_NONE +#define HRTIM_TIMA_CH2_RST HRTIM_OUT_RST_NONE + +#define HRTIM_TIMA_DT_FSLOCK HRTIM_DT_LOCK +#define HRTIM_TIMA_DT_RSLOCK HRTIM_DT_LOCK +#define HRTIM_TIMA_DT_FVLOCK HRTIM_DT_RW +#define HRTIM_TIMA_DT_RVLOCK HRTIM_DT_RW +#define HRTIM_TIMA_DT_FSIGN HRTIM_DT_SIGN_POSITIVE +#define HRTIM_TIMA_DT_RSIGN HRTIM_DT_SIGN_POSITIVE +#define HRTIM_TIMA_DT_PRESCALER HRTIM_DEADTIME_PRESCALER_1 + +/* Timer B configuration - Boost operations */ + +#define HRTIM_TIMB_PRESCALER HRTIM_PRESCALER_1 #define HRTIM_TIMB_MODE HRTIM_MODE_CONT +#define HRTIM_TIMB_CH1_SET HRTIM_OUT_SET_NONE +#define HRTIM_TIMB_CH1_RST HRTIM_OUT_RST_NONE +#define HRTIM_TIMB_CH2_SET HRTIM_OUT_SET_NONE +#define HRTIM_TIMB_CH2_RST HRTIM_OUT_RST_NONE + +#define HRTIM_TIMB_DT_FSLOCK HRTIM_DT_LOCK +#define HRTIM_TIMB_DT_RSLOCK HRTIM_DT_LOCK +#define HRTIM_TIMB_DT_FVLOCK HRTIM_DT_RW +#define HRTIM_TIMB_DT_RVLOCK HRTIM_DT_RW +#define HRTIM_TIMB_DT_FSIGN HRTIM_DT_SIGN_POSITIVE +#define HRTIM_TIMB_DT_RSIGN HRTIM_DT_SIGN_POSITIVE +#define HRTIM_TIMB_DT_PRESCALER HRTIM_DEADTIME_PRESCALER_1 + #define HRTIM_ADC_TRG2 HRTIM_ADCTRG24_AC4 /* DMA channels *************************************************************/ diff --git a/configs/stm32f334-disco/src/stm32_smps.c b/configs/stm32f334-disco/src/stm32_smps.c index 952af64c1b1..b1ae43e216c 100644 --- a/configs/stm32f334-disco/src/stm32_smps.c +++ b/configs/stm32f334-disco/src/stm32_smps.c @@ -105,8 +105,8 @@ /* ADC1 injected channels numeration */ -#define VIN_ADC_INJ_CHANNEL 0 -#define VOUT_ADC_INJ_CHANNEL 1 +#define V_IN_ADC_INJ_CHANNEL 0 +#define V_OUT_ADC_INJ_CHANNEL 1 /* Voltage reference for ADC */ @@ -118,11 +118,11 @@ /* Input voltage convertion ratio - 6.8k/(6.8k + 27k) */ -#define VIN_RATIO (float)((float)(6800+27000)/(float)6800) +#define V_IN_RATIO (float)((float)(6800+27000)/(float)6800) /* Output voltage convertion ratio - 3.3k/(3.3k + 13.3k) */ -#define VOUT_RATIO (float)((float)(3300+13300)/(float)3300) +#define V_OUT_RATIO (float)((float)(3300+13300)/(float)3300) /* Some absolute limits */ @@ -130,6 +130,61 @@ #define SMPS_ABSOLUTE_OUT_VOLTAGE_LIMIT_mV 15000 #define SMPS_ABSOLUTE_IN_VOLTAGE_LIMIT_mV 15000 +#if CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT > SMPS_ABSOLUTE_OUT_CURRENT_LIMIT_mA +# error "Output current limit great than absolute limit!" +#endif +#if CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT > SMPS_ABSOLUTE_OUT_VOLTAGE_LIMIT_mV +# error "Output voltage limit greater than absolute limit!" +#endif +#if CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT > SMPS_ABSOLUTE_IN_VOLTAGE_LIMIT_mV +# error "Input voltage limit greater than absolute limit!" +#endif + +/* Maximum output voltage for boost conveter in float */ + +#define BOOST_VOLT_MAX ((float)CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT/1000.0) + +/* Current limit table dimmension */ + +#define SMPS_CURRENT_LIMIT_TAB_DIM 15 + +/* At this time only PID controller implemented */ + +#define SMPS_CONTROLLER_PID 1 + +/* Converter's finite accuracy */ + +#define SMPS_VOLTAGE_ACCURACY ((float)0.01) + +/* Buck-boost mode threshold */ + +#define SMPS_BUCKBOOST_RANGE ((float)0.5) + +/* PID controller configuration */ + +#define PID_KP ((float)1.0) +#define PID_KI ((float)0.1) +#define PID_KD ((float)0.0) + +/* Converter frequncies: + * - TIMA_PWM_FREQ - buck converter 250kHz + * - TIMB_PWM_FREQ - boost converter 250kHz + */ + +#define TIMA_PWM_FREQ 250000 +#define TIMB_PWM_FREQ 250000 + +/* Deadtime configuration */ + +#define DT_RISING 0x0A0 +#define DT_FALLING 0x0A0 + +/* Helper macros */ + +#define HRTIM_ALL_OUTPUTS_ENABLE(hrtim, state) \ + HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMA_CH1|HRTIM_OUT_TIMA_CH2| \ + HRTIM_OUT_TIMB_CH1|HRTIM_OUT_TIMB_CH2, state); + /**************************************************************************** * Private Types ****************************************************************************/ @@ -138,6 +193,7 @@ enum converter_mode_e { + CONVERTER_MODE_INIT, /* Initial mode */ CONVERTER_MODE_BUCK, /* Buck mode operations (V_in > V_out) */ CONVERTER_MODE_BOOST, /* Boost mode operations (V_in < V_out) */ CONVERTER_MODE_BUCKBOOST, /* Buck-boost operations (V_in near V_out)*/ @@ -159,11 +215,13 @@ struct smps_lower_dev_s struct smps_priv_s { uint8_t conv_mode; /* Converter mode */ - uint16_t vin_raw; /* Voltage input RAW value */ - uint16_t vout_raw; /* Voltage output RAW value */ - float vin; /* Voltage input real value in V */ - float vout; /* Voltage output real value in V */ + uint16_t v_in_raw; /* Voltage input RAW value */ + uint16_t v_out_raw; /* Voltage output RAW value */ + float v_in; /* Voltage input real value in V */ + float v_out; /* Voltage output real value in V */ bool running; /* Running flag */ + float state[3]; /* Controller state vartiables */ + float *c_limit_tab; /* Current limit tab */ }; /**************************************************************************** @@ -215,8 +273,9 @@ struct smps_ops_s g_smps_ops = struct smps_dev_s g_smps_dev = { - .ops = &g_smps_ops, - .priv = &g_smps + .ops = &g_smps_ops, + .priv = &g_smps, + .lower = NULL }; /* ADC configuration: @@ -232,16 +291,16 @@ struct smps_dev_s g_smps_dev = * Transistors configuration in boost mode: * - T4 - ON * - T11 - OFF - * - T5 and T15 - boost operation + * - T5 and T12 - boost operation * Transistors configuration in buck-boost mode: * - T4, T11 - buck operation - * - T5 and T15 - boost operation + * - T5 and T12 - boost operation * * HRTIM outputs configuration: * - T4 -> PA8 -> HRTIM_CHA1 * - T5 -> PA11 -> HRTIM_CHB2 * - T11 -> PA9 -> HRTIM_CHA2 - * - T15 -> PA10 -> HRTIM_CHB1 + * - T12 -> PA10 -> HRTIM_CHB1 * */ @@ -257,8 +316,8 @@ static const uint8_t g_adc1chan[ADC1_NCHANNELS] = static const uint32_t g_adc1pins[ADC1_NCHANNELS] = { - GPIO_ADC1_IN2, /* PA1 - VIN */ - GPIO_ADC1_IN4, /* PA3 - VOUT */ + GPIO_ADC1_IN2, /* PA1 - V_IN */ + GPIO_ADC1_IN4, /* PA3 - V_OUT */ }; /**************************************************************************** @@ -290,7 +349,7 @@ static int smps_shutdown(FAR struct smps_dev_s *dev) * Description: * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ @@ -300,6 +359,7 @@ static int smps_setup(FAR struct smps_dev_s *dev) FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; FAR struct hrtim_dev_s *hrtim = NULL; FAR struct adc_dev_s *adc = NULL; + FAR struct smps_priv_s *priv; /* Initialize smps structure */ @@ -321,6 +381,8 @@ static int smps_setup(FAR struct smps_dev_s *dev) printf("ERROR: failed to get ADC lower level interface"); } + /* TODO: create current limit table */ + errout: return OK; } @@ -331,28 +393,89 @@ static int smps_start(FAR struct smps_dev_s *dev) FAR struct stm32_adc_dev_s *stm32_adc = (FAR struct stm32_adc_dev_s *) lower->adc->ad_priv; FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; + FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; FAR struct hrtim_dev_s *hrtim = lower->hrtim; + volatile uint64_t per = 0; + uint64_t fclk = 0; + int ret = OK; - /* Stop HRTIM PWM */ + /* Disable HRTIM outputs */ - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMA_CH1, false); - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMA_CH2, false); + HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false); - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMB_CH1, false); - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMB_CH2, false); + /* Reset SMPS private structure */ - /* 1 period is 4us - 100% time */ + memset(priv, 0, sizeof(struct smps_priv_s)); - HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMA, 18432); - HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMB, 18432); + /* Get TIMA period value for given frequency */ + + fclk = HRTIM_FCLK_GET(hrtim, HRTIM_TIMER_TIMA); + per = fclk/TIMA_PWM_FREQ; + if (per > HRTIM_PER_MAX) + { + printf("ERROR: can not achieve tima pwm freq=%u if fclk=%llu\n", + (uint32_t)TIMA_PWM_FREQ, (uint64_t)fclk); + ret = -EINVAL; + goto errout; + } + + /* Set TIMA period value */ + + HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMA, (uint16_t)per); + + /* Get TIMB period value for given frequency */ + + fclk = HRTIM_FCLK_GET(hrtim, HRTIM_TIMER_TIMB); + per = fclk/TIMB_PWM_FREQ; + if (per > HRTIM_PER_MAX) + { + printf("ERROR: can not achieve timb pwm freq=%u if fclk=%llu\n", + (uint32_t)TIMB_PWM_FREQ, (uint64_t)fclk); + ret = -EINVAL; + goto errout; + } + + /* Set TIMB period value */ + + HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMB, (uint16_t)per); /* ADC trigger on TIMA CMP4 */ HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMA, HRTIM_CMP4, 10000); + /* Configure TIMER A and TIMER B deadtime mode + * + * NOTE: In deadtime mode we have to configure output 1 only (SETx1, RSTx1), + * output 2 configuration is not significant. + */ + + HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMA, HRTIM_DT_EDGE_RISING, DT_RISING); + HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMA, HRTIM_DT_EDGE_FALLING, DT_FALLING); + HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMB, HRTIM_DT_EDGE_RISING, DT_RISING); + HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMB, HRTIM_DT_EDGE_FALLING, DT_FALLING); + + /* Set T4 and T12 to a low state. + * Deadtime mode force T11 and T5 to a high state. + */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_SET_NONE); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_RST_PER); + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_SET_NONE); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_RST_PER); + + /* Set running flag */ + + priv->running = true; + + HRTIM_ALL_OUTPUTS_ENABLE(hrtim, true); + /* Enable ADC interrupts */ stm32_adc->ops->int_en(stm32_adc, ADC_INT_JEOS); + +errout: + return ret; } static int smps_stop(FAR struct smps_dev_s *dev) @@ -366,11 +489,7 @@ static int smps_stop(FAR struct smps_dev_s *dev) /* Disable HRTIM outputs */ - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMA_CH1, false); - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMA_CH2, false); - - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMB_CH1, false); - HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMB_CH2, false); + HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false); /* Disable ADC interrupts */ @@ -459,27 +578,27 @@ static int smps_limits_set(FAR struct smps_dev_s *dev, goto errout; } - if (limits->v_out * 1000 > SMPS_ABSOLUTE_OUT_VOLTAGE_LIMIT_mV) + if (limits->v_out * 1000 > CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT) { - limits->v_out = (float)SMPS_ABSOLUTE_OUT_VOLTAGE_LIMIT_mV/1000.0; + limits->v_out = (float)CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT/1000.0; printf("SMPS output voltage limiit > SMPS absoulute output voltage limit." - " Set output voltage limit to %d.\n", + " Set output voltage limit to %.2f.\n", limits->v_out); } - if (limits->v_in * 1000 > SMPS_ABSOLUTE_IN_VOLTAGE_LIMIT_mV) + if (limits->v_in * 1000 > CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT) { - limits->v_in = (float)SMPS_ABSOLUTE_IN_VOLTAGE_LIMIT_mV/1000.0; + limits->v_in = (float)CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT/1000.0; printf("SMPS input voltage limiit > SMPS absoulute input voltage limit." - " Set input voltage limit to %d.\n", + " Set input voltage limit to %.2f.\n", limits->v_in); } - if (limits->i_out * 1000 > SMPS_ABSOLUTE_OUT_CURRENT_LIMIT_mA) + if (limits->i_out * 1000 > CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT) { - limits->i_out = (float)SMPS_ABSOLUTE_OUT_CURRENT_LIMIT_mA/1000.0; + limits->i_out = (float)CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT/1000.0; printf("SMPS output current limiit > SMPS absoulute output current limit." - " Set output current limit to %d.\n", + " Set output current limit to %.2f.\n", limits->i_out); } @@ -510,8 +629,8 @@ static int smps_state_get(FAR struct smps_dev_s *dev, /* Copy localy stored feedbacks data to status structure */ - smps->state.fb.v_in = g_smps_priv.vin; - smps->state.fb.v_out = g_smps_priv.vout; + smps->state.fb.v_in = g_smps_priv.v_in; + smps->state.fb.v_out = g_smps_priv.v_out; /* Return state structure to caller */ @@ -544,36 +663,302 @@ static int smps_ioctl(FAR struct smps_dev_s *dev, int cmd, unsigned long arg) return OK; } +/**************************************************************************** + * Name: pid_controller + ****************************************************************************/ + +static float pid_controller(struct smps_priv_s *priv, float err) +{ + float out; + float A0 = PID_KP + PID_KD + PID_KI; + float A1 = -PID_KP - 2.0*PID_KD; + float A2 = PID_KD; + + /* Get PID controller output */ + + out = (A0 * err) + (A1 * priv->state[0]) + (A2 * priv->state[1]) + priv->state[2]; + + /* Store PID contrroller variables */ + + priv->state[1] = priv->state[0]; + priv->state[0] = err; + priv->state[2] = out; + + return out; +} + +/**************************************************************************** + * Name: smps_controller + ****************************************************************************/ + +static float smps_controller(struct smps_priv_s *priv, float err) +{ +#ifdef SMPS_CONTROLLER_PID + return pid_controller(priv, err); +#else +# error "At this time only PID controller implemented" +#endif +} + +/**************************************************************************** + * Name: smps_duty_set + ****************************************************************************/ + +static void smps_duty_set(struct smps_priv_s *priv, struct smps_lower_dev_s *lower, + float out) +{ + FAR struct hrtim_dev_s *hrtim = lower->hrtim; + uint8_t mode = priv->conv_mode; + uint16_t cmp = 0; + float duty = 0.0; + uint16_t per = 0; + + switch (mode) + { + case CONVERTER_MODE_INIT: + { + /* Do nothing */ + + break; + } + + case CONVERTER_MODE_BUCK: + { + if (out >= priv->v_in) out = priv->v_in; + if (out < 0.0) out = 0.0; + + duty = out/priv->v_in; + +#warning TODO: current limit in buck mode + + per = HRTIM_PER_GET(hrtim, HRTIM_TIMER_TIMA); + + cmp = (uint16_t)(per * duty); + + if (cmp > per-30) cmp = per - 30; + + /* Set T4 duty cycle. T11 is complementary to T4 */ + + HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMA, HRTIM_CMP1, cmp); + + break; + } + + case CONVERTER_MODE_BOOST: + { + per = HRTIM_PER_GET(hrtim, HRTIM_TIMER_TIMA); + + + if (out < priv->v_in) out = priv->v_in; + if (out >= BOOST_VOLT_MAX) out = BOOST_VOLT_MAX; + + duty = 1.0 - priv->v_in/out; + +#warning TODO: current limit in boost mode + + cmp = (uint16_t)(per * duty); + + /* Set T12 duty cycle. T5 is complementary to T12 */ + + HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMB, HRTIM_CMP1, cmp); + + break; + } + + case CONVERTER_MODE_BUCKBOOST: + { + /* do something */ + +#warning TODO: buck boost mode + + break; + } + + default: + { + printf("ERROR: unknown converter mode %d!\n", mode); + break; + } + } +} + +/**************************************************************************** + * Name: smps_conv_mode_set + * + * Description: + * Change converter mode (buck/boost/buck-boost). + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void smps_conv_mode_set(struct smps_priv_s *priv, struct smps_lower_dev_s *lower, + uint8_t mode) +{ + FAR struct hrtim_dev_s *hrtim = lower->hrtim; + + /* Disable all outputs */ + + HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false); + + switch (mode) + { + case CONVERTER_MODE_INIT: + { + + break; + } + + case CONVERTER_MODE_BUCK: + { + /* Set T12 low (T5 high) on the next PER */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_SET_NONE); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_RST_PER); + + + /* Set T4 to a high state on PER and reset on CMP1. + T11 is complementary to T4. */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_SET_PER); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_RST_CMP1); + + break; + } + + case CONVERTER_MODE_BOOST: + { + /* Set T4 high (T11 low) on the next PER */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_SET_PER); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_RST_NONE); + + /* Set T12 to a high state on PER and reset on CMP1. + T5 is complementary to T12. */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_SET_PER); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_RST_CMP1); + + break; + } + + case CONVERTER_MODE_BUCKBOOST: + { + /* Set T4 to a high state on PER and reset on CMP1. + T11 is complementary to T4. */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_SET_PER); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMA_CH1, HRTIM_OUT_RST_CMP1); + + /* Set T12 to a high state on PER and reset on CMP1. + T5 is complementary to T12. */ + + HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_SET_PER); + HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMB_CH1, HRTIM_OUT_RST_CMP1); + + break; + } + + default: + { + printf("ERROR: unknown converter mode %d!\n", mode); + break; + } + } + + /* Set mode in private data */ + + priv->conv_mode = mode; + + /* Enable outputs */ + + HRTIM_ALL_OUTPUTS_ENABLE(hrtim, true); + +} + +/**************************************************************************** + * Name: adc12_handler + ****************************************************************************/ + static void adc12_handler(void) { - FAR struct smps_lower_dev_s *lower = g_smps_dev.lower; - FAR struct stm32_adc_dev_s *stm32_adc = + FAR struct smps_dev_s *dev = &g_smps_dev; + FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; + FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; + FAR struct smps_lower_dev_s *lower = dev->lower; + FAR struct stm32_adc_dev_s *adc = (FAR struct stm32_adc_dev_s*)lower->adc->ad_priv; + uint32_t pending; float ref = ADC_REF_VOLTAGE; float bit = ADC_VAL_MAX; - uint32_t pending; + float err; + float out; + uint8_t mode; - pending = stm32_adc->ops->int_get(stm32_adc); + pending = adc->ops->int_get(adc); - if (pending & ADC_INT_JEOC) + if (pending & ADC_INT_JEOC && priv->running == true) { /* Get raw ADC values */ - g_smps_priv.vout_raw = stm32_adc->ops->inj_get(stm32_adc, VOUT_ADC_INJ_CHANNEL); - g_smps_priv.vin_raw = stm32_adc->ops->inj_get(stm32_adc, VIN_ADC_INJ_CHANNEL); + priv->v_out_raw = adc->ops->inj_get(adc, V_OUT_ADC_INJ_CHANNEL); + priv->v_in_raw = adc->ops->inj_get(adc, V_IN_ADC_INJ_CHANNEL); /* Convert raw values to real values */ - g_smps_priv.vout = (g_smps_priv.vout_raw * ref / bit) * VOUT_RATIO; - g_smps_priv.vin = (g_smps_priv.vin_raw * ref / bit) * VIN_RATIO; + priv->v_out = (priv->v_out_raw * ref / bit) * V_OUT_RATIO; + priv->v_in = (priv->v_in_raw * ref / bit) * V_IN_RATIO; -#warning "missing regulator logic!" + /* According to measured voltages we set converter in appropriate mode */ + if (smps->param.v_out > (priv->v_in+SMPS_BUCKBOOST_RANGE)) + { + /* Desired output voltage greather than input voltage - set boost converter */ + + mode = CONVERTER_MODE_BOOST; + } + + else if (smps->param.v_out < (priv->v_in-SMPS_BUCKBOOST_RANGE)) + { + /* Desired output voltage lower than input voltage - set buck converter */ + + mode = CONVERTER_MODE_BUCK; + } + + else + { + /* Desired output voltage close to input voltage - set buck-boost converter */ + + mode = CONVERTER_MODE_BUCKBOOST; + } + + /* Configure converter to the new mode if needed */ + + if (priv->conv_mode != mode) + { + smps_conv_mode_set(priv, lower, mode); + } + + /* Get regualtor error */ + + err = smps->param.v_out - priv->v_out; + + if (err >= SMPS_VOLTAGE_ACCURACY || err <= (-SMPS_VOLTAGE_ACCURACY)) + { + /* PID controller */ + + out = smps_controller(priv, err); + + /* Update duty cycle */ + + smps_duty_set(priv, lower, out); + } } /* Clear pending */ - stm32_adc->ops->int_ack(stm32_adc, pending); + adc->ops->int_ack(adc, pending); } /**************************************************************************** @@ -584,12 +969,12 @@ static void adc12_handler(void) * Name: stm32_smps_setup * * Description: - * Initialize SMPS driver. + * Initialize SMPS driver. * - * This function should be call by board_app_initialize(). + * This function should be call by board_app_initialize(). * * Returned Value: - * 0 on success, a negated errno value on failure + * 0 on success, a negated errno value on failure * ****************************************************************************/ From 2ef098dfdaf9a4e70cf9cadfa046f2707151cee4 Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Mon, 22 Jan 2018 07:14:32 -0600 Subject: [PATCH 23/44] fs/userfs: use correct req type in userfs_truncate, remove use of undeclared buf --- fs/userfs/fs_userfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/userfs/fs_userfs.c b/fs/userfs/fs_userfs.c index bf91d58c1ec..3cb7a10b21e 100644 --- a/fs/userfs/fs_userfs.c +++ b/fs/userfs/fs_userfs.c @@ -944,7 +944,7 @@ static int userfs_truncate(FAR struct file *filep, off_t length) /* Construct and send the request to the server */ req = (FAR struct userfs_truncate_request_s *)priv->iobuffer; - req->req = USERFS_REQ_FSTAT; + req->req = USERFS_REQ_TRUNCATE; req->openinfo = filep->f_priv; req->length = length; @@ -986,7 +986,6 @@ static int userfs_truncate(FAR struct file *filep, off_t length) /* Return the result of truncate operation */ - DEBUGASSERT(buf != NULL); return resp->ret; } From 65afc69dc81daa77257d2b1045f886b056288755 Mon Sep 17 00:00:00 2001 From: David Alessio Date: Mon, 22 Jan 2018 13:20:35 +0000 Subject: [PATCH 24/44] Merged in david_alessio/nuttx/refactor-pll-setup (pull request #581) Refactor pll setup * fix typo in #def * refactor PLL setup code... * refactored PLL/CLK config, easier, checks for correctness * call go_os_start if STACK_COLORIZED * smarter config of EXTCLK output freq * cosmetic Approved-by: Gregory Nutt --- arch/arm/src/xmc4/chip/xmc4_scu.h | 2 +- arch/arm/src/xmc4/xmc4_clockconfig.c | 37 +++- arch/arm/src/xmc4/xmc4_start.c | 8 + configs/xmc4500-relax/include/board.h | 235 +++++++++++++------------- 4 files changed, 156 insertions(+), 126 deletions(-) diff --git a/arch/arm/src/xmc4/chip/xmc4_scu.h b/arch/arm/src/xmc4/chip/xmc4_scu.h index 2d22084252d..afa4d0f8a7f 100644 --- a/arch/arm/src/xmc4/chip/xmc4_scu.h +++ b/arch/arm/src/xmc4/chip/xmc4_scu.h @@ -938,7 +938,7 @@ #define SCU_SLEEPCR_SYSSEL (1 << 0) /* Bit 0: System Clock Selection Value */ # define SCU_SLEEPCR_SYSSEL_OFI (0) /* 0=fOFI */ -# define SCU_SLEEPCR_SYSSEL_ PLL (1 << 0) /* 1=fPLL */ +# define SCU_SLEEPCR_SYSSEL_FPLL (1 << 0) /* 1=fPLL */ #define SCU_SLEEPCR_USBCR (1 << 16) /* Bit 6: USB Clock Control in Sleep Mode */ #define SCU_SLEEPCR_MMCCR (1 << 17) /* Bit 17: MMC Clock Control in Sleep Mode */ #define SCU_SLEEPCR_ETH0CR (1 << 18) /* Bit 18: Ethernet Clock Control in Sleep Mode */ diff --git a/arch/arm/src/xmc4/xmc4_clockconfig.c b/arch/arm/src/xmc4/xmc4_clockconfig.c index eeb71dbe0b4..9d6cc0621eb 100644 --- a/arch/arm/src/xmc4/xmc4_clockconfig.c +++ b/arch/arm/src/xmc4/xmc4_clockconfig.c @@ -58,6 +58,7 @@ #include "up_arch.h" #include "chip/xmc4_scu.h" #include "xmc4_clockconfig.h" +#include "chip/xmc4_ports.h" #include @@ -105,7 +106,7 @@ #define CLKSET_VALUE (0x00000000) #define USBCLKCR_VALUE (0x00010000) -#if BOARD_PBDIV == 1 +#if BOARD_PLL_PBDIV == 1 # define PBCLKCR_VALUE SCU_PBCLKCR_PBDIV_FCPU #else /* BOARD_PBDIV == 2 */ # define PBCLKCR_VALUE SCU_PBCLKCR_PBDIV_DIV2 @@ -387,8 +388,8 @@ void xmc4_clock_configure(void) /* Setup fSYS clock */ - regval = (BOARD_ENABLE_PLL << SCU_SYSCLKCR_SYSSEL); - regval |= SCU_SYSCLKCR_SYSDIV(BOARD_SYSDIV); + regval = (BOARD_ENABLE_PLL ? SCU_SYSCLKCR_SYSSEL : 0); + regval |= SCU_SYSCLKCR_SYSDIV(BOARD_PLL_SYSDIV); putreg32(regval, XMC4_SCU_SYSCLKCR); /* Setup peripheral clock divider */ @@ -411,7 +412,7 @@ void xmc4_clock_configure(void) /* Setup EBU clock */ - regval = SCU_EBUCLKCR_EBUDIV(BOARD_EBUDIV); + regval = SCU_EBUCLKCR_EBUDIV(BOARD_PLL_EBUDIV); putreg32(regval, XMC4_SCU_EBUCLKCR); #ifdef BOARD_ENABLE_USBPLL @@ -423,7 +424,7 @@ void xmc4_clock_configure(void) /* Setup EXT */ regval = (BOARD_EXT_SOURCE << SCU_EXTCLKCR_ECKSEL_SHIFT); - regval |= SCU_EXTCLKCR_ECKDIV(BOARD_EXTDIV); + regval |= SCU_EXTCLKCR_ECKDIV(BOARD_PLL_ECKDIV); putreg32(regval, XMC4_SCU_EXTCLKCR); #if BOARD_ENABLE_PLL @@ -561,4 +562,30 @@ void xmc4_clock_configure(void) /* Enable selected clocks */ putreg32(CLKSET_VALUE, XMC4_SCU_CLKSET); + +#if BOARD_PLL_CLOCKSRC_XTAL == 1 + regval = SCU_SLEEPCR_SYSSEL_FPLL; + putreg32(regval, XMC4_SCU_SLEEPCR); +#endif /* BOARD_PLL_CLOCKSRC_XTAL == 1 */ + +#if BOARD_EXTCKL_ENABLE +#if BOARD_EXTCLK_PIN == EXTCLK_PIN_P0_8 + /* enable EXTCLK output on P0.8 */ + regval = getreg32(XMC4_PORT0_HWSEL); + regval &= ~PORT_HWSEL_HW8_MASK; + putreg32(regval, XMC4_PORT0_HWSEL); + + regval = getreg32(XMC4_PORT0_PDR1); + regval &= ~PORT_PDR1_PD8_MASK; + putreg32(regval, XMC4_PORT0_PDR1); + + regval = getreg32(XMC4_PORT0_IOCR8); + regval &= ~PORT_IOCR8_PC8_MASK; + regval |= PORT_IOCR8_PC8(0x11); /* push-pull output, alt func 1 */ + putreg32(regval, XMC4_PORT0_IOCR8); +#else + /* enable EXTCLK output on P1.15 */ +# warn "Not yet implemented" +#endif +#endif } diff --git a/arch/arm/src/xmc4/xmc4_start.c b/arch/arm/src/xmc4/xmc4_start.c index d1a1b4a1c3f..5e65aecaac7 100644 --- a/arch/arm/src/xmc4/xmc4_start.c +++ b/arch/arm/src/xmc4/xmc4_start.c @@ -396,9 +396,17 @@ void __start(void) /* Then start NuttX */ +#ifdef CONFIG_STACK_COLORATION + /* Set the IDLE stack to the coloration value and jump into os_start() */ + + go_os_start((FAR void *)&_ebss, CONFIG_IDLETHREAD_STACKSIZE); +#else + /* Call os_start() */ + os_start(); /* Shouldn't get here */ for (; ; ); +#endif } diff --git a/configs/xmc4500-relax/include/board.h b/configs/xmc4500-relax/include/board.h index 7190d1c9394..0dfd182eb6c 100644 --- a/configs/xmc4500-relax/include/board.h +++ b/configs/xmc4500-relax/include/board.h @@ -82,99 +82,8 @@ #define BOARD_XTAL_FREQUENCY 12000000 /* 12MHz XTAL */ #undef BOARD_RTC_XTAL_FRQUENCY /* 32.768KHz RTC XTAL not available on the Relax Lite */ - -#if defined(BOARD_FCPU_144MHZ) -/* Default clock initialization - * - * fXTAL = 12Mhz - * -> fPLL = (fXTAL / (2 * 1) * 48) = 288MHz - * -> fSYS = (fPLL / 1) = 288MHz - * -> fCPU = (fSYS / 2) = 144MHz - * -> fPERIPH = (fCPU / 1) = 144MHz - * -> fCCU = (fSYS / 2) = 144MHz - * -> fETH = 72MHz (REVISIT) - * -> fUSB = 48MHz (REVISIT) - * -> fEBU = 72MHz (REVISIT) - * - * fUSBPLL Disabled, only enabled if SCU_CLK_USBCLKCR_USBSEL_USBPLL is selected - * - * fOFI = 24MHz - * -> fWDT = 24MHz (REVISIT) - */ - -/* Select the external crystal as the PLL clock source */ - -# define BOARD_PLL_CLOCKSRC_XTAL 1 /* PLL Clock source == external crystal */ -# undef BOARD_PLL_CLOCKSRC_OFI /* PLL Clock source != internal fast oscillator */ - -/* PLL Configuration: - * - * fPLL = (fPLLSRC / (pdiv * k2div) * ndiv - * - * fPLL = (12000000 / (2 * 1)) * 48 - * = 288MHz - */ - -# define BOARD_ENABLE_PLL 1 -# define BOARD_PLL_PDIV 2 -# define BOARD_PLL_NDIV 48 -# define BOARD_PLL_K2DIV 1 -# define BOARD_PLL_FREQUENCY 288000000 - -/* System frequency, fSYS, is divided down from PLL output */ - -# define BOARD_SYSDIV 1 /* PLL Output divider to get fSYS */ -# define BOARD_SYS_FREQUENCY 288000000 - -/* CPU frequency, fCPU, may be divided down from system frequency */ - -# define BOARD_CPUDIV_ENABLE 1 /* Enable PLL divide by 2 for fCPU */ -# define BOARD_CPU_FREQUENCY 144000000 - -/* CCU frequency may be divided down from system frequency */ - -# define BOARD_CCUDIV_ENABLE 1 /* Enable PLL div by 2 */ -# define BOARD_CCU_FREQUENCY 144000000 - -/* Watchdog clock settings */ - -# define BOARD_WDT_SOURCE WDT_CLKSRC_FOFI -# define BOARD_WDTDIV 1 -# define BOARD_WDT_FREQUENCY 24000000 - -/* EBU frequency may be divided down from system frequency */ - -# define BOARD_EBUDIV 2 /* fSYS / 2 */ -# define BOARD_EBU_FREQUENCY 72000000 - -/* EXT clock settings */ - -# define BOARD_EXT_SOURCE EXT_CLKSRC_FPLL -# define BOARD_EXTDIV 289 /* REVISIT */ -# define BOARD_EXT_FREQUENCY 498270 /* REVISIT */ - -/* The peripheral clock, fPERIPH, derives from fCPU with no division */ - -# define BOARD_PBDIV 1 /* No division */ -# define BOARD_PERIPH_FREQUENCY 144000000 - -#elif defined(BOARD_FCPU_120MHZ) -/* Default clock initialization - * - * fXTAL = 12Mhz - * -> fPLL = (fXTAL / (2 * 4) * 80) = 120 - * -> fSYS = (fPLL / 1) = 120MHz - * -> fCPU = (fSYS / 1) = 120MHz - * -> fPERIPH = (fCPU / 1) = 120MHz - * -> fCCU = (fSYS / 1) = 120MHz - * -> fETH = 60MHz (REVISIT) - * -> fUSB = 48MHz (REVISIT) - * -> fEBU = 60MHz (REVISIT) - * - * fUSBPLL Disabled, only enabled if SCU_CLK_USBCLKCR_USBSEL_USBPLL is selected - * - * fOFI = 24MHz - * -> fWDT = 24MHz (REVISIT) +/* + * TODO: enable the RTC osc, use RTC for time/date */ /* Select the external crystal as the PLL clock source */ @@ -184,56 +93,142 @@ /* PLL Configuration: * - * fPLL = (fPLLSRC / (pdiv * k2div) * ndiv + * fXTAL = 12Mhz + * 260 MHz <= fVCO <= 520 MHz * - * fPLL = (12000000 / (2 * 4)) * 80 - * = 120MHz + * fVCO = fXTAL * ndiv / pdiv + * fPLL = fVCO / k2div + * fSYS = fPLL / sysdiv + * fETH = fSYS / 2 (fixed div by 2) + * fCCU = fSYS / ccudiv (div by 1 or 2) + * fCPU = fSYS / cpudiv (div by 1 or 2) + * fPERIPH = fCPU / pbdiv (div by 1 or 2) */ -# define BOARD_ENABLE_PLL 1 -# define BOARD_PLL_PDIV 2 -# define BOARD_PLL_NDIV 80 +# define BOARD_ENABLE_PLL 1 /* enable the PLL */ +# define CPU_FREQ 120 /* MHz */ + +/* TODO: Automate PLL calculations */ + +#if CPU_FREQ == 120 +/* + * 120 MHz + * + * fVCO = 12MHz * 40 / 2 = 480MHz + * fPLL = 480MHz / 2 = 240MHz + * fSYS = fPLL / 2 = 120MHz + * fCCU = fSYS / 2 = 60MHz + * fCPU = fSYS / 1 = 120MHz + * fPB = fCPU / 2 = 60MHz + * fETH = fSYS / 2 = 60MHz + */ + +# define BOARD_PLL_NDIV 40 +# define BOARD_PLL_PDIV 1 # define BOARD_PLL_K2DIV 4 -# define BOARD_PLL_FREQUENCY 120000000 +# define BOARD_PLL_SYSDIV 1 +# define BOARD_PLL_CPUDIV 1 +# define BOARD_PLL_PBDIV 2 +# define BOARD_PLL_CCUDIV 2 +# define BOARD_PLL_EBUDIV 4 -/* System frequency, fSYS, is divided down from PLL output */ +#elif CPU_FREQ == 144 +/* + * 144 MHz + * + * fVCO = 12MHz * 36 / 1 = 432MHz + * fPLL = 432MHz / 3 = 144MHz + * fSYS = fPLL / 1 = 144MHz + * fCCU = fSYS / 2 = 72MHz + * fCPU = fSYS / 1 = 144MHz + * fPB = fCPU / 2 = 72MHz + * fETH = fSYS / 2 = 72MHz + */ -# define BOARD_SYSDIV 1 /* No division */ -# define BOARD_SYS_FREQUENCY 120000000 +# define BOARD_PLL_NDIV 36 +# define BOARD_PLL_PDIV 1 +# define BOARD_PLL_K2DIV 3 +# define BOARD_PLL_SYSDIV 1 +# define BOARD_PLL_CPUDIV 1 +# define BOARD_PLL_PBDIV 2 +# define BOARD_PLL_CCUDIV 2 +# define BOARD_PLL_EBUDIV 2 -/* CPU frequency, fCPU, may be divided down from system frequency */ +#else +# error "Illegal or Unsupported CPU Frequency" +#endif -# define BOARD_CPUDIV_ENABLE 0 /* No divison */ -# define BOARD_CPU_FREQUENCY 120000000 -/* CCU frequency may be divided down from system frequency */ +# define BOARD_CCUDIV_ENABLE (BOARD_PLL_CCUDIV - 1) +# define BOARD_CPUDIV_ENABLE (BOARD_PLL_CPUDIV - 1) -# define BOARD_CCUDIV_ENABLE 0 /* No divison */ -# define BOARD_CCU_FREQUENCY 120000000 - -/* Watchdog clock setting */ +# define BOARD_VCO_FREQUENCY (BOARD_XTAL_FREQUENCY * BOARD_PLL_NDIV / BOARD_PLL_PDIV) +# define BOARD_PLL_FREQUENCY (BOARD_VCO_FREQUENCY / BOARD_PLL_K2DIV) +# define BOARD_SYS_FREQUENCY (BOARD_PLL_FREQUENCY / BOARD_PLL_SYSDIV) +# define BOARD_CCU_FREQUENCY (BOARD_SYS_FREQUENCY / BOARD_PLL_CCUDIV) +# define BOARD_CPU_FREQUENCY (BOARD_SYS_FREQUENCY / BOARD_PLL_CPUDIV) +# define BOARD_PERIPH_FREQUENCY (BOARD_CPU_FREQUENCY / BOARD_PLL_PBDIV) +# define BOARD_ETH_FREQUENCY (BOARD_SYS_FREQUENCY / 2) # define BOARD_WDT_SOURCE WDT_CLKSRC_FOFI # define BOARD_WDTDIV 1 # define BOARD_WDT_FREQUENCY 24000000 -/* EBU frequency may be divided down from system frequency */ +# define BOARD_EXT_SOURCE EXT_CLKSRC_FPLL +# define BOARD_PLL_ECKDIV 480 /* [1,512] */ + +# define kHz_1 1000 +# define MHz_1 (kHz_1 * kHz_1) +# define MHz_50 ( 50 * MHz_1) +# define MHz_260 (260 * MHz_1) +# define MHz_520 (520 * MHz_1) + + /* range check VCO frequency */ +# if (BOARD_VCO_FREQUENCY < MHz_260) +# error "VCO freq must be >= 260 MHz" +# endif + +# if (BOARD_VCO_FREQUENCY > MHz_520) +# error "VCO freq must be <= 520 MHz" +# endif + + /* range check Ethernet MAC frequency */ +# if (BOARD_ETH_FREQUENCY <= MHz_50) +# error "ETH freq must be > 50 MHz" +# endif + + + +/* check ccudiv cpudiv pbdiv against Table 11-5 + * of XMC4500 User Manual + */ +#define CLKDIV_INDEX (4 * (BOARD_PLL_CCUDIV-1) + \ + 2 * (BOARD_PLL_CPUDIV-1) + \ + (BOARD_PLL_PBDIV-1) ) + +#if (CLKDIV_INDEX == 3) || (CLKDIV_INDEX == 4) || (CLKDIV_INDEX > 6) +# error "Illegal combination of dividers! Ref: Table 11-5 of UM" +#endif -# define BOARD_EBUDIV 2 /* fSYS/2 */ -# define BOARD_EBU_FREQUENCY 60000000 /* EXT clock settings */ +#define BOARD_EXTCKL_ENABLE 1 /* 0 disables output */ +#if BOARD_EXTCKL_ENABLE +# define EXTCLK_PIN_P0_8 8 +# define EXTCLK_PIN_P1_15 15 +# define BOARD_EXTCLK_PIN EXTCLK_PIN_P0_8 # define BOARD_EXT_SOURCE EXT_CLKSRC_FPLL -# define BOARD_EXTDIV 289 /* REVISIT */ -# define BOARD_EXT_FREQUENCY 415225 /* REVISIT */ +# define BOARD_EXT_FREQUENCY (250 * kHz_1) /* Desired output freq */ +# define BOARD_EXTDIV (BOARD_PLL_FREQUENCY / BOARD_EXT_FREQUENCY) -/* The peripheral clock, fPERIPH, derives from fCPU with no division */ - -# define BOARD_PBDIV 1 /* No division */ -# define BOARD_PERIPH_FREQUENCY 120000000 +/* range check EXTDIV */ +# if BOARD_EXTDIV > 512 +# error "EXTCLK Divisor out of range!" +# endif #endif + /* Standby clock source selection * * BOARD_STDBY_CLOCKSRC_OSI - Internal 32.768KHz slow oscillator From fccd44387abcdb5f8368903cb51aae5f2c536d40 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 08:17:31 -0600 Subject: [PATCH 25/44] The existence of the network driver ioctl() method should depend on CONFIG_NETDEV_IOCTL rather than CONFIG_NETDEV_PHY_IOCTL. The former enables the method, the later enables a subset of possible driver IOCTLs. This change should be basically a no-operation. The affected ioctl methods only support those subset of driver IOCTLs selected by CONFIG_NETDEV_PHY_IOCTL and the network logic will tolerate a nul ioctl method. --- arch/arm/src/c5471/c5471_ethernet.c | 2 +- arch/arm/src/kinetis/kinetis_enet.c | 70 ++++----- arch/arm/src/lpc17xx/lpc17_ethernet.c | 2 +- arch/arm/src/lpc43xx/lpc43_ethernet.c | 16 +- arch/arm/src/lpc54xx/lpc54_ethernet.c | 4 + arch/arm/src/sam34/sam_emac.c | 138 +++++++++--------- arch/arm/src/sama5/sam_emaca.c | 138 +++++++++--------- arch/arm/src/sama5/sam_emacb.c | 134 ++++++++--------- arch/arm/src/sama5/sam_gmac.c | 132 +++++++++-------- arch/arm/src/samv7/sam_emac.c | 136 ++++++++--------- arch/arm/src/stm32/stm32_eth.c | 82 ++++++----- arch/arm/src/stm32f7/stm32_ethernet.c | 14 +- arch/arm/src/tiva/tm4c_ethernet.c | 80 +++++----- arch/hc/src/m9s12/m9s12_ethernet.c | 2 +- arch/mips/src/pic32mx/pic32mx-ethernet.c | 2 +- arch/mips/src/pic32mz/pic32mz-ethernet.c | 2 +- arch/misoc/src/common/misoc_net.c | 2 +- arch/z80/src/ez80/ez80_emac.c | 2 +- drivers/net/dm90x0.c | 2 +- drivers/net/enc28j60.c | 2 +- drivers/net/encx24j600.c | 2 +- drivers/net/ftmac100.c | 2 +- drivers/net/tun.c | 2 +- .../wireless/ieee802154/xbee/xbee_netdev.c | 2 +- .../wireless/spirit/drivers/spirit_netdev.c | 2 +- wireless/ieee802154/mac802154_netdev.c | 2 +- 26 files changed, 505 insertions(+), 469 deletions(-) diff --git a/arch/arm/src/c5471/c5471_ethernet.c b/arch/arm/src/c5471/c5471_ethernet.c index b98fd6ecac9..f38497a37ed 100644 --- a/arch/arm/src/c5471/c5471_ethernet.c +++ b/arch/arm/src/c5471/c5471_ethernet.c @@ -2447,7 +2447,7 @@ void up_netinitialize(void) #endif g_c5471[0].c_dev.d_private = (void *)g_c5471; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ g_c5471[0].c_txpoll = wd_create(); /* Create periodic poll timer */ g_c5471[0].c_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/arm/src/kinetis/kinetis_enet.c b/arch/arm/src/kinetis/kinetis_enet.c index 8f51cc6a7b8..4a7e1ba7caa 100644 --- a/arch/arm/src/kinetis/kinetis_enet.c +++ b/arch/arm/src/kinetis/kinetis_enet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/kinetis/kinetis_enet.c * - * Copyright (C) 2011-2012, 2014-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2014-2018 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * David Sidrane * @@ -310,7 +310,7 @@ static int kinetis_addmac(struct net_driver_s *dev, static int kinetis_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int kinetis_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -1449,48 +1449,52 @@ static int kinetis_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int kinetis_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { - int ret; +#ifdef CONFIG_NETDEV_PHY_IOCTL FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)dev->d_private; +#endif + int ret; switch (cmd) - { - case SIOCGMIIPHY: /* Get MII PHY address */ { - struct mii_ioctl_data_s *req = - (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = priv->phyaddr; - ret = OK; - } - break; +#ifdef CONFIG_NETDEV_PHY_IOCTL + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = - (struct mii_ioctl_data_s *)((uintptr_t)arg); - ret = kinetis_readmii(priv, req->phy_id, req->reg_num, &req->val_out); - } - break; + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = kinetis_readmii(priv, req->phy_id, req->reg_num, &req->val_out); + } + break; - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = - (struct mii_ioctl_data_s *)((uintptr_t)arg); - ret = kinetis_writemii(priv, req->phy_id, req->reg_num, req->val_in); - } - break; + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = kinetis_writemii(priv, req->phy_id, req->reg_num, req->val_in); + } + break; +#endif /* ifdef CONFIG_NETDEV_PHY_IOCTL */ - default: - ret = -ENOTTY; - break; - } + default: + ret = -ENOTTY; + break; + } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: kinetis_initmii @@ -2127,12 +2131,12 @@ int kinetis_netinitialize(int intf) priv->dev.d_addmac = kinetis_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = kinetis_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = kinetis_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)g_enet; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/arm/src/lpc17xx/lpc17_ethernet.c b/arch/arm/src/lpc17xx/lpc17_ethernet.c index dd1c05d0d14..196b15bab83 100644 --- a/arch/arm/src/lpc17xx/lpc17_ethernet.c +++ b/arch/arm/src/lpc17xx/lpc17_ethernet.c @@ -3056,7 +3056,7 @@ static inline int lpc17_ethinitialize(int intf) priv->lp_irq = ??; /* Ethernet controller IRQ number */ #endif - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->lp_txpoll = wd_create(); /* Create periodic poll timer */ priv->lp_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/arm/src/lpc43xx/lpc43_ethernet.c b/arch/arm/src/lpc43xx/lpc43_ethernet.c index f5a9cb1e580..e5981788117 100644 --- a/arch/arm/src/lpc43xx/lpc43_ethernet.c +++ b/arch/arm/src/lpc43xx/lpc43_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc43/lpc43_eth.c * - * Copyright (C) 2011-2015, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2015, 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -621,7 +621,7 @@ static int lpc43_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); #ifdef CONFIG_NET_IGMP static int lpc43_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int lpc43_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2744,16 +2744,17 @@ static void lpc43_rxdescinit(FAR struct lpc43_ethmac_s *priv) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int lpc43_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { -#ifdef CONFIG_ARCH_PHY_INTERRUPT +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)dev->d_private; #endif int ret; switch (cmd) { +#ifdef CONFIG_NETDEV_PHY_IOCTL #ifdef CONFIG_ARCH_PHY_INTERRUPT case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { @@ -2791,6 +2792,7 @@ static int lpc43_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) ret = lpc43_phywrite(req->phy_id, req->reg_num, req->val_in); } break; +#endif /* ifdef CONFIG_NETDEV_PHY_IOCTL */ default: ret = -ENOTTY; @@ -2799,7 +2801,7 @@ static int lpc43_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: lpc43_phyintenable @@ -3823,12 +3825,12 @@ static inline int lpc43_ethinitialize(void) priv->dev.d_addmac = lpc43_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = lpc43_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = lpc43_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)&g_lpc43ethmac; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmission */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/arm/src/lpc54xx/lpc54_ethernet.c b/arch/arm/src/lpc54xx/lpc54_ethernet.c index d89317247dc..dde91da5c17 100644 --- a/arch/arm/src/lpc54xx/lpc54_ethernet.c +++ b/arch/arm/src/lpc54xx/lpc54_ethernet.c @@ -2392,13 +2392,16 @@ static int lpc54_eth_rmmac(struct net_driver_s *dev, const uint8_t *mac) static int lpc54_eth_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { +#ifdef CONFIG_NETDEV_PHY_IOCTL struct lpc54_ethdriver_s *priv = (struct lpc54_ethdriver_s *)dev->d_private; +#endif int ret; /* Decode and dispatch the driver-specific IOCTL command */ switch (cmd) { +#ifdef CONFIG_NETDEV_PHY_IOCTL case SIOCGMIIPHY: /* Get MII PHY address */ { struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); @@ -2422,6 +2425,7 @@ static int lpc54_eth_ioctl(struct net_driver_s *dev, int cmd, ret = OK } break; +#endif /* ifdef CONFIG_NETDEV_PHY_IOCTL */ default: nerr("ERROR: Unrecognized IOCTL command: %d\n", command); diff --git a/arch/arm/src/sam34/sam_emac.c b/arch/arm/src/sam34/sam_emac.c index c45ea9f3838..88d43258d56 100644 --- a/arch/arm/src/sam34/sam_emac.c +++ b/arch/arm/src/sam34/sam_emac.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/sam34/sam_emac.c * - * Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic derives from the SAM34D3 Ethernet driver. @@ -408,7 +408,7 @@ static int sam_addmac(struct net_driver_s *dev, const uint8_t *mac); static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2309,86 +2309,90 @@ static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { +#ifdef CONFIG_NETDEV_PHY_IOCTL struct sam_emac_s *priv = (struct sam_emac_s *)dev->d_private; +#endif int ret; switch (cmd) - { -#ifdef CONFIG_ARCH_PHY_INTERRUPT - case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - /* Enable PHY link up/down interrupts */ + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - ret = sam_phyintenable(priv); + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = sam_phyintenable(priv); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = priv->phyaddr; - ret = OK; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR); + sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); + + /* Read from the requested register */ + + ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR, regval); + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR); + sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); + + /* Write to the requested register */ + + ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR, regval); + } + break; +#endif /* ifdef CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; } - break; - - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR); - sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); - - /* Read from the requested register */ - - ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR, regval); - } - break; - - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR); - sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); - - /* Write to the requested register */ - - ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR, regval); - } - break; - - default: - ret = -ENOTTY; - break; - } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: sam_phydump @@ -3630,7 +3634,7 @@ void up_netinitialize(void) priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = sam_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)&g_emac; /* Used to recover private state from dev */ diff --git a/arch/arm/src/sama5/sam_emaca.c b/arch/arm/src/sama5/sam_emaca.c index 1648cab5258..3a011a5b7cb 100644 --- a/arch/arm/src/sama5/sam_emaca.c +++ b/arch/arm/src/sama5/sam_emaca.c @@ -4,7 +4,7 @@ * 10/100 Base-T Ethernet driver for the SAMA5D3. Denoted as 'A' to * distinguish it from the SAMA5D4 EMAC driver. * - * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -413,7 +413,7 @@ static int sam_addmac(struct net_driver_s *dev, const uint8_t *mac); static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2345,86 +2345,90 @@ static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { +#ifdef CONFIG_NETDEV_PHY_IOCTL struct sam_emac_s *priv = (struct sam_emac_s *)dev->d_private; +#endif int ret; switch (cmd) - { -#ifdef CONFIG_ARCH_PHY_INTERRUPT - case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - /* Enable PHY link up/down interrupts */ + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - ret = sam_phyintenable(priv); + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = sam_phyintenable(priv); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = priv->phyaddr; - ret = OK; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR); + sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); + + /* Read from the requested register */ + + ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR, regval); + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR); + sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); + + /* Write to the requested register */ + + ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR, regval); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; } - break; - - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR); - sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); - - /* Read from the requested register */ - - ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR, regval); - } - break; - - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR); - sam_putreg(priv, SAM_EMAC_NCR, regval | EMAC_NCR_MPE); - - /* Write to the requested register */ - - ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR, regval); - } - break; - - default: - ret = -ENOTTY; - break; - } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: sam_phydump @@ -3672,7 +3676,7 @@ int sam_emac_initialize(void) priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = sam_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)&g_emac; /* Used to recover private state from dev */ diff --git a/arch/arm/src/sama5/sam_emacb.c b/arch/arm/src/sama5/sam_emacb.c index c9fb251acac..9f6f366e245 100644 --- a/arch/arm/src/sama5/sam_emacb.c +++ b/arch/arm/src/sama5/sam_emacb.c @@ -507,7 +507,7 @@ static int sam_addmac(struct net_driver_s *dev, const uint8_t *mac); static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2715,79 +2715,83 @@ static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac) #ifdef CONFIG_NETDEV_PHY_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { +#ifdef CONFIG_NETDEV_PHY_IOCTL struct sam_emac_s *priv = (struct sam_emac_s *)dev->d_private; +#endif int ret; switch (cmd) - { -#ifdef CONFIG_ARCH_PHY_INTERRUPT - case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ + { + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) - { - /* Enable PHY link up/down interrupts */ + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ - ret = sam_phyintenable(priv); + ret = sam_phyintenable(priv); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = priv->phyaddr; - ret = OK; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); + + /* Read from the requested register */ + + ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); + + /* Write to the requested register */ + + ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; } - break; - - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); - - /* Read from the requested register */ - - ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); - } - break; - - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); - - /* Write to the requested register */ - - ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); - } - break; - - default: - ret = -ENOTTY; - break; - } return ret; } @@ -4357,9 +4361,9 @@ int sam_emac_initialize(int intf) priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = sam_ioctl; /* Support PHY ioctl() calls */ -#ifdef CONFIG_ARCH_PHY_INTERRUPT +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) priv->phytype = phytype; /* Type of PHY on port */ #endif #endif diff --git a/arch/arm/src/sama5/sam_gmac.c b/arch/arm/src/sama5/sam_gmac.c index d9099621906..d70a40c5a33 100644 --- a/arch/arm/src/sama5/sam_gmac.c +++ b/arch/arm/src/sama5/sam_gmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/sama5/sam_gmac.c * - * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -338,7 +338,7 @@ static int sam_addmac(struct net_driver_s *dev, const uint8_t *mac); static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2300,82 +2300,86 @@ static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { +#ifdef CONFIG_NETDEV_PHY_IOCTL struct sam_gmac_s *priv = (struct sam_gmac_s *)dev->d_private; +#endif int ret; switch (cmd) - { -#ifdef CONFIG_ARCH_PHY_INTERRUPT - case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - /* Enable PHY link up/down interrupts */ + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - ret = sam_phyintenable(priv); + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = sam_phyintenable(priv); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = priv->phyaddr; - ret = OK; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + + /* Enable the management port */ + + sam_enablemdio(priv); + + /* Read from the requested register */ + + ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); + + /* Disable the management port */ + + sam_disablemdio(priv); + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + + /* Enable the management port */ + + sam_enablemdio(priv); + + /* Write to the requested register */ + + ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); + + /* Disable the management port */ + + sam_disablemdio(priv); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; } - break; - - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - - /* Enable the management port */ - - sam_enablemdio(priv); - - /* Read from the requested register */ - - ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); - - /* Disable the management port */ - - sam_disablemdio(priv); - } - break; - - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - - /* Enable the management port */ - - sam_enablemdio(priv); - - /* Write to the requested register */ - - ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); - - /* Disable the management port */ - - sam_disablemdio(priv); - } - break; - - default: - ret = -ENOTTY; - break; - } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: sam_phydump @@ -3744,12 +3748,12 @@ int sam_gmac_initialize(void) priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = sam_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)&g_gmac; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); if (!priv->txpoll) diff --git a/arch/arm/src/samv7/sam_emac.c b/arch/arm/src/samv7/sam_emac.c index 3496331898c..94c5956b2bd 100644 --- a/arch/arm/src/samv7/sam_emac.c +++ b/arch/arm/src/samv7/sam_emac.c @@ -2,7 +2,7 @@ * arch/arm/src/samv7/sam_emac.c * 10/100 Base-T Ethernet driver for the SAMV71. * - * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * This logic derives from the SAMA5 Ethernet driver which, in turn, derived @@ -622,7 +622,7 @@ static int sam_addmac(struct net_driver_s *dev, const uint8_t *mac); static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -3196,86 +3196,90 @@ static int sam_rmmac(struct net_driver_s *dev, const uint8_t *mac) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int sam_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { +#ifdef CONFIG_NETDEV_PHY_IOCTL struct sam_emac_s *priv = (struct sam_emac_s *)dev->d_private; +#endif int ret; switch (cmd) - { + { +#ifdef CONFIG_NETDEV_PHY_IOCTL #ifdef CONFIG_ARCH_PHY_INTERRUPT case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) - { - /* Enable PHY link up/down interrupts */ + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ - ret = sam_phyintenable(priv); + ret = sam_phyintenable(priv); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = priv->phyaddr; - ret = OK; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); + + /* Read from the requested register */ + + ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + uint32_t regval; + + /* Enable management port */ + + regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); + + /* Write to the requested register */ + + ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); + + /* Disable management port (probably) */ + + sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; } - break; - - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); - - /* Read from the requested register */ - - ret = sam_phyread(priv, req->phy_id, req->reg_num, &req->val_out); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); - } - break; - - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - uint32_t regval; - - /* Enable management port */ - - regval = sam_getreg(priv, SAM_EMAC_NCR_OFFSET); - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval | EMAC_NCR_MPE); - - /* Write to the requested register */ - - ret = sam_phywrite(priv, req->phy_id, req->reg_num, req->val_in); - - /* Disable management port (probably) */ - - sam_putreg(priv, SAM_EMAC_NCR_OFFSET, regval); - } - break; - - default: - ret = -ENOTTY; - break; - } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: sam_phydump @@ -5017,9 +5021,9 @@ int sam_emac_initialize(int intf) priv->dev.d_addmac = sam_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = sam_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = sam_ioctl; /* Support PHY ioctl() calls */ -#ifdef CONFIG_ARCH_PHY_INTERRUPT +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) priv->phytype = phytype; /* Type of PHY on port */ #endif #endif diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c index 62e44a0ff23..0c2aac13116 100644 --- a/arch/arm/src/stm32/stm32_eth.c +++ b/arch/arm/src/stm32/stm32_eth.c @@ -721,7 +721,7 @@ static int stm32_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); #ifdef CONFIG_NET_IGMP static int stm32_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2847,62 +2847,64 @@ static void stm32_rxdescinit(FAR struct stm32_ethmac_s *priv) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { -#ifdef CONFIG_ARCH_PHY_INTERRUPT +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)dev->d_private; #endif int ret; switch (cmd) - { -#ifdef CONFIG_ARCH_PHY_INTERRUPT - case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - /* Enable PHY link up/down interrupts */ + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - ret = stm32_phyintenable(priv); + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = stm32_phyintenable(priv); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = CONFIG_STM32_PHYADDR; - ret = OK; - } - break; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = CONFIG_STM32_PHYADDR; + ret = OK; + } + break; - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - ret = stm32_phyread(req->phy_id, req->reg_num, &req->val_out); - } - break; + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = stm32_phyread(req->phy_id, req->reg_num, &req->val_out); + } + break; - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - ret = stm32_phywrite(req->phy_id, req->reg_num, req->val_in); - } - break; + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = stm32_phywrite(req->phy_id, req->reg_num, req->val_in); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ - default: - ret = -ENOTTY; - break; - } + default: + ret = -ENOTTY; + break; + } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: stm32_phyintenable @@ -4014,12 +4016,12 @@ int stm32_ethinitialize(int intf) priv->dev.d_addmac = stm32_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = stm32_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = stm32_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)g_stm32ethmac; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c index 8c0eddd847e..d5337d8f48c 100644 --- a/arch/arm/src/stm32f7/stm32_ethernet.c +++ b/arch/arm/src/stm32f7/stm32_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_ethernet.c * - * Copyright (C) 2015-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2015-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -732,7 +732,7 @@ static int stm32_addmac(struct net_driver_s *dev, const uint8_t *mac); #ifdef CONFIG_NET_IGMP static int stm32_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2958,16 +2958,17 @@ static void stm32_rxdescinit(struct stm32_ethmac_s *priv, * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { -#ifdef CONFIG_ARCH_PHY_INTERRUPT +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)dev->d_private; #endif int ret; switch (cmd) { +#ifdef CONFIG_NETDEV_PHY_IOCTL #ifdef CONFIG_ARCH_PHY_INTERRUPT case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { @@ -3005,6 +3006,7 @@ static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) ret = stm32_phywrite(req->phy_id, req->reg_num, req->val_in); } break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ default: ret = -ENOTTY; @@ -3013,7 +3015,7 @@ static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: stm32_phyintenable @@ -4095,7 +4097,7 @@ int stm32_ethinitialize(int intf) priv->dev.d_addmac = stm32_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = stm32_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = stm32_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)g_stm32ethmac; /* Used to recover private state from dev */ diff --git a/arch/arm/src/tiva/tm4c_ethernet.c b/arch/arm/src/tiva/tm4c_ethernet.c index 3458db363cd..be2dd123502 100644 --- a/arch/arm/src/tiva/tm4c_ethernet.c +++ b/arch/arm/src/tiva/tm4c_ethernet.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/tiva/tm4c_ethernet.c * - * Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -733,7 +733,7 @@ static int tiva_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); #ifdef CONFIG_NET_IGMP static int tiva_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int tiva_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); #endif @@ -2860,59 +2860,61 @@ static void tiva_rxdescinit(FAR struct tiva_ethmac_s *priv) * ****************************************************************************/ -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL static int tiva_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { int ret; switch (cmd) - { -#ifdef CONFIG_TIVA_PHY_INTERRUPTS - case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - - ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); - if (ret == OK) +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_TIVA_PHY_INTERRUPTS + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { - /* Enable PHY link up/down interrupts */ + struct mii_iotcl_notify_s *req = (struct mii_iotcl_notify_s *)((uintptr_t)arg); - tiva_phy_intenable(true); + ret = phy_notify_subscribe(dev->d_ifname, req->pid, req->signo, req->arg); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + tiva_phy_intenable(true); + } } - } - break; + break; #endif - case SIOCGMIIPHY: /* Get MII PHY address */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - req->phy_id = CONFIG_TIVA_PHYADDR; - ret = OK; - } - break; + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = CONFIG_TIVA_PHYADDR; + ret = OK; + } + break; - case SIOCGMIIREG: /* Get register from MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - ret = tiva_phyread(req->phy_id, req->reg_num, &req->val_out); - } - break; + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = tiva_phyread(req->phy_id, req->reg_num, &req->val_out); + } + break; - case SIOCSMIIREG: /* Set register in MII PHY */ - { - struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); - ret = tiva_phywrite(req->phy_id, req->reg_num, req->val_in); - } - break; + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = tiva_phywrite(req->phy_id, req->reg_num, req->val_in); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ - default: - ret = -ENOTTY; - break; - } + default: + ret = -ENOTTY; + break; + } return ret; } -#endif /* CONFIG_NETDEV_PHY_IOCTL */ +#endif /* CONFIG_NETDEV_IOCTL */ /**************************************************************************** * Function: tiva_phy_intenable @@ -4040,7 +4042,7 @@ int tiva_ethinitialize(int intf) priv->dev.d_addmac = tiva_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = tiva_rmmac; /* Remove multicast MAC address */ #endif -#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_NETDEV_IOCTL priv->dev.d_ioctl = tiva_ioctl; /* Support PHY ioctl() calls */ #endif priv->dev.d_private = (void *)g_tiva_ethmac; /* Used to recover private state from dev */ diff --git a/arch/hc/src/m9s12/m9s12_ethernet.c b/arch/hc/src/m9s12/m9s12_ethernet.c index 3b3fcf0d741..a56a267c910 100644 --- a/arch/hc/src/m9s12/m9s12_ethernet.c +++ b/arch/hc/src/m9s12/m9s12_ethernet.c @@ -772,7 +772,7 @@ int emac_initialize(int intf) #endif priv->d_dev.d_private = (void*)g_emac; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->d_txpoll = wd_create(); /* Create periodic poll timer */ priv->d_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/mips/src/pic32mx/pic32mx-ethernet.c b/arch/mips/src/pic32mx/pic32mx-ethernet.c index f436b298b6a..d772a8ba14b 100644 --- a/arch/mips/src/pic32mx/pic32mx-ethernet.c +++ b/arch/mips/src/pic32mx/pic32mx-ethernet.c @@ -3348,7 +3348,7 @@ static inline int pic32mx_ethinitialize(int intf) priv->pd_irqsrc = ??; /* Ethernet controller IRQ source number */ #endif - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->pd_txpoll = wd_create(); /* Create periodic poll timer */ priv->pd_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/mips/src/pic32mz/pic32mz-ethernet.c b/arch/mips/src/pic32mz/pic32mz-ethernet.c index 5e1b2f5e046..046b2861e93 100644 --- a/arch/mips/src/pic32mz/pic32mz-ethernet.c +++ b/arch/mips/src/pic32mz/pic32mz-ethernet.c @@ -3384,7 +3384,7 @@ static inline int pic32mz_ethinitialize(int intf) priv->pd_irqsrc = ??; /* Ethernet controller IRQ source number */ #endif - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->pd_txpoll = wd_create(); /* Create periodic poll timer */ priv->pd_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/misoc/src/common/misoc_net.c b/arch/misoc/src/common/misoc_net.c index a7df3654352..595cbbbcff2 100644 --- a/arch/misoc/src/common/misoc_net.c +++ b/arch/misoc/src/common/misoc_net.c @@ -1172,7 +1172,7 @@ int misoc_net_initialize(int intf) #endif priv->misoc_net_dev.d_private = (FAR void *)g_misoc_net; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->misoc_net_txpoll = wd_create(); /* Create periodic poll timer */ priv->misoc_net_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/arch/z80/src/ez80/ez80_emac.c b/arch/z80/src/ez80/ez80_emac.c index 55896c08ff6..7ef110f8112 100644 --- a/arch/z80/src/ez80/ez80_emac.c +++ b/arch/z80/src/ez80/ez80_emac.c @@ -2537,7 +2537,7 @@ int up_netinitialize(void) #endif priv->dev.d_private = (FAR void*)&g_emac; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/drivers/net/dm90x0.c b/drivers/net/dm90x0.c index b6cfa6dfb74..c55c222a99c 100644 --- a/drivers/net/dm90x0.c +++ b/drivers/net/dm90x0.c @@ -1948,7 +1948,7 @@ int dm9x_initialize(void) #endif g_dm9x[0].dm_dev.d_private = (FAR void *)g_dm9x; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ g_dm9x[0].dm_txpoll = wd_create(); /* Create periodic poll timer */ g_dm9x[0].dm_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 23c4c770671..9c45d4b115b 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -2632,7 +2632,7 @@ int enc_initialize(FAR struct spi_dev_s *spi, #endif priv->dev.d_private = priv; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/drivers/net/encx24j600.c b/drivers/net/encx24j600.c index 5c2b590e2e5..31732a0b687 100644 --- a/drivers/net/encx24j600.c +++ b/drivers/net/encx24j600.c @@ -2815,7 +2815,7 @@ int enc_initialize(FAR struct spi_dev_s *spi, #endif priv->dev.d_private = priv; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index 9acc93d643b..cb7749706f2 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -1554,7 +1554,7 @@ int ftmac100_initialize(int intf) #endif priv->ft_dev.d_private = (FAR void *)g_ftmac100; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->ft_txpoll = wd_create(); /* Create periodic poll timer */ priv->ft_txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 6c5beeba5e0..f397f847df4 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -891,7 +891,7 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep, nxsem_setprotocol(&priv->read_wait_sem, SEM_PRIO_NONE); - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ diff --git a/drivers/wireless/ieee802154/xbee/xbee_netdev.c b/drivers/wireless/ieee802154/xbee/xbee_netdev.c index d408d21ec34..1c0c682057d 100644 --- a/drivers/wireless/ieee802154/xbee/xbee_netdev.c +++ b/drivers/wireless/ieee802154/xbee/xbee_netdev.c @@ -1392,7 +1392,7 @@ int xbee_netdev_register(XBEEHANDLE xbee) #endif dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->xd_mac = xbee; /* Save the MAC interface instance */ priv->xd_txpoll = wd_create(); /* Create periodic poll timer */ diff --git a/drivers/wireless/spirit/drivers/spirit_netdev.c b/drivers/wireless/spirit/drivers/spirit_netdev.c index 9e9b0655c08..e951f3fe0a9 100644 --- a/drivers/wireless/spirit/drivers/spirit_netdev.c +++ b/drivers/wireless/spirit/drivers/spirit_netdev.c @@ -2812,7 +2812,7 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi, priv->lower = lower; - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->txpoll = wd_create(); /* Create periodic poll timer */ priv->txtimeout = wd_create(); /* Create TX timeout timer */ diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c index 953c37f26da..aa4abe8ab2a 100644 --- a/wireless/ieee802154/mac802154_netdev.c +++ b/wireless/ieee802154/mac802154_netdev.c @@ -1400,7 +1400,7 @@ int mac802154netdev_register(MACHANDLE mac) #endif dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ - /* Create a watchdog for timing polling for and timing of transmisstions */ + /* Create a watchdog for timing polling for and timing of transmissions */ priv->md_mac = mac; /* Save the MAC interface instance */ priv->md_txpoll = wd_create(); /* Create periodic poll timer */ From 5ab4eb4f30177522c4dd2e79da6a26a32c83a8aa Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 11:11:23 -0600 Subject: [PATCH 26/44] net/tcp: Write buffering logic should not wait for a free buffer if the socket was opened non-blocking. Also, rename the TCP write buffering macros from WRB_* to TCPWB_* to make room in the namespace for write buffering with other protocols. --- TODO | 20 +++--- net/tcp/tcp.h | 37 ++++++------ net/tcp/tcp_send_buffered.c | 117 ++++++++++++++++++++---------------- net/tcp/tcp_wrbuffer_dump.c | 6 +- 4 files changed, 98 insertions(+), 82 deletions(-) diff --git a/TODO b/TODO index 4d46a3e5b0b..dd4dca76ac2 100644 --- a/TODO +++ b/TODO @@ -332,17 +332,17 @@ o Task/Scheduler (sched/) alternating between a high and a low priority. In either state, it may have its priority boosted. However, under some circumstances, it is impossible in the current design to - switch to the correct correct priority if a semaphore is - participating in priority inheritance: + switch to the correct priority if a semaphore held by the + sporadic thread is participating in priority inheritance: - There is an when switching from the high to the low priority - state. If the priority was NOT boosted above the higher - priority, it still may still need to boosted with respect to - the lower priority. If the highest priority thread waiting - on a semaphore held by the sporadic thread is higher in - priority than the low priority but less than the higher - priority, then new thread priority should be set to that - middle priority, not to the lower priority + There is an issue when switching from the high to the low + priority state. If the priority was NOT boosted above the + higher priority, it still may still need to boosted with + respect to the lower priority. If the highest priority + thread waiting on a semaphore held by the sporadic thread is + higher in priority than the low priority but less than the + higher priority, then new thread priority should be set to + that middle priority, not to the lower priority. In order to do this we would need to know the highest priority from among all tasks waiting for the all semaphores diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 91e13ffe7ba..bf8948da73a 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -1,7 +1,7 @@ /**************************************************************************** * net/tcp/tcp.h * - * Copyright (C) 2014-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2016, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -77,23 +77,26 @@ #ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* TCP write buffer access macros */ -# define WRB_SEQNO(wrb) ((wrb)->wb_seqno) -# define WRB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen) -# define WRB_SENT(wrb) ((wrb)->wb_sent) -# define WRB_NRTX(wrb) ((wrb)->wb_nrtx) -# define WRB_IOB(wrb) ((wrb)->wb_iob) -# define WRB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0)) -# define WRB_COPYIN(wrb,src,n) (iob_copyin((wrb)->wb_iob,src,(n),0,false)) +# define TCPWB_SEQNO(wrb) ((wrb)->wb_seqno) +# define TCPWB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen) +# define TCPWB_SENT(wrb) ((wrb)->wb_sent) +# define TCPWB_NRTX(wrb) ((wrb)->wb_nrtx) +# define TCPWB_IOB(wrb) ((wrb)->wb_iob) +# define TCPWB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0)) +# define TCPWB_COPYIN(wrb,src,n) \ + (iob_copyin((wrb)->wb_iob,src,(n),0,false)) +# define TCPWB_TRYCOPYIN(wrb,src,n) \ + (iob_trycopyin((wrb)->wb_iob,src,(n),0,false)) -# define WRB_TRIM(wrb,n) \ - do { (wrb)->wb_iob = iob_trimhead((wrb)->wb_iob,(n)); } while (0) +# define TCPWB_TRIM(wrb,n) \ + do { (wrb)->wb_iob = iob_trimhead((wrb)->wb_iob,(n)); } while (0) #ifdef CONFIG_DEBUG_FEATURES -# define WRB_DUMP(msg,wrb,len,offset) \ +# define TCPWB_DUMP(msg,wrb,len,offset) \ tcp_wrbuffer_dump(msg,wrb,len,offset) -#else -# define WRB_DUMP(msg,wrb,len,offset) -#endif +# else +# define TCPWB_DUMP(msg,wrb,len,offset) +# endif #endif /**************************************************************************** @@ -438,7 +441,7 @@ int tcp_local_ipv6_device(FAR struct tcp_conn_s *conn); * * Description: * Select the network driver to use with the IPv6 TCP transaction based - * on the remotely conected IPv6 address + * on the remotely connected IPv6 address * * Input Parameters: * conn - TCP connection structure. The remotely connected address, raddr, @@ -558,7 +561,7 @@ int tcp_start_monitor(FAR struct socket *psock); * * Description: * Stop monitoring TCP connection changes for a sockets associated with - * a given TCP connection stucture. + * a given TCP connection structure. * * Input Parameters: * conn - The TCP connection of interest @@ -1282,7 +1285,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, * * Returned Value: * OK - * At least one byte of data could be succesfully written. + * At least one byte of data could be successfully written. * -EWOULDBLOCK * There is no room in the output buffer. * -EBADF diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c index df54f338c37..5abb417e701 100644 --- a/net/tcp/tcp_send_buffered.c +++ b/net/tcp/tcp_send_buffered.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/tcp/tcp_send_buffered.c * - * Copyright (C) 2007-2014, 2016-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * Jason Jiang * @@ -98,8 +98,8 @@ # define BUF_DUMP(msg,buf,len) lib_dumpbuffer(msg,buf,len) #else # define BUF_DUMP(msg,buf,len) -# undef WRB_DUMP -# define WRB_DUMP(msg,wrb,len,offset) +# undef TCPWB_DUMP +# define TCPWB_DUMP(msg,wrb,len,offset) #endif /**************************************************************************** @@ -135,7 +135,7 @@ static void psock_insert_segment(FAR struct tcp_wrbuffer_s *wrb, for (itr = sq_peek(q); itr; itr = sq_next(itr)) { FAR struct tcp_wrbuffer_s *wrb0 = (FAR struct tcp_wrbuffer_s *)itr; - if (WRB_SEQNO(wrb0) < WRB_SEQNO(wrb)) + if (TCPWB_SEQNO(wrb0) < TCPWB_SEQNO(wrb)) { insert = itr; } @@ -417,13 +417,14 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * the write buffer has been ACKed. */ - if (ackno > WRB_SEQNO(wrb)) + if (ackno > TCPWB_SEQNO(wrb)) { /* Get the sequence number at the end of the data */ - lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb); + lastseq = TCPWB_SEQNO(wrb) + TCPWB_PKTLEN(wrb); ninfo("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n", - wrb, WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno); + wrb, TCPWB_SEQNO(wrb), lastseq, TCPWB_PKTLEN(wrb), + ackno); /* Has the entire buffer been ACKed? */ @@ -449,24 +450,24 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * buffers in the chain. */ - trimlen = ackno - WRB_SEQNO(wrb); - if (trimlen > WRB_SENT(wrb)) + trimlen = ackno - TCPWB_SEQNO(wrb); + if (trimlen > TCPWB_SENT(wrb)) { /* More data has been ACKed then we have sent? */ - trimlen = WRB_SENT(wrb); + trimlen = TCPWB_SENT(wrb); } ninfo("ACK: wrb=%p trim %u bytes\n", wrb, trimlen); - WRB_TRIM(wrb, trimlen); - WRB_SEQNO(wrb) = ackno; - WRB_SENT(wrb) -= trimlen; + TCPWB_TRIM(wrb, trimlen); + TCPWB_SEQNO(wrb) = ackno; + TCPWB_SENT(wrb) -= trimlen; /* Set the new sequence number for what remains */ ninfo("ACK: wrb=%p seqno=%u pktlen=%u\n", - wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb)); + wrb, TCPWB_SEQNO(wrb), TCPWB_PKTLEN(wrb)); } } } @@ -477,31 +478,31 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); - if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb)) + if (wrb && TCPWB_SENT(wrb) > 0 && ackno > TCPWB_SEQNO(wrb)) { uint32_t nacked; /* Number of bytes that were ACKed */ - nacked = ackno - WRB_SEQNO(wrb); - if (nacked > WRB_SENT(wrb)) + nacked = ackno - TCPWB_SEQNO(wrb); + if (nacked > TCPWB_SENT(wrb)) { /* More data has been ACKed then we have sent? ASSERT? */ - nacked = WRB_SENT(wrb); + nacked = TCPWB_SENT(wrb); } ninfo("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n", - wrb, WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno); + wrb, TCPWB_SEQNO(wrb), nacked, TCPWB_SENT(wrb), ackno); /* Trim the ACKed bytes from the beginning of the write buffer. */ - WRB_TRIM(wrb, nacked); - WRB_SEQNO(wrb) = ackno; - WRB_SENT(wrb) -= nacked; + TCPWB_TRIM(wrb, nacked); + TCPWB_SEQNO(wrb) = ackno; + TCPWB_SENT(wrb) -= nacked; ninfo("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n", - wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb)); + wrb, TCPWB_SEQNO(wrb), TCPWB_PKTLEN(wrb), TCPWB_SENT(wrb)); } } @@ -543,16 +544,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); - ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? WRB_SENT(wrb) : 0); + ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? TCPWB_SENT(wrb) : 0); - if (wrb != NULL && WRB_SENT(wrb) > 0) + if (wrb != NULL && TCPWB_SENT(wrb) > 0) { FAR struct tcp_wrbuffer_s *tmp; uint16_t sent; /* Yes.. Reset the number of bytes sent sent from the write buffer */ - sent = WRB_SENT(wrb); + sent = TCPWB_SENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; @@ -571,16 +572,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, conn->sent = 0; } - WRB_SENT(wrb) = 0; + TCPWB_SENT(wrb) = 0; ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", - wrb, WRB_SENT(wrb), conn->unacked, conn->sent); + wrb, TCPWB_SENT(wrb), conn->unacked, conn->sent); /* Increment the retransmit count on this write buffer. */ - if (++WRB_NRTX(wrb) >= TCP_MAXRTX) + if (++TCPWB_NRTX(wrb) >= TCP_MAXRTX) { nwarn("WARNING: Expiring wrb=%p nrtx=%u\n", - wrb, WRB_NRTX(wrb)); + wrb, TCPWB_NRTX(wrb)); /* The maximum retry count as been exhausted. Remove the write * buffer at the head of the queue. @@ -618,7 +619,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, /* Reset the number of bytes sent sent from the write buffer */ - sent = WRB_SENT(wrb); + sent = TCPWB_SENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; @@ -637,16 +638,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, conn->sent = 0; } - WRB_SENT(wrb) = 0; + TCPWB_SENT(wrb) = 0; ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", - wrb, WRB_SENT(wrb), conn->unacked, conn->sent); + wrb, TCPWB_SENT(wrb), conn->unacked, conn->sent); /* Free any write buffers that have exceed the retry count */ - if (++WRB_NRTX(wrb) >= TCP_MAXRTX) + if (++TCPWB_NRTX(wrb) >= TCP_MAXRTX) { nwarn("WARNING: Expiring wrb=%p nrtx=%u\n", - wrb, WRB_NRTX(wrb)); + wrb, TCPWB_NRTX(wrb)); /* Return the write buffer to the free list */ @@ -671,7 +672,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * is pulled from the write_q again. */ - ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); + ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, TCPWB_NRTX(wrb)); psock_insert_segment(wrb, &conn->write_q); } @@ -726,7 +727,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * window size. */ - sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb); + sndlen = TCPWB_PKTLEN(wrb) - TCPWB_SENT(wrb); if (sndlen > conn->mss) { sndlen = conn->mss; @@ -738,16 +739,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, } ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n", - wrb, WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen); + wrb, TCPWB_PKTLEN(wrb), TCPWB_SENT(wrb), sndlen); /* Set the sequence number for this segment. If we are * retransmitting, then the sequence number will already * be set for this write buffer. */ - if (WRB_SEQNO(wrb) == (unsigned)-1) + if (TCPWB_SEQNO(wrb) == (unsigned)-1) { - WRB_SEQNO(wrb) = conn->isn + conn->sent; + TCPWB_SEQNO(wrb) = conn->isn + conn->sent; } /* The TCP stack updates sndseq on receipt of ACK *before* @@ -757,7 +758,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * before the packet is sent. */ - tcp_setsequence(conn->sndseq, WRB_SEQNO(wrb) + WRB_SENT(wrb)); + tcp_setsequence(conn->sndseq, TCPWB_SEQNO(wrb) + TCPWB_SENT(wrb)); #ifdef NEED_IPDOMAIN_SUPPORT /* If both IPv4 and IPv6 support are enabled, then we will need to @@ -773,7 +774,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * won't actually happen until the polling cycle completes). */ - devif_iob_send(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb)); + devif_iob_send(dev, TCPWB_IOB(wrb), sndlen, TCPWB_SENT(wrb)); /* Remember how much data we send out now so that we know * when everything has been acknowledged. Just increment @@ -795,21 +796,21 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, } ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n", - wrb, WRB_NRTX(wrb), conn->unacked, conn->sent); + wrb, TCPWB_NRTX(wrb), conn->unacked, conn->sent); /* Increment the count of bytes sent from this write buffer */ - WRB_SENT(wrb) += sndlen; + TCPWB_SENT(wrb) += sndlen; ninfo("SEND: wrb=%p sent=%u pktlen=%u\n", - wrb, WRB_SENT(wrb), WRB_PKTLEN(wrb)); + wrb, TCPWB_SENT(wrb), TCPWB_PKTLEN(wrb)); /* Remove the write buffer from the write queue if the * last of the data has been sent from the buffer. */ - DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb)); - if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb)) + DEBUGASSERT(TCPWB_SENT(wrb) <= TCPWB_PKTLEN(wrb)); + if (TCPWB_SENT(wrb) >= TCPWB_PKTLEN(wrb)) { FAR struct tcp_wrbuffer_s *tmp; @@ -1060,13 +1061,25 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, /* Initialize the write buffer */ - WRB_SEQNO(wrb) = (unsigned)-1; - WRB_NRTX(wrb) = 0; - result = WRB_COPYIN(wrb, (FAR uint8_t *)buf, len); + TCPWB_SEQNO(wrb) = (unsigned)-1; + TCPWB_NRTX(wrb) = 0; + + /* Copy the user data into the write buffer. We cannot wait for + * buffer space if the socket was opened non-blocking. + */ + + if (_SS_ISNONBLOCK(psock->s_flags)) + { + result = TCPWB_TRYCOPYIN(wrb, (FAR uint8_t *)buf, len); + } + else + { + result = TCPWB_COPYIN(wrb, (FAR uint8_t *)buf, len); + } /* Dump I/O buffer chain */ - WRB_DUMP("I/O buffer chain", wrb, WRB_PKTLEN(wrb), 0); + TCPWB_DUMP("I/O buffer chain", wrb, TCPWB_PKTLEN(wrb), 0); /* psock_send_eventhandler() will send data in FIFO order from the * conn->write_q @@ -1074,7 +1087,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, sq_addlast(&wrb->wb_node, &conn->write_q); ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n", - wrb, WRB_PKTLEN(wrb), + wrb, TCPWB_PKTLEN(wrb), conn->write_q.head, conn->write_q.tail); /* Notify the device driver of the availability of TX data */ diff --git a/net/tcp/tcp_wrbuffer_dump.c b/net/tcp/tcp_wrbuffer_dump.c index ad92bfb904f..a27bb60253d 100644 --- a/net/tcp/tcp_wrbuffer_dump.c +++ b/net/tcp/tcp_wrbuffer_dump.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/tcp/tcp_wrbuffer_dump.c * - * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2014, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -64,8 +64,8 @@ void tcp_wrbuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb, unsigned int len, unsigned int offset) { syslog(LOG_DEBUG, "%s: wrb=%p segno=%d sent=%d nrtx=%d\n", - msg, wrb, WRB_SEQNO(wrb), WRB_SENT(wrb), WRB_NRTX(wrb)); - iob_dump("I/O Buffer Chain", WRB_IOB(wrb), len, offset); + msg, wrb, TCPWB_SEQNO(wrb), TCPWB_SENT(wrb), TCPWB_NRTX(wrb)); + iob_dump("I/O Buffer Chain", TCPWB_IOB(wrb), len, offset); } #endif /* CONFIG_DEBUG_FEATURES */ From 055a3ef844a51361d3f96e91e75b4f57ec8d5d6a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 14:14:32 -0600 Subject: [PATCH 27/44] net/udp: Remove some conditional logic that was true if there is only a single network device, but not true in the multi-device context. --- net/udp/udp_psock_sendto.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/net/udp/udp_psock_sendto.c b/net/udp/udp_psock_sendto.c index 4710fb36d68..ff362a310e4 100644 --- a/net/udp/udp_psock_sendto.c +++ b/net/udp/udp_psock_sendto.c @@ -70,36 +70,16 @@ # define NEED_IPDOMAIN_SUPPORT 1 #endif -/* Timeouts on sendto() do not make sense. Each polling cycle from the - * driver is an opportunity to send a packet. If the driver is not polling, - * then the network is not up (and there are no polling cycles to drive - * the timeout). - * - * There is a remote possibility that if there is a lot of other network - * traffic that a UDP sendto could get delayed, but I would not expect this - * generate a timeout. - */ - -#undef CONFIG_NET_SENDTO_TIMEOUT - -/* If supported, the sendto timeout function would depend on socket options - * and a system clock. - */ - -#ifndef CONFIG_NET_SOCKOPTS -# undef CONFIG_NET_SENDTO_TIMEOUT -#endif - /**************************************************************************** * Private Types ****************************************************************************/ struct sendto_s { -#if defined(CONFIG_NET_SENDTO_TIMEOUT) || defined(NEED_IPDOMAIN_SUPPORT) +#if defined(CONFIG_NET_SOCKOPTS) || defined(NEED_IPDOMAIN_SUPPORT) FAR struct socket *st_sock; /* Points to the parent socket structure */ #endif -#ifdef CONFIG_NET_SENDTO_TIMEOUT +#ifdef CONFIG_NET_SOCKOPTS systime_t st_time; /* Last send time for determining timeout */ #endif FAR struct devif_callback_s *st_cb; /* Reference to callback instance */ @@ -130,7 +110,7 @@ struct sendto_s * ****************************************************************************/ -#ifdef CONFIG_NET_SENDTO_TIMEOUT +#ifdef CONFIG_NET_SOCKOPTS static inline int send_timeout(FAR struct sendto_s *pstate) { FAR struct socket *psock; @@ -151,7 +131,7 @@ static inline int send_timeout(FAR struct sendto_s *pstate) return FALSE; } -#endif /* CONFIG_NET_SENDTO_TIMEOUT */ +#endif /* CONFIG_NET_SOCKOPTS */ /**************************************************************************** * Name: sendto_ipselect @@ -254,7 +234,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, * polling cycle and check again. */ -#ifdef CONFIG_NET_SENDTO_TIMEOUT +#ifdef CONFIG_NET_SOCKOPTS if (send_timeout(pstate)) { /* Yes.. report the timeout */ @@ -263,7 +243,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, pstate->st_sndlen = -ETIMEDOUT; } else -#endif /* CONFIG_NET_SENDTO_TIMEOUT */ +#endif /* CONFIG_NET_SOCKOPTS */ { /* No timeout. Just wait for the next polling cycle */ @@ -403,7 +383,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, state.st_buflen = len; state.st_buffer = buf; -#if defined(CONFIG_NET_SENDTO_TIMEOUT) || defined(NEED_IPDOMAIN_SUPPORT) +#if defined(CONFIG_NET_SOCKOPTS) || defined(NEED_IPDOMAIN_SUPPORT) /* Save the reference to the socket structure if it will be needed for * asynchronous processing. */ @@ -411,7 +391,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, state.st_sock = psock; #endif -#ifdef CONFIG_NET_SENDTO_TIMEOUT +#ifdef CONFIG_NET_SOCKOPTS /* Set the initial time for calculating timeouts */ state.st_time = clock_systimer(); From 880176e1cb6893e836df219df17cf4f022b6254f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 18:32:02 -0600 Subject: [PATCH 28/44] This commit adds an as-of-yet untested implemented of UDP write buffering. Squashed commit of the following: net/udp: Address most of the issues with UDP write buffering. There is a remaining issue with handling one network going down in a multi-network environment. None of this has been test but it is certainly ready for test. Hence, the feature is marked EXPERIMENTAL. net/udp: Some baby steps toward a corrected write buffering design. net/udp: Remove pesky write buffer macros. Eliminate trailing space at the end of lines. net/udp: A little more UDP write buffering logic. Still at least on big gaping hole in the design. net/udp: Undefined CONFIG_NET_SENDTO_TIMEOUT. net/udp: Crude, naive port of the TCP write buffering logic into UDP. This commit is certainly non-functional and is simply a starting point for the implementatin of UDP write buffering. net/udp: Rename udp/udp_psock_sendto.c udp/udp_psock_sendto_unbuffered.c. --- include/nuttx/net/net.h | 4 +- mm/iob/Kconfig | 14 +- net/Kconfig | 8 + net/inet/inet_sockif.c | 2 +- net/net_initialize.c | 4 + net/socket/socket.c | 2 +- net/tcp/Kconfig | 4 +- net/udp/Kconfig | 50 ++ net/udp/Make.defs | 19 +- net/udp/udp.h | 129 ++- net/udp/udp_conn.c | 21 +- net/udp/udp_psock_sendto_buffered.c | 821 ++++++++++++++++++ ...sendto.c => udp_psock_sendto_unbuffered.c} | 11 +- net/udp/udp_wrbuffer.c | 217 +++++ net/udp/udp_wrbuffer_dump.c | 70 ++ 15 files changed, 1354 insertions(+), 22 deletions(-) create mode 100644 net/udp/udp_psock_sendto_buffered.c rename net/udp/{udp_psock_sendto.c => udp_psock_sendto_unbuffered.c} (98%) create mode 100644 net/udp/udp_wrbuffer.c create mode 100644 net/udp/udp_wrbuffer_dump.c diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index fb4de5c4737..9e1eec09db0 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -208,8 +208,8 @@ struct socket FAR const struct sock_intf_s *s_sockif; -#ifdef CONFIG_NET_TCP_WRITE_BUFFERS - /* Callback instance for TCP send */ +#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_UDP_WRITE_BUFFERS) + /* Callback instance for TCP send() or UDP sendto() */ FAR struct devif_callback_s *s_sndcb; #endif diff --git a/mm/iob/Kconfig b/mm/iob/Kconfig index b64f90e3ce8..62893db0940 100644 --- a/mm/iob/Kconfig +++ b/mm/iob/Kconfig @@ -16,9 +16,9 @@ if MM_IOB config IOB_NBUFFERS int "Number of pre-allocated I/O buffers" - default 24 if (NET_TCP_WRITE_BUFFERS && !NET_TCP_READAHEAD) || (!NET_TCP_WRITE_BUFFERS && NET_TCP_READAHEAD) - default 36 if NET_TCP_WRITE_BUFFERS && NET_TCP_READAHEAD - default 8 if !NET_TCP_WRITE_BUFFERS && !NET_TCP_READAHEAD + default 24 if (NET_WRITE_BUFFERS && !NET_READAHEAD) || (!NET_WRITE_BUFFERS && NET_READAHEAD) + default 36 if NET_WRITE_BUFFERS && NET_READAHEAD + default 8 if !NET_WRITE_BUFFERS && !NET_READAHEAD ---help--- Each packet is represented by a series of small I/O buffers in a chain. This setting determines the number of preallocated I/O @@ -34,8 +34,8 @@ config IOB_BUFSIZE config IOB_NCHAINS int "Number of pre-allocated I/O buffer chain heads" - default 0 if !NET_TCP_READAHEAD && !NET_UDP_READAHEAD - default 8 if NET_TCP_READAHEAD || NET_UDP_READAHEAD + default 0 if !NET_READAHEAD && !NET_UDP_READAHEAD + default 8 if NET_READAHEAD || NET_UDP_READAHEAD ---help--- These tiny nodes are used as "containers" to support queueing of I/O buffer chains. This will limit the number of I/O transactions @@ -49,8 +49,8 @@ config IOB_NCHAINS config IOB_THROTTLE int "I/O buffer throttle value" - default 0 if !NET_TCP_WRITE_BUFFERS || !NET_TCP_READAHEAD - default 8 if NET_TCP_WRITE_BUFFERS && NET_TCP_READAHEAD + default 0 if !NET_WRITE_BUFFERS || !NET_READAHEAD + default 8 if NET_WRITE_BUFFERS && NET_READAHEAD ---help--- TCP write buffering and read-ahead buffer use the same pool of free I/O buffers. In order to prevent uncontrolled incoming TCP packets diff --git a/net/Kconfig b/net/Kconfig index 48163d26bfa..3c4f969486b 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -11,6 +11,14 @@ config ARCH_HAVE_PHY bool default n +config NET_WRITE_BUFFERS + bool + default n + +config NET_READAHEAD + bool + default n + config NET bool "Networking support" default n diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index 761a65bb1ba..9ab4be7336e 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -1146,7 +1146,7 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, #if defined(CONFIG_NET_6LOWPAN) /* Try 6LoWPAN UDP packet sendto() */ - nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen); + nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, minlen); #ifdef NET_UDP_HAVE_STACK if (nsent < 0) diff --git a/net/net_initialize.c b/net/net_initialize.c index 4d0105acf7f..0447f88dfcf 100644 --- a/net/net_initialize.c +++ b/net/net_initialize.c @@ -172,6 +172,10 @@ void net_setup(void) /* Initialize the UDP connection structures */ udp_initialize(); + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + udp_wrbuffer_initialize(); +#endif #endif #ifdef CONFIG_NET_IGMP diff --git a/net/socket/socket.c b/net/socket/socket.c index 539ef0b2160..caaed28320b 100644 --- a/net/socket/socket.c +++ b/net/socket/socket.c @@ -105,7 +105,7 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) psock->s_domain = domain; psock->s_type = type; psock->s_conn = NULL; -#ifdef CONFIG_NET_TCP_WRITE_BUFFERS +#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_UDP_WRITE_BUFFERS) psock->s_sndcb = NULL; #endif diff --git a/net/tcp/Kconfig b/net/tcp/Kconfig index 77cebe81fbe..c3647ae2898 100644 --- a/net/tcp/Kconfig +++ b/net/tcp/Kconfig @@ -70,6 +70,7 @@ config NET_MAX_LISTENPORTS config NET_TCP_READAHEAD bool "Enable TCP/IP read-ahead buffering" default y + select NET_READAHEAD select MM_IOB ---help--- Read-ahead buffers allows buffering of TCP/IP packets when there is no @@ -91,6 +92,7 @@ endif # NET_TCP_READAHEAD config NET_TCP_WRITE_BUFFERS bool "Enable TCP/IP write buffering" default n + select NET_WRITE_BUFFERS select MM_IOB ---help--- Write buffers allows buffering of ongoing TCP/IP packets, providing @@ -105,7 +107,7 @@ config NET_TCP_NWRBCHAINS int "Number of pre-allocated I/O buffer chain heads" default 8 ---help--- - These tiny nodes are used as "containers" to support queueing of + These tiny nodes are used as "containers" to support queuing of TCP write buffers. This setting will limit the number of TCP write operations that can be "in-flight" at any give time. So a good choice for this value would be the same as the maximum number of diff --git a/net/udp/Kconfig b/net/udp/Kconfig index ba710b8629e..16d40a72efa 100644 --- a/net/udp/Kconfig +++ b/net/udp/Kconfig @@ -44,7 +44,57 @@ config NET_BROADCAST config NET_UDP_READAHEAD bool "Enable UDP/IP read-ahead buffering" default y + select NET_READAHEAD select MM_IOB +config NET_UDP_WRITE_BUFFERS + bool "Enable UDP/IP write buffering" + default n + select NET_WRITE_BUFFERS + select MM_IOB + depends on EXPERIMENTAL + ---help--- + Write buffers allows buffering of ongoing UDP/IP packets, providing + for higher performance, streamed output. + + You might want to disable UDP/IP write buffering on a highly memory + memory constrained system where there are no performance issues. + +if NET_UDP_WRITE_BUFFERS + +config NET_UDP_NWRBCHAINS + int "Number of pre-allocated I/O buffer chain heads" + default 8 + ---help--- + These tiny nodes are used as "containers" to support queuing of + UDP write buffers. This setting will limit the number of UDP write + operations that can be "in-flight" at any give time. So a good + choice for this value would be the same as the maximum number of + UDP connections. + +config NET_UDP_WRBUFFER_DEBUG + bool "Force write buffer debug" + default n + depends on DEBUG_FEATURES + select IOB_DEBUG + ---help--- + This option will force debug output from UDP write buffer logic, + even without network debug output. This is not normally something + that would want to do but is convenient if you are debugging the + write buffer logic and do not want to get overloaded with other + network-related debug output. + +config NET_UDP_WRBUFFER_DUMP + bool "Force write buffer dump" + default n + depends on DEBUG_NET || NET_UDP_WRBUFFER_DEBUG + select IOB_DEBUG + ---help--- + Dump the contents of the write buffers. You do not want to do this + unless you really want to analyze the write buffer transfers in + detail. + +endif # NET_UDP_WRITE_BUFFERS + endif # NET_UDP && !NET_UDP_NO_STACK endmenu # UDP Networking diff --git a/net/udp/Make.defs b/net/udp/Make.defs index 4b3992911df..5c8918ea9a3 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # net/udp/Make.defs # -# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. +# Copyright (C) 2014-2015, 2018 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -40,7 +40,13 @@ ifneq ($(CONFIG_NET_UDP_NO_STACK),y) # Socket layer -NET_CSRCS += udp_psock_send.c udp_psock_sendto.c +NET_CSRCS += udp_psock_send.c + +ifeq ($(CONFIG_NET_UDP_WRITE_BUFFERS),y) +SOCK_CSRCS += udp_psock_sendto_buffered.c +else +SOCK_CSRCS += udp_psock_sendto_unbuffered.c +endif ifneq ($(CONFIG_DISABLE_POLL),y) ifeq ($(CONFIG_NET_UDP_READAHEAD),y) @@ -53,6 +59,15 @@ endif NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c NET_CSRCS += udp_callback.c udp_ipselect.c +# UDP write buffering + +ifeq ($(CONFIG_NET_UDP_WRITE_BUFFERS),y) +NET_CSRCS += udp_wrbuffer.c +ifeq ($(CONFIG_DEBUG_FEATURES),y) +NET_CSRCS += udp_wrbuffer_dump.c +endif +endif + # Include UDP build support DEPPATH += --dep-path udp diff --git a/net/udp/udp.h b/net/udp/udp.h index cb6ca378f5c..ee591ed0782 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -1,7 +1,7 @@ /**************************************************************************** * net/udp/udp.h * - * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include #include +#include #include #ifdef CONFIG_NET_UDP_READAHEAD @@ -66,6 +67,17 @@ # define HAVE_UDP_POLL #endif +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +/* UDP write buffer dump macros */ + +# ifdef CONFIG_DEBUG_FEATURES +# define UDPWB_DUMP(msg,wrb,len,offset) \ + udp_wrbuffer_dump(msg,wrb,len,offset) +# else +# define UDPWB_DUMP(msg,wrb,len,offset) +# endif +#endif + /* Allocate a new UDP data callback */ #define udp_callback_alloc(dev,conn) \ @@ -102,11 +114,38 @@ struct udp_conn_s struct iob_queue_s readahead; /* Read-ahead buffering */ #endif +#ifdef CONFIG_NET_TCP_WRITE_BUFFERS + /* Write buffering + * + * write_q - The queue of unsent I/O buffers. The head of this + * list may be partially sent. FIFO ordering. + */ + + sq_queue_t write_q; /* Write buffering for UDP packets */ + FAR struct net_driver_s *dev; /* Last device */ +#endif + /* Defines the list of UDP callbacks */ FAR struct devif_callback_s *list; }; +/* This structure supports UDP write buffering. It is simply a container + * for a IOB list and associated destination address. + */ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +struct udp_wrbuffer_s +{ + sq_entry_t wb_node; /* Supports a singly linked list */ + union ip_addr_u wb_dest; /* Destination address */ +#ifdef CONFIG_NET_SOCKOPTS + systime_t wb_start; /* Start time for timeout calculation */ +#endif + struct iob_s *wb_iob; /* Head of the I/O buffer chain */ +}; +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -291,6 +330,92 @@ void udp_poll(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn); void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn); +/**************************************************************************** + * Name: udp_wrbuffer_initialize + * + * Description: + * Initialize the list of free write buffers + * + * Assumptions: + * Called once early initialization. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +void udp_wrbuffer_initialize(void); +#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ + +/**************************************************************************** + * Name: udp_wrbuffer_alloc + * + * Description: + * Allocate a UDP write buffer by taking a pre-allocated buffer from + * the free list. This function is called from UDP logic when a buffer + * of UDP data is about to sent + * + * Input parameters: + * None + * + * Assumptions: + * Called from user logic with the network locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +struct udp_wrbuffer_s; + +FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void); +#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ + +/**************************************************************************** + * Name: udp_wrbuffer_release + * + * Description: + * Release a UDP write buffer by returning the buffer to the free list. + * This function is called from user logic after it is consumed the + * buffered data. + * + * Assumptions: + * Called from network stack logic with the network stack locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +void udp_wrbuffer_release(FAR struct udp_wrbuffer_s *wrb); +#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ + +/**************************************************************************** + * Name: udp_wrbuffer_test + * + * Description: + * Check if there is room in the write buffer. Does not reserve any space. + * + * Assumptions: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +int udp_wrbuffer_test(void); +#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ + +/**************************************************************************** + * Name: udp_wrbuffer_dump + * + * Description: + * Dump the contents of a write buffer. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +#ifdef CONFIG_DEBUG_FEATURES +void udp_wrbuffer_dump(FAR const char *msg, FAR struct udp_wrbuffer_s *wrb, + unsigned int len, unsigned int offset); +#else +# define udp_wrbuffer_dump(msg,wrb) +#endif +#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ + /**************************************************************************** * Name: udp_ipv4_input * @@ -495,7 +620,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds); * Teardown monitoring of events on an UDP/IP socket * * Input Parameters: - * psock - The TCP/IP socket of interest + * psock - The UDP/IP socket of interest * fds - The structure describing the events to be monitored, OR NULL if * this is a request to stop monitoring events. * diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index 97037c444f9..61e67028f64 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -1,7 +1,8 @@ /**************************************************************************** * net/udp/udp_conn.c * - * Copyright (C) 2007-2009, 2011-2012, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2012, 2016, 2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Large parts of this file were leveraged from uIP logic: @@ -485,6 +486,11 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain) conn->lport = 0; conn->ttl = IP_TTL; +#ifdef CONFIG_NET_TCP_WRITE_BUFFERS + /* Initialize the write buffer lists */ + + sq_init(&conn->write_q); +#endif /* Enqueue the connection into the active list */ dq_addlast(&conn->node, &g_active_udp_connections); @@ -505,6 +511,10 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain) void udp_free(FAR struct udp_conn_s *conn) { +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + FAR struct udp_wrbuffer_s *wrbuffer; +#endif + /* The free list is protected by a semaphore (that behaves like a mutex). */ DEBUGASSERT(conn->crefs == 0); @@ -522,6 +532,15 @@ void udp_free(FAR struct udp_conn_s *conn) iob_free_queue(&conn->readahead); #endif +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + /* Release any write buffers attached to the connection */ + + while ((wrbuffer = (struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q)) != NULL) + { + udp_wrbuffer_release(wrbuffer); + } +#endif + /* Free the connection */ dq_addlast(&conn->node, &g_free_udp_connections); diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c new file mode 100644 index 00000000000..3f5e5305b48 --- /dev/null +++ b/net/udp/udp_psock_sendto_buffered.c @@ -0,0 +1,821 @@ +/**************************************************************************** + * net/udp/udp_send_buffered.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && \ + defined(CONFIG_NET_UDP_WRITE_BUFFERS) + +#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_NET_UDP_WRBUFFER_DEBUG) +/* Force debug output (from this file only) */ + +# undef CONFIG_DEBUG_NET +# define CONFIG_DEBUG_NET 1 +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "netdev/netdev.h" +#include "socket/socket.h" +#include "inet/inet.h" +#include "arp/arp.h" +#include "icmpv6/icmpv6.h" +#include "neighbor/neighbor.h" +#include "udp/udp.h" +#include "devif/devif.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* If both IPv4 and IPv6 support are both enabled, then we will need to build + * in some additional domain selection support. + */ + +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) +# define NEED_IPDOMAIN_SUPPORT 1 +#endif + +#define UDPIPv4BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN]) +#define UDPIPv6BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) + +/* Debug */ + +#ifdef CONFIG_NET_UDP_WRBUFFER_DUMP +# define BUF_DUMP(msg,buf,len) lib_dumpbuffer(msg,buf,len) +#else +# define BUF_DUMP(msg,buf,len) +# undef UDPWB_DUMP +# define UDPWB_DUMP(msg,wrb,len,offset) +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline void sendto_netdev_down(FAR struct socket *psock, + FAR struct udp_conn_s *conn); + +#ifdef NEED_IPDOMAIN_SUPPORT +static inline void sendto_ipselect(FAR struct net_driver_s *dev, + FAR struct udp_conn_s *conn); +#endif +#ifdef CONFIG_NET_ETHERNET +static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn, + FAR struct net_driver_s *dev); +#else +# define sendto_addrcheck(c,d) (true) +#endif +#ifdef CONFIG_NET_SOCKOPTS +static inline int sendto_timeout(FAR struct socket *psock, + FAR struct udp_conn_s *conn); +#endif +static int sendto_next_transfer(FAR struct socket *psock, + FAR struct udp_conn_s *conn); +static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags); +static inline void sendto_txnotify(FAR struct socket *psock, + FAR struct udp_conn_s *conn); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sendto_netdev_down + * + * Description: + * The network device is down. Free all write buffers. + * REVISIT: Should only free write buffers associated with the device + * that went down. + * + * Parameters: + * psock The socket structure + * conn The connection structure associated with the socket + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void sendto_netdev_down(FAR struct socket *psock, + FAR struct udp_conn_s *conn) +{ + FAR sq_entry_t *entry; + FAR sq_entry_t *next; + + /* Do not allow any further callbacks */ + + if (psock->s_sndcb != NULL) + { + psock->s_sndcb->flags = 0; + psock->s_sndcb->event = NULL; + } + + /* Free all queued write buffers */ + + for (entry = sq_peek(&conn->write_q); entry; entry = next) + { + next = sq_next(entry); + udp_wrbuffer_release((FAR struct udp_wrbuffer_s *)entry); + } + + /* Reset write buffering variables */ + + sq_init(&conn->write_q); +} + +/**************************************************************************** + * Name: sendto_ipselect + * + * Description: + * If both IPv4 and IPv6 support are enabled, then we will need to select + * which one to use when generating the outgoing packet. If only one + * domain is selected, then the setup is already in place and we need do + * nothing. + * + * Parameters: + * dev - The structure of the network driver that caused the event + * psock - Socket state structure + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +#ifdef NEED_IPDOMAIN_SUPPORT +static inline void sendto_ipselect(FAR struct net_driver_s *dev, + FAR struct udp_conn_s *conn) +{ + /* Which domain the socket support */ + + if (conn->domain == PF_INET) + { + /* Select the IPv4 domain */ + + udp_ipv4_select(dev); + } + else /* if (conn->domain == PF_INET6) */ + { + /* Select the IPv6 domain */ + + DEBUGASSERT(conn->domain == PF_INET6); + udp_ipv6_select(dev); + } +} +#endif + +/**************************************************************************** + * Name: sendto_addrcheck + * + * Description: + * Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor + * tables. If not, then the send won't actually make it out... it will be + * replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6). + * + * NOTE 1: This could be an expensive check if there are a lot of + * entries in the ARP or Neighbor tables. + * + * NOTE 2: If we are actually harvesting IP addresses on incoming IP + * packets, then this check should not be necessary; the MAC mapping + * should already be in the ARP table in many cases (IPv4 only). + * + * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP + * address mapping is already in the ARP table. + * + * Parameters: + * conn - The UDP connection structure + * dev - Polling network device + * + * Returned Value: + * true - The Ethernet MAC address is in the ARP or Neighbor table (OR + * the network device is not Ethernet). + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ETHERNET +static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn, + FAR struct net_driver_s *dev) +{ + /* REVISIT: Could the MAC address not also be in a routing table? */ + + if (dev->d_lltype != NET_LL_ETHERNET) + { + return true; + } + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET) +#endif + { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + return (arp_find(conn->u.ipv4.raddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { +#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) + return (neighbor_findentry(conn->u.ipv6.raddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv6 */ +} +#endif /* CONFIG_NET_ETHERNET */ + +/**************************************************************************** + * Name: sendto_timeout + * + * Description: + * Check for send timeout. + * + * Parameters: + * pstate - sendto state structure + * + * Returned Value: + * TRUE:timeout FALSE:no timeout + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +#ifdef CONFIG_NET_SOCKOPTS +static inline int sendto_timeout(FAR struct socket *psock, + FAR struct udp_conn_s *conn) +{ + FAR struct udp_wrbuffer_s *wrb; + + /* Peek at the head of the write queue (without altering the write queue). */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q); + if (wrb != NULL) + { + /* Check for a timeout configured via setsockopts(SO_SNDTIMEO). + * If none... we well let the send wait forever. + */ + + if (psock->s_sndtimeo != 0) + { + /* Check if the configured timeout has elapsed */ + + return net_timeo(wrb->wb_start, psock->s_sndtimeo); + } + } + + /* No timeout */ + + return FALSE; +} +#endif /* CONFIG_NET_SOCKOPTS */ + +/**************************************************************************** + * Name: sendto_next_transfer + * + * Description: + * Setup for the next packet transfer + * + * Parameters: + * psock - Socket state structure + * conn - The UDP connection structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int sendto_next_transfer(FAR struct socket *psock, + FAR struct udp_conn_s *conn) +{ + FAR struct udp_wrbuffer_s *wrb; + FAR struct net_driver_s *dev; + int ret; + + /* Set the UDP "connection" to the destination address of the write buffer + * at the head of the queue. + */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q); + DEBUGASSERT(wrb != NULL); + + ret = udp_connect(conn, (FAR const struct sockaddr *)wrb->wb_iob->io_data); + if (ret < 0) + { + nerr("ERROR: udp_connect failed: %d\n", ret); + return ret; + } + + /* Get the device that will handle the remote packet transfers. This + * should never be NULL. + */ + + dev = udp_find_raddr_device(conn); + if (dev == NULL) + { + nerr("ERROR: udp_find_raddr_device failed\n"); + return -ENETUNREACH; + } + + /* If this is not the same device that we used in the last call to + * udp_callback_alloc(), then we need to release and reallocate the old + * callback instance. + */ + + if (psock->s_sndcb != NULL && conn->dev != dev) + { + udp_callback_free(conn->dev, conn, psock->s_sndcb); + psock->s_sndcb = NULL; + } + + /* Allocate resources to receive a callback from this device if the + * callback is not already in place. + */ + + if (psock->s_sndcb == NULL) + { + psock->s_sndcb = udp_callback_alloc(dev, conn); + } + + /* Test if the callback has been allocated */ + + if (psock->s_sndcb == NULL) + { + /* A buffer allocation error occurred */ + + nerr("ERROR: Failed to allocate callback\n"); + return -ENOMEM; + } + + conn->dev = dev; + + /* Set up the callback in the connection */ + + psock->s_sndcb->flags = (UDP_POLL | NETDEV_DOWN); + psock->s_sndcb->priv = (FAR void *)psock; + psock->s_sndcb->event = sendto_eventhandler; + return OK; +} + +/**************************************************************************** + * Name: sendto_eventhandler + * + * Description: + * This function is called to perform the actual send operation when + * polled by the lower, device interfacing layer. + * + * Parameters: + * dev The structure of the network driver that caused the event + * conn The connection structure associated with the socket + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvconn, FAR void *pvpriv, + uint16_t flags) +{ + FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)pvconn; + FAR struct socket *psock = (FAR struct socket *)pvpriv; + int ret; + + ninfo("flags: %04x\n", flags); + + /* Check if the network device has gone down */ + + if ((flags & NETDEV_DOWN) != 0) + { + ninfo("Device down: %04x\n", flags); + + /* Free write buffers and terminate polling */ + + sendto_netdev_down(psock, conn); + return flags; + } + + /* Check for a normal polling cycle and if the outgoing packet is + * available. It would not be available if it has been claimed by a send + * event serving a different thread -OR- if the output buffer currently + * contains unprocessed incoming data. In these cases we will just have + * to wait for the next polling cycle. + * + * And, of course, we can do nothing if we have no data in the write + * buffers to send. + */ + + if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) != 0 && + (flags & UDP_POLL) != 0 && !sq_empty(&conn->write_q)) + { + /* Check if the destination IP address is in the ARP or Neighbor + * table. If not, then the send won't actually make it out... it + * will be replaced with an ARP request or Neighbor Solicitation. + */ + + if (sendto_addrcheck(conn, dev)) + { + FAR struct udp_wrbuffer_s *wrb; + FAR struct udp_wrbuffer_s *tmp; + size_t sndlen; + + /* Peek at the head of the write queue (but don't remove anything + * from the write queue yet). We know from the above test that + * the write_q is not empty. + */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q); + DEBUGASSERT(wrb != NULL); + + /* Get the amount of data that we can send in the next packet. + * We will send either the remaining data in the buffer I/O + * buffer chain, or as much as will fit given the MSS and current + * window size. + */ + + sndlen = wrb->wb_iob->io_pktlen; + ninfo("wrb=%p sndlen=%u\n", wrb, sndlen); + +#ifdef NEED_IPDOMAIN_SUPPORT + /* If both IPv4 and IPv6 support are enabled, then we will need to + * select which one to use when generating the outgoing packet. + * If only one domain is selected, then the setup is already in + * place and we need do nothing. + */ + + sendto_ipselect(dev, conn); +#endif + /* Then set-up to send that amount of data with the offset + * corresponding to the size of the IP-dependent address structure. + */ + + devif_iob_send(dev, wrb->wb_iob, sndlen, 0); + + /* Remove and free the write buffer from the head of the write + * buffer queue. + */ + + do + { + tmp = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q); + DEBUGASSERT(tmp == wrb); + + udp_wrbuffer_release(tmp); + + /* Check if the write queue became empty */ + + if (sq_empty(&conn->write_q)) + { + /* Yes.. stifle any further callbacks until more write + * data is enqueued. + */ + + psock->s_sndcb->flags = 0; + psock->s_sndcb->priv = NULL; + psock->s_sndcb->event = NULL; + ret = OK; + } + else + { + /* Set up for the next packet transfer by setting the + * connection address to the address of the next packet + * now at the header of of the write buffer queue. + */ + + ret = sendto_next_transfer(psock, conn); + } + } + while (ret < 0); + + /* Only one data can be sent by low level driver at once, + * tell the caller stop polling the other connections. + */ + + flags &= ~UDP_POLL; + } + } + +#ifdef CONFIG_NET_SOCKOPTS + /* We cannot send the data now. Check for a timeout. */ + + else if (sendto_timeout(psock, conn)) + { + FAR struct udp_wrbuffer_s *wrb; + + do + { + /* Remove and free the write buffer from the head of the write + * buffer queue. Here we know that the write queue is not empty + * because the entry at the head of the queue just timed out! + */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q); + DEBUGASSERT(wrb != NULL); + + udp_wrbuffer_release(wrb); + + /* Set up for the next packet transfer by setting the connection + * address to the address of the next packet now at the header of the + * write buffer queue. + */ + + ret = sendto_next_transfer(psock, conn); + } + while (ret < 0); + } +#endif /* CONFIG_NET_SOCKOPTS */ + + /* Continue waiting */ + + return flags; +} + +/**************************************************************************** + * Name: sendto_txnotify + * + * Description: + * Notify the appropriate device driver that we are have data ready to + * be send (UDP) + * + * Parameters: + * psock - Socket state structure + * conn - The UDP connection structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void sendto_txnotify(FAR struct socket *psock, + FAR struct udp_conn_s *conn) +{ +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + /* If both IPv4 and IPv6 support are enabled, then we will need to select + * the device driver using the appropriate IP domain. + */ + + if (psock->s_domain == PF_INET) +#endif + { + /* Notify the device driver that send data is available */ + + netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else /* if (psock->s_domain == PF_INET6) */ +#endif /* CONFIG_NET_IPv4 */ + { + /* Notify the device driver that send data is available */ + + DEBUGASSERT(psock->s_domain == PF_INET6); + netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr); + } +#endif /* CONFIG_NET_IPv6 */ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_udp_sendto + * + * Description: + * This function implements the UDP-specific logic of the standard + * sendto() socket operation. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * NOTE: All input parameters were verified by sendto() before this + * function was called. + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * a negated errno value is returned. See the description in + * net/socket/sendto.c for the list of appropriate return value. + * + ****************************************************************************/ + +ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen) +{ + FAR struct udp_conn_s *conn; + FAR struct udp_wrbuffer_s *wrb; + int ret = OK; + + /* Make sure that we have the IP address mapping */ + + conn = (FAR struct udp_conn_s *)psock->s_conn; + DEBUGASSERT(conn); + +#if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) +#ifdef CONFIG_NET_ARP_SEND +#ifdef CONFIG_NET_ICMPv6_NEIGHBOR + if (psock->s_domain == PF_INET) +#endif + { + /* Make sure that the IP address mapping is in the ARP table */ + + ret = arp_send(conn->u.ipv4.raddr); + } +#endif /* CONFIG_NET_ARP_SEND */ + +#ifdef CONFIG_NET_ICMPv6_NEIGHBOR +#ifdef CONFIG_NET_ARP_SEND + else +#endif + { + /* Make sure that the IP address mapping is in the Neighbor Table */ + + ret = icmpv6_neighbor(conn->u.ipv6.raddr); + } +#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ + + /* Did we successfully get the address mapping? */ + + if (ret < 0) + { + nerr("ERROR: Not reachable\n"); + return -ENETUNREACH; + } +#endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ + + /* Dump the incoming buffer */ + + BUF_DUMP("psock_udp_send", buf, len); + + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + + if (len > 0) + { + /* Allocate a write buffer. Careful, the network will be momentarily + * unlocked here. + */ + + net_lock(); + wrb = udp_wrbuffer_alloc(); + if (wrb == NULL) + { + /* A buffer allocation error occurred */ + + nerr("ERROR: Failed to allocate write buffer\n"); + ret = -ENOMEM; + goto errout_with_lock; + } + + /* Initialize the write buffer */ + + memcpy(&wrb->wb_dest, to, tolen); + wrb->wb_start = clock_systimer(); + + /* Copy the user data into the write buffer. We cannot wait for + * buffer space if the socket was opened non-blocking. + */ + + if (_SS_ISNONBLOCK(psock->s_flags)) + { + ret = iob_trycopyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false); + } + else + { + ret = iob_copyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false); + } + + if (ret < 0) + { + goto errout_with_wrb; + } + + /* Dump I/O buffer chain */ + + UDPWB_DUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0); + + /* sendto_eventhandler() will send data in FIFO order from the + * conn->write_q + */ + + sq_addlast(&wrb->wb_node, &conn->write_q); + ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n", + wrb, wrb->wb_iob->io_pktlen, + conn->write_q.head, conn->write_q.tail); + + /* Set up for the next packet transfer by setting the connection + * address to the address of the next packet now at the header of the + * write buffer queue. + */ + + ret = sendto_next_transfer(psock, conn); + if (ret < 0) + { + /* REVISIT: An error here is not recoverable */ + + goto errout_with_lock; + } + + /* Notify the device driver of the availability of TX data */ + + sendto_txnotify(psock, conn); + net_unlock(); + } + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Return the number of bytes that will be sent */ + + return len; + +errout_with_wrb: + udp_wrbuffer_release(wrb); + +errout_with_lock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NET_UDP_WRITE_BUFFERS */ diff --git a/net/udp/udp_psock_sendto.c b/net/udp/udp_psock_sendto_unbuffered.c similarity index 98% rename from net/udp/udp_psock_sendto.c rename to net/udp/udp_psock_sendto_unbuffered.c index ff362a310e4..809ee2ce9e0 100644 --- a/net/udp/udp_psock_sendto.c +++ b/net/udp/udp_psock_sendto_unbuffered.c @@ -1,7 +1,8 @@ /**************************************************************************** - * net/udp/udp_psock_sendto.c + * net/udp/udp_psock_sendto_unbuffered.c * - * Copyright (C) 2007-2009, 2011-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2016, 2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -94,7 +95,7 @@ struct sendto_s ****************************************************************************/ /**************************************************************************** - * Name: send_timeout + * Name: sendto_timeout * * Description: * Check for send timeout. @@ -111,7 +112,7 @@ struct sendto_s ****************************************************************************/ #ifdef CONFIG_NET_SOCKOPTS -static inline int send_timeout(FAR struct sendto_s *pstate) +static inline int sendto_timeout(FAR struct sendto_s *pstate) { FAR struct socket *psock; @@ -235,7 +236,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, */ #ifdef CONFIG_NET_SOCKOPTS - if (send_timeout(pstate)) + if (sendto_timeout(pstate)) { /* Yes.. report the timeout */ diff --git a/net/udp/udp_wrbuffer.c b/net/udp/udp_wrbuffer.c new file mode 100644 index 00000000000..ae8fafd7ffb --- /dev/null +++ b/net/udp/udp_wrbuffer.c @@ -0,0 +1,217 @@ +/**************************************************************************** + * net/udp/udp_wrbuffer.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_WRITE_BUFFERS) + +#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_NET_UDP_WRBUFFER_DEBUG) +/* Force debug output (from this file only) */ + +# undef CONFIG_DEBUG_NET +# define CONFIG_DEBUG_NET 1 +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include "udp/udp.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Package all globals used by this logic into a structure */ + +struct wrbuffer_s +{ + /* The semaphore to protect the buffers */ + + sem_t sem; + + /* This is the list of available write buffers */ + + sq_queue_t freebuffers; + + /* These are the pre-allocated write buffers */ + + struct udp_wrbuffer_s buffers[CONFIG_NET_UDP_NWRBCHAINS]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the state of the global write buffer resource */ + +static struct wrbuffer_s g_wrbuffer; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_wrbuffer_initialize + * + * Description: + * Initialize the list of free write buffers + * + * Assumptions: + * Called once early initialization. + * + ****************************************************************************/ + +void udp_wrbuffer_initialize(void) +{ + int i; + + sq_init(&g_wrbuffer.freebuffers); + + for (i = 0; i < CONFIG_NET_UDP_NWRBCHAINS; i++) + { + sq_addfirst(&g_wrbuffer.buffers[i].wb_node, &g_wrbuffer.freebuffers); + } + + nxsem_init(&g_wrbuffer.sem, 0, CONFIG_NET_UDP_NWRBCHAINS); +} + +/**************************************************************************** + * Name: udp_wrbuffer_alloc + * + * Description: + * Allocate a UDP write buffer by taking a pre-allocated buffer from + * the free list. This function is called from UDP logic when a buffer + * of UDP data is about to sent + * + * Input parameters: + * None + * + * Assumptions: + * Called from user logic with the network locked. + * + ****************************************************************************/ + +FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void) +{ + FAR struct udp_wrbuffer_s *wrb; + + /* We need to allocate two things: (1) A write buffer structure and (2) + * at least one I/O buffer to start the chain. + * + * Allocate the write buffer structure first then the IOBG. In order to + * avoid deadlocks, we will need to free the IOB first, then the write + * buffer + */ + + DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem)); /* TODO: Handle EINTR. */ + + /* Now, we are guaranteed to have a write buffer structure reserved + * for us in the free list. + */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); + DEBUGASSERT(wrb); + memset(wrb, 0, sizeof(struct udp_wrbuffer_s)); + + /* Now get the first I/O buffer for the write buffer structure */ + + wrb->wb_iob = iob_alloc(false); + if (!wrb->wb_iob) + { + nerr("ERROR: Failed to allocate I/O buffer\n"); + udp_wrbuffer_release(wrb); + return NULL; + } + + return wrb; +} + +/**************************************************************************** + * Name: udp_wrbuffer_release + * + * Description: + * Release a UDP write buffer by returning the buffer to the free list. + * This function is called from user logic after it is consumed the + * buffered data. + * + * Assumptions: + * This function must be called with the network locked. + * + ****************************************************************************/ + +void udp_wrbuffer_release(FAR struct udp_wrbuffer_s *wrb) +{ + DEBUGASSERT(wrb && wrb->wb_iob); + + /* To avoid deadlocks, we must following this ordering: Release the I/O + * buffer chain first, then the write buffer structure. + */ + + iob_free_chain(wrb->wb_iob); + + /* Then free the write buffer structure */ + + sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers); + nxsem_post(&g_wrbuffer.sem); +} + +/**************************************************************************** + * Name: udp_wrbuffer_test + * + * Description: + * Check if there is room in the write buffer. Does not reserve any space. + * + * Assumptions: + * None. + * + ****************************************************************************/ + +int udp_wrbuffer_test(void) +{ + int val = 0; + nxsem_getvalue(&g_wrbuffer.sem, &val); + return val > 0 ? OK : ERROR; +} + +#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NET_UDP_WRITE_BUFFERS */ diff --git a/net/udp/udp_wrbuffer_dump.c b/net/udp/udp_wrbuffer_dump.c new file mode 100644 index 00000000000..e3e8df1f59d --- /dev/null +++ b/net/udp/udp_wrbuffer_dump.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * net/udp/udp_wrbuffer_dump.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "udp/udp.h" + +#ifdef CONFIG_DEBUG_FEATURES + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: udp_wrbuffer_dump + * + * Description: + * Dump the contents of a write buffer + * + ****************************************************************************/ + +void udp_wrbuffer_dump(FAR const char *msg, FAR struct udp_wrbuffer_s *wrb, + unsigned int len, unsigned int offset) +{ + syslog(LOG_DEBUG, "%s: wrb=%p pktlen=%d\n", msg, wrb, wrb->wb_iob->io_pktlen); + iob_dump("I/O Buffer Chain", wrb->wb_iob, len, offset); +} + +#endif /* CONFIG_DEBUG_FEATURES */ From 2f548a880c329dfef0588f7a13c87ad0d46ea32f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 18:46:58 -0600 Subject: [PATCH 29/44] net/udp: In sendto(), return EHOSTUNREACH if if the network is down. --- net/udp/udp_psock_sendto_buffered.c | 8 ++++++++ net/udp/udp_psock_sendto_unbuffered.c | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c index 3f5e5305b48..b9a8a891893 100644 --- a/net/udp/udp_psock_sendto_buffered.c +++ b/net/udp/udp_psock_sendto_buffered.c @@ -384,6 +384,14 @@ static int sendto_next_transfer(FAR struct socket *psock, return -ENETUNREACH; } + /* Make sure that the device is in the UP state */ + + if ((dev->d_flags & IFF_UP) == 0) + { + nwarn("WARNING: device is DOWN\n"); + return -EHOSTUNREACH; + } + /* If this is not the same device that we used in the last call to * udp_callback_alloc(), then we need to release and reallocate the old * callback instance. diff --git a/net/udp/udp_psock_sendto_unbuffered.c b/net/udp/udp_psock_sendto_unbuffered.c index 809ee2ce9e0..7024d12baf0 100644 --- a/net/udp/udp_psock_sendto_unbuffered.c +++ b/net/udp/udp_psock_sendto_unbuffered.c @@ -424,6 +424,15 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, goto errout_with_lock; } + /* Make sure that the device is in the UP state */ + + if ((dev->d_flags & IFF_UP) == 0) + { + nwarn("WARNING: device is DOWN\n"); + ret = -EHOSTUNREACH; + goto errout_with_lock; + } + /* Set up the callback in the connection */ state.st_cb = udp_callback_alloc(dev, conn); From 7dc436a1349ab53a2160d6065eb8b7c2e6ec8fe2 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 19:27:05 -0600 Subject: [PATCH 30/44] net/udp: Resolves final design issues with UDP write buffering. 100% code complete but also 100% untested. --- net/udp/udp_psock_sendto_buffered.c | 150 +++++++++++----------------- 1 file changed, 58 insertions(+), 92 deletions(-) diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c index b9a8a891893..b084837b6e2 100644 --- a/net/udp/udp_psock_sendto_buffered.c +++ b/net/udp/udp_psock_sendto_buffered.c @@ -105,9 +105,6 @@ * Private Function Prototypes ****************************************************************************/ -static inline void sendto_netdev_down(FAR struct socket *psock, - FAR struct udp_conn_s *conn); - #ifdef NEED_IPDOMAIN_SUPPORT static inline void sendto_ipselect(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn); @@ -135,47 +132,64 @@ static inline void sendto_txnotify(FAR struct socket *psock, ****************************************************************************/ /**************************************************************************** - * Name: sendto_netdev_down + * Name: sendto_writebuffer_release * * Description: - * The network device is down. Free all write buffers. - * REVISIT: Should only free write buffers associated with the device - * that went down. + * Release the write buffer at the head of the write buffer queue. * * Parameters: - * psock The socket structure - * conn The connection structure associated with the socket + * dev - The structure of the network driver that caused the event + * psock - Socket state structure * * Returned Value: * None * + * Assumptions: + * The network is locked + * ****************************************************************************/ -static inline void sendto_netdev_down(FAR struct socket *psock, - FAR struct udp_conn_s *conn) +static void sendto_writebuffer_release(FAR struct socket *psock, + FAR struct udp_conn_s *conn) { - FAR sq_entry_t *entry; - FAR sq_entry_t *next; + FAR struct udp_wrbuffer_s *wrb; + int ret = OK; - /* Do not allow any further callbacks */ - - if (psock->s_sndcb != NULL) + do { - psock->s_sndcb->flags = 0; - psock->s_sndcb->event = NULL; + /* Check if the write queue became empty */ + + if (sq_empty(&conn->write_q)) + { + /* Yes.. stifle any further callbacks until more write data is + * enqueued. + */ + + psock->s_sndcb->flags = 0; + psock->s_sndcb->priv = NULL; + psock->s_sndcb->event = NULL; + wrb = NULL; + } + else + { + /* Remove the write buffer from the head of the write buffer queue + * and release it. + */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q); + DEBUGASSERT(wrb != NULL); + + udp_wrbuffer_release(wrb); + + /* Set up for the next packet transfer by setting the connection + * address to the address of the next packet now at the header of + * the write buffer queue. + */ + + ret = sendto_next_transfer(psock, conn); + } } - - /* Free all queued write buffers */ - - for (entry = sq_peek(&conn->write_q); entry; entry = next) - { - next = sq_next(entry); - udp_wrbuffer_release((FAR struct udp_wrbuffer_s *)entry); - } - - /* Reset write buffering variables */ - - sq_init(&conn->write_q); + while (wrb != NULL && ret < 0); } /**************************************************************************** @@ -254,7 +268,7 @@ static inline void sendto_ipselect(FAR struct net_driver_s *dev, #ifdef CONFIG_NET_ETHERNET static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn, - FAR struct net_driver_s *dev) + FAR struct net_driver_s *dev) { /* REVISIT: Could the MAC address not also be in a routing table? */ @@ -458,7 +472,6 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, { FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)pvconn; FAR struct socket *psock = (FAR struct socket *)pvpriv; - int ret; ninfo("flags: %04x\n", flags); @@ -468,9 +481,11 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, { ninfo("Device down: %04x\n", flags); - /* Free write buffers and terminate polling */ + /* Free the write buffer at the head of the queue and attempt to setup + * the next transfer. + */ - sendto_netdev_down(psock, conn); + sendto_writebuffer_release(psock, conn); return flags; } @@ -495,7 +510,6 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, if (sendto_addrcheck(conn, dev)) { FAR struct udp_wrbuffer_s *wrb; - FAR struct udp_wrbuffer_s *tmp; size_t sndlen; /* Peek at the head of the write queue (but don't remove anything @@ -530,41 +544,11 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, devif_iob_send(dev, wrb->wb_iob, sndlen, 0); - /* Remove and free the write buffer from the head of the write - * buffer queue. + /* Free the write buffer at the head of the queue and attempt to + * setup the next transfer. */ - do - { - tmp = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q); - DEBUGASSERT(tmp == wrb); - - udp_wrbuffer_release(tmp); - - /* Check if the write queue became empty */ - - if (sq_empty(&conn->write_q)) - { - /* Yes.. stifle any further callbacks until more write - * data is enqueued. - */ - - psock->s_sndcb->flags = 0; - psock->s_sndcb->priv = NULL; - psock->s_sndcb->event = NULL; - ret = OK; - } - else - { - /* Set up for the next packet transfer by setting the - * connection address to the address of the next packet - * now at the header of of the write buffer queue. - */ - - ret = sendto_next_transfer(psock, conn); - } - } - while (ret < 0); + sendto_writebuffer_release(psock, conn); /* Only one data can be sent by low level driver at once, * tell the caller stop polling the other connections. @@ -579,28 +563,11 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, else if (sendto_timeout(psock, conn)) { - FAR struct udp_wrbuffer_s *wrb; + /* Free the write buffer at the head of the queue and attempt to setup + * the next transfer. + */ - do - { - /* Remove and free the write buffer from the head of the write - * buffer queue. Here we know that the write queue is not empty - * because the entry at the head of the queue just timed out! - */ - - wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q); - DEBUGASSERT(wrb != NULL); - - udp_wrbuffer_release(wrb); - - /* Set up for the next packet transfer by setting the connection - * address to the address of the next packet now at the header of the - * write buffer queue. - */ - - ret = sendto_next_transfer(psock, conn); - } - while (ret < 0); + sendto_writebuffer_release(psock, conn); } #endif /* CONFIG_NET_SOCKOPTS */ @@ -799,9 +766,8 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, ret = sendto_next_transfer(psock, conn); if (ret < 0) { - /* REVISIT: An error here is not recoverable */ - - goto errout_with_lock; + (void)sq_remlast(&conn->write_q); + goto errout_with_wrb; } /* Notify the device driver of the availability of TX data */ From f04dec14cc07539eccc3046ef826b9e1aaac9417 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Jan 2018 19:33:14 -0600 Subject: [PATCH 31/44] net/udp and tcp: Yet another (cosmetic) change to UDP and TCP write buffer macro naming. --- net/tcp/tcp.h | 22 +++--- net/tcp/tcp_send_buffered.c | 104 ++++++++++++++-------------- net/tcp/tcp_wrbuffer_dump.c | 4 +- net/udp/udp.h | 4 +- net/udp/udp_psock_sendto_buffered.c | 6 +- 5 files changed, 70 insertions(+), 70 deletions(-) diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index bf8948da73a..bfd402c00a1 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -77,25 +77,25 @@ #ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* TCP write buffer access macros */ -# define TCPWB_SEQNO(wrb) ((wrb)->wb_seqno) -# define TCPWB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen) -# define TCPWB_SENT(wrb) ((wrb)->wb_sent) -# define TCPWB_NRTX(wrb) ((wrb)->wb_nrtx) -# define TCPWB_IOB(wrb) ((wrb)->wb_iob) -# define TCPWB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0)) -# define TCPWB_COPYIN(wrb,src,n) \ +# define TCP_WBSEQNO(wrb) ((wrb)->wb_seqno) +# define TCP_WBPKTLEN(wrb) ((wrb)->wb_iob->io_pktlen) +# define TCP_WBSENT(wrb) ((wrb)->wb_sent) +# define TCP_WBNRTX(wrb) ((wrb)->wb_nrtx) +# define TCP_WBIOB(wrb) ((wrb)->wb_iob) +# define TCP_WBCOPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0)) +# define TCP_WBCOPYIN(wrb,src,n) \ (iob_copyin((wrb)->wb_iob,src,(n),0,false)) -# define TCPWB_TRYCOPYIN(wrb,src,n) \ +# define TCP_WBTRYCOPYIN(wrb,src,n) \ (iob_trycopyin((wrb)->wb_iob,src,(n),0,false)) -# define TCPWB_TRIM(wrb,n) \ +# define TCP_WBTRIM(wrb,n) \ do { (wrb)->wb_iob = iob_trimhead((wrb)->wb_iob,(n)); } while (0) #ifdef CONFIG_DEBUG_FEATURES -# define TCPWB_DUMP(msg,wrb,len,offset) \ +# define TCP_WBDUMP(msg,wrb,len,offset) \ tcp_wrbuffer_dump(msg,wrb,len,offset) # else -# define TCPWB_DUMP(msg,wrb,len,offset) +# define TCP_WBDUMP(msg,wrb,len,offset) # endif #endif diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c index 5abb417e701..b8463b0643f 100644 --- a/net/tcp/tcp_send_buffered.c +++ b/net/tcp/tcp_send_buffered.c @@ -98,8 +98,8 @@ # define BUF_DUMP(msg,buf,len) lib_dumpbuffer(msg,buf,len) #else # define BUF_DUMP(msg,buf,len) -# undef TCPWB_DUMP -# define TCPWB_DUMP(msg,wrb,len,offset) +# undef TCP_WBDUMP +# define TCP_WBDUMP(msg,wrb,len,offset) #endif /**************************************************************************** @@ -135,7 +135,7 @@ static void psock_insert_segment(FAR struct tcp_wrbuffer_s *wrb, for (itr = sq_peek(q); itr; itr = sq_next(itr)) { FAR struct tcp_wrbuffer_s *wrb0 = (FAR struct tcp_wrbuffer_s *)itr; - if (TCPWB_SEQNO(wrb0) < TCPWB_SEQNO(wrb)) + if (TCP_WBSEQNO(wrb0) < TCP_WBSEQNO(wrb)) { insert = itr; } @@ -417,13 +417,13 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * the write buffer has been ACKed. */ - if (ackno > TCPWB_SEQNO(wrb)) + if (ackno > TCP_WBSEQNO(wrb)) { /* Get the sequence number at the end of the data */ - lastseq = TCPWB_SEQNO(wrb) + TCPWB_PKTLEN(wrb); + lastseq = TCP_WBSEQNO(wrb) + TCP_WBPKTLEN(wrb); ninfo("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n", - wrb, TCPWB_SEQNO(wrb), lastseq, TCPWB_PKTLEN(wrb), + wrb, TCP_WBSEQNO(wrb), lastseq, TCP_WBPKTLEN(wrb), ackno); /* Has the entire buffer been ACKed? */ @@ -450,24 +450,24 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * buffers in the chain. */ - trimlen = ackno - TCPWB_SEQNO(wrb); - if (trimlen > TCPWB_SENT(wrb)) + trimlen = ackno - TCP_WBSEQNO(wrb); + if (trimlen > TCP_WBSENT(wrb)) { /* More data has been ACKed then we have sent? */ - trimlen = TCPWB_SENT(wrb); + trimlen = TCP_WBSENT(wrb); } ninfo("ACK: wrb=%p trim %u bytes\n", wrb, trimlen); - TCPWB_TRIM(wrb, trimlen); - TCPWB_SEQNO(wrb) = ackno; - TCPWB_SENT(wrb) -= trimlen; + TCP_WBTRIM(wrb, trimlen); + TCP_WBSEQNO(wrb) = ackno; + TCP_WBSENT(wrb) -= trimlen; /* Set the new sequence number for what remains */ ninfo("ACK: wrb=%p seqno=%u pktlen=%u\n", - wrb, TCPWB_SEQNO(wrb), TCPWB_PKTLEN(wrb)); + wrb, TCP_WBSEQNO(wrb), TCP_WBPKTLEN(wrb)); } } } @@ -478,31 +478,31 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); - if (wrb && TCPWB_SENT(wrb) > 0 && ackno > TCPWB_SEQNO(wrb)) + if (wrb && TCP_WBSENT(wrb) > 0 && ackno > TCP_WBSEQNO(wrb)) { uint32_t nacked; /* Number of bytes that were ACKed */ - nacked = ackno - TCPWB_SEQNO(wrb); - if (nacked > TCPWB_SENT(wrb)) + nacked = ackno - TCP_WBSEQNO(wrb); + if (nacked > TCP_WBSENT(wrb)) { /* More data has been ACKed then we have sent? ASSERT? */ - nacked = TCPWB_SENT(wrb); + nacked = TCP_WBSENT(wrb); } ninfo("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n", - wrb, TCPWB_SEQNO(wrb), nacked, TCPWB_SENT(wrb), ackno); + wrb, TCP_WBSEQNO(wrb), nacked, TCP_WBSENT(wrb), ackno); /* Trim the ACKed bytes from the beginning of the write buffer. */ - TCPWB_TRIM(wrb, nacked); - TCPWB_SEQNO(wrb) = ackno; - TCPWB_SENT(wrb) -= nacked; + TCP_WBTRIM(wrb, nacked); + TCP_WBSEQNO(wrb) = ackno; + TCP_WBSENT(wrb) -= nacked; ninfo("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n", - wrb, TCPWB_SEQNO(wrb), TCPWB_PKTLEN(wrb), TCPWB_SENT(wrb)); + wrb, TCP_WBSEQNO(wrb), TCP_WBPKTLEN(wrb), TCP_WBSENT(wrb)); } } @@ -544,16 +544,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); - ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? TCPWB_SENT(wrb) : 0); + ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? TCP_WBSENT(wrb) : 0); - if (wrb != NULL && TCPWB_SENT(wrb) > 0) + if (wrb != NULL && TCP_WBSENT(wrb) > 0) { FAR struct tcp_wrbuffer_s *tmp; uint16_t sent; /* Yes.. Reset the number of bytes sent sent from the write buffer */ - sent = TCPWB_SENT(wrb); + sent = TCP_WBSENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; @@ -572,16 +572,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, conn->sent = 0; } - TCPWB_SENT(wrb) = 0; + TCP_WBSENT(wrb) = 0; ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", - wrb, TCPWB_SENT(wrb), conn->unacked, conn->sent); + wrb, TCP_WBSENT(wrb), conn->unacked, conn->sent); /* Increment the retransmit count on this write buffer. */ - if (++TCPWB_NRTX(wrb) >= TCP_MAXRTX) + if (++TCP_WBNRTX(wrb) >= TCP_MAXRTX) { nwarn("WARNING: Expiring wrb=%p nrtx=%u\n", - wrb, TCPWB_NRTX(wrb)); + wrb, TCP_WBNRTX(wrb)); /* The maximum retry count as been exhausted. Remove the write * buffer at the head of the queue. @@ -619,7 +619,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, /* Reset the number of bytes sent sent from the write buffer */ - sent = TCPWB_SENT(wrb); + sent = TCP_WBSENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; @@ -638,16 +638,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, conn->sent = 0; } - TCPWB_SENT(wrb) = 0; + TCP_WBSENT(wrb) = 0; ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", - wrb, TCPWB_SENT(wrb), conn->unacked, conn->sent); + wrb, TCP_WBSENT(wrb), conn->unacked, conn->sent); /* Free any write buffers that have exceed the retry count */ - if (++TCPWB_NRTX(wrb) >= TCP_MAXRTX) + if (++TCP_WBNRTX(wrb) >= TCP_MAXRTX) { nwarn("WARNING: Expiring wrb=%p nrtx=%u\n", - wrb, TCPWB_NRTX(wrb)); + wrb, TCP_WBNRTX(wrb)); /* Return the write buffer to the free list */ @@ -672,7 +672,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * is pulled from the write_q again. */ - ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, TCPWB_NRTX(wrb)); + ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, TCP_WBNRTX(wrb)); psock_insert_segment(wrb, &conn->write_q); } @@ -727,7 +727,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * window size. */ - sndlen = TCPWB_PKTLEN(wrb) - TCPWB_SENT(wrb); + sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb); if (sndlen > conn->mss) { sndlen = conn->mss; @@ -739,16 +739,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, } ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n", - wrb, TCPWB_PKTLEN(wrb), TCPWB_SENT(wrb), sndlen); + wrb, TCP_WBPKTLEN(wrb), TCP_WBSENT(wrb), sndlen); /* Set the sequence number for this segment. If we are * retransmitting, then the sequence number will already * be set for this write buffer. */ - if (TCPWB_SEQNO(wrb) == (unsigned)-1) + if (TCP_WBSEQNO(wrb) == (unsigned)-1) { - TCPWB_SEQNO(wrb) = conn->isn + conn->sent; + TCP_WBSEQNO(wrb) = conn->isn + conn->sent; } /* The TCP stack updates sndseq on receipt of ACK *before* @@ -758,7 +758,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * before the packet is sent. */ - tcp_setsequence(conn->sndseq, TCPWB_SEQNO(wrb) + TCPWB_SENT(wrb)); + tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb)); #ifdef NEED_IPDOMAIN_SUPPORT /* If both IPv4 and IPv6 support are enabled, then we will need to @@ -774,7 +774,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, * won't actually happen until the polling cycle completes). */ - devif_iob_send(dev, TCPWB_IOB(wrb), sndlen, TCPWB_SENT(wrb)); + devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, TCP_WBSENT(wrb)); /* Remember how much data we send out now so that we know * when everything has been acknowledged. Just increment @@ -796,21 +796,21 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, } ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n", - wrb, TCPWB_NRTX(wrb), conn->unacked, conn->sent); + wrb, TCP_WBNRTX(wrb), conn->unacked, conn->sent); /* Increment the count of bytes sent from this write buffer */ - TCPWB_SENT(wrb) += sndlen; + TCP_WBSENT(wrb) += sndlen; ninfo("SEND: wrb=%p sent=%u pktlen=%u\n", - wrb, TCPWB_SENT(wrb), TCPWB_PKTLEN(wrb)); + wrb, TCP_WBSENT(wrb), TCP_WBPKTLEN(wrb)); /* Remove the write buffer from the write queue if the * last of the data has been sent from the buffer. */ - DEBUGASSERT(TCPWB_SENT(wrb) <= TCPWB_PKTLEN(wrb)); - if (TCPWB_SENT(wrb) >= TCPWB_PKTLEN(wrb)) + DEBUGASSERT(TCP_WBSENT(wrb) <= TCP_WBPKTLEN(wrb)); + if (TCP_WBSENT(wrb) >= TCP_WBPKTLEN(wrb)) { FAR struct tcp_wrbuffer_s *tmp; @@ -1061,8 +1061,8 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, /* Initialize the write buffer */ - TCPWB_SEQNO(wrb) = (unsigned)-1; - TCPWB_NRTX(wrb) = 0; + TCP_WBSEQNO(wrb) = (unsigned)-1; + TCP_WBNRTX(wrb) = 0; /* Copy the user data into the write buffer. We cannot wait for * buffer space if the socket was opened non-blocking. @@ -1070,16 +1070,16 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, if (_SS_ISNONBLOCK(psock->s_flags)) { - result = TCPWB_TRYCOPYIN(wrb, (FAR uint8_t *)buf, len); + result = TCP_WBTRYCOPYIN(wrb, (FAR uint8_t *)buf, len); } else { - result = TCPWB_COPYIN(wrb, (FAR uint8_t *)buf, len); + result = TCP_WBCOPYIN(wrb, (FAR uint8_t *)buf, len); } /* Dump I/O buffer chain */ - TCPWB_DUMP("I/O buffer chain", wrb, TCPWB_PKTLEN(wrb), 0); + TCP_WBDUMP("I/O buffer chain", wrb, TCP_WBPKTLEN(wrb), 0); /* psock_send_eventhandler() will send data in FIFO order from the * conn->write_q @@ -1087,7 +1087,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, sq_addlast(&wrb->wb_node, &conn->write_q); ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n", - wrb, TCPWB_PKTLEN(wrb), + wrb, TCP_WBPKTLEN(wrb), conn->write_q.head, conn->write_q.tail); /* Notify the device driver of the availability of TX data */ diff --git a/net/tcp/tcp_wrbuffer_dump.c b/net/tcp/tcp_wrbuffer_dump.c index a27bb60253d..1af76573952 100644 --- a/net/tcp/tcp_wrbuffer_dump.c +++ b/net/tcp/tcp_wrbuffer_dump.c @@ -64,8 +64,8 @@ void tcp_wrbuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb, unsigned int len, unsigned int offset) { syslog(LOG_DEBUG, "%s: wrb=%p segno=%d sent=%d nrtx=%d\n", - msg, wrb, TCPWB_SEQNO(wrb), TCPWB_SENT(wrb), TCPWB_NRTX(wrb)); - iob_dump("I/O Buffer Chain", TCPWB_IOB(wrb), len, offset); + msg, wrb, TCP_WBSEQNO(wrb), TCP_WBSENT(wrb), TCP_WBNRTX(wrb)); + iob_dump("I/O Buffer Chain", TCP_WBIOB(wrb), len, offset); } #endif /* CONFIG_DEBUG_FEATURES */ diff --git a/net/udp/udp.h b/net/udp/udp.h index ee591ed0782..f670f7bbfb9 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -71,10 +71,10 @@ /* UDP write buffer dump macros */ # ifdef CONFIG_DEBUG_FEATURES -# define UDPWB_DUMP(msg,wrb,len,offset) \ +# define UDP_WBDUMP(msg,wrb,len,offset) \ udp_wrbuffer_dump(msg,wrb,len,offset) # else -# define UDPWB_DUMP(msg,wrb,len,offset) +# define UDP_WBDUMP(msg,wrb,len,offset) # endif #endif diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c index b084837b6e2..29308e12747 100644 --- a/net/udp/udp_psock_sendto_buffered.c +++ b/net/udp/udp_psock_sendto_buffered.c @@ -97,8 +97,8 @@ # define BUF_DUMP(msg,buf,len) lib_dumpbuffer(msg,buf,len) #else # define BUF_DUMP(msg,buf,len) -# undef UDPWB_DUMP -# define UDPWB_DUMP(msg,wrb,len,offset) +# undef UDP_WBDUMP +# define UDP_WBDUMP(msg,wrb,len,offset) #endif /**************************************************************************** @@ -747,7 +747,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, /* Dump I/O buffer chain */ - UDPWB_DUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0); + UDP_WBDUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0); /* sendto_eventhandler() will send data in FIFO order from the * conn->write_q From 7f245e272045b5d7238a75491f4c25c01bf66a18 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 23 Jan 2018 07:32:17 -0600 Subject: [PATCH 32/44] net/udp: UDP write buffering is basically functional but needs a lot more verification. --- net/udp/Kconfig | 1 - net/udp/udp.h | 9 ++-- net/udp/udp_psock_sendto_buffered.c | 75 ++++++++--------------------- 3 files changed, 24 insertions(+), 61 deletions(-) diff --git a/net/udp/Kconfig b/net/udp/Kconfig index 16d40a72efa..7deccfc4caa 100644 --- a/net/udp/Kconfig +++ b/net/udp/Kconfig @@ -52,7 +52,6 @@ config NET_UDP_WRITE_BUFFERS default n select NET_WRITE_BUFFERS select MM_IOB - depends on EXPERIMENTAL ---help--- Write buffers allows buffering of ongoing UDP/IP packets, providing for higher performance, streamed output. diff --git a/net/udp/udp.h b/net/udp/udp.h index f670f7bbfb9..24be51dc21e 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -137,12 +138,12 @@ struct udp_conn_s #ifdef CONFIG_NET_UDP_WRITE_BUFFERS struct udp_wrbuffer_s { - sq_entry_t wb_node; /* Supports a singly linked list */ - union ip_addr_u wb_dest; /* Destination address */ + sq_entry_t wb_node; /* Supports a singly linked list */ + struct sockaddr_storage wb_dest; /* Destination address */ #ifdef CONFIG_NET_SOCKOPTS - systime_t wb_start; /* Start time for timeout calculation */ + systime_t wb_start; /* Start time for timeout calculation */ #endif - struct iob_s *wb_iob; /* Head of the I/O buffer chain */ + struct iob_s *wb_iob; /* Head of the I/O buffer chain */ }; #endif diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c index 29308e12747..9f8716d3552 100644 --- a/net/udp/udp_psock_sendto_buffered.c +++ b/net/udp/udp_psock_sendto_buffered.c @@ -124,8 +124,6 @@ static int sendto_next_transfer(FAR struct socket *psock, static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags); -static inline void sendto_txnotify(FAR struct socket *psock, - FAR struct udp_conn_s *conn); /**************************************************************************** * Private Functions @@ -378,9 +376,13 @@ static int sendto_next_transfer(FAR struct socket *psock, */ wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q); - DEBUGASSERT(wrb != NULL); + if (wrb == NULL) + { + ninfo("Write buffer queue is empty\n"); + return -ENOENT; + } - ret = udp_connect(conn, (FAR const struct sockaddr *)wrb->wb_iob->io_data); + ret = udp_connect(conn, (FAR const struct sockaddr *)&wrb->wb_dest); if (ret < 0) { nerr("ERROR: udp_connect failed: %d\n", ret); @@ -443,6 +445,10 @@ static int sendto_next_transfer(FAR struct socket *psock, psock->s_sndcb->flags = (UDP_POLL | NETDEV_DOWN); psock->s_sndcb->priv = (FAR void *)psock; psock->s_sndcb->event = sendto_eventhandler; + + /* Notify the device driver of the availability of TX data */ + + netdev_txnotify_dev(dev); return OK; } @@ -499,7 +505,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, * buffers to send. */ - if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) != 0 && + if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) == 0 && (flags & UDP_POLL) != 0 && !sq_empty(&conn->write_q)) { /* Check if the destination IP address is in the ARP or Neighbor @@ -576,53 +582,6 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, return flags; } -/**************************************************************************** - * Name: sendto_txnotify - * - * Description: - * Notify the appropriate device driver that we are have data ready to - * be send (UDP) - * - * Parameters: - * psock - Socket state structure - * conn - The UDP connection structure - * - * Returned Value: - * None - * - ****************************************************************************/ - -static inline void sendto_txnotify(FAR struct socket *psock, - FAR struct udp_conn_s *conn) -{ -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - /* If both IPv4 and IPv6 support are enabled, then we will need to select - * the device driver using the appropriate IP domain. - */ - - if (psock->s_domain == PF_INET) -#endif - { - /* Notify the device driver that send data is available */ - - netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else /* if (psock->s_domain == PF_INET6) */ -#endif /* CONFIG_NET_IPv4 */ - { - /* Notify the device driver that send data is available */ - - DEBUGASSERT(psock->s_domain == PF_INET6); - netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr); - } -#endif /* CONFIG_NET_IPv6 */ -} - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -750,7 +709,14 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, UDP_WBDUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0); /* sendto_eventhandler() will send data in FIFO order from the - * conn->write_q + * conn->write_q. + * + * REVISIT: Why FIFO order? Because it is easy. In a real world + * environment where there are multiple network devices this might + * be inefficient because we could be sending data to different + * device out-of-queued-order to optimize performance. Sending + * data to different networks from a single UDP socket is probably + * not a very common use case, however. */ sq_addlast(&wrb->wb_node, &conn->write_q); @@ -770,9 +736,6 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, goto errout_with_wrb; } - /* Notify the device driver of the availability of TX data */ - - sendto_txnotify(psock, conn); net_unlock(); } From 58b95f4629d3f768a6215463f1adc4500e3a97f4 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 23 Jan 2018 11:54:03 -0600 Subject: [PATCH 33/44] net/udp: Fix memory leak with UDP + write buffer is closed. Also update TODO and comments and refresh a configuration. --- TODO | 30 +++++++++------------ configs/viewtool-stm32f107/README.txt | 6 ----- configs/viewtool-stm32f107/netnsh/defconfig | 14 +++++++--- net/inet/inet_close.c | 18 +++++++++++-- net/tcp/tcp_netpoll.c | 6 ++++- net/udp/udp_netpoll.c | 6 ++++- 6 files changed, 49 insertions(+), 31 deletions(-) diff --git a/TODO b/TODO index dd4dca76ac2..b5ab5f89dae 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated January 21, 2018) +NuttX TODO List (Last updated January 23, 2018) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -19,7 +19,7 @@ nuttx/: (8) Kernel/Protected Build (3) C++ Support (6) Binary loaders (binfmt/) - (17) Network (net/, drivers/net) + (16) Network (net/, drivers/net) (4) USB (drivers/usbdev, drivers/usbhost) (0) Other drivers (drivers/) (12) Libraries (libc/, libm/) @@ -1075,23 +1075,19 @@ o Network (net/, drivers/net) Title: POLL/SELECT ON TCP/UDP SOCKETS NEEDS READ-AHEAD Description: poll()/select() only works for availability of buffered TCP/UDP read data (when read-ahead is enabled). The way writing is - handled in the network layer, all sockets must wait when send and - cannot be notified when they can send without waiting. + handled in the network layer, either (1) If CONFIG_UDP/TCP_WRITE_BUFFERS=y + then we never have to wait to send; otherwise, we always have + to wait to send. So it is impossible to notify the caller + when it can send without waiting. + + An exception "never having to wait" is the case where we are + out of memory for use in write buffering. In that case, the + blocking send()/sendto() would have to wait for the memory + to become available. Status: Open, probably will not be fixed. Priority: Medium... this does effect porting of applications that expect different behavior from poll()/select() - Title: SOCKETS DO NOT ALWAYS SUPPORT O_NONBLOCK - Description: sockets do not support all modes for O_NONBLOCK. Sockets - support nonblocking operations only (1) for TCP/IP non- - blocking read operations when read-ahead buffering is - enabled, (2) TCP/IP accept() operations when TCP/IP - connection backlog is enabled, (2) UDP/IP read() operations - when UDP read-ahead is enabled, and (3) non-blocking - operations on Unix domain sockets. - Status: Open - Priority: Low. - Title: INTERFACES TO LEAVE/JOIN IGMP MULTICAST GROUP Description: The interfaces used to leave/join IGMP multicast groups is non-standard. RFC3678 (IGMPv3) suggests ioctl() commands to do this (SIOCSIPMSFILTER) but @@ -1124,8 +1120,8 @@ o Network (net/, drivers/net) however. Others support the address filtering interfaces but have never been verifed: - C5471, LM3S, ez80, DM0x90 NIC, PIC: Do not support address - filtering. + C5471, LM3S, ez80, DM0x90 NIC, PIC, LPC54: Do not support + address filtering. Kinetis, LPC17xx, LPC43xx: Untested address filter support Status: Open diff --git a/configs/viewtool-stm32f107/README.txt b/configs/viewtool-stm32f107/README.txt index 3bb13a31662..42faf94f79d 100644 --- a/configs/viewtool-stm32f107/README.txt +++ b/configs/viewtool-stm32f107/README.txt @@ -630,12 +630,6 @@ Configurations 6. USB support is disabled by default. See the section above entitled, "USB Interface" - STATUS. The first time I build the configuration, I get some undefined - external references. No idea why. Simply cleaning the apps/ directory - and rebuilding fixes the problem: - - make apps_clean all - nsh: This configuration directory provide the basic NuttShell (NSH). diff --git a/configs/viewtool-stm32f107/netnsh/defconfig b/configs/viewtool-stm32f107/netnsh/defconfig index 131d3b620b1..72a2921d02a 100644 --- a/configs/viewtool-stm32f107/netnsh/defconfig +++ b/configs/viewtool-stm32f107/netnsh/defconfig @@ -1,5 +1,4 @@ # CONFIG_NSH_ARGCAT is not set -# CONFIG_NSH_CMDOPT_DF_H is not set # CONFIG_NSH_CMDOPT_HEXDUMP is not set # CONFIG_NSH_CMDPARMS is not set CONFIG_ARCH_BOARD_VIEWTOOL_STM32F107=y @@ -23,9 +22,15 @@ CONFIG_NET_ARP_SEND=y CONFIG_NET_BROADCAST=y CONFIG_NET_ETH_MTU=650 CONFIG_NET_ETH_TCP_RECVWNDO=624 +CONFIG_NET_HOSTNAME="Viewtool-STM32F107" CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ICMP=y +CONFIG_NET_ICMPv6_NEIGHBOR=y +CONFIG_NET_ICMPv6_SOCKET=y +CONFIG_NET_ICMPv6=y +CONFIG_NET_IPv6=y CONFIG_NET_MAX_LISTENPORTS=40 +CONFIG_NET_ROUTE=y CONFIG_NET_SOCKOPTS=y CONFIG_NET_TCP_CONNS=40 CONFIG_NET_TCP_WRITE_BUFFERS=y @@ -56,9 +61,9 @@ CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_HPWORKSTACKSIZE=1024 CONFIG_SDCLONE_DISABLE=y -CONFIG_START_DAY=21 -CONFIG_START_MONTH=9 -CONFIG_START_YEAR=2009 +CONFIG_START_DAY=23 +CONFIG_START_MONTH=1 +CONFIG_START_YEAR=2018 CONFIG_STM32_ETHMAC=y CONFIG_STM32_JTAG_FULL_ENABLE=y CONFIG_STM32_PHYSR_100MBPS=0x0000 @@ -70,6 +75,7 @@ CONFIG_STM32_PWR=y CONFIG_STM32_RMII_EXTCLK=y CONFIG_STM32_USART1=y CONFIG_SYSTEM_PING=y +CONFIG_SYSTEM_PING6=y CONFIG_TASK_NAME_SIZE=0 CONFIG_USART1_SERIAL_CONSOLE=y CONFIG_USER_ENTRYPOINT="nsh_main" diff --git a/net/inet/inet_close.c b/net/inet/inet_close.c index a36089e5417..14c463c628b 100644 --- a/net/inet/inet_close.c +++ b/net/inet/inet_close.c @@ -345,7 +345,7 @@ static inline int tcp_close_disconnect(FAR struct socket *psock) #ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* If we have a semi-permanent write buffer callback in place, then - * is needs to be be nullifed. + * is needs to be be nullified. * * Commit f1ef2c6cdeb032eaa1833cc534a63b50c5058270: * "When a socket is closed, it should make sure that any pending write @@ -357,6 +357,9 @@ static inline int tcp_close_disconnect(FAR struct socket *psock) * data. However, to be able to actually send any new data, the send * callback must be left. The callback should be freed later when the * socket is actually destroyed." + * + * REVISIT: Where and how exactly is s_sndcb ever freed? Is there a + * memory leak here? */ psock->s_sndcb = NULL; @@ -548,7 +551,18 @@ int inet_close(FAR struct socket *psock) if (conn->crefs <= 1) { - /* Yes... free the connection structure */ + /* Yes... */ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + /* Free any semi-permanent write buffer callback in place. */ + + if (psock->s_sndcb != NULL) + { + udp_callback_free(conn->dev, conn, psock->s_sndcb); + psock->s_sndcb = NULL; + } +#endif + /* And free the connection structure */ conn->crefs = 0; udp_free(psock->s_conn); diff --git a/net/tcp/tcp_netpoll.c b/net/tcp/tcp_netpoll.c index 615fb84b565..3979cf7c8dd 100644 --- a/net/tcp/tcp_netpoll.c +++ b/net/tcp/tcp_netpoll.c @@ -112,7 +112,11 @@ static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev, eventset |= POLLIN & info->fds->events; } - /* A poll is a sign that we are free to send data. */ + /* A poll is a sign that we are free to send data. + * REVISIT: This is bogus: If CONFIG_TCP_WRITE_BUFFERS=y then + * we never have to wait to send; otherwise, we always have to + * wait to send. Receiving a poll is irrelevant. + */ if ((flags & TCP_POLL) != 0) { diff --git a/net/udp/udp_netpoll.c b/net/udp/udp_netpoll.c index 0145c3303ea..1479a00b96d 100644 --- a/net/udp/udp_netpoll.c +++ b/net/udp/udp_netpoll.c @@ -111,7 +111,11 @@ static uint16_t udp_poll_eventhandler(FAR struct net_driver_s *dev, eventset |= (POLLIN & info->fds->events); } - /* poll is a sign that we are free to send data. */ + /* A poll is a sign that we are free to send data. + * REVISIT: This is bogus: If CONFIG_UDP_WRITE_BUFFERS=y then + * we never have to wait to send; otherwise, we always have to + * wait to send. Receiving a poll is irrelevant. + */ if ((flags & UDP_POLL) != 0) { From bfbedceea0607cc661cd4170f28c2448f39f7b2c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 24 Jan 2018 06:50:20 -0600 Subject: [PATCH 34/44] Update some comments. --- net/inet/inet_sockif.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index 9ab4be7336e..d9c56ad76d8 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -286,6 +286,10 @@ static sockcaps_t inet_sockcaps(FAR struct socket *psock) { #ifdef NET_TCP_HAVE_STACK case SOCK_STREAM: + /* REVISIT: Non-blocking recv() depends on CONFIG_NET_TCP_READAHEAD, + * but non-blocking send() depends on CONFIG_NET_TCP_WRITE_BUFFERS. + */ + #ifdef CONFIG_NET_TCP_READAHEAD return SOCKCAP_NONBLOCKING; #else @@ -295,6 +299,10 @@ static sockcaps_t inet_sockcaps(FAR struct socket *psock) #ifdef NET_UDP_HAVE_STACK case SOCK_DGRAM: + /* REVISIT: Non-blocking recvfrom() depends on CONFIG_NET_UDP_READAHEAD, + * but non-blocking sendto() depends on CONFIG_NET_UDP_WRITE_BUFFERS. + */ + #ifdef CONFIG_NET_UDP_READAHEAD return SOCKCAP_NONBLOCKING; #else From f232c862da8bb4d540b621866e1fe6d8672d704d Mon Sep 17 00:00:00 2001 From: Alexander Oryshchenko Date: Wed, 24 Jan 2018 06:51:34 -0600 Subject: [PATCH 35/44] drivers/mtd/at24xx.c: Correct page size for AT24C02 part. --- drivers/mtd/at24xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/at24xx.c b/drivers/mtd/at24xx.c index f08cec9d618..a09b948db2c 100644 --- a/drivers/mtd/at24xx.c +++ b/drivers/mtd/at24xx.c @@ -86,9 +86,9 @@ /* Get the part configuration based on the size configuration */ -#if CONFIG_AT24XX_SIZE == 2 /* AT24C02: 2Kbits = 256; 16 * 16 = 256 */ -# define AT24XX_NPAGES 16 -# define AT24XX_PAGESIZE 16 +#if CONFIG_AT24XX_SIZE == 2 /* AT24C02: 2Kbits = 256; 32 * 8 = 256 */ +# define AT24XX_NPAGES 32 +# define AT24XX_PAGESIZE 8 # define AT24XX_ADDRSIZE 1 #elif CONFIG_AT24XX_SIZE == 4 /* AT24C04: 4Kbits = 512B; 32 * 16 = 512 */ # define AT24XX_NPAGES 32 From 871419c3cd0253045d23a2fd0f9184061f6cdf3b Mon Sep 17 00:00:00 2001 From: Alexander Oryshchenko Date: Wed, 24 Jan 2018 06:55:14 -0600 Subject: [PATCH 36/44] arch/arm/src/stm32: Make STM32 usable with an external RTC. drivers/timers/ds3231.c: Correct some debug statments. --- arch/arm/src/stm32/stm32_irq.c | 2 +- arch/arm/src/stm32/stm32f40xxx_rtcc.c | 5 +++-- drivers/timers/ds3231.c | 12 ++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm/src/stm32/stm32_irq.c b/arch/arm/src/stm32/stm32_irq.c index 98adf74f36c..402351aafa2 100644 --- a/arch/arm/src/stm32/stm32_irq.c +++ b/arch/arm/src/stm32/stm32_irq.c @@ -387,7 +387,7 @@ void up_irqinitialize(void) up_enable_irq(STM32_IRQ_MEMFAULT); #endif -#ifdef CONFIG_RTC +#if defined(CONFIG_RTC) && !defined(CONFIG_RTC_EXTERNAL) /* RTC was initialized earlier but IRQs weren't ready at that time */ stm32_rtc_irqinitialize(); diff --git a/arch/arm/src/stm32/stm32f40xxx_rtcc.c b/arch/arm/src/stm32/stm32f40xxx_rtcc.c index 8657d6e1667..460a3872d87 100644 --- a/arch/arm/src/stm32/stm32f40xxx_rtcc.c +++ b/arch/arm/src/stm32/stm32f40xxx_rtcc.c @@ -58,7 +58,7 @@ #include -#ifdef CONFIG_RTC +#if defined(CONFIG_RTC) && !defined(CONFIG_RTC_EXTERNAL) /**************************************************************************** * Pre-processor Definitions @@ -1659,4 +1659,5 @@ int stm32_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo) } #endif -#endif /* CONFIG_RTC */ +#endif /* CONFIG_RTC && !CONFIG_RTC_EXTERNAL */ + diff --git a/drivers/timers/ds3231.c b/drivers/timers/ds3231.c index 4f1e2a1c9f5..113fb977433 100644 --- a/drivers/timers/ds3231.c +++ b/drivers/timers/ds3231.c @@ -321,7 +321,7 @@ int up_rtc_getdatetime(FAR struct tm *tp) ret = I2C_TRANSFER(g_ds3231.i2c, msg, 4); if (ret < 0) { - rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret) + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); return ret; } } @@ -415,7 +415,7 @@ int up_rtc_settime(FAR const struct timespec *tp) return -EAGAIN; } - rtc_dumptime(tp, "Setting time"); + rtcinfo("Setting time tp=(%d,%d)\n", (int)tp->tv_sec, (int)tp->tv_nsec); /* Get the broken out time */ @@ -430,18 +430,18 @@ int up_rtc_settime(FAR const struct timespec *tp) #ifdef CONFIG_LIBC_LOCALTIME if (localtime_r(&newtime, &newtm) == NULL) { - rtcerr("ERROR: localtime_r failed\n") + rtcerr("ERROR: localtime_r failed\n"); return -EINVAL; } #else if (gmtime_r(&newtime, &newtm) == NULL) { - rtcerr("ERROR: gmtime_r failed\n") + rtcerr("ERROR: gmtime_r failed\n"); return -EINVAL; } #endif - rtc_dumptime(&tm, "New time"); + rtc_dumptime(&newtm, "New time"); /* Construct the message */ /* Write starting with the seconds regiser */ @@ -536,7 +536,7 @@ int up_rtc_settime(FAR const struct timespec *tp) ret = I2C_TRANSFER(g_ds3231.i2c, msg, 3); if (ret < 0) { - rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret) + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); return ret; } } From ec6145e8f754819699997014aec840f34e6b830f Mon Sep 17 00:00:00 2001 From: Alexander Oryshchenko Date: Wed, 24 Jan 2018 06:57:17 -0600 Subject: [PATCH 37/44] arch/arm/src/stm32/stm32_spi.c: Removed unnecessary (and incorrect) speed limitation --- arch/arm/src/stm32/stm32_spi.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/src/stm32/stm32_spi.c b/arch/arm/src/stm32/stm32_spi.c index 71f6dbfb3a5..1be51d49c2f 100644 --- a/arch/arm/src/stm32/stm32_spi.c +++ b/arch/arm/src/stm32/stm32_spi.c @@ -1122,13 +1122,6 @@ static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency) uint16_t setbits; uint32_t actual; - /* Limit to max possible (if STM32_SPI_CLK_MAX is defined in board.h) */ - - if (frequency > STM32_SPI_CLK_MAX) - { - frequency = STM32_SPI_CLK_MAX; - } - /* Has the frequency changed? */ if (frequency != priv->frequency) From 9e965247e42ad18c6a94f124cfbc05d1b079b54f Mon Sep 17 00:00:00 2001 From: Alexander Oryshchenko Date: Wed, 24 Jan 2018 06:58:47 -0600 Subject: [PATCH 38/44] arch/arm/src/stm32/stm32f40xxx_i2c.c: Correct some recent changes to STM32F4 I2C that broke poll mode of operation. --- arch/arm/src/stm32/stm32f40xxx_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/src/stm32/stm32f40xxx_i2c.c b/arch/arm/src/stm32/stm32f40xxx_i2c.c index 86de66e7f56..9317b3608c0 100644 --- a/arch/arm/src/stm32/stm32f40xxx_i2c.c +++ b/arch/arm/src/stm32/stm32f40xxx_i2c.c @@ -1273,7 +1273,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) if (priv->dcnt == -1 && priv->msgc != 0 && (status & I2C_SR1_SB) == 0) { -#ifdef CONFIG_STM32_I2C_DMA +#if defined(CONFIG_STM32_I2C_DMA) || defined(CONFIG_I2C_POLLED) return OK; #else priv->status |= I2C_SR1_TIMEOUT; @@ -2049,7 +2049,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) /* Clear interrupt flags */ -#ifndef CONFIG_STM32_I2C_DMA +#if !defined(CONFIG_STM32_I2C_DMA) && !defined(CONFIG_I2C_POLLED) state_error: #endif stm32_i2c_putreg(priv, STM32_I2C_SR1_OFFSET, 0); From 822e67692b127e7fe63f72b1bfd0ed9dacabc012 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 24 Jan 2018 08:52:40 -0600 Subject: [PATCH 39/44] configs/flipnclick-sam3x: Using JTAG (vs. Bossac) I was finally able to load code and verify the basic NSH configuration. Updated READMEs. Also switched to USART0 (vs UART0) for the serial console because I was not getting bi-directional communication on the VCOM. --- configs/arduino-due/README.txt | 6 +++ configs/flipnclick-sam3x/README.txt | 70 +++++++++++++++++--------- configs/flipnclick-sam3x/nsh/defconfig | 4 +- configs/freedom-k64f/README.txt | 2 +- configs/freedom-k66f/README.txt | 5 +- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/configs/arduino-due/README.txt b/configs/arduino-due/README.txt index bb6d7f08aa8..0de6bcb4d22 100644 --- a/configs/arduino-due/README.txt +++ b/configs/arduino-due/README.txt @@ -330,6 +330,12 @@ Serial Consoles Loading Code ============ + [NOTE: I believe that there have been significant changes to the more + recent tool environment such that Bossac may no longer be usable. I + don't know that for certain and perhaps someone with more knowledge of + the tools than I could make this work. See the Flip'n'Clip SAM3X README + file for additional information.] + Installing the Arduino USB Driver under Windows: ------------------------------------------------ diff --git a/configs/flipnclick-sam3x/README.txt b/configs/flipnclick-sam3x/README.txt index 6cbf47b5697..8ab7a159a8f 100644 --- a/configs/flipnclick-sam3x/README.txt +++ b/configs/flipnclick-sam3x/README.txt @@ -22,23 +22,11 @@ STATUS ====== 2018-01-07: Created the configuration. At present it does not work; I - believe because of tool-related issues. I do the following: - - a) Open TeraTerm, select COM7 at 1200 baud, type a few ENTERs, and - close teraterm. - - b) Execute the following command which claims to have successfully - written to FLASH. - - bossac.exe --info --debug --port COM7 --usb-port=0 --erase --write --verify -b nuttx.bin -R - - But the code does not boot. There is no indication of life. - - c) Repeat a) then - - bossac.exe --info --debug --port COM7 --usb-port=0 --verify -b nuttx.bin - - And it says that the content of the FLASH is not good. + believe because of tool-related issues. See discussion under "Loading + Code" below. + 2018-01-24: I ordered a JTAG connector and soldered that to the Flip'n'Click + and I am now successfully able to load code. The NSH configuration appears + to be fully functional. Buttons and LEDs ================ @@ -99,10 +87,11 @@ Serial Consoles serial chip connected to the first of the MCU (RX0 and TX0 on PA8 and PA9, respectively). The output from that port is visible using the Arduino tool. - Any of UART and USART0-3 may be used as a serial console. By default, - UART0 is used as the serial console in all configurations. But that is - easily changed by modifying the configuration as described under - "Configurations" below. + [NOTE: My experience so far: I get serial output on the virtual COM port + via the UART, but I receive no serial input for keyboard data entered in + the PC serial terminal. I have not investigated this problem. It may + be something as simple as the Rx pin configuration. Instead, I just + switched to USART0.] Other convenient U[S]ARTs that may be used as the Serial console include: @@ -125,9 +114,22 @@ Serial Consoles transceiver to get the signals to RS232 levels (or connect to the USB virtual COM port in the case of UART0). + Any of UART and USART0-3 may be used as a serial console. UART0 would + be the preferred default console setting. However, due to the communication + problems mentioned above, USART0 is used as the default serial console + in all configurations. But that is easily changed by modifying the + configuration as described under "Configurations" below. + Loading Code ============ + [NOTE: This text was mostly copied from the Arduino Due README.txt. I + believe, however, that there have been significant changes to the + tool environment such that Bossac may no longer be usable. I don't + know that for certain and perhaps someone with more knowledge of + the tools than I could make this work. See STATUS below for the + current issues that I see.] + Installing the Arduino USB Driver under Windows ----------------------------------------------- @@ -302,6 +304,25 @@ Loading Code $ bossac.exe --port=COM7 --usb-port=false --boot=1 Set boot flash true + STATUS: + At present this procedure does not work. I do the following: + + a) Open TeraTerm, select COM7 at 1200 baud, type a few ENTERs, and + close teraterm. + + b) Execute the following command which claims to have successfully + written to FLASH. + + bossac.exe --info --debug --port COM7 --usb-port=0 --erase --write --verify -b nuttx.bin -R + + But the code does not boot. There is no indication of life. + + c) Repeat a) then + + bossac.exe --info --debug --port COM7 --usb-port=0 --verify -b nuttx.bin + + And it says that the content of the FLASH is not good. + Uploading NuttX to the Flip&Click Using JTAG -------------------------------------------- @@ -465,15 +486,16 @@ Configurations reconfiguration process. 2. Unless stated otherwise, all configurations generate console - output on UART0 which is available both on the USB virtual COM port - and on the PWML connector (see the section "Serial Consoles" above). + output on USART0 which is available either on the Arduion Shield + connector or on mikroBUS A as described above in the section entitled + "Serial Consoles". 3. Unless otherwise stated, the configurations are setup for Cygwin under Windows: Build Setup: CONFIG_HOST_WINDOWS=y : Microsoft Windows - CONFIG_WINDIWS_CYGWIN=y : Cygwin under Windoes + CONFIG_WINDIWS_CYGWIN=y : Cygwin under Windows 3. All of these configurations are set up to build under Windows using the "GNU Tools for ARM Embedded Processors" that is maintained by ARM diff --git a/configs/flipnclick-sam3x/nsh/defconfig b/configs/flipnclick-sam3x/nsh/defconfig index 79057461ad6..f0ba4aedf39 100644 --- a/configs/flipnclick-sam3x/nsh/defconfig +++ b/configs/flipnclick-sam3x/nsh/defconfig @@ -1,4 +1,5 @@ # CONFIG_ARCH_RAMFUNCS is not set +# CONFIG_SAM34_UART0 is not set CONFIG_ARCH_BOARD_FLIPNCLICK_SAM3X=y CONFIG_ARCH_BOARD="flipnclick-sam3x" CONFIG_ARCH_CHIP_ATSAM3X8E=y @@ -33,12 +34,13 @@ CONFIG_RAM_SIZE=65536 CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 +CONFIG_SAM34_USART0=y CONFIG_SCHED_WAITPID=y CONFIG_SDCLONE_DISABLE=y CONFIG_START_DAY=28 CONFIG_START_MONTH=6 CONFIG_START_YEAR=2013 CONFIG_TASK_NAME_SIZE=0 -CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_USART0_SERIAL_CONSOLE=y CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_WDOG_INTRESERVE=0 diff --git a/configs/freedom-k64f/README.txt b/configs/freedom-k64f/README.txt index 5559b2fe5f1..a2ce126b7de 100644 --- a/configs/freedom-k64f/README.txt +++ b/configs/freedom-k64f/README.txt @@ -618,7 +618,7 @@ GNU Toolchain Options ===================== The NuttX make system supports several GNU-based toolchains under Linux, - Cygwin under Windows, and Windoes native. To select a toolchain: + Cygwin under Windows, and Windows native. To select a toolchain: 1. Use 'make menuconfig' and select the toolchain that you are using under the System Type menu. diff --git a/configs/freedom-k66f/README.txt b/configs/freedom-k66f/README.txt index 7f5da7cffaa..c78a3c4c807 100644 --- a/configs/freedom-k66f/README.txt +++ b/configs/freedom-k66f/README.txt @@ -621,7 +621,7 @@ GNU Toolchain Options ===================== The NuttX make system supports several GNU-based toolchains under Linux, - Cygwin under Windows, and Windoes native. To select a toolchain: + Cygwin under Windows, and Windows native. To select a toolchain: 1. Use 'make menuconfig' and select the toolchain that you are using under the System Type menu. @@ -972,4 +972,5 @@ Status 2017-02-14: nsh: SDHC DMA is not working yet. Buttons and SDIO with automounter is working. netnsh:Is building but Ehternet is not working yet. TX is called but - not IRQ is issued. \ No newline at end of file + not IRQ is issued. + From 1ae8daf5d5f0fc8172699ea364661d3353ad2e6b Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Wed, 24 Jan 2018 19:06:00 -0800 Subject: [PATCH 40/44] SAMDL: Added SAMD DAC header file. Fixed SAMD EVSYS header. Added SAMD TC header file. Fixed some minor typos --- arch/arm/src/samdl/chip/samd_dac.h | 136 +++++++++++++++ arch/arm/src/samdl/chip/samd_evsys.h | 34 ++-- arch/arm/src/samdl/chip/samd_tc.h | 249 +++++++++++++++++++++++++++ arch/arm/src/samdl/sam_dac.h | 77 +++++++++ arch/arm/src/samdl/sam_evsys.h | 76 ++++++++ arch/arm/src/samdl/samd_periphclks.h | 6 +- 6 files changed, 560 insertions(+), 18 deletions(-) create mode 100644 arch/arm/src/samdl/chip/samd_dac.h create mode 100644 arch/arm/src/samdl/chip/samd_tc.h create mode 100644 arch/arm/src/samdl/sam_dac.h create mode 100644 arch/arm/src/samdl/sam_evsys.h diff --git a/arch/arm/src/samdl/chip/samd_dac.h b/arch/arm/src/samdl/chip/samd_dac.h new file mode 100644 index 00000000000..274cab701ef --- /dev/null +++ b/arch/arm/src/samdl/chip/samd_dac.h @@ -0,0 +1,136 @@ +/******************************************************************************************** + * arch/arm/src/samdl/chip/saml_dac.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * "Atmel SAM L21E / SAM L21G / SAM L21J Smart ARM-Based Microcontroller + * Datasheet", Atmel-42385C-SAML21_Datasheet_Preliminary-03/20/15 + * + * 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 NuttX 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 OWNER 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_SAMDL_CHIP_SAMD_DAC_H +#define __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_DAC_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_ARCH_FAMILY_SAMD21 + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ +/* DAC register offsets ********************************************************************/ + +#define SAM_DAC_CTRLA_OFFSET 0x0000 /* Control A Register */ +#define SAM_DAC_CTRLB_OFFSET 0x0001 /* Control B Register */ +#define SAM_DAC_EVCTRL_OFFSET 0x0002 /* Event Control Register */ +#define SAM_DAC_INTENCLR_OFFSET 0x0004 /* Interrupt Enable Clear Register */ +#define SAM_DAC_INTENSET_OFFSET 0x0005 /* Interrupt Enable Set Register */ +#define SAM_DAC_INTFLAG_OFFSET 0x0006 /* Interrupt Flag Status and Clear Register */ +#define SAM_DAC_STATUS_OFFSET 0x0007 /* Status Register */ +#define SAM_DAC_DATA0_OFFSET 0x0008 /* Data DAC0 Register */ +#define SAM_DAC_DATA1_OFFSET 0x0009 /* Data DAC1 Register */ +#define SAM_DAC_DATABUF0_OFFSET 0x000C /* Data Buffer DAC0 Register */ +#define SAM_DAC_DATABUF1_OFFSET 0x000D /* Data Buffer DAC1 Register */ + +/* DAC register addresses ******************************************************************/ + +#define SAM_DAC_CTRLA (SAM_DAC_BASE+SAM_DAC_CTRLA_OFFSET) +#define SAM_DAC_CTRLB (SAM_DAC_BASE+SAM_DAC_CTRLB_OFFSET) +#define SAM_DAC_EVCTRL (SAM_DAC_BASE+SAM_DAC_EVCTRL_OFFSET) +#define SAM_DAC_INTENCLR (SAM_DAC_BASE+SAM_DAC_INTENCLR_OFFSET) +#define SAM_DAC_INTENSET (SAM_DAC_BASE+SAM_DAC_INTENSET_OFFSET) +#define SAM_DAC_INTFLAG (SAM_DAC_BASE+SAM_DAC_INTFLAG_OFFSET) +#define SAM_DAC_STATUS (SAM_DAC_BASE+SAM_DAC_STATUS_OFFSET) +#define SAM_DAC_DATA0 (SAM_DAC_BASE+SAM_DAC_DATA0_OFFSET) +#define SAM_DAC_DATA1 (SAM_DAC_BASE+SAM_DAC_DATA1_OFFSET) +#define SAM_DAC_DATABUF0 (SAM_DAC_BASE+SAM_DAC_DATABUF0_OFFSET) +#define SAM_DAC_DATABUF1 (SAM_DAC_BASE+SAM_DAC_DATABUF1_OFFSET) + +/* DAC register bit definitions ************************************************************/ + +/* Control A Register */ + +#define DAC_CTRLA_SWRTS (1 << 0) /* Bit 0: Software reset */ +#define DAC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable DAC controller */ +#define DAC_CTRLA_RUNSTDBY (1 << 2) /* Bit 1: Run in standby */ + +/* Control B Register */ + +#define DAC_CTRLB_EOEN (1 << 0) /* Bit 0: External Output Enable (to Vout) */ +#define DAC_CTRLB_IOEN (1 << 1) /* Bit 1: Internal Output Enable (to analog comparator) */ +#define DAC_CTRLB_LEFTADJ (1 << 2) /* Bit 2: Left-Adjusted Data */ +#define DAC_CTRLB_VPD (1 << 3) /* Bit 3: Voltage Pump Disabled */ +#define DAC_CTRLB_BDWP (1 << 4) /* Bit 4: Bypass DATABUF Write protection */ +#define DAC_CTRLB_REFSEL_SHIFT (6) /* Bit 7:6: Reference selection */ +#define DAC_CTRLB_REFSEL_MASK (3 << DAC_CTRLB_REFSEL_SHIFT) +# define DAC_CTRLB_REFSEL_INTREF (0 << DAC_CTRLB_REFSEL_SHIFT) /* Internal voltage reference */ +# define DAC_CTRLB_REFSEL_VDDANA (1 << DAC_CTRLB_REFSEL_SHIFT) /* Analog voltage supply */ +# define DAC_CTRLB_REFSEL_VREFA (2 << DAC_CTRLB_REFSEL_SHIFT) /* External voltage reference */ + +/* Event Control Register */ + +#define DAC_EVCTRL_STARTEI (1 << 0) /* Bit 0: Start conversion event input */ +#define DAC_EVCTRL_EMPTYEO (1 << 1) /* Bit 1: Data buffer empty event output */ + +/* Common bit definitions for Interrupt Enable Clear Register, Interrupt Enable Set + * Register, and Interrupt Flag Status and Clear Register + */ + +#define DAC_INT_UNDERRUN (1 << 0) /* Bit 0: Underrun interrupt */ +#define DAC_INT_EMPTY (1 << 1) /* Bit 1: Data buffer empty interrupt */ +#define DAC_INT_SYNCRDY (1 << 2) /* Bit 2: Sync ready */ +#define DAC_INT_ALL 0x07 + +/* Status Register */ + +#define DAC_STATUS_SYNCBUSY (1 << 7) /* Bit 0: Sync busy */ + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* CONFIG_ARCH_FAMILY_SAMD21 */ +#endif /* __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_DAC_H */ diff --git a/arch/arm/src/samdl/chip/samd_evsys.h b/arch/arm/src/samdl/chip/samd_evsys.h index e1489a2622b..84ea384f092 100644 --- a/arch/arm/src/samdl/chip/samd_evsys.h +++ b/arch/arm/src/samdl/chip/samd_evsys.h @@ -68,9 +68,9 @@ #define SAM_EVSYS_CTRL (SAM_EVSYS_BASE+SAM_EVSYS_CTRL_OFFSET) #define SAM_EVSYS_CHANNEL (SAM_EVSYS_BASE+SAM_EVSYS_CHANNEL_OFFSET) #define SAM_EVSYS_USER (SAM_EVSYS_BASE+SAM_EVSYS_USER_OFFSET) -#define SAM_EVSYS_CHSTATUS (SAM_EVSYS_BASE+SAM_EVSYS_CHSTATUS_OFFSET -#define SAM_EVSYS_INTENCLR (SAM_EVSYS_BASE+SAM_EVSYS_INTENCLR_OFFSET -#define SAM_EVSYS_INTENSET (SAM_EVSYS_BASE+SAM_EVSYS_INTENSET_OFFSET +#define SAM_EVSYS_CHSTATUS (SAM_EVSYS_BASE+SAM_EVSYS_CHSTATUS_OFFSET) +#define SAM_EVSYS_INTENCLR (SAM_EVSYS_BASE+SAM_EVSYS_INTENCLR_OFFSET) +#define SAM_EVSYS_INTENSET (SAM_EVSYS_BASE+SAM_EVSYS_INTENSET_OFFSET) #define SAM_EVSYS_INTFLAG (SAM_EVSYS_BASE+SAM_EVSYS_INTFLAG_OFFSET) /* EVSYS register bit definitions ***********************************************************/ @@ -302,12 +302,14 @@ /* Channel status register */ -#define EVSYS_CHSTATUS_USRRDY_SHIFT (0) /* Bits 0-7: User Ready for Channel n, n=0-7 */ -#define EVSYS_CHSTATUS_USRRDY_MASK (0xff << EVSYS_CHSTATUS_USRRDY_SHIFT) -# define EVSYS_CHSTATUS_USRRDY(n) (1 << (n)) -#define EVSYS_CHSTATUS_CHBUSY_SHIFT (8) /* Bits 8-15: Channel Busy n, n=0-7 */ -#define EVSYS_CHSTATUS_CHBUSY_MASK (0xff << EVSYS_CHSTATUS_CHBUSY_SHIFT) -# define EVSYS_CHSTATUS_CHBUSY(n) (1 << ((n) + 8)) +#ifdef CONFIG_ARCH_FAMILY_SAMD20 +# define EVSYS_CHSTATUS_USRRDY_SHIFT (0) /* Bits 0-7: User Ready for Channel n, n=0-7 */ +# define EVSYS_CHSTATUS_USRRDY_MASK (0xff << EVSYS_CHSTATUS_USRRDY_SHIFT) +# define EVSYS_CHSTATUS_USRRDY(n) (1 << (n)) +# define EVSYS_CHSTATUS_CHBUSY_SHIFT (8) /* Bits 8-15: Channel Busy n, n=0-7 */ +# define EVSYS_CHSTATUS_CHBUSY_MASK (0xff << EVSYS_CHSTATUS_CHBUSY_SHIFT) +# define EVSYS_CHSTATUS_CHBUSY(n) (1 << ((n) + 8)) +#endif #ifdef CONFIG_ARCH_FAMILY_SAMD21 # define EVSYS_CHSTATUS_USRRDYH_SHIFT (16) /* Bits 16-19: User Ready for Channel n, n=8-11 */ @@ -320,12 +322,14 @@ /* Interrupt enable clear, interrupt enable set, and interrupt flag status and clear registers */ -#define EVSYS_INT_OVR_SHIFT (0) /* Bits 0-7: Overrun channel n interrupt, n=0-7 */ -#define EVSYS_INT_OVR_MASK (0xff << EVSYS_INT_OVR_SHIFT) -# define EVSYS_INT_OVR(n) (1 << (n)) -#define EVSYS_INT_EVD_SHIFT (8) /* Bits 8-15: Event detected channel n interrupt, n=0-7 */ -#define EVSYS_INT_EVD_MASK (0xff << EVSYS_INT_EVD_SHIFT) -# define EVSYS_INT_EVD(n) (1 << ((n) + 8)) +#ifdef CONFIG_ARCH_FAMILY_SAMD20 +# define EVSYS_INT_OVR_SHIFT (0) /* Bits 0-7: Overrun channel n interrupt, n=0-7 */ +# define EVSYS_INT_OVR_MASK (0xff << EVSYS_INT_OVR_SHIFT) +# define EVSYS_INT_OVR(n) (1 << (n)) +# define EVSYS_INT_EVD_SHIFT (8) /* Bits 8-15: Event detected channel n interrupt, n=0-7 */ +# define EVSYS_INT_EVD_MASK (0xff << EVSYS_INT_EVD_SHIFT) +# define EVSYS_INT_EVD(n) (1 << ((n) + 8)) +#endif #ifdef CONFIG_ARCH_FAMILY_SAMD21 # define EVSYS_INT_OVR_SHIFT (16) /* Bits 16-19: Overrun channel n interrupt, n=8-11 */ diff --git a/arch/arm/src/samdl/chip/samd_tc.h b/arch/arm/src/samdl/chip/samd_tc.h new file mode 100644 index 00000000000..02e502af8ec --- /dev/null +++ b/arch/arm/src/samdl/chip/samd_tc.h @@ -0,0 +1,249 @@ +/******************************************************************************************** + * arch/arm/src/samdl/chip/samd_tc.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * References: + * "Microchip SAMD21 datasheet" + * + * 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 NuttX 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 OWNER 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_SAMDL_CHIP_SAMD_TC_H +#define __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_TC_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_ARCH_FAMILY_SAMD21 + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ +/* TC register offsets *********************************************************************/ + +#define SAM_TC_CTRLA_OFFSET 0x0000 /* Control A register */ +#define SAM_TC_READREQ_OFFSET 0x0002 /* Read request register */ +#define SAM_TC_CTRLBCLR_OFFSET 0x0004 /* Control B clear register */ +#define SAM_TC_CTRLBSET_OFFSET 0x0005 /* Control B clear register */ +#define SAM_TC_CTRLC_OFFSET 0x0006 /* Control C register */ +#define SAM_TC_DBGCTRL_OFFSET 0x0008 /* Debug control register */ +#define SAM_TC_EVCTRL_OFFSET 0x000A /* Event control register */ +#define SAM_TC_INTENCLR_OFFSET 0x000C /* Interrupt enable clear register */ +#define SAM_TC_INTENSET_OFFSET 0x000D /* Interrupt enable set register */ +#define SAM_TC_INTFLAG_OFFSET 0x000E /* Interrupt flag register */ +#define SAM_TC_STATUS_OFFSET 0x000F /* Status register */ +#define SAM_TC_COUNT_OFFSET 0x0010 /* Count register */ +#define SAM_TC_CC0_OFFSET 0x0018 /* Capture Compare 0 register */ +#define SAM_TC_CC1_OFFSET 0x001C /* Capture Compare 1 register */ + +/* TC register addresses *******************************************************************/ + +#define SAM_TC3_CTRLA (SAM_TC3_BASE+SAM_TC_CTRLA_OFFSET) +#define SAM_TC3_READREQ (SAM_TC3_BASE+SAM_TC_READREQ_OFFSET) +#define SAM_TC3_CTRLBCLR (SAM_TC3_BASE+SAM_TC_CTRLBCLR_OFFSET) +#define SAM_TC3_CTRLBSET (SAM_TC3_BASE+SAM_TC_CTRLBSET_OFFSET) +#define SAM_TC3_CTRLC (SAM_TC3_BASE+SAM_TC_CTRLC_OFFSET) +#define SAM_TC3_DBGCTRL (SAM_TC3_BASE+SAM_TC_DBGCTRL_OFFSET) +#define SAM_TC3_EVCTRL (SAM_TC3_BASE+SAM_TC_EVCTRL_OFFSET) +#define SAM_TC3_INTENCLR (SAM_TC3_BASE+SAM_TC_INTENCLR_OFFSET) +#define SAM_TC3_INTENSET (SAM_TC3_BASE+SAM_TC_INTENSET_OFFSET) +#define SAM_TC3_INTFLAG (SAM_TC3_BASE+SAM_TC_INTFLAG_OFFSET) +#define SAM_TC3_STATUS (SAM_TC3_BASE+SAM_TC_STATUS_OFFSET) +#define SAM_TC3_COUNT (SAM_TC3_BASE+SAM_TC_COUNT_OFFSET) +#define SAM_TC3_CC0 (SAM_TC3_BASE+SAM_TC_CC0_OFFSET) +#define SAM_TC3_CC1 (SAM_TC3_BASE+SAM_TC_CC1_OFFSET) + +#define SAM_TC4_CTRLA (SAM_TC4_BASE+SAM_TC_CTRLA_OFFSET) +#define SAM_TC4_READREQ (SAM_TC4_BASE+SAM_TC_READREQ_OFFSET) +#define SAM_TC4_CTRLBCLR (SAM_TC4_BASE+SAM_TC_CTRLBCLR_OFFSET) +#define SAM_TC4_CTRLBSET (SAM_TC4_BASE+SAM_TC_CTRLBSET_OFFSET) +#define SAM_TC4_CTRLC (SAM_TC4_BASE+SAM_TC_CTRLC_OFFSET) +#define SAM_TC4_DBGCTRL (SAM_TC4_BASE+SAM_TC_DBGCTRL_OFFSET) +#define SAM_TC4_EVCTRL (SAM_TC4_BASE+SAM_TC_EVCTRL_OFFSET) +#define SAM_TC4_INTENCLR (SAM_TC4_BASE+SAM_TC_INTENCLR_OFFSET) +#define SAM_TC4_INTENSET (SAM_TC4_BASE+SAM_TC_INTENSET_OFFSET) +#define SAM_TC4_INTFLAG (SAM_TC4_BASE+SAM_TC_INTFLAG_OFFSET) +#define SAM_TC4_STATUS (SAM_TC4_BASE+SAM_TC_STATUS_OFFSET) +#define SAM_TC4_COUNT (SAM_TC4_BASE+SAM_TC_COUNT_OFFSET) +#define SAM_TC4_CC0 (SAM_TC4_BASE+SAM_TC_CC0_OFFSET) +#define SAM_TC4_CC1 (SAM_TC4_BASE+SAM_TC_CC1_OFFSET) + +#define SAM_TC5_CTRLA (SAM_TC5_BASE+SAM_TC_CTRLA_OFFSET) +#define SAM_TC5_READREQ (SAM_TC5_BASE+SAM_TC_READREQ_OFFSET) +#define SAM_TC5_CTRLBCLR (SAM_TC5_BASE+SAM_TC_CTRLBCLR_OFFSET) +#define SAM_TC5_CTRLBSET (SAM_TC5_BASE+SAM_TC_CTRLBSET_OFFSET) +#define SAM_TC5_CTRLC (SAM_TC5_BASE+SAM_TC_CTRLC_OFFSET) +#define SAM_TC5_DBGCTRL (SAM_TC5_BASE+SAM_TC_DBGCTRL_OFFSET) +#define SAM_TC5_EVCTRL (SAM_TC5_BASE+SAM_TC_EVCTRL_OFFSET) +#define SAM_TC5_INTENCLR (SAM_TC5_BASE+SAM_TC_INTENCLR_OFFSET) +#define SAM_TC5_INTENSET (SAM_TC5_BASE+SAM_TC_INTENSET_OFFSET) +#define SAM_TC5_INTFLAG (SAM_TC5_BASE+SAM_TC_INTFLAG_OFFSET) +#define SAM_TC5_STATUS (SAM_TC5_BASE+SAM_TC_STATUS_OFFSET) +#define SAM_TC5_COUNT (SAM_TC5_BASE+SAM_TC_COUNT_OFFSET) +#define SAM_TC5_CC0 (SAM_TC5_BASE+SAM_TC_CC0_OFFSET) +#define SAM_TC5_CC1 (SAM_TC5_BASE+SAM_TC_CC1_OFFSET) + +#define SAM_TC6_CTRLA (SAM_TC6_BASE+SAM_TC_CTRLA_OFFSET) +#define SAM_TC6_READREQ (SAM_TC6_BASE+SAM_TC_READREQ_OFFSET) +#define SAM_TC6_CTRLBCLR (SAM_TC6_BASE+SAM_TC_CTRLBCLR_OFFSET) +#define SAM_TC6_CTRLBSET (SAM_TC6_BASE+SAM_TC_CTRLBSET_OFFSET) +#define SAM_TC6_CTRLC (SAM_TC6_BASE+SAM_TC_CTRLC_OFFSET) +#define SAM_TC6_DBGCTRL (SAM_TC6_BASE+SAM_TC_DBGCTRL_OFFSET) +#define SAM_TC6_EVCTRL (SAM_TC6_BASE+SAM_TC_EVCTRL_OFFSET) +#define SAM_TC6_INTENCLR (SAM_TC6_BASE+SAM_TC_INTENCLR_OFFSET) +#define SAM_TC6_INTENSET (SAM_TC6_BASE+SAM_TC_INTENSET_OFFSET) +#define SAM_TC6_INTFLAG (SAM_TC6_BASE+SAM_TC_INTFLAG_OFFSET) +#define SAM_TC6_STATUS (SAM_TC6_BASE+SAM_TC_STATUS_OFFSET) +#define SAM_TC6_COUNT (SAM_TC6_BASE+SAM_TC_COUNT_OFFSET) +#define SAM_TC6_CC0 (SAM_TC6_BASE+SAM_TC_CC0_OFFSET) +#define SAM_TC6_CC1 (SAM_TC6_BASE+SAM_TC_CC1_OFFSET) + +#define SAM_TC7_CTRLA (SAM_TC7_BASE+SAM_TC_CTRLA_OFFSET) +#define SAM_TC7_READREQ (SAM_TC7_BASE+SAM_TC_READREQ_OFFSET) +#define SAM_TC7_CTRLBCLR (SAM_TC7_BASE+SAM_TC_CTRLBCLR_OFFSET) +#define SAM_TC7_CTRLBSET (SAM_TC7_BASE+SAM_TC_CTRLBSET_OFFSET) +#define SAM_TC7_CTRLC (SAM_TC7_BASE+SAM_TC_CTRLC_OFFSET) +#define SAM_TC7_DBGCTRL (SAM_TC7_BASE+SAM_TC_DBGCTRL_OFFSET) +#define SAM_TC7_EVCTRL (SAM_TC7_BASE+SAM_TC_EVCTRL_OFFSET) +#define SAM_TC7_INTENCLR (SAM_TC7_BASE+SAM_TC_INTENCLR_OFFSET) +#define SAM_TC7_INTENSET (SAM_TC7_BASE+SAM_TC_INTENSET_OFFSET) +#define SAM_TC7_INTFLAG (SAM_TC7_BASE+SAM_TC_INTFLAG_OFFSET) +#define SAM_TC7_STATUS (SAM_TC7_BASE+SAM_TC_STATUS_OFFSET) +#define SAM_TC7_COUNT (SAM_TC7_BASE+SAM_TC_COUNT_OFFSET) +#define SAM_TC7_CC0 (SAM_TC7_BASE+SAM_TC_CC0_OFFSET) +#define SAM_TC7_CC1 (SAM_TC7_BASE+SAM_TC_CC1_OFFSET) + +/* TC register bit definitions *************************************************************/ + +/* Control A register */ + +#define TC_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */ +#define TC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */ +#define TC_CTRLA_MODE_SHIFT (2) +#define TC_CTRLA_MODE_MASK (3 << TC_CTRLA_SHIFT) +# define TC_CTRLA_MODE_COUNT16 (0 << TC_CTRLA_SHIFT) +# define TC_CTRLA_MODE_COUNT8 (1 << TC_CTRLA_SHIFT) +# define TC_CTRLA_MODE_COUNT32 (2 << TC_CTRLA_SHIFT) +#define TC_CTRLA_WAVEGEN_SHIFT (5) +#define TC_CTRLA_WAVEGEN_MASK (3 << TC_CTRLA_WAVEGEN_SHIFT) +# define TC_CTRLA_WAVEGEN_NFRQ (0 << TC_CTRLA_WAVEGEN_SHIFT) +# define TC_CTRLA_WAVEGEN_MFRQ (1 << TC_CTRLA_WAVEGEN_SHIFT) +# define TC_CTRLA_WAVEGEN_NPWM (2 << TC_CTRLA_WAVEGEN_SHIFT) +# define TC_CTRLA_WAVEGEN_MPWM (3 << TC_CTRLA_WAVEGEN_SHIFT) +#define TC_CTRLA_PRESCALER_SHIFT (8) +#define TC_CTRLA_PRESCALER_MASK (7 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV1 (0 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV2 (1 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV4 (2 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV8 (3 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV16 (4 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV64 (5 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV256 (6 << TC_CTRLA_PRESCALER_SHIFT) +# define TC_CTRLA_PRESCALER_DIV1024 (7 << TC_CTRLA_PRESCALER_SHIFT) +#define TC_CTRLA_RUNSTDBY (1 << 11) +#define TC_CTRLA_PRESCSYNC_SHIFT (12) +#define TC_CTRLA_PRESCSYNC_MASK (3 << TC_CTRLA_PRESCSYNC_SHIFT) +# define TC_CTRLA_PRESCSYNC_GCLK (0 << TC_CTRLA_PRESCSYNC_SHIFT) +# define TC_CTRLA_PRESCSYNC_PRESC (1 << TC_CTRLA_PRESCSYNC_SHIFT) +# define TC_CTRLA_PRESCSYNC_RESYNC (2 << TC_CTRLA_PRESCSYNC_SHIFT) + +/* Read Request register */ + +#define TC_READREQ_ADDR_SHIFT (0) +#define TC_READREQ_ADDR_MASK (0x1F << TC_READREQ_ADDR_SHIFT) +#define TC_READREQ_RCONT (1 << 14) +#define TC_READREQ_RREQ (1 << 15) + +/* Control B Set/Clear register */ + +#define TC_CTRLB_DIR (1 << 0) +#define TC_CTRLB_ONESHOT (1 << 2) +#define TC_CTRLB_CMD_SHIFT (6) +#define TC_CTRLB_CMD_MASK (3 << TC_CTRLBCLR_CMD_SHIFT) +# define TC_CTRLB_CMD_NONE (0 << TC_CTRLBCLR_CMD_SHIFT) +# define TC_CTRLB_CMD_RETRIGGER (1 << TC_CTRLBCLR_CMD_SHIFT) +# define TC_CTRLB_CMD_STOP (2 << TC_CTRLBCLR_CMD_SHIFT) + +/* Control C register */ + +#define TC_CTRLC_INVEN0 (1 << 0) +#define TC_CTRLC_INVEN1 (1 << 1) +#define TC_CTRLC_CPTEN0 (1 << 4) +#define TC_CTRLC_CPTEN1 (1 << 5) + +/* Debug control register */ + +#define TC_DBGCTRL_DBGRUN (1 << 0) + +/* Event control register */ + +#define TC_EVCTRL_EVACT_SHIFT (0) +#define TC_EVCTRL_EVACT_MASK (7 << TC_EVCTRL_EVACT_SHIFT) +# define TC_EVCTRL_EVACT_OFF (0 << TC_EVCTRL_EVACT_SHIFT) +# define TC_EVCTRL_EVACT_RETRIGGER (1 << TC_EVCTRL_EVACT_SHIFT) +# define TC_EVCTRL_EVACT_COUNT (2 << TC_EVCTRL_EVACT_SHIFT) +# define TC_EVCTRL_EVACT_START (3 << TC_EVCTRL_EVACT_SHIFT) +# define TC_EVCTRL_EVACT_PPW (5 << TC_EVCTRL_EVACT_SHIFT) +# define TC_EVCTRL_EVACT_PWP (6 << TC_EVCTRL_EVACT_SHIFT) + +/* Interrupt register bits */ + +#define TC_INT_OVF (1 << 0) +#define TC_INT_ERR (1 << 1) +#define TC_INT_SYNCRDY (1 << 3) +#define TC_INT_MC0 (1 << 4) +#define TC_INT_MC1 (1 << 5) + +/* Status register */ + +#define TC_STATUS_STOP (1 << 3) +#define TC_STATUS_SLAVE (1 << 4) +#define TC_STATUS_SYNCBUSY (1 << 7) + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* CONFIG_ARCH_FAMILY_SAMD21 */ +#endif /* __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_TC_H */ diff --git a/arch/arm/src/samdl/sam_dac.h b/arch/arm/src/samdl/sam_dac.h new file mode 100644 index 00000000000..b78afd36c1d --- /dev/null +++ b/arch/arm/src/samdl/sam_dac.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_dac.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * 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 NuttX 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 OWNER 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_SAMDL_SAM_DAC_H +#define __ARCH_ARM_SRC_SAMDL_SAM_DAC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_config.h" +#include "sam_port.h" + +#if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) +# include "chip/samd_dac.h" +#elif defined(CONFIG_ARCH_FAMILY_SAML21) +# include "chip/saml_dac.h" +#else +# error Unrecognized SAMD/L architecture +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM_SRC_SAMDL_SAM_DAC_H */ diff --git a/arch/arm/src/samdl/sam_evsys.h b/arch/arm/src/samdl/sam_evsys.h new file mode 100644 index 00000000000..13b41fa3e55 --- /dev/null +++ b/arch/arm/src/samdl/sam_evsys.h @@ -0,0 +1,76 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_evsys.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * 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 NuttX 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 OWNER 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_SAMDL_SAM_EVSYS_H +#define __ARCH_ARM_SRC_SAMDL_SAM_EVSYS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_config.h" +#include "sam_port.h" + +#if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) +# include "chip/samd_evsys.h" +#elif defined(CONFIG_ARCH_FAMILY_SAML21) +# include "chip/saml_evsys.h" +#else +# error Unrecognized SAMD/L architecture +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM_SRC_SAMDL_SAM_EVSYS_H */ diff --git a/arch/arm/src/samdl/samd_periphclks.h b/arch/arm/src/samdl/samd_periphclks.h index 0ba3df0f879..e5de81f754d 100644 --- a/arch/arm/src/samdl/samd_periphclks.h +++ b/arch/arm/src/samdl/samd_periphclks.h @@ -75,7 +75,7 @@ #define sam_apbc_enableperiph(s) modifyreg32(SAM_PM_APBCMASK,0,s) #define sam_pac2_enableperiph() sam_apbc_enableperiph(PM_APBCMASK_PAC2) -#define sam_devsys_enableperiph() sam_apbc_enableperiph(PM_APBCMASK_EVSYS) +#define sam_evsys_enableperiph() sam_apbc_enableperiph(PM_APBCMASK_EVSYS) #define sam_sercom_enableperiph(n) sam_apbc_enableperiph(PM_APBCMASK_SERCOM(n)) #define sam_sercom0_enableperiph() sam_apbc_enableperiph(PM_APBCMASK_SERCOM0) #define sam_sercom1_enableperiph() sam_apbc_enableperiph(PM_APBCMASK_SERCOM1) @@ -135,7 +135,7 @@ #define sam_apbc_disableperiph(s) modifyreg32(SAM_PM_APBCMASK,s,0) #define sam_pac2_disableperiph() sam_apbc_disableperiph(PM_APBCMASK_PAC2) -#define sam_devsys_disableperiph() sam_apbc_disableperiph(PM_APBCMASK_EVSYS) +#define sam_evsys_disableperiph() sam_apbc_disableperiph(PM_APBCMASK_EVSYS) #define sam_sercom_disableperiph(n) sam_apbc_disableperiph(PM_APBCMASK_SERCOM(n)) #define sam_sercom0_disableperiph() sam_apbc_disableperiph(PM_APBCMASK_SERCOM0) #define sam_sercom1_disableperiph() sam_apbc_disableperiph(PM_APBCMASK_SERCOM1) @@ -195,7 +195,7 @@ #define sam_apbc_isenabled(s) (getreg32(SAM_PM_APBCMASK) & (s)) != 0) #define sam_pac2_isenabled() sam_apbc_isenabled(PM_APBCMASK_PAC2) -#define sam_devsys_isenabled() sam_apbc_isenabled(PM_APBCMASK_EVSYS) +#define sam_evsys_isenabled() sam_apbc_isenabled(PM_APBCMASK_EVSYS) #define sam_sercom_isenabled(n) sam_apbc_isenabled(PM_APBCMASK_SERCOM(n)) #define sam_sercom0_isenabled() sam_apbc_isenabled(PM_APBCMASK_SERCOM0) #define sam_sercom1_isenabled() sam_apbc_isenabled(PM_APBCMASK_SERCOM1) From 357455ff0f551be9cdd39fc43628541ea45862b3 Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Wed, 24 Jan 2018 19:23:11 -0800 Subject: [PATCH 41/44] fix typo --- arch/arm/src/samdl/chip/samd_tc.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/samdl/chip/samd_tc.h b/arch/arm/src/samdl/chip/samd_tc.h index 02e502af8ec..db3c72b835a 100644 --- a/arch/arm/src/samdl/chip/samd_tc.h +++ b/arch/arm/src/samdl/chip/samd_tc.h @@ -153,10 +153,10 @@ #define TC_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */ #define TC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */ #define TC_CTRLA_MODE_SHIFT (2) -#define TC_CTRLA_MODE_MASK (3 << TC_CTRLA_SHIFT) -# define TC_CTRLA_MODE_COUNT16 (0 << TC_CTRLA_SHIFT) -# define TC_CTRLA_MODE_COUNT8 (1 << TC_CTRLA_SHIFT) -# define TC_CTRLA_MODE_COUNT32 (2 << TC_CTRLA_SHIFT) +#define TC_CTRLA_MODE_MASK (3 << TC_CTRLA_MODE_SHIFT) +# define TC_CTRLA_MODE_COUNT16 (0 << TC_CTRLA_MODE_SHIFT) +# define TC_CTRLA_MODE_COUNT8 (1 << TC_CTRLA_MODE_SHIFT) +# define TC_CTRLA_MODE_COUNT32 (2 << TC_CTRLA_MODE_SHIFT) #define TC_CTRLA_WAVEGEN_SHIFT (5) #define TC_CTRLA_WAVEGEN_MASK (3 << TC_CTRLA_WAVEGEN_SHIFT) # define TC_CTRLA_WAVEGEN_NFRQ (0 << TC_CTRLA_WAVEGEN_SHIFT) From 92448a1053dbf50a409c36c4284bdc597508d2b7 Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Wed, 24 Jan 2018 19:33:06 -0800 Subject: [PATCH 42/44] added missing EVCTRL register bits in TC --- arch/arm/src/samdl/chip/samd_tc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/src/samdl/chip/samd_tc.h b/arch/arm/src/samdl/chip/samd_tc.h index db3c72b835a..fe3d2c40592 100644 --- a/arch/arm/src/samdl/chip/samd_tc.h +++ b/arch/arm/src/samdl/chip/samd_tc.h @@ -218,6 +218,11 @@ # define TC_EVCTRL_EVACT_START (3 << TC_EVCTRL_EVACT_SHIFT) # define TC_EVCTRL_EVACT_PPW (5 << TC_EVCTRL_EVACT_SHIFT) # define TC_EVCTRL_EVACT_PWP (6 << TC_EVCTRL_EVACT_SHIFT) +#define TC_EVCTRL_TCINV (1 << 4) +#define TC_EVCTRL_TCEI (1 << 5) +#define TC_EVCTRL_OVFEO (1 << 8) +#define TC_EVCTRL_MCEO0 (1 << 12) +#define TC_EVCTRL_MCEO1 (1 << 13) /* Interrupt register bits */ From 424a3aa827b38a8698abcbf1ff24cdc22187abfa Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Thu, 25 Jan 2018 11:44:37 -0800 Subject: [PATCH 43/44] SAMDL: Added DMAC header for SAMD, fixed up sam_dmac to compile with debugging enabled --- arch/arm/src/samdl/chip/samd_dmac.h | 399 ++++++++++++++++++++++++++++ arch/arm/src/samdl/sam_dmac.c | 20 +- arch/arm/src/samdl/sam_dmac.h | 4 +- 3 files changed, 413 insertions(+), 10 deletions(-) create mode 100644 arch/arm/src/samdl/chip/samd_dmac.h diff --git a/arch/arm/src/samdl/chip/samd_dmac.h b/arch/arm/src/samdl/chip/samd_dmac.h new file mode 100644 index 00000000000..318fc38a42b --- /dev/null +++ b/arch/arm/src/samdl/chip/samd_dmac.h @@ -0,0 +1,399 @@ +/******************************************************************************************** + * arch/arm/src/samdl/chip/samd_dmac.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * Matt Thompson + * + * References: + * "Atmel SAM L21E / SAM L21G / SAM L21J Smart ARM-Based Microcontroller + * Datasheet", Atmel-42385C-SAML21_Datasheet_Preliminary-03/20/15 + * + * 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 NuttX 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 OWNER 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_SAMDL_CHIP_SAMD_DMAC_H +#define __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_DMAC_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ +/* DMAC register offsets ********************************************************************/ + +#define SAM_DMAC_CTRL_OFFSET 0x0000 /* Control Register */ +#define SAM_DMAC_CRCCTRL_OFFSET 0x0002 /* CRC Control Register */ +#define SAM_DMAC_CRCDATAIN_OFFSET 0x0004 /* CRC Data Input Register */ +#define SAM_DMAC_CRCCHKSUM_OFFSET 0x0008 /* CRC Checksum Register */ +#define SAM_DMAC_CRCSTATUS_OFFSET 0x000c /* CRC Status Register */ +#define SAM_DMAC_DBGCTRL_OFFSET 0x000d /* Debug Control Register */ +#define SAM_DMAC_QOSCTRL_OFFSET 0x000e /* Quality of Service Control Register */ +#define SAM_DMAC_SWTRIGCTRL_OFFSET 0x0010 /* Software Trigger Control Register */ +#define SAM_DMAC_PRICTRL0_OFFSET 0x0014 /* Priority Control 0 Register */ +#define SAM_DMAC_INTPEND_OFFSET 0x0020 /* Interrupt Pending Register */ +#define SAM_DMAC_INTSTATUS_OFFSET 0x0024 /* Interrupt Status Register */ +#define SAM_DMAC_BUSYCH_OFFSET 0x0028 /* Busy Channels Register */ +#define SAM_DMAC_PENDCH_OFFSET 0x002c /* Pending Channels Register */ +#define SAM_DMAC_ACTIVE_OFFSET 0x0030 /* Active Channels and Levels Register */ +#define SAM_DMAC_BASEADDR_OFFSET 0x0034 /* Descriptor Memory Section Base Address Register */ +#define SAM_DMAC_WRBADDR_OFFSET 0x0038 /* Write-Back Memory Section Base Address Register */ +#define SAM_DMAC_CHID_OFFSET 0x003f /* Channel ID Register */ +#define SAM_DMAC_CHCTRLA_OFFSET 0x0040 /* Channel Control A Register */ +#define SAM_DMAC_CHCTRLB_OFFSET 0x0044 /* Channel Control B Register */ +#define SAM_DMAC_CHINTENCLR_OFFSET 0x004c /* Channel Interrupt Enable Clear Register */ +#define SAM_DMAC_CHINTENSET_OFFSET 0x004d /* Channel Interrupt Enable Set Register */ +#define SAM_DMAC_CHINTFLAG_OFFSET 0x004e /* Channel Interrupt Flag Status and Clear Register */ +#define SAM_DMAC_CHSTATUS_OFFSET 0x004f /* Channel Status Register */ + +/* LPSRAM Registers Relative to BASEADDR or WRBADDR */ + +#define SAM_LPSRAM_BTCTRL_OFFSET 0x0000 /* Block Transfer Control Register */ +#define SAM_LPSRAM_BTCNT_OFFSET 0x0002 /* Block Transfer Count Register */ +#define SAM_LPSRAM_SRCADDR_OFFSET 0x0004 /* Block Transfer Source Address Register */ +#define SAM_LPSRAM_DSTADDR_OFFSET 0x0008 /* Block Transfer Destination Address Register */ +#define SAM_LPSRAM_DESCADDR_OFFSET 0x000c /* Next Address Descriptor Register */ + +/* DMAC register addresses ******************************************************************/ + +#define SAM_DMAC_CTRL (SAM_DMAC_BASE+SAM_DMAC_CTRL_OFFSET) +#define SAM_DMAC_CRCCTRL (SAM_DMAC_BASE+SAM_DMAC_CRCCTRL_OFFSET) +#define SAM_DMAC_CRCDATAIN (SAM_DMAC_BASE+SAM_DMAC_CRCDATAIN_OFFSET) +#define SAM_DMAC_CRCCHKSUM (SAM_DMAC_BASE+SAM_DMAC_CRCCHKSUM_OFFSET) +#define SAM_DMAC_CRCSTATUS (SAM_DMAC_BASE+SAM_DMAC_CRCSTATUS_OFFSET) +#define SAM_DMAC_DBGCTRL (SAM_DMAC_BASE+SAM_DMAC_DBGCTRL_OFFSET) +#define SAM_DMAC_QOSCTRL (SAM_DMAC_BASE+SAM_DMAC_QOSCTRL_OFFSET) +#define SAM_DMAC_SWTRIGCTRL (SAM_DMAC_BASE+SAM_DMAC_SWTRIGCTRL_OFFSET) +#define SAM_DMAC_PRICTRL0 (SAM_DMAC_BASE+SAM_DMAC_PRICTRL0_OFFSET) +#define SAM_DMAC_INTPEND (SAM_DMAC_BASE+SAM_DMAC_INTPEND_OFFSET) +#define SAM_DMAC_INTSTATUS (SAM_DMAC_BASE+SAM_DMAC_INTSTATUS_OFFSET) +#define SAM_DMAC_BUSYCH (SAM_DMAC_BASE+SAM_DMAC_BUSYCH_OFFSET) +#define SAM_DMAC_PENDCH (SAM_DMAC_BASE+SAM_DMAC_PENDCH_OFFSET) +#define SAM_DMAC_ACTIVE (SAM_DMAC_BASE+SAM_DMAC_ACTIVE_OFFSET) +#define SAM_DMAC_BASEADDR (SAM_DMAC_BASE+SAM_DMAC_BASEADDR_OFFSET) +#define SAM_DMAC_WRBADDR (SAM_DMAC_BASE+SAM_DMAC_WRBADDR_OFFSET) +#define SAM_DMAC_CHID (SAM_DMAC_BASE+SAM_DMAC_CHID_OFFSET) +#define SAM_DMAC_CHCTRLA (SAM_DMAC_BASE+SAM_DMAC_CHCTRLA_OFFSET) +#define SAM_DMAC_CHCTRLB (SAM_DMAC_BASE+SAM_DMAC_CHCTRLB_OFFSET) +#define SAM_DMAC_CHINTENCLR (SAM_DMAC_BASE+SAM_DMAC_CHINTENCLR_OFFSET) +#define SAM_DMAC_CHINTENSET (SAM_DMAC_BASE+SAM_DMAC_CHINTENSET_OFFSET) +#define SAM_DMAC_CHINTFLAG (SAM_DMAC_BASE+SAM_DMAC_CHINTFLAG_OFFSET) +#define SAM_DMAC_CHSTATUS (SAM_DMAC_BASE+SAM_DMAC_CHSTATUS_OFFSET) + +/* DMAC register bit definitions ************************************************************/ + +/* Control Register */ + +#define DMAC_CTRL_SWRST (1 << 0) /* Bit 0: Software Reset */ +#define DMAC_CTRL_DMAENABLE (1 << 1) /* Bit 1: DMA Enable */ +#define DMAC_CTRL_CRCENABLE (1 << 2) /* Bit 2: CRC Enable */ +#define DMAC_CTRL_LVLEN0 (1 << 8) /* Bit 8: Priority level 0 Enable */ +#define DMAC_CTRL_LVLEN1 (1 << 9) /* Bit 9: Priority level 1 Enable */ +#define DMAC_CTRL_LVLEN2 (1 << 10) /* Bit 10: Priority level 2 Enable */ +#define DMAC_CTRL_LVLEN3 (1 << 11) /* Bit 10: Priority level 2 Enable */ + +/* CRC Control Register */ + +#define DMAC_CRCCTRL_CRCBEATSIZE_SHIFT (0) /* Bits 0-1: CRC beat size */ +#define DMAC_CRCCTRL_CRCBEATSIZE_MASK (3 < DMAC_CRCCTRL_CRCBEATSIZE_SHIFT) +# define DMAC_CRCCTRL_CRCBEATSIZE_BYTE (0 < DMAC_CRCCTRL_CRCBEATSIZE_SHIFT) /* 8-bit bus transfer */ +# define DMAC_CRCCTRL_CRCBEATSIZE_HWORD (1 < DMAC_CRCCTRL_CRCBEATSIZE_SHIFT) /* 16-bit bus transfer */ +# define DMAC_CRCCTRL_CRCBEATSIZE_WORD (2 < DMAC_CRCCTRL_CRCBEATSIZE_SHIFT) /* 32-bit bus transfer */ +#define DMAC_CRCCTRL_CRCPOLY_SHIFT (2) /* Bits 2-3: CRC polynomial type */ +#define DMAC_CRCCTRL_CRCPOLY_MASK (3 < DMAC_CRCCTRL_CRCPOLY_SHIFT) +# define DMAC_CRCCTRL_CRCPOLY_CRC16 (0 < DMAC_CRCCTRL_CRCPOLY_SHIFT) /* CRC-16 (CRC-CCITT) */ +# define DMAC_CRCCTRL_CRCPOLY_CRC32 (1 < DMAC_CRCCTRL_CRCPOLY_SHIFT) /* CRC32 (IEEE 802.3) */ +#define DMAC_CRCCTRL_CRCSRC_SHIFT (8) /* Bits 8-13: CRC Input Source */ +#define DMAC_CRCCTRL_CRCSRC_MASK (0x3f < DMAC_CRCCTRL_CRCSRC_SHIFT) +# define DMAC_CRCCTRL_CRCSRC_NOACTION (0 < DMAC_CRCCTRL_CRCSRC_SHIFT) /* No action */ +# define DMAC_CRCCTRL_CRCSRC_IO (1 < DMAC_CRCCTRL_CRCSRC_SHIFT) /* I/O interface */ +# define DMAC_CRCCTRL_CRCSRC_CHAN(n) (((uint32_t)(n) + 0x20) < DMAC_CRCCTRL_CRCSRC_SHIFT) + +/* CRC Data Input Register (32-bit value) */ +/* CRC Checksum Register (32-bit value) */ + +/* CRC Status Register */ + +#define DMAC_CRCSTATUS_CRCBUSY (1 << 0) /* Bit 0: CRC module busy */ +#define DMAC_CRCSTATUS_CRCZERO (1 << 1) /* Bit 1: CRC zero */ + +/* Debug Control Register */ + +#define DMAC_DBGCTRL_DBGRUN (1 << 0) /* Bit 0: Debug run */ + +/* Quality of Service Control Register */ + +#define DMAC_QOSCTRL_WRBQOS_SHIFT (0) /* Bits 0-1: Write back quality of service */ +#define DMAC_QOSCTRL_WRBQOS_MASK (3 << DMAC_QOSCTRL_WRBQOS_SHIFT) +# define DMAC_QOSCTRL_WRBQOS_DISABLE (0 << DMAC_QOSCTRL_WRBQOS_SHIFT) /* Background */ +# define DMAC_QOSCTRL_WRBQOS_LOW (1 << DMAC_QOSCTRL_WRBQOS_SHIFT) /* Sensitive bandwidth */ +# define DMAC_QOSCTRL_WRBQOS_MEDIUM (2 << DMAC_QOSCTRL_WRBQOS_SHIFT) /* Sensitive latency */ +# define DMAC_QOSCTRL_WRBQOS_HIGH (3 << DMAC_QOSCTRL_WRBQOS_SHIFT) /* Critical latency */ +#define DMAC_QOSCTRL_FQOS_SHIFT (2) /* Bits 2-3: Fetch quality of service */ +#define DMAC_QOSCTRL_FQOS_MASK (3 << DMAC_QOSCTRL_FQOS_SHIFT) +# define DMAC_QOSCTRL_FQOS_DISABLE (0 << DMAC_QOSCTRL_FQOS_SHIFT) /* Background */ +# define DMAC_QOSCTRL_FQOS_LOW (1 << DMAC_QOSCTRL_FQOS_SHIFT) /* Sensitive bandwidth */ +# define DMAC_QOSCTRL_FQOS_MEDIUM (2 << DMAC_QOSCTRL_FQOS_SHIFT) /* Sensitive latency */ +# define DMAC_QOSCTRL_FQOS_HIGH (3 << DMAC_QOSCTRL_FQOS_SHIFT) /* Critical latency */ +#define DMAC_QOSCTRL_DQOS_SHIFT (4) /* Bits 4-5: Data transfer quality of service */ +#define DMAC_QOSCTRL_DQOS_MASK (3 << DMAC_QOSCTRL_DQOS_SHIFT) +# define DMAC_QOSCTRL_DQOS_DISABLE (0 << DMAC_QOSCTRL_DQOS_SHIFT) /* Background */ +# define DMAC_QOSCTRL_DQOS_LOW (1 << DMAC_QOSCTRL_DQOS_SHIFT) /* Sensitive bandwidth */ +# define DMAC_QOSCTRL_DQOS_MEDIUM (2 << DMAC_QOSCTRL_DQOS_SHIFT) /* Sensitive latency */ +# define DMAC_QOSCTRL_DQOS_HIGH (3 << DMAC_QOSCTRL_DQOS_SHIFT) /* Critical latency */ + +/* Common bit definitions for: Software Trigger Control Register, Interrupt Status Register, + * Busy Channels Register, and Pending Channels Register + */ + +#define DMAC_CHAN(n) (1 << (n)) /* DMAC Channel n, n=0-11 */ + +/* Priority Control 0 Register */ + +#define DMAC_PRICTRL0_LVLPRI0_SHIFT (0) /* Bits 0-3: Level 0 channel priority number */ +#define DMAC_PRICTRL0_LVLPRI0_MASK (15 << DMAC_PRICTRL0_LVLPRI0_SHIFT) +# define DMAC_PRICTRL0_LVLPRI0(n) ((uint32_t)(n) << DMAC_PRICTRL0_LVLPRI0_SHIFT) +#define DMAC_PRICTRL0_RRLVLEN0 (1 << 7) /* Bit 7: Level 0 round-robin arbitrarion enable */ +#define DMAC_PRICTRL0_LVLPRI1_SHIFT (8) /* Bits 8-11: Level 1 channel priority number */ +#define DMAC_PRICTRL0_LVLPRI1_MASK (15 << DMAC_PRICTRL0_LVLPRI1_SHIFT) +# define DMAC_PRICTRL0_LVLPRI1(n) ((uint32_t)(n) << DMAC_PRICTRL0_LVLPRI1_SHIFT) +#define DMAC_PRICTRL0_RRLVLEN1 (1 << 15) /* Bit 15: Level 1 round-robin arbitrarion enable */ +#define DMAC_PRICTRL0_LVLPRI2_SHIFT (16) /* Bits 16-18: Level 2 channel priority number */ +#define DMAC_PRICTRL0_LVLPRI2_MASK (7 << DMAC_PRICTRL0_LVLPRI2_SHIFT) +# define DMAC_PRICTRL0_LVLPRI2(n) ((uint32_t)(n) << DMAC_PRICTRL0_LVLPRI2_SHIFT) +#define DMAC_PRICTRL0_RRLVLEN2 (1 << 23) /* Bit 23: Level 2 round-robin arbitrarion enable */ +#define DMAC_PRICTRL0_LVLPRI3_SHIFT (24) /* Bits 24-27: Level 3 channel priority number */ +#define DMAC_PRICTRL0_LVLPRI3_MASK (7 << DMAC_PRICTRL0_LVLPRI3_SHIFT) +# define DMAC_PRICTRL0_LVLPRI3(n) ((uint32_t)(n) << DMAC_PRICTRL0_LVLPRI3_SHIFT) +#define DMAC_PRICTRL0_RRLVLEN3 (1 << 31) /* Bit 23: Level 3 round-robin arbitrarion enable */ + +/* Interrupt Pending Register */ + +#define DMAC_INTPEND_ID_SHIFT (0) /* Bit 0-3: Channel ID */ +#define DMAC_INTPEND_ID_MASK (15 << DMAC_INTPEND_ID_SHIFT) +#define DMAC_INTPEND_TERR (1 << 8) /* Bit 8: Transfer error */ +#define DMAC_INTPEND_TCMPL (1 << 9) /* Bit 9: Transfer complete */ +#define DMAC_INTPEND_SUSP (1 << 10) /* Bit 10: Channel suspend */ +#define DMAC_INTPEND_FERR (1 << 13) /* Bit 13: Fetch error */ +#define DMAC_INTPEND_BUSY (1 << 14) /* Bit 14: Busy */ +#define DMAC_INTPEND_PEND (1 << 15) /* Bit 15: Pending */ + +/* Interrupt Status Register */ +/* Busy Channels Register */ +/* Pending Channels Register */ + +/* Active Channels and Levels Register */ + +#define DMAC_ACTIVE_LVLEX0 (1 << 0) /* Bit 0: Level 0 channel trigger request executing */ +#define DMAC_ACTIVE_LVLEX1 (1 << 1) /* Bit 1: Level 1 channel trigger request executing */ +#define DMAC_ACTIVE_LVLEX2 (1 << 2) /* Bit 2: Level 2 channel trigger request executing */ +#define DMAC_ACTIVE_LVLEX3 (1 << 3) /* Bit 3: Level 3 channel trigger request executing */ +#define DMAC_ACTIVE_ID_SHIFT (8) /* Bits 8-11: Active channel ID */ +#define DMAC_ACTIVE_ID_MASK (15 << DMAC_ACTIVE_ID_SHIFT) +#define DMAC_ACTIVE_ABUSY (1 << 15) /* Bit 15: Active channel busy */ +#define DMAC_ACTIVE_BTCNT_SHIFT (16) /* Bit 16-31: Active channel block transfer count */ +#define DMAC_ACTIVE_BTCNT_MASK (0xffff << DMAC_ACTIVE_BTCNT_SHIFT) + +/* Descriptor Memory Section Base Address Register (32-bit address) */ +/* Write-Back Memory Section Base Address Register (31-bit address) */ + +/* Channel ID Register */ + +#define DMAC_CHID_MASK 0x0f /* Bits 0-3: Channel ID */ + +/* Channel Control A Register */ + +#define DMAC_CHCTRLA_SWRST (1 << 0) /* Bit 0: Channel software reset */ +#define DMAC_CHCTRLA_ENABLE (1 << 1) /* Bit 1: Channel enable */ + +/* Channel Control B Register */ + +#define DMAC_CHCTRLB_EVACT_SHIFT (0) /* Bits 0-2: Event input action */ +#define DMAC_CHCTRLB_EVACT_MASK (7 << DMAC_CHCTRLB_EVACT_SHIFT) +# define DMAC_CHCTRLB_EVACT_NOACT (0 << DMAC_CHCTRLB_EVACT_SHIFT) /* No action */ +# define DMAC_CHCTRLB_EVACT_TRIG (1 << DMAC_CHCTRLB_EVACT_SHIFT) /* Normal Transfer and Conditional Transfer on Strobe +trigger */ +# define DMAC_CHCTRLB_EVACT_CTRIG (2 << DMAC_CHCTRLB_EVACT_SHIFT) /* Conditional transfer trigger */ +# define DMAC_CHCTRLB_EVACT_CBLOCK (3 << DMAC_CHCTRLB_EVACT_SHIFT) /* Conditional block transfer */ +# define DMAC_CHCTRLB_EVACT_SUSPEND (4 << DMAC_CHCTRLB_EVACT_SHIFT) /* Channel suspend operation */ +# define DMAC_CHCTRLB_EVACT_RESUME (5 << DMAC_CHCTRLB_EVACT_SHIFT) /* Channel resume operation */ +# define DMAC_CHCTRLB_EVACT_SSKIP (6 << DMAC_CHCTRLB_EVACT_SHIFT) /* Skip next block suspend action */ +#define DMAC_CHCTRLB_EVIE (1 << 3) /* Bit 3: Channel event input enable */ +#define DMAC_CHCTRLB_EVOE (1 << 4) /* Bit 4: Channel event output enable */ +#define DMAC_CHCTRLB_LVL_SHIFT (5) /* Bits 5-6: Channel arbitration level */ +#define DMAC_CHCTRLB_LVL_MASK (3 << DMAC_CHCTRLB_LVL_SHIFT) +# define DMAC_CHCTRLB_LVL(n) ((uint32_t)(n) << DMAC_CHCTRLB_LVL_SHIFT) +# define DMAC_CHCTRLB_LVL_LVL0 (0 << DMAC_CHCTRLB_LVL_SHIFT) /* Channel priority level 0 */ +# define DMAC_CHCTRLB_LVL_LVL1 (1 << DMAC_CHCTRLB_LVL_SHIFT) /* Channel priority level 1 */ +# define DMAC_CHCTRLB_LVL_LVL2 (2 << DMAC_CHCTRLB_LVL_SHIFT) /* Channel priority level 2 */ +# define DMAC_CHCTRLB_LVL_LVL3 (3 << DMAC_CHCTRLB_LVL_SHIFT) /* Channel priority level 3 */ +#define DMAC_CHCTRLB_TRIGSRC_SHIFT (8) /* Bits 8-13: Trigger source */ +#define DMAC_CHCTRLB_TRIGSRC_MASK (0x3f << DMAC_CHCTRLB_TRIGSRC_SHIFT) + #define DMAC_CHCTRLB_TRIGSRC(n) ((uint32_t)(n) << DMAC_CHCTRLB_TRIGSRC_SHIFT) +#define DMAC_CHCTRLB_TRIGACT_SHIFT (22) /* Bits 22-23: Trigger action */ +#define DMAC_CHCTRLB_TRIGACT_MASK (3 << DMAC_CHCTRLB_TRIGACT_SHIFT) +# define DMAC_CHCTRLB_TRIGACT_BLOCK (0 << DMAC_CHCTRLB_TRIGACT_SHIFT) /* One trigger required for each action */ +# define DMAC_CHCTRLB_TRIGACT_BEAT (2 << DMAC_CHCTRLB_TRIGACT_SHIFT) /* One trigger required for beat transfer */ +# define DMAC_CHCTRLB_TRIGACT_TRANSACT (3 << DMAC_CHCTRLB_TRIGACT_SHIFT) /* One trigger required for each transaction */ +#define DMAC_CHCTRLB_CMD_SHIFT (24) /* Bits 24-25: Software command */ +#define DMAC_CHCTRLB_CMD_MASK (3 << DMAC_CHCTRLB_CMD_SHIFT) +# define DMAC_CHCTRLB_CMD_NOACTION (0 << DMAC_CHCTRLB_CMD_SHIFT) /* No action */ +# define DMAC_CHCTRLB_CMD_SUSPEND (1 << DMAC_CHCTRLB_CMD_SHIFT) /* Channel suspend operation */ +# define DMAC_CHCTRLB_CMD_RESUME (2 << DMAC_CHCTRLB_CMD_SHIFT) /* Channel resume operation */ + +/* Values for use with the DMAC_CHCTRLB_TRIGSRC(n) macro: */ + +#define DMAC_TRIGSRC_DISABLE (0) /* Only software/event triggers */ +#define DMAC_TRIGSRC_SERCOM0_RX (1) /* SERCOM0 RX Trigger */ +#define DMAC_TRIGSRC_SERCOM0_TX (2) /* SERCOM0 TX Trigger */ +#define DMAC_TRIGSRC_SERCOM1_RX (3) /* SERCOM1 RX Trigger */ +#define DMAC_TRIGSRC_SERCOM1_TX (4) /* SERCOM1 TX Trigger */ +#define DMAC_TRIGSRC_SERCOM2_RX (5) /* SERCOM2 RX Trigger */ +#define DMAC_TRIGSRC_SERCOM2_TX (6) /* SERCOM2 TX Trigger */ +#define DMAC_TRIGSRC_SERCOM3_RX (7) /* SERCOM3 RX Trigger */ +#define DMAC_TRIGSRC_SERCOM3_TX (8) /* SERCOM3 TX Trigger */ +#define DMAC_TRIGSRC_SERCOM4_RX (9) /* SERCOM4 RX Trigger */ +#define DMAC_TRIGSRC_SERCOM4_TX (10) /* SERCOM4 TX Trigger */ +#define DMAC_TRIGSRC_SERCOM5_RX (11) /* SERCOM4 RX Trigger */ +#define DMAC_TRIGSRC_SERCOM5_TX (12) /* SERCOM4 TX Trigger */ +#define DMAC_TRIGSRC_TCC0_OVF (13) /* TCC0 Overflow Trigger */ +#define DMAC_TRIGSRC_TCC0_MC0 (14) /* TCC0 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TCC0_MC1 (15) /* TCC0 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TCC0_MC2 (16) /* TCC0 Match/Compare 2 Trigger */ +#define DMAC_TRIGSRC_TCC0_MC3 (17) /* TCC0 Match/Compare 3 Trigger */ +#define DMAC_TRIGSRC_TCC1_OVF (18) /* TCC1 Overflow Trigger */ +#define DMAC_TRIGSRC_TCC1_MC0 (19) /* TCC1 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TCC1_MC1 (20) /* TCC1 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TCC2_OVF (21) /* TCC2 Overflow Trigger */ +#define DMAC_TRIGSRC_TCC2_MC0 (22) /* TCC2 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TCC2_MC1 (23) /* TCC2 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TC0_OVF (24) /* TC0 Overflow Trigger */ +#define DMAC_TRIGSRC_TC0_MC0 (25) /* TC0 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TC0 MC1 (26) /* TC0 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TC1_OVF (27) /* TC1 Overflow Trigger */ +#define DMAC_TRIGSRC_TC1_MC0 (28) /* TC1 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TC1_MC1 (29) /* TC1 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TC2_OVF (30) /* TC2 Overflow Trigger */ +#define DMAC_TRIGSRC_TC2_MC0 (31) /* TC2 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TC2_MC1 (32) /* TC2 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TC3_OVF (33) /* TC3 Overflow Trigger */ +#define DMAC_TRIGSRC_TC3_MC0 (34) /* TC3 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TC3_MC1 (35) /* TC3 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_TC4_OVF (36) /* TC4 Overflow Trigger */ +#define DMAC_TRIGSRC_TC4_MC0 (37) /* TC4 Match/Compare 0 Trigger */ +#define DMAC_TRIGSRC_TC4_MC1 (38) /* TC4 Match/Compare 1 Trigger */ +#define DMAC_TRIGSRC_ADC_RESRDY (39) /* ADC Result Ready Trigger */ +#define DMAC_TRIGSRC_DAC_EMPTY (40) /* DAC0 Empty Trigger */ +#define DMAC_TRIGSRC_I2S0_RX (41) /* I2S0 RX Trigger */ +#define DMAC_TRIGSRC_I2S1_RX (42) /* I2S1 RX Trigger */ +#define DMAC_TRIGSRC_I2S0_TX (43) /* I2S0 TX Trigger */ +#define DMAC_TRIGSRC_I2S1_TX (44) /* I2S1 TX Trigger */ + +/* Common register bit definitions: Channel Interrupt Enable Clear Register, Channel Interrupt + * Enable Set Register, and Channel Interrupt Flag Status and Clear Register + */ + +#define DMAC_INT_TERR (1 << 0) /* Bit 0: Transfer error interrupt */ +#define DMAC_INT_TCMPL (1 << 1) /* Bit 1: Channel transfer complete interrupt */ +#define DMAC_INT_SUSP (1 << 2) /* Bit 2: Channel suspend interrupt */ +#define DMAC_INT_ALL (0x07) + +/* Channel Status Register */ + +#define DMAC_CHSTATUS_PEND (1 << 0) /* Bit 0: Chennel pending */ +#define DMAC_CHSTATUS_BUSY (1 << 1) /* Bit 1: Channel busy */ +#define DMAC_CHSTATUS_FERR (1 << 2) /* Bit 2: Channel fetch error */ + +/* Block Transfer Control Register */ + +#define LPSRAM_BTCTRL_VALID (1 << 0) /* Bit 0: Descriptor valid */ +#define LPSRAM_BTCTRL_EVOSEL_SHIFT (1) /* Bits 1-2: Event output selection */ +#define LPSRAM_BTCTRL_EVOSEL_MASK (3 << LPSRAM_BTCTRL_EVOSEL_SHIFT) +# define LPSRAM_BTCTRL_EVOSEL_DISABLE (0 << LPSRAM_BTCTRL_EVOSEL_SHIFT) /* Event generation disabled */ +# define LPSRAM_BTCTRL_EVOSEL_BLOCK (1 << LPSRAM_BTCTRL_EVOSEL_SHIFT) /* Event strobe when block transfer complete */ +# define LPSRAM_BTCTRL_EVOSEL_BEAT (3 << LPSRAM_BTCTRL_EVOSEL_SHIFT) /* Event strobe when beat transfer complete */ +#define LPSRAM_BTCTRL_BLOCKACT_SHIFT (3) /* Bits 3-4: Block action */ +#define LPSRAM_BTCTRL_BLOCKACT_MASK (3 << LPSRAM_BTCTRL_BLOCKACT_SHIFT) +# define LPSRAM_BTCTRL_BLOCKACT_NOACT (0 << LPSRAM_BTCTRL_BLOCKACT_SHIFT) /* Channel disabled if last block transfer */ +# define LPSRAM_BTCTRL_BLOCKACT_INT (1 << LPSRAM_BTCTRL_BLOCKACT_SHIFT) /* Channel disabled if last block transfer + block int */ +# define LPSRAM_BTCTRL_BLOCKACT_SUSPEND (2 << LPSRAM_BTCTRL_BLOCKACT_SHIFT) /* Channel suspend operation is completed */ +# define LPSRAM_BTCTRL_BLOCKACT_BOTH (3 << LPSRAM_BTCTRL_BLOCKACT_SHIFT) /* Both channel suspend operation + block int */ +#define LPSRAM_BTCTRL_BEATSIZE_SHIFT (8) /* Bits 8-9: Beat size */ +#define LPSRAM_BTCTRL_BEATSIZE_MASK (3 << LPSRAM_BTCTRL_BEATSIZE_SHIFT) +# define LPSRAM_BTCTRL_BEATSIZE_BYTE (0 << LPSRAM_BTCTRL_BEATSIZE_SHIFT) /* 8-bit bus transfer */ +# define LPSRAM_BTCTRL_BEATSIZE_HWORD (1 << LPSRAM_BTCTRL_BEATSIZE_SHIFT) /* 16-bit bus transfer */ +# define LPSRAM_BTCTRL_BEATSIZE_WORD (2 << LPSRAM_BTCTRL_BEATSIZE_SHIFT) /* 32-bit bus transfer */ +#define LPSRAM_BTCTRL_SRCINC (1 << 10) /* Bit 10: Source address increment enable */ +#define LPSRAM_BTCTRL_DSTINC (1 << 11) /* Bit 11: Destination address increment enable */ +#define LPSRAM_BTCTRL_STEPSEL (1 << 12) /* Bit 12: Step selection */ +#define LPSRAM_BTCTRL_STEPSIZE_SHIFT (13) /* Bits 13-15: Address increment step */ +#define LPSRAM_BTCTRL_STEPSIZE_MASK (7 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) +# define LPSRAM_BTCTRL_STEPSIZE_X1 (0 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 1 */ +# define LPSRAM_BTCTRL_STEPSIZE_X2 (1 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 2 */ +# define LPSRAM_BTCTRL_STEPSIZE_X4 (2 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 4 */ +# define LPSRAM_BTCTRL_STEPSIZE_X8 (3 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 8 */ +# define LPSRAM_BTCTRL_STEPSIZE_X16 (4 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 16 */ +# define LPSRAM_BTCTRL_STEPSIZE_X32 (5 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 32 */ +# define LPSRAM_BTCTRL_STEPSIZE_X64 (6 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 64 */ +# define LPSRAM_BTCTRL_STEPSIZE_X128 (7 << LPSRAM_BTCTRL_STEPSIZE_SHIFT) /* Next ADDR = ADDR + (BEATSIZE+1) * 128 */ + +/* Block Transfer Count Register (16-bit count) */ +/* Block Transfer Source Address Register (32-bit address) */ +/* Block Transfer Destination Address Register (32-bit address) */ +/* Next Address Descriptor Register (32-bit address) */ + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ +/* DMA descriptor */ + +struct dma_desc_s +{ + uint16_t btctrl; /* Block Transfer Control Register */ + uint16_t btcnt; /* Block Transfer Count Register */ + uint32_t srcaddr; /* Block Transfer Source Address Register */ + uint32_t dstaddr; /* Block Transfer Destination Address Register */ + uint32_t descaddr; /* Next Address Descriptor Register */ +}; + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_DMAC_H */ diff --git a/arch/arm/src/samdl/sam_dmac.c b/arch/arm/src/samdl/sam_dmac.c index 5ca812ea4f8..cf4d495b3a8 100644 --- a/arch/arm/src/samdl/sam_dmac.c +++ b/arch/arm/src/samdl/sam_dmac.c @@ -500,7 +500,7 @@ static struct dma_desc_s *sam_append_desc(struct sam_dmach_s *dmach, { /* There is no previous link. This is the new head of the list */ - DEBUGASSERT(desc == g_base_desc[dmach->dc_chan]); + DEBUGASSERT(desc == &g_base_desc[dmach->dc_chan]); } #if CONFIG_SAMDL_DMAC_NDESC > 0 @@ -627,7 +627,7 @@ static int sam_txbuffer(struct sam_dmach_s *dmach, uint32_t paddr, uint16_t btcnt; uint16_t tmp; - DEBUGASSERT(dmac->dc_dir == DMADIR_UNKOWN || dmac->dc_dir == DMADIR_TX); + DEBUGASSERT(dmach->dc_dir == DMADIR_UNKOWN || dmach->dc_dir == DMADIR_TX); /* Set up the Block Transfer Control Register configuration: * @@ -703,7 +703,7 @@ static int sam_rxbuffer(struct sam_dmach_s *dmach, uint32_t paddr, uint16_t btcnt; uint16_t tmp; - DEBUGASSERT(dmac->dc_dir == DMADIR_UNKOWN || dmac->dc_dir == DMADIR_RX); + DEBUGASSERT(dmach->dc_dir == DMADIR_UNKOWN || dmach->dc_dir == DMADIR_RX); /* Set up the Block Transfer Control Register configuration: * @@ -1218,10 +1218,13 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) /* Enable the channel */ ctrla = DMAC_CHCTRLA_ENABLE; + +#ifdef CONFIG_ARCH_FAMILY_SAML21 if (dmach->dc_flags & DMACH_FLAG_RUNINSTDBY) { ctrla |= DMAC_CHCTRLA_RUNSTDBY; } +#endif putreg8(ctrla, SAM_DMAC_CHCTRLA); @@ -1272,19 +1275,18 @@ void sam_dmastop(DMA_HANDLE handle) #ifdef CONFIG_DEBUG_DMA_INFO void sam_dmasample(DMA_HANDLE handle, struct sam_dmaregs_s *regs) { - struct sam_dmach_s *dmach = (struct sam_dmach_s *)handle; - uintptr_t base; irqstate_t flags; /* Sample DMAC registers. */ flags = enter_critical_section(); + regs->ctrl = getreg16(SAM_DMAC_CTRL); /* Control Register */ regs->crcctrl = getreg16(SAM_DMAC_CRCCTRL); /* CRC Control Register */ regs->crcdatain = getreg32(SAM_DMAC_CRCDATAIN); /* CRC Data Input Register */ regs->crcchksum = getreg32(SAM_DMAC_CRCCHKSUM); /* CRC Checksum Register */ regs->crcstatus = getreg8(SAM_DMAC_CRCSTATUS); /* CRC Status Register */ - regs->errctrl = getreg8(SAM_DMAC_DBGCTRL); /* Debug Control Register */ + regs->dbgctrl = getreg8(SAM_DMAC_DBGCTRL); /* Debug Control Register */ regs->qosctrl = getreg8(SAM_DMAC_QOSCTRL); /* Quality of Service Control Register */ regs->swtrigctrl = getreg32(SAM_DMAC_SWTRIGCTRL); /* Software Trigger Control Register */ regs->prictrl0 = getreg32(SAM_DMAC_PRICTRL0); /* Priority Control 0 Register */ @@ -1300,6 +1302,8 @@ void sam_dmasample(DMA_HANDLE handle, struct sam_dmaregs_s *regs) regs->chctrlb = getreg32(SAM_DMAC_CHCTRLB); /* Channel Control B Register */ regs->chintflag = getreg8(SAM_DMAC_CHINTFLAG); /* Channel Interrupt Flag Status and Clear Register */ regs->chstatus = getreg8(SAM_DMAC_CHSTATUS); /* Channel Status Register */ + + leave_critical_section(flags); } #endif /* CONFIG_DEBUG_DMA_INFO */ @@ -1325,13 +1329,13 @@ void sam_dmadump(DMA_HANDLE handle, const struct sam_dmaregs_s *regs, dmainfo(" CTRL: %04x CRCCTRL: %04x CRCDATAIN: %08x CRCCHKSUM: %08x\n", regs->ctrl, regs->crcctrl, regs->crcdatain, regs->crcchksum); dmainfo(" CRCSTATUS: %02x DBGCTRL: %02x QOSCTRL: %02x SWTRIGCTRL: %08x\n", - regs->crcstatus, regs->errctrl, regs->qosctrl, regs->swtrigctrl); + regs->crcstatus, regs->dbgctrl, regs->qosctrl, regs->swtrigctrl); dmainfo(" PRICTRL0: %08x INTPEND: %04x INSTSTATUS: %08x BUSYCH: %08x\n", regs->prictrl0, regs->intpend, regs->intstatus, regs->busych); dmainfo(" PENDCH: %08x ACTIVE: %08x BASEADDR: %08x WRBADDR: %08x\n", regs->pendch, regs->active, regs->baseaddr, regs->wrbaddr); dmainfo(" CHID: %02x CHCRTRLA: %02x CHCRTRLB: %08x CHINFLAG: %02x\n", - regs->chid, regs->chctrla, regs->chctrlb, regs->chintflag, + regs->chid, regs->chctrla, regs->chctrlb, regs->chintflag); dmainfo(" CHSTATUS: %02x\n", regs->chstatus); } diff --git a/arch/arm/src/samdl/sam_dmac.h b/arch/arm/src/samdl/sam_dmac.h index 2a6937dd682..f7b7a18b7bb 100644 --- a/arch/arm/src/samdl/sam_dmac.h +++ b/arch/arm/src/samdl/sam_dmac.h @@ -50,8 +50,8 @@ #ifdef CONFIG_SAMDL_DMAC -#if defined(CONFIG_ARCH_FAMILY_SAMD20) -# error Missing support for the SAMD20 architecture +#if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) +# include "chip/samd_dmac.h" #elif defined(CONFIG_ARCH_FAMILY_SAML21) # include "chip/saml_dmac.h" #else From c5e231beddddae8f34540e269e54b458acca06df Mon Sep 17 00:00:00 2001 From: Matt Thompson Date: Sun, 28 Jan 2018 21:11:37 -0800 Subject: [PATCH 44/44] SAMDL: Added Analog Comparator headers and basic initialization --- arch/arm/src/samdl/Make.defs | 4 + arch/arm/src/samdl/chip/samd_ac.h | 209 ++++++++++++++++++++++++++++++ arch/arm/src/samdl/sam_ac.c | 177 +++++++++++++++++++++++++ arch/arm/src/samdl/sam_ac.h | 81 ++++++++++++ 4 files changed, 471 insertions(+) create mode 100644 arch/arm/src/samdl/chip/samd_ac.h create mode 100644 arch/arm/src/samdl/sam_ac.c create mode 100644 arch/arm/src/samdl/sam_ac.h diff --git a/arch/arm/src/samdl/Make.defs b/arch/arm/src/samdl/Make.defs index 1ce9c0e5b8e..e62eba81f3b 100644 --- a/arch/arm/src/samdl/Make.defs +++ b/arch/arm/src/samdl/Make.defs @@ -106,3 +106,7 @@ endif ifeq ($(CONFIG_SAMDL_EIC),y) CHIP_CSRCS += sam_eic.c endif + +ifeq ($(CONFIG_SAMDL_AC),y) +CHIP_CSRCS += sam_ac.c +endif diff --git a/arch/arm/src/samdl/chip/samd_ac.h b/arch/arm/src/samdl/chip/samd_ac.h new file mode 100644 index 00000000000..31c89640202 --- /dev/null +++ b/arch/arm/src/samdl/chip/samd_ac.h @@ -0,0 +1,209 @@ +/******************************************************************************************** + * arch/arm/src/samdl/chip/samd_ac.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * References: + * "Atmel SAM L21E / SAM L21G / SAM L21J Smart ARM-Based Microcontroller + * Datasheet", Atmel-42385C-SAML21_Datasheet_Preliminary-03/20/15 + * + * 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 NuttX 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 OWNER 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_SAMDL_CHIP_SAMD_AC_H +#define __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_AC_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_ARCH_FAMILY_SAMD21 + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ +/* AC register offsets **********************************************************************/ + +#define SAM_AC_CTRLA_OFFSET 0x0000 /* Control A Register */ +#define SAM_AC_CTRLB_OFFSET 0x0001 /* Control B Register */ +#define SAM_AC_EVCTRL_OFFSET 0x0002 /* Event Control Register */ +#define SAM_AC_INTENCLR_OFFSET 0x0004 /* Interrupt Enable Clear Register */ +#define SAM_AC_INTENSET_OFFSET 0x0005 /* Interrupt Enable Set Register */ +#define SAM_AC_INTFLAG_OFFSET 0x0006 /* Interrupt Flag Status and Clear Register */ +#define SAM_AC_STATUSA_OFFSET 0x0008 /* Status A Register */ +#define SAM_AC_STATUSB_OFFSET 0x0009 /* Status B Register */ +#define SAM_AC_STATUSC_OFFSET 0x000A /* Status C Register */ +#define SAM_AC_WINCTRL_OFFSET 0x000C /* Window Control Register */ +#define SAM_AC_COMPCTRL0_OFFSET 0x0010 /* Comparator 0 Control Register */ +#define SAM_AC_COMPCTRL1_OFFSET 0x0014 /* Comparator 1 Control Register */ +#define SAM_AC_SCALER0_OFFSET 0x0020 /* Scaler 0 Register */ +#define SAM_AC_SCALER1_OFFSET 0x0021 /* Scaler 1 Register */ + +/* AC register addresses *******************************************************************/ + +#define SAM_AC_CTRLA (SAM_AC_BASE+SAM_AC_CTRLA_OFFSET) +#define SAM_AC_CTRLB (SAM_AC_BASE+SAM_AC_CTRLB_OFFSET) +#define SAM_AC_EVCTRL (SAM_AC_BASE+SAM_AC_EVCTRL_OFFSET) +#define SAM_AC_INTENCLR (SAM_AC_BASE+SAM_AC_INTENCLR_OFFSET) +#define SAM_AC_INTENSET (SAM_AC_BASE+SAM_AC_INTENSET_OFFSET) +#define SAM_AC_INTFLAG (SAM_AC_BASE+SAM_AC_INTFLAG_OFFSET) +#define SAM_AC_STATUSA (SAM_AC_BASE+SAM_AC_STATUSA_OFFSET) +#define SAM_AC_STATUSB (SAM_AC_BASE+SAM_AC_STATUSB_OFFSET) +#define SAM_AC_STATUSC (SAM_AC_BASE+SAM_AC_STATUSC_OFFSET) +#define SAM_AC_WINCTRL (SAM_AC_BASE+SAM_AC_WINCTRL_OFFSET) +#define SAM_AC_COMPCTRL0 (SAM_AC_BASE+SAM_AC_COMPCTRL0_OFFSET) +#define SAM_AC_COMPCTRL1 (SAM_AC_BASE+SAM_AC_COMPCTRL1_OFFSET) +#define SAM_AC_SCALER0 (SAM_AC_BASE+SAM_AC_SCALER0_OFFSET) +#define SAM_AC_SCALER1 (SAM_AC_BASE+SAM_AC_SCALER1_OFFSET) + +/* AC register bit definitions ************************************************************/ + +/* Control A Register */ + +#define AC_CTRLA_SWRTS (1 << 0) /* Bit 0: Software reset */ +#define AC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable AC */ +#define AC_CTRLA_RUNSTDBY (1 << 2) /* Bit 2: Run in standby */ +#define AC_CTRLA_LPMUX (1 << 7) /* Bit 7: Low-Power Mux */ + +/* Control B Register */ + +#define AC_CTRLB_START0 (1 << 0) /* Bit 0: Comparator 0 start */ +#define AC_CTRLB_START1 (1 << 1) /* Bit 1: Comparator 1 start */ + +/* Event Control Register */ + +#define AC_EVCTRL_COMPEO0 (1 << 0) /* Bit 0: Comparator 0 Event Output enable */ +#define AC_EVCTRL_COMPEO1 (1 << 1) /* Bit 1: Comparator 1 Event Output enable */ +#define AC_EVCTRL_WINEO0 (1 << 4) /* Bit 4: Window 0 Event Output enable */ +#define AC_EVCTRL_COMPEI0 (1 << 8) /* Bit 8: Comparator 0 Event Input enable */ +#define AC_EVCTRL_COMPEI1 (1 << 9) /* Bit 9: Comparator 1 Event Input enable */ + +/* Common bit definitions for Interrupt Enable Clear Register, Interrupt Enable Set + * Register, and Interrupt Flag Status and Clear Register + */ + +#define AC_INT_COMP0 (1 << 0) /* Bit 0: Comparator 0 */ +#define AC_INT_COMP1 (1 << 1) /* Bit 1: Comparator 1 */ +#define AC_INT_WIN0 (1 << 4) /* Bit 4: Window 0 */ +#define AC_INT_ALL 0x13 + +/* Status A Register */ + +#define AC_STATUSA_STATE0 (1 << 0) /* Bit 0: State 0 - Output state of comparator 0 */ +#define AC_STATUSA_STATE1 (1 << 1) /* Bit 1: State 1 - Output state of comparator 1 */ +#define AC_STATUSA_WSTATE_SHIFT (4) +#define AC_STATUSA_WSTATE_MASK (3 << AC_STATUSA_WSTATE_SHIFT) +# define AC_STATUSA_WSTATE_ABOVE (0 << AC_STATUSA_WSTATE_SHIFT) +# define AC_STATUSA_WSTATE_INSIDE (1 << AC_STATUSA_WSTATE_SHIFT) +# define AC_STATUSA_WSTATE_BELOW (2 << AC_STATUSA_WSTATE_SHIFT) + +/* Status B Register */ + +#define AC_STATUSB_READY0 (1 << 0) /* Bit 0: Ready 0 - Comparator 0 ready status */ +#define AC_STATUSB_READY1 (1 << 1) /* Bit 1: Ready 1 - Comparator 1 ready status */ +#define AC_STATUSB_SYNCBUSY (1 << 7) /* Bit 7: Synchronoziation ready */ + +/* Status C Register */ + +/* Window Control Register */ + +#define AC_WINCTRL_WEN0 (1 << 0) /* Bit 0: Window enable (both comparators) */ +#define AC_WINCTRL_WINTSEL_SHIFT (1) +#define AC_WINCTRL_WINTSEL_MASK (3 << AC_WINCTRL_WINTSEL_SHIFT) +# define AC_WINCTRL_WINTSEL_ABOVE (0 << AC_WINCTRL_WINTSEL_SHIFT) +# define AC_WINCTRL_WINTSEL_INSIDE (1 << AC_WINCTRL_WINTSEL_SHIFT) +# define AC_WINCTRL_WINTSEL_BELOW (2 << AC_WINCTRL_WINTSEL_SHIFT) +# define AC_WINCTRL_WINTSEL_OUTSIDE (3 << AC_WINCTRL_WINTSEL_SHIFT) + +/* Comparator Control Registers */ + +#define AC_COMPCTRL_ENABLE (1 << 0) /* Bit 0: Enable Comparator */ +#define AC_COMPCTRL_SINGLE (1 << 1) /* Bit 1: Single Shot Mode */ +#define AC_COMPCTRL_SPEED_SHIFT (2) +#define AC_COMPCTRL_SPEED_MASK (3 << AC_COMPCTRL_SPEED_SHIFT) +# define AC_COMPCTRL_SPEED_LOW (0 << AC_COMPCTRL_SPEED_SHIFT) +# define AC_COMPCTRL_SPEED_HIGH (1 << AC_COMPCTRL_SPEED_SHIFT) +#define AC_COMPCTRL_INTSEL_SHIFT (5) +#define AC_COMPCTRL_INTSEL_MASK (3 << AC_COMPCTRL_INTSEL_SHIFT) +# define AC_COMPCTRL_INTSEL_TOGGLE (0 << AC_COMPCTRL_INTSEL_SHIFT) +# define AC_COMPCTRL_INTSEL_RISING (1 << AC_COMPCTRL_INTSEL_SHIFT) +# define AC_COMPCTRL_INTSEL_FALLING (2 << AC_COMPCTRL_INTSEL_SHIFT) +# define AC_COMPCTRL_INTSEL_EOC (3 << AC_COMPCTRL_INTSEL_SHIFT) +#define AC_COMPCTRL_MUXNEG_SHIFT (8) +#define AC_COMPCTRL_MUXNEG_MASK (7 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_PIN0 (0 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_PIN1 (1 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_PIN2 (2 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_PIN3 (3 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_GND (4 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_VSCALE (5 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_BANDGAP (6 << AC_COMPCTRL_MUXNEG_SHIFT) +# define AC_COMPCTRL_MUXNEG_DAC (7 << AC_COMPCTRL_MUXNEG_SHIFT) +#define AC_COMPCTRL_MUXPOS_SHIFT (12) +#define AC_COMPCTRL_MUXPOS_MASK (3 << AC_COMPCTRL_MUXPOS_SHIFT) +# define AC_COMPCTRL_MUXPOS_PIN0 (0 << AC_COMPCTRL_MUXPOS_SHIFT) +# define AC_COMPCTRL_MUXPOS_PIN1 (1 << AC_COMPCTRL_MUXPOS_SHIFT) +# define AC_COMPCTRL_MUXPOS_PIN2 (2 << AC_COMPCTRL_MUXPOS_SHIFT) +# define AC_COMPCTRL_MUXPOS_PIN3 (3 << AC_COMPCTRL_MUXPOS_SHIFT) +#define AC_COMPCTRL_SWAP (1 << 13) /* Bit 13: Swap Inputs and Invert */ +#define AC_COMPCTRL_OUT_SHIFT (16) +#define AC_COMPCTRL_OUT_MASK (3 << AC_COMPCTRL_OUT_SHIFT) +# define AC_COMPCTRL_OUT_OFF (0 << AC_COMPCTRL_OUT_SHIFT) +# define AC_COMPCTRL_OUT_ASYNC (1 << AC_COMPCTRL_OUT_SHIFT) +# define AC_COMPCTRL_OUT_SYNC (2 << AC_COMPCTRL_OUT_SHIFT) +#define AC_COMPCTRL_HYST (1 << 19) /* Bit 19: Hysteresis Enable */ +#define AC_COMPCTRL_FLEN_SHIFT (24) +#define AC_COMPCTRL_FLEN_MASK (7 << AC_COMPCTRL_FLEN_SHIFT) +# define AC_COMPCTRL_FLEN_OFF (0 << AC_COMPCTRL_FLEN_SHIFT) +# define AC_COMPCTRL_FLEN_MAJ3 (1 << AC_COMPCTRL_FLEN_SHIFT) +# define AC_COMPCTRL_FLEN_MAJ5 (2 << AC_COMPCTRL_FLEN_SHIFT) + +/* Scaler Registers */ + +#define AC_COMPCTRL_SCALER_MASK (0x3f) + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* CONFIG_ARCH_FAMILY_SAMD21 */ +#endif /* __ARCH_ARM_SRC_SAMDL_CHIP_SAMD_AC_H */ diff --git a/arch/arm/src/samdl/sam_ac.c b/arch/arm/src/samdl/sam_ac.c new file mode 100644 index 00000000000..62872da31d9 --- /dev/null +++ b/arch/arm/src/samdl/sam_ac.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_ac.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * References: + * 1. "Microchip SAM D21E / SAM D21G / SAM D21J Datasheet" + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "up_arch.h" + +#include "sam_config.h" + +#include "sam_pm.h" +#include "sam_gclk.h" +#include "sam_periphclks.h" +#include "sam_ac.h" +#include "sam_port.h" + +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int sam_ac_isr(int irq, FAR void *context, FAR void *arg) +{ + return OK; +} + +static void sam_ac_syncwait(void) +{ + while ((getreg8(SAM_AC_STATUSB) & AC_STATUSB_SYNCBUSY) != 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_ac_initialize + * + * Description: + * Initialize the Analog Comparator (AC). + * + * Input Parameters: + * gclkgen - GCLK Generator + * + * Returned Value: + * None + * + ****************************************************************************/ + +int sam_ac_initialize(uint8_t gclkgen) +{ + uint16_t regval; + + sam_ac_enableperiph(); + + /* The Analog Comparators use two GCLKs */ + + /* Enable comparator digital GCLK which provides the sampling rate */ + + regval = GCLK_CLKCTRL_ID_ACDIG | GCLK_CLKCTRL_GEN(gclkgen) | GCLK_CLKCTRL_CLKEN; + putreg16(regval, SAM_GCLK_CLKCTRL); + + /* Enable comparator analog GCLK */ + + regval = GCLK_CLKCTRL_ID_ACANA | GCLK_CLKCTRL_GEN(gclkgen) | GCLK_CLKCTRL_CLKEN; + putreg16(regval, SAM_GCLK_CLKCTRL); + + putreg8(AC_CTRLA_ENABLE, SAM_AC_CTRLA); + sam_ac_syncwait(); + + irq_attach(SAM_IRQ_AC, sam_ac_isr, NULL); + + up_enable_irq(SAM_IRQ_AC); + + return OK; +} + +int sam_ac_config(uint8_t channel, uint32_t compctrl) +{ + switch(channel) + { + case 0: + putreg32(compctrl, SAM_AC_COMPCTRL0); + break; + case 1: + putreg32(compctrl, SAM_AC_COMPCTRL1); + break; + default: + return -ENODEV; + } + + sam_ac_syncwait(); + + return OK; +} + +int sam_ac_enable(uint8_t channel, bool enable) +{ + uint32_t regval; + switch(channel) + { + case 0: + regval = getreg32(SAM_AC_COMPCTRL0); + if(enable == true) + regval |= AC_COMPCTRL_ENABLE; + else + regval &= ~AC_COMPCTRL_ENABLE; + putreg32(regval, SAM_AC_COMPCTRL0); + break; + case 1: + regval = getreg32(SAM_AC_COMPCTRL1); + if(enable == true) + regval |= AC_COMPCTRL_ENABLE; + else + regval &= ~AC_COMPCTRL_ENABLE; + putreg32(regval, SAM_AC_COMPCTRL1); + break; + default: + return -ENODEV; + } + + sam_ac_syncwait(); + + return OK; +} diff --git a/arch/arm/src/samdl/sam_ac.h b/arch/arm/src/samdl/sam_ac.h new file mode 100644 index 00000000000..bdf4b5928dd --- /dev/null +++ b/arch/arm/src/samdl/sam_ac.h @@ -0,0 +1,81 @@ +/**************************************************************************** + * arch/arm/src/samdl/sam_ac.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Matt Thompson + * + * 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 NuttX 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 OWNER 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_SAMDL_SAM_AC_H +#define __ARCH_ARM_SRC_SAMDL_SAM_AC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_config.h" +#include "sam_port.h" + +#if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) +# include "chip/samd_ac.h" +#elif defined(CONFIG_ARCH_FAMILY_SAML21) +# include "chip/saml_ac.h" +#else +# error Unrecognized SAMD/L architecture +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int sam_ac_initialize(uint8_t gclkgen); +int sam_ac_config(uint8_t channel, uint32_t compctrl); +int sam_ac_enable(uint8_t channel, bool enable); + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM_SRC_SAMDL_SAM_AC_H */