From 9f80e4ccf16f4f0a84eca921043bb21e0a6e2338 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 12 Jan 2018 08:34:19 -0600 Subject: [PATCH 01/16] sched/: Various fixes for typos, improved parameter verification. --- sched/pthread/pthread_setschedparam.c | 7 ++----- sched/sched/sched.h | 6 +++++- sched/semaphore/sem_recover.c | 2 +- sched/task/task_create.c | 4 ++-- sched/task/task_setcanceltype.c | 2 +- sched/wdog/wd_delete.c | 14 ++++++++++---- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/sched/pthread/pthread_setschedparam.c b/sched/pthread/pthread_setschedparam.c index 3c04cfb0232..f5ce5c5391d 100644 --- a/sched/pthread/pthread_setschedparam.c +++ b/sched/pthread/pthread_setschedparam.c @@ -1,7 +1,8 @@ /**************************************************************************** * sched/pthread/pthread_setschedparam.c * - * Copyright (C) 2007, 2008, 2012, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008, 2012, 2015, 2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -105,10 +106,6 @@ int pthread_setschedparam(pthread_t thread, int policy, sinfo("thread ID=%d policy=%d param=0x%p\n", thread, policy, param); - /* Set the errno to some non-zero value (failsafe) */ - - set_errno(EINVAL); - /* Let sched_setscheduler do all of the work */ ret = sched_setscheduler((pid_t)thread, policy, param); diff --git a/sched/sched/sched.h b/sched/sched/sched.h index eea2a3b1c2c..d083dc6a59d 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -1,7 +1,7 @@ /**************************************************************************** * sched/sched/sched.h * - * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -63,6 +63,10 @@ * tasks built into the design). */ +#if CONFIG_MAX_TASKS & (CONFIG_MAX_TASKS - 1) +# error CONFIG_MAX_TASKS must be power of 2 +#endif + #define MAX_TASKS_MASK (CONFIG_MAX_TASKS-1) #define PIDHASH(pid) ((pid) & MAX_TASKS_MASK) diff --git a/sched/semaphore/sem_recover.c b/sched/semaphore/sem_recover.c index bccb904e07b..6305f0d35e8 100644 --- a/sched/semaphore/sem_recover.c +++ b/sched/semaphore/sem_recover.c @@ -105,7 +105,7 @@ void nxsem_recover(FAR struct tcb_s *tcb) nxsem_canceled(tcb, sem); /* And increment the count on the semaphore. This releases the count - * that was taken by sem_post(). This count decremented the semaphore + * that was taken by sem_wait(). This count decremented the semaphore * count to negative and caused the thread to be blocked in the first * place. */ diff --git a/sched/task/task_create.c b/sched/task/task_create.c index a1d07e1d8ec..2cc8c1a9118 100644 --- a/sched/task/task_create.c +++ b/sched/task/task_create.c @@ -103,11 +103,11 @@ static int thread_create(FAR const char *name, uint8_t ttype, int priority, goto errout; } +#ifdef HAVE_TASK_GROUP /* Allocate a new task group with privileges appropriate for the parent * thread type. */ -#ifdef HAVE_TASK_GROUP ret = group_allocate(tcb, ttype); if (ret < 0) { @@ -157,9 +157,9 @@ static int thread_create(FAR const char *name, uint8_t ttype, int priority, (void)task_argsetup(tcb, name, argv); +#ifdef HAVE_TASK_GROUP /* Now we have enough in place that we can join the group */ -#ifdef HAVE_TASK_GROUP ret = group_initialize(tcb); if (ret < 0) { diff --git a/sched/task/task_setcanceltype.c b/sched/task/task_setcanceltype.c index b7536f46258..3c08c5d3206 100644 --- a/sched/task/task_setcanceltype.c +++ b/sched/task/task_setcanceltype.c @@ -52,7 +52,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: task_setcancelstate + * Name: task_setcanceltype * * Description: * The task_setcanceltype() function atomically both sets the calling diff --git a/sched/wdog/wd_delete.c b/sched/wdog/wd_delete.c index a497c1146e0..7b56bede466 100644 --- a/sched/wdog/wd_delete.c +++ b/sched/wdog/wd_delete.c @@ -1,7 +1,8 @@ /**************************************************************************** * sched/wdog/wd_delete.c * - * Copyright (C) 2007-2009, 2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2014, 2016, 2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -113,9 +114,7 @@ int wd_delete(WDOG_ID wdog) sched_kfree(wdog); } - /* This was a pre-allocated timer. This function should not be called for - * statically allocated timers. - */ + /* Check if this is pre-allocated timer. */ else if (!WDOG_ISSTATIC(wdog)) { @@ -129,6 +128,13 @@ int wd_delete(WDOG_ID wdog) leave_critical_section(flags); } + /* This function should not be called for statically allocated timers. */ + + else + { + leave_critical_section(flags); + } + /* Return success */ return OK; From 335d1e00305b5f8799d26f705a94ebf4fcaa985e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 12 Jan 2018 17:40:04 -0600 Subject: [PATCH 02/16] fs/procfs: Fix an error in a common function that manages read data. --- fs/procfs/fs_procfsutil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/procfs/fs_procfsutil.c b/fs/procfs/fs_procfsutil.c index 7a71ff18540..9dd4f536740 100644 --- a/fs/procfs/fs_procfsutil.c +++ b/fs/procfs/fs_procfsutil.c @@ -124,7 +124,7 @@ size_t procfs_memcpy(FAR const char *src, size_t srclen, /* Handle the remaining offset */ srclen -= lnoffset; - dest += lnoffset; + src += lnoffset; *offset = 0; /* Copy the line into the user destination buffer */ From 008022547376d4f725672a5f45cf1b5548e9f380 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 12 Jan 2018 17:41:09 -0600 Subject: [PATCH 03/16] sched/irq: Add a configuration option to show interrupt information via a procfs file. --- fs/procfs/fs_procfs.c | 13 +- include/nuttx/irq.h | 4 +- sched/Kconfig | 9 + sched/irq/Make.defs | 9 +- sched/irq/irq.h | 53 ++++- sched/irq/irq_attach.c | 12 +- sched/irq/irq_dispatch.c | 32 ++- sched/irq/irq_foreach.c | 118 ++++++++++ sched/irq/irq_initialize.c | 11 +- sched/irq/irq_procfs.c | 443 +++++++++++++++++++++++++++++++++++++ 10 files changed, 690 insertions(+), 14 deletions(-) create mode 100644 sched/irq/irq_foreach.c create mode 100644 sched/irq/irq_procfs.c diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index e269d873e3a..5b5801aa91a 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -77,6 +77,7 @@ ****************************************************************************/ extern const struct procfs_operations proc_operations; +extern const struct procfs_operations irq_operations; extern const struct procfs_operations cpuload_operations; extern const struct procfs_operations meminfo_operations; extern const struct procfs_operations module_operations; @@ -124,8 +125,12 @@ static const struct procfs_entry_s g_procfs_entries[] = { "cpuload", &cpuload_operations, PROCFS_FILE_TYPE }, #endif +#ifdef CONFIG_SCHED_IRQMONITOR + { "irqs", &irq_operations, PROCFS_FILE_TYPE }, +#endif + #ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO - { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE }, + { "meminfo", &meminfo_operations, PROCFS_FILE_TYPE }, #endif #if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) @@ -133,15 +138,15 @@ static const struct procfs_entry_s g_procfs_entries[] = #endif #ifndef CONFIG_FS_PROCFS_EXCLUDE_BLOCKS - { "fs/blocks", &mount_procfsoperations, PROCFS_FILE_TYPE }, + { "fs/blocks", &mount_procfsoperations, PROCFS_FILE_TYPE }, #endif #ifndef CONFIG_FS_PROCFS_EXCLUDE_MOUNT - { "fs/mount", &mount_procfsoperations, PROCFS_FILE_TYPE }, + { "fs/mount", &mount_procfsoperations, PROCFS_FILE_TYPE }, #endif #ifndef CONFIG_FS_PROCFS_EXCLUDE_USAGE - { "fs/usage", &mount_procfsoperations, PROCFS_FILE_TYPE }, + { "fs/usage", &mount_procfsoperations, PROCFS_FILE_TYPE }, #endif #if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) diff --git a/include/nuttx/irq.h b/include/nuttx/irq.h index 8f4ed3824f4..e5674d81c09 100644 --- a/include/nuttx/irq.h +++ b/include/nuttx/irq.h @@ -114,8 +114,8 @@ typedef uint32_t irq_mapped_t; /* This struct defines the form of an interrupt service routine */ -typedef int (*xcpt_t)(int irq, FAR void *context, FAR void *arg); -#endif +typedef CODE int (*xcpt_t)(int irq, FAR void *context, FAR void *arg); +#endif /* __ASSEMBLY__ */ /* Now include architecture-specific types */ diff --git a/sched/Kconfig b/sched/Kconfig index 6a50b93fe89..64af6daf108 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -623,6 +623,15 @@ endmenu # Pthread Options menu "Performance Monitoring" +config SCHED_IRQMONITOR + bool "Enable IRQ monitoring" + default n + depends on FS_PROCFS + ---help--- + Enabling counting of interrupts from all interrupt sources. These + counts will be available in the mounted procfs file systems at the + top-level file, "irqs". + config SCHED_CPULOAD bool "Enable CPU load monitoring" default n diff --git a/sched/irq/Make.defs b/sched/irq/Make.defs index 72636e3ea20..8ae2fde5c3e 100644 --- a/sched/irq/Make.defs +++ b/sched/irq/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # sched/irq/Make.defs # -# 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 @@ -44,6 +44,13 @@ else ifeq ($(CONFIG_SCHED_INSTRUMENTATION_CSECTION),y) CSRCS += irq_csection.c endif +ifeq ($(CONFIG_SCHED_IRQMONITOR),y) +CSRCS += irq_foreach.c +ifeq ($(CONFIG_FS_PROCFS),y) +CSRCS += irq_procfs.c +endif +endif + # Include irq build support DEPPATH += --dep-path irq diff --git a/sched/irq/irq.h b/sched/irq/irq.h index ffb6e9859aa..ac38158f3cc 100644 --- a/sched/irq/irq.h +++ b/sched/irq/irq.h @@ -1,7 +1,8 @@ /**************************************************************************** * sched/irq/irq.h * - * Copyright (C) 2007, 2008, 2013-2014, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008, 2013-2014, 2017-2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -71,10 +72,26 @@ struct irq_info_s { - xcpt_t handler; /* Address of the interrupt handler */ - FAR void *arg; /* The argument provided to the interrupt handler. */ + xcpt_t handler; /* Address of the interrupt handler */ + FAR void *arg; /* The argument provided to the interrupt handler. */ +#ifdef CONFIG_SCHED_IRQMONITOR + systime_t start; /* Time interrupt attached */ +#ifdef CONFIG_HAVE_LONG_LONG + uint64_t count; /* Number of interrupts on this IRQ */ +#else + uint32_t mscount; /* Number of interrupts on this IRQ (MS) */ + uint32_t lscount; /* Number of interrupts on this IRQ (LS) */ +#endif +#endif }; +#ifdef CONFIG_SCHED_IRQMONITOR +/* This is the type of the callback from irq_foreach(). */ + +typedef CODE int (*irq_foreach_t)(int irq, FAR struct irq_info_s *info, + FAR void *arg); +#endif + /**************************************************************************** * Public Data ****************************************************************************/ @@ -180,6 +197,36 @@ int irq_unexpected_isr(int irq, FAR void *context, FAR void *arg); bool irq_cpu_locked(int cpu); #endif +/**************************************************************************** + * Name: irq_foreach + * + * Description: + * This function traverses the internal list of interrupts and provides + * information about each attached interrupt. + * + * Some caution may be necessary: If interrupts are disabled then the + * counts may change during the traversal. If pre-emption is enabled, then + * the traversed sequence may be widely separated in time. + * + * Input Parameters: + * callback - This function will be called for each attached interrupt + * along with the IRQ number, an instance of struct irq_info_s, + * and the caller provided argument + * args - This is an opaque argument provided with each call to the + * callback function. + * + * Returned Value: + * Zero (OK) is returned after callback has been invoked for all of + * the attached interrupts. The callback function may terminate the + * traversal at any time by returning a non-zero value. In that case, + * irq_foreach will return that non-zero value. + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_IRQMONITOR +int irq_foreach(irq_foreach_t callback, FAR void *arg); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/sched/irq/irq_attach.c b/sched/irq/irq_attach.c index a55ba758e60..da03f094275 100644 --- a/sched/irq/irq_attach.c +++ b/sched/irq/irq_attach.c @@ -1,7 +1,8 @@ /**************************************************************************** * sched/irq/irq_attach.c * - * Copyright (C) 2007-2008, 2010, 2012, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2008, 2010, 2012, 2017-2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -115,6 +116,15 @@ int irq_attach(int irq, xcpt_t isr, FAR void *arg) g_irqvector[ndx].handler = isr; g_irqvector[ndx].arg = arg; +#ifdef CONFIG_SCHED_IRQMONITOR + g_irqvector[ndx].start = clock_systimer(); +#ifdef CONFIG_HAVE_LONG_LONG + g_irqvector[ndx].count = 0; +#else + g_irqvector[ndx].mscount = 0; + g_irqvector[ndx].lscount = 0; +#endif +#endif leave_critical_section(flags); ret = OK; diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c index b311e8a2c11..ef78824213f 100644 --- a/sched/irq/irq_dispatch.c +++ b/sched/irq/irq_dispatch.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/irq/irq_dispatch.c * - * Copyright (C) 2007, 2008, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008, 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,33 @@ #include "irq/irq.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_SCHED_IRQMONITOR +# ifdef CONFIG_HAVE_LONG_LONG +# define INCR_COUNT(ndx) \ + do \ + { \ + g_irqvector[ndx].count++; \ + } \ + while (0) +# else +# define INCR_COUNT(ndx) \ + do \ + { \ + if (++g_irqvector[ndx].lscount == 0) \ + { \ + g_irqvector[ndx].mscount++; \ + } \ + } \ + while (0) +# endif +#else +# define INCR_COUNT(ndx) +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -86,13 +113,14 @@ void irq_dispatch(int irq, FAR void *context) { vector = g_irqvector[ndx].handler; arg = g_irqvector[ndx].arg; + INCR_COUNT(ndx); } #else vector = g_irqvector[irq].handler; arg = g_irqvector[irq].arg; + INCR_COUNT(irq); #endif } - #else vector = irq_unexpected_isr; arg = NULL; diff --git a/sched/irq/irq_foreach.c b/sched/irq/irq_foreach.c new file mode 100644 index 00000000000..731fcf706f5 --- /dev/null +++ b/sched/irq/irq_foreach.c @@ -0,0 +1,118 @@ +/**************************************************************************** + * sched/irq/irq_foreach.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 "irq/irq.h" + +#ifdef CONFIG_SCHED_IRQMONITOR + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* This is the number of entries in the interrupt vector table */ + +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE +# define TAB_SIZE CONFIG_ARCH_NUSER_INTERRUPTS +#else +# define TAB_SIZE NR_IRQS +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: irq_foreach + * + * Description: + * This function traverses the internal list of interrupts and provides + * information about each attached interrupt. + * + * Some caution may be necessary: If interrupts are disabled then the + * counts may change during the traversal. If pre-emption is enabled, then + * the traversed sequence may be widely separated in time. + * + * Input Parameters: + * callback - This function will be called for each attached interrupt + * along with the IRQ number, an instance of struct irq_info_s, + * and the caller provided argument + * args - This is an opaque argument provided with each call to the + * callback function. + * + * Returned Value: + * Zero (OK) is returned after callback has been invoked for all of + * the attached interrupts. The callback function may terminate the + * traversal at any time by returning a non-zero value. In that case, + * irq_foreach will return that non-zero value. + * + ****************************************************************************/ + +int irq_foreach(irq_foreach_t callback, FAR void *arg) +{ + int irq; + int ret; + + DEBUGASSERT(callback != NULL); + + /* Visit each interrupt in the interrupt table */ + + for (irq = 0; irq < TAB_SIZE; irq++) + { + if (g_irqvector[irq].handler != NULL && + g_irqvector[irq].handler != irq_unexpected_isr) + { + ret = callback(irq, &g_irqvector[irq], arg); + if (ret != 0) + { + return ret; + } + } + } + + return OK; +} + +#endif /* CONFIG_SCHED_IRQMONITOR */ diff --git a/sched/irq/irq_initialize.c b/sched/irq/irq_initialize.c index 18bbafc4b37..b2355f9a90d 100644 --- a/sched/irq/irq_initialize.c +++ b/sched/irq/irq_initialize.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/irq/irq_initialize.c * - * Copyright (C) 2007-2008, 2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2008, 2010, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -89,5 +89,14 @@ void irq_initialize(void) { g_irqvector[i].handler = irq_unexpected_isr; g_irqvector[i].arg = NULL; +#ifdef CONFIG_SCHED_IRQMONITOR + g_irqvector[i].start = 0; +#ifdef CONFIG_HAVE_LONG_LONG + g_irqvector[i].count = 0; +#else + g_irqvector[i].mscount = 0; + g_irqvector[i].lscount = 0; +#endif +#endif } } diff --git a/sched/irq/irq_procfs.c b/sched/irq/irq_procfs.c new file mode 100644 index 00000000000..bbfb76df179 --- /dev/null +++ b/sched/irq/irq_procfs.c @@ -0,0 +1,443 @@ +/**************************************************************************** + * sched/irq/irq_procfs.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 +#include +#include + +#include +#include +#include + +#include "irq/irq.h" + +#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) +#ifdef CONFIG_SCHED_IRQMONITOR + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Output format: + * + * 11111111112222222222333333333344 + * 12345678901234567890123456789012345678901 + * + * IRQ HANDLER ARGUMENT COUNT RATE + * DDD XXXXXXXX XXXXXXXX DDDDDDDDDD DDDD.DDD + * + * NOTE: This assumes that an address can be represented in 32-bits. In + * the typical configuration where CONFIG_HAVE_LONG_LONG=y, the COUNT field + * may not be wide enough. + */ + +#define HDR_FMT "IRQ HANDLER ARGUMENT COUNT RATE\n" +#define IRQ_FMT "%3u %08lx %08lx %10lu %4lu.%03lu\n" + +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic (plus a couple of + * bytes). + */ + +#define IRQ_LINELEN 44 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one open "file" */ + +struct irq_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + FAR char *buffer; /* User provided buffer */ + size_t remaining; /* Number of available characters in buffer */ + size_t ncopied; /* Number of characters in buffer */ + off_t offset; /* Current file offset */ + char line[IRQ_LINELEN]; /* Pre-allocated buffer for formatted lines */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* irq_foreach() callback function */ + +static int irq_callback(int irq, FAR struct irq_info_s *info, + FAR void *arg); + +/* File system methods */ + +static int irq_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int irq_close(FAR struct file *filep); +static ssize_t irq_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static int irq_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int irq_stat(FAR const char *relpath, FAR struct stat *buf); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* See fs_mount.c -- this structure is explicitly extern'ed there. + * We use the old-fashioned kind of initializers so that this will compile + * with any compiler. + */ + +const struct procfs_operations irq_operations = +{ + irq_open, /* open */ + irq_close, /* close */ + irq_read, /* read */ + NULL, /* write */ + + irq_dup, /* dup */ + + NULL, /* opendir */ + NULL, /* closedir */ + NULL, /* readdir */ + NULL, /* rewinddir */ + + irq_stat /* stat */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: irq_callback + ****************************************************************************/ + +static int irq_callback(int irq, FAR struct irq_info_s *info, + FAR void *arg) +{ + FAR struct irq_file_s *irqfile = (FAR struct irq_file_s *)arg; + struct irq_info_s copy; + irqstate_t flags; + systime_t elapsed; + systime_t now; + size_t linesize; + size_t copysize; + unsigned long intpart; + unsigned long fracpart; + unsigned long count; + + DEBUGASSERT(irqfile != NULL); + + /* Take a snapshot and reset the counts */ + + flags = enter_critical_section(); + memcpy(©, info, sizeof(struct irq_info_s)); + now = clock_systimer(); + info->start = now; +#ifdef CONFIG_HAVE_LONG_LONG + info->count = 0; +#else + info->mscount = 0; + info->lscount = 0; +#endif + leave_critical_section(flags); + + /* Don't bother if count == 0 */ + + if (copy.count == 0) + { + return 0; + } + + /* Calculate the interrupt rate from the interrupt count and the elapsed + * time. + * + * REVISIT: If these counts have not been samples and reset in a long time + * then the following will likely overflow. + */ + + elapsed = now - copy.start; + +#ifdef CONFIG_HAVE_LONG_LONG + /* elapsed = - , units=clock ticks + * rate = * TICKS_PER_SEC / elapsed + */ + + intpart = (unsigned int)((copy.count * TICK_PER_SEC) / elapsed); + if (intpart >= 10000) + { + intpart = 9999; + fracpart = 999; + } + else + { + uint64_t intcount = (uint64_t)intpart * elapsed / TICK_PER_SEC; + fracpart = (unsigned int) + (((copy.count - intcount) * TICK_PER_SEC * 1000) / elapsed); + } + + /* Make sure that the count is representable with snprintf format */ + + if (copy.count > ULONG_MAX) + { + count = ULONG_MAX; + } + else + { + count = (unsigned long)copy.count; + } + +#else +# error Missing logic +#endif + + /* Output information about this interrupt */ + + linesize = snprintf(irqfile->line, IRQ_LINELEN, IRQ_FMT, + (unsigned int)irq, + (unsigned long)((uintptr_t)copy.handler), + (unsigned long)((uintptr_t)copy.arg), + count, intpart, fracpart); + + copysize = procfs_memcpy(irqfile->line, linesize, irqfile->buffer, + irqfile->remaining, &irqfile->offset); + + irqfile->ncopied += copysize; + irqfile->buffer += copysize; + irqfile->remaining -= copysize; + + /* Return a non-zero value to stop the traversal if the user-provided + * buffer is full. + */ + + if (irqfile->remaining > 0) + { + return 0; + } + else + { + return 1; + } +} + +/**************************************************************************** + * Name: irq_open + ****************************************************************************/ + +static int irq_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct irq_file_s *irqfile; + + finfo("Open '%s'\n", relpath); + + /* PROCFS is read-only. Any attempt to open with any kind of write + * access is not permitted. + * + * REVISIT: Write-able proc files could be quite useful. + */ + + if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) + { + ferr("ERROR: Only O_RDONLY supported\n"); + return -EACCES; + } + + /* "irqs" is the only acceptable value for the relpath */ + + if (strcmp(relpath, "irqs") != 0) + { + ferr("ERROR: relpath is '%s'\n", relpath); + return -ENOENT; + } + + /* Allocate a container to hold the file attributes */ + + irqfile = (FAR struct irq_file_s *)kmm_zalloc(sizeof(struct irq_file_s)); + if (!irqfile) + { + ferr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* Save the attributes as the open-specific state in filep->f_priv */ + + filep->f_priv = (FAR void *)irqfile; + return OK; +} + +/**************************************************************************** + * Name: irq_close + ****************************************************************************/ + +static int irq_close(FAR struct file *filep) +{ + FAR struct irq_file_s *irqfile; + + /* Recover our private data from the struct file instance */ + + irqfile = (FAR struct irq_file_s *)filep->f_priv; + DEBUGASSERT(irqfile); + + /* Release the file attributes structure */ + + kmm_free(irqfile); + filep->f_priv = NULL; + return OK; +} + +/**************************************************************************** + * Name: irq_read + ****************************************************************************/ + +static ssize_t irq_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct irq_file_s *irqfile; + size_t linesize; + size_t copysize; + + finfo("buffer=%p buflen=%d\n", buffer, (int)buflen); + + /* Recover our private data from the struct file instance */ + + irqfile = (FAR struct irq_file_s *)filep->f_priv; + DEBUGASSERT(irqfile); + + /* Save the file offset and the user buffer information */ + + irqfile->offset = filep->f_pos; + irqfile->buffer = buffer; + irqfile->remaining = buflen; + + /* The first line to output is the header */ + + linesize = snprintf(irqfile->line, IRQ_LINELEN, HDR_FMT); + + copysize = procfs_memcpy(irqfile->line, linesize, irqfile->buffer, + irqfile->remaining, &irqfile->offset); + + irqfile->ncopied = copysize; + irqfile->buffer += copysize; + irqfile->remaining -= copysize; + + /* Now traverse the list of attached interrupts, generating output for + * each. + */ + + (void)irq_foreach(irq_callback, (FAR void *)irqfile); + + /* Update the file position */ + + filep->f_pos += irqfile->ncopied; + return irqfile->ncopied; +} + +/**************************************************************************** + * Name: irq_dup + * + * Description: + * Duplicate open file data in the new file structure. + * + ****************************************************************************/ + +static int irq_dup(FAR const struct file *oldp, FAR struct file *newp) +{ + FAR struct irq_file_s *oldattr; + FAR struct irq_file_s *newattr; + + finfo("Dup %p->%p\n", oldp, newp); + + /* Recover our private data from the old struct file instance */ + + oldattr = (FAR struct irq_file_s *)oldp->f_priv; + DEBUGASSERT(oldattr); + + /* Allocate a new container to hold the task and attribute selection */ + + newattr = (FAR struct irq_file_s *)kmm_malloc(sizeof(struct irq_file_s)); + if (!newattr) + { + ferr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* The copy the file attributes from the old attributes to the new */ + + memcpy(newattr, oldattr, sizeof(struct irq_file_s)); + + /* Save the new attributes in the new file structure */ + + newp->f_priv = (FAR void *)newattr; + return OK; +} + +/**************************************************************************** + * Name: irq_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int irq_stat(const char *relpath, struct stat *buf) +{ + /* "irqs" is the only acceptable value for the relpath */ + + if (strcmp(relpath, "irqs") != 0) + { + ferr("ERROR: relpath is '%s'\n", relpath); + return -ENOENT; + } + + /* "irqs" is the name for a read-only file */ + + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* CONFIG_SCHED_IRQMONITOR */ +#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */ From de8f3ebedbcd5138bceddefebf72cff644a33a48 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 12 Jan 2018 17:59:13 -0600 Subject: [PATCH 04/16] Documentation: Update NSH documention to discuss the irqinfo command. --- Documentation/NuttShell.html | 217 +++++++++++++++++++++-------------- 1 file changed, 128 insertions(+), 89 deletions(-) diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html index c23950484cd..6095357a5ce 100644 --- a/Documentation/NuttShell.html +++ b/Documentation/NuttShell.html @@ -8,7 +8,7 @@

NuttShell (NSH)

-

Last Updated: January 10, 2018

+

Last Updated: January 12, 2018

@@ -251,259 +251,265 @@
- 2.28 Send a signal to a task (kill) + 2.28 Show Interrupt Status (irqinfo)
- 2.29 Setup/teardown the Loop Device (losetup) + 2.29 Send a signal to a task (kill)
- 2.30 List to a File or Directory (ln) + 2.30 Setup/teardown the Loop Device (losetup)
- 2.31 List Directory Contents (ls) + 2.31 List to a File or Directory (ln)
- 2.32 Show information about installed OS modules (lsmod) + 2.32 List Directory Contents (ls)
- 2.33 Calculate MD5 (md5) + 2.33 Show information about installed OS modules (lsmod)
- 2.34 Access Memory (mb, mh, and mw) + 2.34 Calculate MD5 (md5)
- 2.35 Show Current Tasks and Threads (ps) + 2.35 Access Memory (mb, mh, and mw)
- 2.36 Create a Directory (mkdir) + 2.36 Show Current Tasks and Threads (ps)
- 2.37 Create a FAT File System (mkfatfs) + 2.37 Create a Directory (mkdir)
- 2.38 Create a FIFO (mkfifo) + 2.38 Create a FAT File System (mkfatfs)
- 2.39 Create a RAMDISK (mkrd) + 2.39 Create a FIFO (mkfifo)
- 2.40 Mount a File System (mount) + 2.40 Create a RAMDISK (mkrd)
- 2.41 Rename a File (mv) + 2.41 Mount a File System (mount)
- 2.42 Mount an NFS File System (nfsmount) + 2.42 Rename a File (mv)
- 2.43 Lookup a network address (nslookup) + 2.43 Mount an NFS File System (nfsmount)
- 2.44 Change a User's Password (passwd) + 2.44 Lookup a network address (nslookup)
- 2.45 Shut the system down (poweroff) + 2.45 Change a User's Password (passwd)
- 2.46 Send File Via TFTP (put) + 2.46 Shut the system down (poweroff)
- 2.47 Show Current Working Directory (pwd) + 2.47 Send File Via TFTP (put)
- 2.48 Show target of a link (readlink) + 2.48 Show Current Working Directory (pwd)
- 2.49 Reset and reboot the system (reboot) + 2.49 Show target of a link (readlink)
- 2.50 Remove a File (rm) + 2.50 Reset and reboot the system (reboot)
- 2.51 Remove a Directory (rmdir) + 2.51 Remove a File (rm)
- 2.52 Remove on OS Module (rmmod) + 2.52 Remove a Directory (rmdir)
- 2.53 Show routing table (route) + 2.53 Remove on OS Module (rmmod)
- 2.54 Set an Environment Variable (set) + 2.54 Show routing table (route)
- 2.55 Execute an NSH Script (sh) + 2.55 Set an Environment Variable (set)
- 2.56 Shut the system down (shutdown) + 2.56 Execute an NSH Script (sh)
- 2.57 Wait for Seconds (sleep) + 2.57 Shut the system down (shutdown)
- 2.58 Start the Telnet Daemon (telnetd) + 2.58 Wait for Seconds (sleep)
- 2.59 Time execution of another command (time) + 2.59 Start the Telnet Daemon (telnetd)
- 2.60 Set the Size of a File (truncate) + 2.60 Time execution of another command (time)
- 2.61 Unmount a File System (umount) + 2.61 Set the Size of a File (truncate)
- 2.62 Print system information (uname) + 2.62 Unmount a File System (umount)
- 2.63 Unset an Environment Variable (unset) + 2.63 Print system information (uname)
- 2.64 URL Decode (urldecode) + 2.64 Unset an Environment Variable (unset)
- 2.65 URL Encode (urlencode) + 2.65 URL Decode (urldecode)
- 2.66 Add a New User (useradd) + 2.66 URL Encode (urlencode)
- 2.67 Delete a user (userdel) + 2.67 Add a New User (useradd)
- 2.68 Wait for Microseconds (usleep) + 2.68 Delete a user (userdel)
- 2.69 Get File Via HTTP (wget) + 2.69 Wait for Microseconds (usleep)
- 2.70 Hexadecimal Dump of Memory (xd) + 2.70 Get File Via HTTP (wget) + + + +
+ + 2.71 Hexadecimal Dump of Memory (xd) @@ -1941,7 +1947,34 @@ mydriver 20404659 20404625 0 20404580 552 204047a8 0 + +
-

2.28 Send a signal to a task (kill)

+

2.28 Show Interrupt Status (irqinfo)

+
+ +

Command Syntax:

+
    +irqinfo
    +
+

+ Synopsis. + Show the current count of interrupts taken on all attached interrupts. +

+

+ Example:. +

+
    +nsh> irqinfo
    +IRQ HANDLER  ARGUMENT    COUNT    RATE
    +  3 00001b3d 00000000        156   19.122
    + 15 0000800d 00000000        817  100.000
    + 30 00000fd5 20000018         20    2.490
    +
+ + + +
+

2.29 Send a signal to a task (kill)

@@ -1983,7 +2016,7 @@ nsh>
-

2.29 Setup/teardown the Loop Device (losetup)

+

2.30 Setup/teardown the Loop Device (losetup)

@@ -2036,7 +2069,7 @@ losetup d <dev-path>
-

2.30 Link to a File or Directory (ln)

+

2.31 Link to a File or Directory (ln)

@@ -2061,7 +2094,7 @@ ln [-s] <target> <link>
-

2.31 List Directory Contents (ls)

+

2.32 List Directory Contents (ls)

@@ -2099,7 +2132,7 @@ ls [-lRs] <dir-path>
-

2.32 Show information about installed OS modules (lsmod)

+

2.33 Show information about installed OS modules (lsmod)

@@ -2132,7 +2165,7 @@ mydriver 20404659 20404625 0 20404580 552 204047a8 0
-

2.33 Calculate MD5 (md5)

+

2.34 Calculate MD5 (md5)

@@ -2149,7 +2182,7 @@ md5 [-f] <string or filepath>
-

2.34 Access Memory (mb, mh, and mw)

+

2.35 Access Memory (mb, mh, and mw)

@@ -2202,7 +2235,7 @@ nsh>
-

2.35 Show Current Tasks and Threads (ps)

+

2.36 Show Current Tasks and Threads (ps)

@@ -2236,7 +2269,7 @@ nsh> mount -t procfs /proc
-

2.36 Create a Directory (mkdir)

+

2.37 Create a Directory (mkdir)

@@ -2271,7 +2304,7 @@ nsh>
-

2.37 Create a FAT File System (mkfatfs)

+

2.38 Create a FAT File System (mkfatfs)

@@ -2296,7 +2329,7 @@ mkfatfs [-F <fatsize>] <block-driver>
-

2.38 Create a FIFO (mkfifo)

+

2.39 Create a FIFO (mkfifo)

@@ -2334,7 +2367,7 @@ nsh>
-

2.39 Create a RAMDISK (mkrd)

+

2.40 Create a RAMDISK (mkrd)

@@ -2385,7 +2418,7 @@ nsh>
-

2.40 Mount a File System (mount)

+

2.41 Mount a File System (mount)

@@ -2464,7 +2497,7 @@ nsh> mount
-

2.41 Rename a File (mv)

+

2.42 Rename a File (mv)

@@ -2482,7 +2515,7 @@ mv <old-path> <new-path>
-

2.42 Mount an NFS file system (nfsmount)

+

2.43 Mount an NFS file system (nfsmount)

@@ -2501,7 +2534,7 @@ nfsmount <server-address> <mount-point> <remote-path>
-

2.43 Lookup a network address (nslookup)

+

2.44 Lookup a network address (nslookup)

@@ -2518,7 +2551,7 @@ nslookup <host-name>
-

2.44 Change a User's Password (passwd)

+

2.45 Change a User's Password (passwd)

@@ -2535,7 +2568,7 @@ passwd <username> <password>
-

2.45 Shut the system down (poweroff)

+

2.46 Shut the system down (poweroff)

@@ -2557,7 +2590,7 @@ poweroff
-

2.46 Send File Via TFTP (put)

+

2.47 Send File Via TFTP (put)

@@ -2592,7 +2625,7 @@ put [-b|-n] [-f <remote-path>] -h <ip-address> <local-path>
-

2.47 Show Current Working Directory (pwd)

+

2.48 Show Current Working Directory (pwd)

@@ -2622,7 +2655,7 @@ nsh>
-

2.48 Show target of a link (readlink)

+

2.49 Show target of a link (readlink)

@@ -2639,7 +2672,7 @@ readlink <link>
-

2.49 Reboot the system (reboot)

+

2.50 Reboot the system (reboot)

@@ -2660,7 +2693,7 @@ reboot
-

2.50 Remove a File (rm)

+

2.51 Remove a File (rm)

@@ -2694,7 +2727,7 @@ nsh>
-

2.51 Remove a Directory (rmdir)

+

2.52 Remove a Directory (rmdir)

@@ -2729,7 +2762,7 @@ nsh>
-

2.52 Remove on OS Module (rmmod)

+

2.53 Remove on OS Module (rmmod)

@@ -2757,7 +2790,7 @@ nsh>
-

2.53 Show routing table (route)

+

2.54 Show routing table (route)

@@ -2777,7 +2810,7 @@ route ipv4|ipv6
-

2.54 Set an Environment Variable (set)

+

2.55 Set an Environment Variable (set)

@@ -2846,7 +2879,7 @@ nsh>
-

2.55 Execute an NSH Script (sh)

+

2.56 Execute an NSH Script (sh)

@@ -2864,7 +2897,7 @@ sh <script-path>
-

2.56 Shut the system down (shutdown)

+

2.57 Shut the system down (shutdown)

@@ -2885,7 +2918,7 @@ shutdown [--reboot]
-

2.57 Wait for Seconds (sleep)

+

2.58 Wait for Seconds (sleep)

@@ -2902,7 +2935,7 @@ sleep <sec>
-

2.58 Time Start the Telnet Daemon (telnetd)

+

2.59 Time Start the Telnet Daemon (telnetd)

@@ -2928,7 +2961,7 @@ telnetd
-

2.59 Time execution of another command (time)

+

2.60 Time execution of another command (time)

@@ -2986,7 +3019,7 @@ nsh>
-

2.60 Set the Size of a File (truncate)

+

2.61 Set the Size of a File (truncate)

@@ -3014,7 +3047,7 @@ truncate -s <length> <file-path>
-

2.61 Unmount a File System (umount)

+

2.62 Unmount a File System (umount)

@@ -3044,7 +3077,7 @@ nsh>
-

2.62 Print system information (uname)

+

2.63 Print system information (uname)

@@ -3111,7 +3144,7 @@ uname [-a | -imnoprsv]
-

2.63 Unset an Environment Variable (unset)

+

2.64 Unset an Environment Variable (unset)

@@ -3137,7 +3170,7 @@ nsh>
-

2.64 URL Decode (urldecode)

+

2.65 URL Decode (urldecode)

@@ -3154,7 +3187,7 @@ urldecode [-f] <string or filepath>
-

2.65 URL Encode (urlencode)

+

2.66 URL Encode (urlencode)

@@ -3171,7 +3204,7 @@ urlencode [-f] <string or filepath>
-

2.66 Add a New User (useradd)

+

2.67 Add a New User (useradd)

@@ -3188,7 +3221,7 @@ useradd <username> <password>
-

2.67 Delete a user (userdel)

+

2.68 Delete a user (userdel)

@@ -3205,7 +3238,7 @@ userdel <username>
-

2.68 Wait for Microseconds (usleep)

+

2.69 Wait for Microseconds (usleep)

@@ -3222,7 +3255,7 @@ usleep <usec>
-

2.69 Get File Via HTTP (wget)

+

2.70 Get File Via HTTP (wget)

@@ -3249,7 +3282,7 @@ wget [-o <local-path>] <url>
-

2.70 Hexadecimal Dump of Memory (xd)

+

2.71 Hexadecimal Dump of Memory (xd)

@@ -3506,6 +3539,11 @@ nsh> CONFIG_MODULE CONFIG_NSH_DISABLE_MODCMDS + + irqinfo + !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS && CONFIG_SCHED_IRQMONITOR +
+ kill !CONFIG_DISABLE_SIGNALS @@ -5486,10 +5524,10 @@ xxd -i romfs_img >nsh_romfsimg.h
  • CONFIG_NSH_ROMFSMOUNTPT
  • CONFIG_NSH_ROMFSSECTSIZE
  • CONFIG_NSH_STRERROR
  • +
  • CONFIG_NSH_TELNET
    • -
    • NSH library (nshlib)
    • NSH library (nshlib)
    • nsh_consolemain()
    • nsh_initialize()
    • From fdf4e40b6a5adce1e7d5f27f844c19cb2755052c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 13 Jan 2018 08:34:58 -0600 Subject: [PATCH 05/16] configs/lpcxpresso-lpc54628: Correct SRAM base address in all configurations. --- configs/lpcxpresso-lpc54628/fb/defconfig | 2 +- configs/lpcxpresso-lpc54628/netnsh/defconfig | 2 +- configs/lpcxpresso-lpc54628/nsh/defconfig | 2 +- configs/lpcxpresso-lpc54628/nxwm/defconfig | 2 +- configs/lpcxpresso-lpc54628/scripts/flash.ld | 2 +- sched/init/os_start.c | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/configs/lpcxpresso-lpc54628/fb/defconfig b/configs/lpcxpresso-lpc54628/fb/defconfig index 2234418cfcc..2dc326a0794 100644 --- a/configs/lpcxpresso-lpc54628/fb/defconfig +++ b/configs/lpcxpresso-lpc54628/fb/defconfig @@ -64,7 +64,7 @@ CONFIG_PREALLOC_MQ_MSGS=4 CONFIG_PREALLOC_TIMERS=4 CONFIG_PREALLOC_WDOGS=4 CONFIG_RAM_SIZE=163840 -CONFIG_RAM_START=0x10000000 +CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_HPWORK=y diff --git a/configs/lpcxpresso-lpc54628/netnsh/defconfig b/configs/lpcxpresso-lpc54628/netnsh/defconfig index 89836e60109..b84ff13d81e 100644 --- a/configs/lpcxpresso-lpc54628/netnsh/defconfig +++ b/configs/lpcxpresso-lpc54628/netnsh/defconfig @@ -55,7 +55,7 @@ CONFIG_PREALLOC_MQ_MSGS=4 CONFIG_PREALLOC_TIMERS=4 CONFIG_PREALLOC_WDOGS=4 CONFIG_RAM_SIZE=163840 -CONFIG_RAM_START=0x10000000 +CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_HPWORK=y diff --git a/configs/lpcxpresso-lpc54628/nsh/defconfig b/configs/lpcxpresso-lpc54628/nsh/defconfig index 70d2e780688..bdcaa769d36 100644 --- a/configs/lpcxpresso-lpc54628/nsh/defconfig +++ b/configs/lpcxpresso-lpc54628/nsh/defconfig @@ -42,7 +42,7 @@ CONFIG_PREALLOC_MQ_MSGS=4 CONFIG_PREALLOC_TIMERS=4 CONFIG_PREALLOC_WDOGS=4 CONFIG_RAM_SIZE=163840 -CONFIG_RAM_START=0x10000000 +CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_RTC_ALARM=y diff --git a/configs/lpcxpresso-lpc54628/nxwm/defconfig b/configs/lpcxpresso-lpc54628/nxwm/defconfig index 4c2f839ee1a..5bc987dbb5e 100644 --- a/configs/lpcxpresso-lpc54628/nxwm/defconfig +++ b/configs/lpcxpresso-lpc54628/nxwm/defconfig @@ -87,7 +87,7 @@ CONFIG_NXWM=y CONFIG_PREALLOC_TIMERS=4 CONFIG_PREALLOC_WDOGS=8 CONFIG_RAM_SIZE=163840 -CONFIG_RAM_START=0x10000000 +CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_HPWORK=y diff --git a/configs/lpcxpresso-lpc54628/scripts/flash.ld b/configs/lpcxpresso-lpc54628/scripts/flash.ld index fc09e2fffc5..42a0396af85 100644 --- a/configs/lpcxpresso-lpc54628/scripts/flash.ld +++ b/configs/lpcxpresso-lpc54628/scripts/flash.ld @@ -33,7 +33,7 @@ * ****************************************************************************/ -/* The LPC54628 on the LPCXPressio has 512Kb of FLASH at address 0x0000:0000. +/* The LPC54628 on the LPCXPresso has 512Kb of FLASH at address 0x0000:0000. * The Main SRAM is comprised of up to a total 160 KB of contiguous, on-chip * static RAM memory beginning at address 0x2000:0000 (this is in addition * to SRAMX aso the total device SRAM can be up to 200 KB). diff --git a/sched/init/os_start.c b/sched/init/os_start.c index 80fc944956e..93f5cf0f1e9 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -229,7 +229,7 @@ struct pidhash_s g_pidhash[CONFIG_MAX_TASKS]; /* This is a table of task lists. This table is indexed by the task stat * enumeration type (tstate_t) and provides a pointer to the associated * static task list (if there is one) as well as a a set of attribute flags - * indicating properities of the list, for example, if the list is an + * indicating properties of the list, for example, if the list is an * ordered list or not. */ @@ -311,7 +311,7 @@ uint8_t g_os_initstate; /* See enum os_initstate_e */ /**************************************************************************** * Private Data ****************************************************************************/ -/* This is an arry of task control block (TCB) for the IDLE thread of each +/* This is an array of task control block (TCB) for the IDLE thread of each * CPU. For the non-SMP case, this is a a single TCB; For the SMP case, * there is one TCB per CPU. NOTE: The system boots on CPU0 into the IDLE * task. The IDLE task later starts the other CPUs and spawns the user From 134bac381093d1b8ab82de3dd7ba717e7bd14abb Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 13 Jan 2018 15:38:55 -0600 Subject: [PATCH 06/16] arch/arm/src/lpc54xx: Add configuration logic to the empty SPI driver. Still missing all data tranfer logic. --- arch/arm/src/lpc54xx/chip/lpc54_spi.h | 83 +++- arch/arm/src/lpc54xx/lpc54_spi_master.c | 564 +++++++++++++++++++----- arch/arm/src/lpc54xx/lpc54_spi_master.h | 145 ++++-- sched/init/os_start.c | 4 +- 4 files changed, 647 insertions(+), 149 deletions(-) diff --git a/arch/arm/src/lpc54xx/chip/lpc54_spi.h b/arch/arm/src/lpc54xx/chip/lpc54_spi.h index 9ab286e18a9..01e3a5830dd 100644 --- a/arch/arm/src/lpc54xx/chip/lpc54_spi.h +++ b/arch/arm/src/lpc54xx/chip/lpc54_spi.h @@ -260,33 +260,104 @@ /* Register bit definitions *************************************************************************/ /* SPI Configuration register */ -#define SPI_CFG_ + +#define SPI_CFG_ENABLE (1 << 0) /* Bit 0: SPI enable */ +#define SPI_CFG_MASTER (1 << 2) /* Bit 2: Master mode select */ +#define SPI_CFG_LSBF (1 << 3) /* Bit 3: LSB First mode enable */ +#define SPI_CFG_CPHA (1 << 4) /* Bit 4: Clock Phase select */ +#define SPI_CFG_CPOL (1 << 5) /* Bit 5: Clock Polarity select */ +#define SPI_CFG_LOOP (1 << 7) /* Bit 7: Loopback mode enable */ +#define SPI_CFG_SPOL0 (1 << 8) /* Bit 8: SSEL0 Polarity select */ +#define SPI_CFG_SPOL1 (1 << 9) /* Bit 9: SSEL1 Polarity select */ +#define SPI_CFG_SPOL2 (1 << 10) /* Bit 10: SSEL2 Polarity select */ +#define SPI_CFG_SPOL3 (1 << 11) /* Bit 11: SSEL3 Polarity select */ + /* SPI Delay register */ -#define SPI_DLY_ + +#define SPI_DLY_PRE_DELAY_SHIFT (0) /* Bits 0-3: Time between SSEL assertion and data transfer */ +#define SPI_DLY_PRE_DELAY_MASK (15 << SPI_DLY_PRE_DELAY_SHIFT) +# define SPI_DLY_PRE_DELAY(n) ((uint32_t)(n) << SPI_DLY_PRE_DELAY_SHIFT) +#define SPI_DLY_POST_DELAY_SHIFT (4) /* Bits 4-7: Time between tdata transfer and SSEL deassertion */ +#define SPI_DLY_POST_DELAY_MASK (15 << SPI_DLY_POST_DELAY_SHIFT) +# define SPI_DLY_POST_DELAY(n) ((uint32_t)(n) << SPI_DLY_POST_DELAY_SHIFT) +#define SPI_DLY_FRAME_DELAY_SHIFT (8) /* Bits 8-11: Minimum amount of time between frames */ +#define SPI_DLY_FRAME_DELAY_MASK (15 << SPI_DLY_FRAME_DELAY_SHIFT) +# define SPI_DLY_FRAME_DELAY(n) ((uint32_t)(n) << SPI_DLY_FRAME_DELAY_SHIFT) +#define SPI_DLY_TRANSFER_DELAY_SHIFT (12) /* Bits 12-15: Time SSEL deasserted between transfers */ +#define SPI_DLY_TRANSFER_DELAY_MASK (15 << SPI_DLY_TRANSFER_DELAY_SHIFT) +# define SPI_DLY_TRANSFER_DELAY(n) ((uint32_t)(n) << SPI_DLY_TRANSFER_DELAY_SHIFT) + /* SPI Status register */ #define SPI_STAT_ /* SPI Interrupt Enable read and set */ #define SPI_INTENSET_ /* SPI Interrupt Enable Clear */ #define SPI_INTENCLR_ + /* SPI clock Divider */ -#define SPI_DIV_ + +#define SPI_DIV_SHIFT (0) /* Bits 0-15: Rate divider value */ +#define SPI_DIV_MASK (0xffff << SPI_DIV_SHIFT) +# define SPI_DIV(n) ((uint32_t)((n)-1) << SPI_DIV_SHIFT) + /* SPI Interrupt Status */ #define SPI_INTSTAT_ + /* FIFO configuration and enable register */ -#define SPI_FIFOCFG_ + +#define SPI_FIFOCFG_ENABLETX (1 << 0) /* Bit 0: Enable the transmit FIFO) */ +#define SPI_FIFOCFG_ENABLERX (1 << 1) /* Bit 1: Enable the receive FIFO) */ +#define SPI_FIFOCFG_SIZE_SHIFT (4) /* Bits 4-5: FIFO size configuration (read-only) */ +#define SPI_FIFOCFG_SIZE_MASK (3 << SPI_FIFOCFG_SIZE_SHIFT) +# define SPI_FIFOCFG_SIZE_8x16 (1 << SPI_FIFOCFG_SIZE_SHIFT) /* FIFO is configured as 8 entries of 16 bits */ +#define SPI_FIFOCFG_DMATX (1 << 12) /* Bit 12: DMA configuration for transmit */ +#define SPI_FIFOCFG_DMARX (1 << 13) /* Bit 13: DMA configuration for receive */ +#define SPI_FIFOCFG_WAKETX (1 << 14) /* Bit 14: Wake-up for transmit FIFO level */ +#define SPI_FIFOCFG_WAKERX (1 << 15) /* Bit 15: Wake-up for receive FIFO level */ +#define SPI_FIFOCFG_EMPTYTX (1 << 16) /* Bit 16: Empty command for the transmit FIFO) */ +#define SPI_FIFOCFG_EMPTYRX (1 << 17) /* Bit 17: Empty command for the receive FIFO) */ + /* FIFO status register */ #define SPI_FIFOSTAT_ + /* FIFO trigger level settings for interrupt and DMA request */ -#define SPI_FIFOTRIG_ + +#define SPI_FIFOTRIG_TXLVLENA (1 << 0) /* Bit 0 Transmit FIFO level trigger enable */ +#define SPI_FIFOTRIG_RXLVLENA (1 << 1) /* Bit 1 Receive FIFO level trigger enable */ +#define SPI_FIFOTRIG_TXLVL_SHIFT (8) /* Bits 8-11: Transmit FIFO level trigger point */ +#define SPI_FIFOTRIG_TXLVL_MASK (15 << SPI_FIFOTRIG_TXLVL_SHIFT) +# define SPI_FIFOTRIG_TXLVL(n) ((uint32_t)(n) << SPI_FIFOTRIG_TXLVL_SHIFT) +# define SPI_FIFOTRIG_TXLVL_EMPTY (0 << SPI_FIFOTRIG_TXLVL_SHIFT) +# define SPI_FIFOTRIG_TXLVL_NOTFULL (7 << SPI_FIFOTRIG_TXLVL_SHIFT) +#define SPI_FIFOTRIG_RXLVL_SHIFT (16) /* Bits 16-19: Receive FIFO level trigger point */ +#define SPI_FIFOTRIG_RXLVL_MASK (15 << SPI_FIFOTRIG_RXLVL_SHIFT) +# define SPI_FIFOTRIG_RXLVL(n) ((uint32_t)((n)-1) << SPI_FIFOTRIG_RXLVL_SHIFT) +# define SPI_FIFOTRIG_RXLVL_NOTEMPTY (0 << SPI_FIFOTRIG_RXLVL_SHIFT) +# define SPI_FIFOTRIG_RXLVL_FULL (7 << SPI_FIFOTRIG_RXLVL_SHIFT) + /* FIFO interrupt enable set (enable) and read register */ #define SPI_FIFOINTENSET_ /* FIFO interrupt enable clear (disable) and read register */ #define SPI_FIFOINTENCLR_ /* FIFO interrupt status register */ #define SPI_FIFOINTSTAT_ + /* FIFO write data */ -#define SPI_FIFOWR_ + +#define SPI_FIFOWR_TXDATA_SHIFT (0) /* Bits 0-15: Transmit data to the FIFO */ +#define SPI_FIFOWR_TXDATA_MASK (0xffff << SPI_FIFOWR_TXDATA_SHIFT) +# define SPI_FIFOWR_TXDATA(n) ((uint32_t)(n) << SPI_FIFOWR_TXDATA_SHIFT) +#define SPI_FIFOWR_TXSSEL0_N (1 << 16) /* Bit 16: Transmit Slave Select */ +#define SPI_FIFOWR_TXSSEL1_N (1 << 17) /* Bit 17: Transmit Slave Select */ +#define SPI_FIFOWR_TXSSEL2_N (1 << 18) /* Bit 18: Transmit Slave Select */ +#define SPI_FIFOWR_TXSSEL3_N (1 << 19) /* Bit 19: Transmit Slave Select */ +#define SPI_FIFOWR_EOT (1 << 20) /* Bit 20: End of Transfer */ +#define SPI_FIFOWR_EOF (1 << 21) /* Bit 21: End of Frame */ +#define SPI_FIFOWR_RXIGNORE (1 << 22) /* Bit 22: Receive Ignore */ +#define SPI_FIFOWR_LEN_SHIFT (24) /* Bits 24-27: Data Length */ +#define SPI_FIFOWR_LEN_MASK (15 << SPI_FIFOWR_LEN_SHIFT) +# define SPI_FIFOWR_LEN(n) ((uint32_t)((n)-1) << SPI_FIFOWR_LEN_SHIFT) + /* FIFO read data */ #define SPI_FIFORD_ /* FIFO data read with no FIFO pop */ diff --git a/arch/arm/src/lpc54xx/lpc54_spi_master.c b/arch/arm/src/lpc54xx/lpc54_spi_master.c index 665c1a4242d..6189dc9135c 100644 --- a/arch/arm/src/lpc54xx/lpc54_spi_master.c +++ b/arch/arm/src/lpc54xx/lpc54_spi_master.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc54xx/lpc54_spi.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -67,11 +67,13 @@ * Pre-processor Definitions ****************************************************************************/ +#define SPI_DUMMYDATA 0xff + /**************************************************************************** * Private Types ****************************************************************************/ -/* This structure descibes the state of the SSP driver */ +/* This structure describes the state of the SSP driver */ struct lpc54_spidev_s { @@ -82,8 +84,8 @@ struct lpc54_spidev_s uint32_t frequency; /* Requested clock frequency */ uint32_t actual; /* Actual clock frequency */ uint16_t irq; /* Flexcomm IRQ number */ - uint8_t nbits; /* Width of word in bits (8 to 16) */ - uint8_t mode; /* Mode 0,1,2,3 */ + uint8_t nbits; /* Width of word in bits (8 to 16) */ + uint8_t mode; /* Mode 0,1,2,3 */ }; /**************************************************************************** @@ -95,8 +97,6 @@ static inline bool lpc54_spi_16bitmode(FAR struct lpc54_spidev_s *priv); /* SPI methods */ static int lpc54_spi_lock(FAR struct spi_dev_s *dev, bool lock); -static void lpc54_spi_select(FAR struct spi_dev_s *dev, uint32_t devid, - bool selected); static uint32_t lpc54_spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency); static void lpc54_spi_setmode(FAR struct spi_dev_s *dev, @@ -122,19 +122,20 @@ static void lpc54_spi_recvblock(FAR struct spi_dev_s *dev, * Private Data ****************************************************************************/ -static const struct spi_ops_s g_spi_ops = +#ifdef CONFIG_LPC54_SPI0_MASTER +static const struct spi_ops_s g_spi0_ops = { .lock = lpc54_spi_lock, - .select = lpc54_spiselect, + .select = lpc54_spi0_select, /* Provided externally */ .setfrequency = lpc54_spi_setfrequency, .setmode = lpc54_spi_setmode, .setbits = lpc54_spi_setbits, #ifdef CONFIG_SPI_HWFEATURES - .hwfeatures = 0, /* Not supported */ + .hwfeatures = NULL, /* Not supported */ #endif - .status = lpc54_spistatus, + .status = lpc54_spi0_status, /* Provided externally */ #ifdef CONFIG_SPI_CMDDATA - .cmddata = lpc54_spicmddata, + .cmddata = lpc54_spi0_cmddata, /* Provided externally */ #endif .send = lpc54_spi_send, #ifdef CONFIG_SPI_EXCHANGE @@ -144,40 +145,300 @@ static const struct spi_ops_s g_spi_ops = .recvblock = lpc54_spi_recvblock, #endif #ifdef CONFIG_SPI_CALLBACK - .registercallback = lpc54_spiregister, /* Provided externally */ + .registercallback = lpc54_spi0_register, /* Provided externally */ #else - .registercallback = 0, /* Not implemented */ + .registercallback = NULL, /* Not implemented */ #endif }; -#ifdef CONFIG_LPC54_I2C0_MASTER static struct lpc54_spidev_s g_spi0_dev; #endif -#ifdef CONFIG_LPC54_I2C1_MASTER + +#ifdef CONFIG_LPC54_SPI1_MASTER +static const struct spi_ops_s g_spi1_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi1_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi1_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi1_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi1_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi1_dev; #endif -#ifdef CONFIG_LPC54_I2C2_MASTER + +#ifdef CONFIG_LPC54_SPI2_MASTER +static const struct spi_ops_s g_spi2_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi2_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi2_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi2_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi2_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi2_dev; #endif -#ifdef CONFIG_LPC54_I2C3_MASTER + +#ifdef CONFIG_LPC54_SPI3_MASTER +static const struct spi_ops_s g_spi3_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi3_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi3_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi3_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi3_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi3_dev; #endif -#ifdef CONFIG_LPC54_I2C4_MASTER + +#ifdef CONFIG_LPC54_SPI4_MASTER +static const struct spi_ops_s g_spi4_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi4_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi4_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi4_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi4_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi4_dev; #endif -#ifdef CONFIG_LPC54_I2C5_MASTER + +#ifdef CONFIG_LPC54_SPI5_MASTER +static const struct spi_ops_s g_spi5_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi5_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi5_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi5_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi5_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi5_dev; #endif -#ifdef CONFIG_LPC54_I2C6_MASTER + +#ifdef CONFIG_LPC54_SPI6_MASTER +static const struct spi_ops_s g_spi6_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi6_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi6_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi6_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi6_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi6_dev; #endif -#ifdef CONFIG_LPC54_I2C7_MASTER + +#ifdef CONFIG_LPC54_SPI7_MASTER +static const struct spi_ops_s g_spi7_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi7_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi7_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi7_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi7_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi7_dev; #endif -#ifdef CONFIG_LPC54_I2C8_MASTER + +#ifdef CONFIG_LPC54_SPI8_MASTER +static const struct spi_ops_s g_spi8_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi8_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi8_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi8_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi8_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi8_dev; #endif -#ifdef CONFIG_LPC54_I2C9_MASTER + +#ifdef CONFIG_LPC54_SPI9_MASTER +static const struct spi_ops_s g_spi9_ops = +{ + .lock = lpc54_spi_lock, + .select = lpc54_spi9_select, /* Provided externally */ + .setfrequency = lpc54_spi_setfrequency, + .setmode = lpc54_spi_setmode, + .setbits = lpc54_spi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = NULL, /* Not supported */ +#endif + .status = lpc54_spi9_status, /* Provided externally */ +#ifdef CONFIG_SPI_CMDDATA + .cmddata = lpc54_spi9_cmddata, /* Provided externally */ +#endif + .send = lpc54_spi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = lpc54_spi_exchange, +#else + .sndblock = lpc54_spi_sndblock, + .recvblock = lpc54_spi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc54_spi9_register, /* Provided externally */ +#else + .registercallback = NULL, /* Not implemented */ +#endif +}; + static struct lpc54_spidev_s g_spi9_dev; #endif @@ -196,19 +457,19 @@ static struct lpc54_spidev_s g_spi9_dev; static inline void lpc54_spi_putreg(struct lpc54_spidev_s *priv, unsigned int regoffset, uint32_t regval) { - putreg32(value, priv->base + regoffset); + putreg32(regval, priv->base + regoffset); } /**************************************************************************** - * Name: lpc54_spi_gettreg + * Name: lpc54_spi_getreg * * Description: * Read the content of a register at the offset from the Flexcomm base. * ****************************************************************************/ -static inline void lpc54_spi_gettreg(struct lpc54_spidev_s *priv, - unsigned int regoffset) +static inline uint32_t lpc54_spi_getreg(struct lpc54_spidev_s *priv, + unsigned int regoffset) { return getreg32(priv->base + regoffset); } @@ -237,8 +498,8 @@ static inline bool lpc54_spi_16bitmode(FAR struct lpc54_spidev_s *priv) * Name: lpc54_spi_lock * * Description: - * On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of + * On SPI buses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the buses for a sequence of * transfers. The bus should be locked before the chip is selected. After * locking the SPI bus, the caller should then also call the setfrequency, * setbits, and setmode methods to make sure that the SPI is properly @@ -303,11 +564,15 @@ static uint32_t lpc54_spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency) { FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; + uint32_t divider; uint32_t actual; + uint32_t regval; - /* Check if the requested frequence is the same as the frequency selection */ + /* Check if the requested frequency is the same as the current frequency + * selection. + */ - DEBUGASSERT(priv && frequency <= priv->fclock / 2); + DEBUGASSERT(priv != NULL && frequency <= priv->fclock / 2); if (priv->frequency == frequency) { @@ -317,7 +582,21 @@ static uint32_t lpc54_spi_setfrequency(FAR struct spi_dev_s *dev, } /* Set the new SPI frequency */ -#warning Missing logic + + divider = priv->fclock / frequency; + if (divider > 0x10000) + { + divider = 0x10000; + } + + regval = lpc54_spi_getreg(priv, LPC54_SPI_DIV_OFFSET); + regval &= ~SPI_DIV_MASK; + regval |= SPI_DIV(divider); + lpc54_spi_putreg(priv, LPC54_SPI_DIV_OFFSET, regval); + + /* Calculate the actual frequency */ + + actual = priv->fclock / divider; /* Save the frequency setting */ @@ -354,24 +633,25 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev, if (mode != priv->mode) { /* Yes... Set the new mode */ -#warning Missing logic + + regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval &= ~(SPI_CFG_CPHA | SPI_CFG_CPOL); switch (mode) { case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */ -#warning Missing logic break; case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */ -#warning Missing logic + regval |= SPI_CFG_CPHA; break; case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */ -#warning Missing logic + regval |= SPI_CFG_CPOL; break; case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */ -#warning Missing logic + regval |= (SPI_CFG_CPHA | SPI_CFG_CPOL); break; default: @@ -379,9 +659,9 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev, return; } -#warning Missing logic + lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); - /* Save the mode so that subsequent re-configuratins will be faster */ + /* Save the mode so that subsequent re-configurations will be faster */ priv->mode = mode; } @@ -405,18 +685,14 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev, static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits) { FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; - uint32_t regval; - /* Has the number of bits changed? */ + /* The valid range of bit selections is 4 through 16 */ - DEBUGASSERT(priv && nbits > 7 && nbits < 17); + DEBUGASSERT(priv != NULL && nbits >=4 && nbits <= 16); - if (nbits != priv->nbits) + if (nbits >= 4 && nbits <= 16) { - /* Yes... Set the number word width */ -#warning Missing logic - - /* Save the selection so the subsequence re-configurations will be faster */ + /* Save the selection. It will be applied when data is transferred. */ priv->nbits = nbits; } @@ -494,9 +770,9 @@ static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev, { /* 16-bit mode */ - const uint16_t *src = (const uint16_t *)txbuffer; - uint16_t *dest = (uint16_t *)rxbuffer; - uint16_t word; + FAR const uint16_t *src = (FAR const uint16_t *)txbuffer; + FAR uint16_t *dest = (FAR uint16_t *)rxbuffer; + uint16_t word; while (nwords-- > 0) { @@ -513,7 +789,7 @@ static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev, /* Exchange one word */ - word = spi_send(dev, word); + word = lpc54_spi_send(dev, word); /* Is there a buffer to receive the return value? */ @@ -527,9 +803,9 @@ static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev, { /* 8-bit mode */ - const uint8_t *src = (const uint8_t *)txbuffer; - uint8_t *dest = (uint8_t *)rxbuffer; - uint8_t word; + FAR const uint8_t *src = (FAR const uint8_t *)txbuffer; + FAR uint8_t *dest = (FAR uint8_t *)rxbuffer; + uint8_t word; while (nwords-- > 0) { @@ -546,7 +822,7 @@ static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev, /* Exchange one word */ - word = (uint8_t)spi_send(dev, (uint16_t)word); + word = (uint8_t)lpc54_spi_send(dev, (uint16_t)word); /* Is there a buffer to receive the return value? */ @@ -615,8 +891,8 @@ static void lpc54_spi_exchange(FAR struct spi_dev_s *dev, static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords) { - spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords); - return lpc54_spi_exchange(dev, txbuffer, NULL, nwords); + spiinfo("txbuffer=%p nwords=%d\n", buffer, nwords); + return lpc54_spi_exchange(dev, buffer, NULL, nwords); } /**************************************************************************** @@ -642,8 +918,8 @@ static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev, static void lpc54_spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords) { - spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords); - return lpc54_spi_exchange(dev, NULL, rxbuffer, nwords); + spiinfo("rxbuffer=%p nwords=%d\n", buffer, nwords); + return lpc54_spi_exchange(dev, NULL, buffer, nwords); } /**************************************************************************** @@ -672,6 +948,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) { struct lpc54_spidev_s *priv; irqstate_t flags; + uint32_t regval; flags = enter_critical_section(); @@ -680,7 +957,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) * lpc54_lowputc.c. */ -#ifdef CONFIG_LPC54_I2C0_MASTER +#ifdef CONFIG_LPC54_SPI0_MASTER if (port == 0) { /* Attach 12 MHz clock to FLEXCOMM0 */ @@ -698,14 +975,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi0_dev; priv->base = LPC54_FLEXCOMM0_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM0; + priv->irq = LPC54_IRQ_FLEXCOMM0; priv->fclock = BOARD_FLEXCOMM0_FCLK; + priv->dev.ops = &g_spi0_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C0_SCK); - lpc54_gpio_config(GPIO_I2C0_MOSI); - lpc54_gpio_config(GPIO_I2C0_MISO); + lpc54_gpio_config(GPIO_SPI0_SCK); + lpc54_gpio_config(GPIO_SPI0_MOSI); + lpc54_gpio_config(GPIO_SPI0_MISO); /* Set up the FLEXCOMM0 function clock */ @@ -713,7 +991,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C1_MASTER +#ifdef CONFIG_LPC54_SPI1_MASTER if (port == 1) { /* Attach 12 MHz clock to FLEXCOMM1 */ @@ -731,14 +1009,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi1_dev; priv->base = LPC54_FLEXCOMM1_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM1; + priv->irq = LPC54_IRQ_FLEXCOMM1; priv->fclock = BOARD_FLEXCOMM1_FCLK; + priv->dev.ops = &g_spi1_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C1_SCK); - lpc54_gpio_config(GPIO_I2C1_MOSI); - lpc54_gpio_config(GPIO_I2C1_MISO); + lpc54_gpio_config(GPIO_SPI1_SCK); + lpc54_gpio_config(GPIO_SPI1_MOSI); + lpc54_gpio_config(GPIO_SPI1_MISO); /* Set up the FLEXCOMM1 function clock */ @@ -746,7 +1025,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C2_MASTER +#ifdef CONFIG_LPC54_SPI2_MASTER if (port == 2) { /* Attach 12 MHz clock to FLEXCOMM2 */ @@ -764,14 +1043,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi2_dev; priv->base = LPC54_FLEXCOMM2_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM2; + priv->irq = LPC54_IRQ_FLEXCOMM2; priv->fclock = BOARD_FLEXCOMM2_FCLK; + priv->dev.ops = &g_spi2_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C2_SCK); - lpc54_gpio_config(GPIO_I2C2_MOSI); - lpc54_gpio_config(GPIO_I2C2MISO); + lpc54_gpio_config(GPIO_SPI2_SCK); + lpc54_gpio_config(GPIO_SPI2_MOSI); + lpc54_gpio_config(GPIO_SPI2MISO); /* Set up the FLEXCOMM2 function clock */ @@ -779,7 +1059,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C3_MASTER +#ifdef CONFIG_LPC54_SPI3_MASTER if (port == 3) { /* Attach 12 MHz clock to FLEXCOMM3 */ @@ -797,14 +1077,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi3_dev; priv->base = LPC54_FLEXCOMM3_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM3; + priv->irq = LPC54_IRQ_FLEXCOMM3; priv->fclock = BOARD_FLEXCOMM3_FCLK; + priv->dev.ops = &g_spi3_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C3_SCK); - lpc54_gpio_config(GPIO_I2C3_MOSI); - lpc54_gpio_config(GPIO_I2C3_MISO); + lpc54_gpio_config(GPIO_SPI3_SCK); + lpc54_gpio_config(GPIO_SPI3_MOSI); + lpc54_gpio_config(GPIO_SPI3_MISO); /* Set up the FLEXCOMM3 function clock */ @@ -812,7 +1093,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C4_MASTER +#ifdef CONFIG_LPC54_SPI4_MASTER if (port == 4) { /* Attach 12 MHz clock to FLEXCOMM4 */ @@ -830,14 +1111,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi4_dev; priv->base = LPC54_FLEXCOMM4_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM4; + priv->irq = LPC54_IRQ_FLEXCOMM4; priv->fclock = BOARD_FLEXCOMM4_FCLK; + priv->dev.ops = &g_spi4_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C4_SCK); - lpc54_gpio_config(GPIO_I2C4_MOSI); - lpc54_gpio_config(GPIO_I2C4_MISO); + lpc54_gpio_config(GPIO_SPI4_SCK); + lpc54_gpio_config(GPIO_SPI4_MOSI); + lpc54_gpio_config(GPIO_SPI4_MISO); /* Set up the FLEXCOMM4 function clock */ @@ -845,7 +1127,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C5_MASTER +#ifdef CONFIG_LPC54_SPI5_MASTER if (port == 5) { /* Attach 12 MHz clock to FLEXCOMM5 */ @@ -863,14 +1145,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi5_dev; priv->base = LPC54_FLEXCOMM5_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM5; + priv->irq = LPC54_IRQ_FLEXCOMM5; priv->fclock = BOARD_FLEXCOMM5_FCLK; + priv->dev.ops = &g_spi5_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C5_SCK); - lpc54_gpio_config(GPIO_I2C5_MOSI); - lpc54_gpio_config(GPIO_I2C5_MISO); + lpc54_gpio_config(GPIO_SPI5_SCK); + lpc54_gpio_config(GPIO_SPI5_MOSI); + lpc54_gpio_config(GPIO_SPI5_MISO); /* Set up the FLEXCOMM5 function clock */ @@ -878,7 +1161,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C6_MASTER +#ifdef CONFIG_LPC54_SPI6_MASTER if (port == 6) { /* Attach 12 MHz clock to FLEXCOMM6 */ @@ -896,14 +1179,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi6_dev; priv->base = LPC54_FLEXCOMM6_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM6; + priv->irq = LPC54_IRQ_FLEXCOMM6; priv->fclock = BOARD_FLEXCOMM6_FCLK; + priv->dev.ops = &g_spi6_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C6_SCK); - lpc54_gpio_config(GPIO_I2C6_MOSI); - lpc54_gpio_config(GPIO_I2C6_MISO); + lpc54_gpio_config(GPIO_SPI6_SCK); + lpc54_gpio_config(GPIO_SPI6_MOSI); + lpc54_gpio_config(GPIO_SPI6_MISO); /* Set up the FLEXCOMM6 function clock */ @@ -911,7 +1195,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C7_MASTER +#ifdef CONFIG_LPC54_SPI7_MASTER if (port == 7) { /* Attach 12 MHz clock to FLEXCOMM7 */ @@ -929,14 +1213,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi7_dev; priv->base = LPC54_FLEXCOMM7_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM7; + priv->irq = LPC54_IRQ_FLEXCOMM7; priv->fclock = BOARD_FLEXCOMM7_FCLK; + priv->dev.ops = &g_spi7_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C7_SCK); - lpc54_gpio_config(GPIO_I2C7_MOSI); - lpc54_gpio_config(GPIO_I2C7_MISO); + lpc54_gpio_config(GPIO_SPI7_SCK); + lpc54_gpio_config(GPIO_SPI7_MOSI); + lpc54_gpio_config(GPIO_SPI7_MISO); /* Set up the FLEXCOMM7 function clock */ @@ -944,7 +1229,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C8_MASTER +#ifdef CONFIG_LPC54_SPI8_MASTER if (port == 8) { /* Attach 12 MHz clock to FLEXCOMM8 */ @@ -962,14 +1247,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi8_dev; priv->base = LPC54_FLEXCOMM8_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM8; + priv->irq = LPC54_IRQ_FLEXCOMM8; priv->fclock = BOARD_FLEXCOMM8_FCLK; + priv->dev.ops = &g_spi8_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C8_SCK); - lpc54_gpio_config(GPIO_I2C8_MOSI); - lpc54_gpio_config(GPIO_I2C8_MISO); + lpc54_gpio_config(GPIO_SPI8_SCK); + lpc54_gpio_config(GPIO_SPI8_MOSI); + lpc54_gpio_config(GPIO_SPI8_MISO); /* Set up the FLEXCOMM8 function clock */ @@ -977,7 +1263,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) } else #endif -#ifdef CONFIG_LPC54_I2C9_MASTER +#ifdef CONFIG_LPC54_SPI9_MASTER if (port == 9) { /* Attach 12 MHz clock to FLEXCOMM9 */ @@ -995,14 +1281,15 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) priv = &g_spi9_dev; priv->base = LPC54_FLEXCOMM9_BASE; - priv->irqid = LPC54_IRQ_FLEXCOMM9; + priv->irq = LPC54_IRQ_FLEXCOMM9; priv->fclock = BOARD_FLEXCOMM9_FCLK; + priv->dev.ops = &g_spi9_ops; /* Configure SPI pins (defined in board.h) */ - lpc54_gpio_config(GPIO_I2C9_SCK); - lpc54_gpio_config(GPIO_I2C9_MOSI); - lpc54_gpio_config(GPIO_I2C9_MISO); + lpc54_gpio_config(GPIO_SPI9_SCK); + lpc54_gpio_config(GPIO_SPI9_MOSI); + lpc54_gpio_config(GPIO_SPI9_MISO); /* Set up the FLEXCOMM9 function clock */ @@ -1016,24 +1303,69 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) leave_critical_section(flags); - /* Enable the SPI peripheral*/ - /* Configure 8-bit SPI mode and master mode */ -#warning Missing logic - /* Set the initial SPI configuration */ priv->frequency = 0; priv->nbits = 8; priv->mode = SPIDEV_MODE0; - priv->dev.ops = &g_spi_ops; + + /* Initialize the SPI semaphore that enforces mutually exclusive access */ + + nxsem_init(&priv->exclsem, 0, 1); + + /* Configure master mode in mode 0: + * + * ENABLE - Disabled for now (0) + * MASTER - Master mode (1) + * LSBF - MSB first (0) + * CPHA/CPOL - Mode 0 (0,0) + * LOOP - Disable loopback mode (0) + * SPOLn - Active low (0,0,0) + */ + + regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval &= ~(SPI_CFG_ENABLE | SPI_CFG_LSBF | SPI_CFG_CPHA | SPI_CFG_CPOL | + SPI_CFG_LOOP | SPI_CFG_SPOL0 | SPI_CFG_SPOL1 | SPI_CFG_SPOL2 | + SPI_CFG_SPOL3); + regval |= SPI_CFG_MASTER; + lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + + /* Enable FIFOs */ + + regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval |= (SPI_FIFOCFG_EMPTYTX | SPI_FIFOCFG_EMPTYRX); + lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + + regval |= (SPI_FIFOCFG_ENABLETX | SPI_FIFOCFG_ENABLERX); + lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + + /* Set FIFO trigger levels: Empty for Tx FIFO; 1 word for RxFIFO */ + + regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval &= ~(SPI_FIFOTRIG_TXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK); + regval |= (SPI_FIFOTRIG_TXLVL_EMPTY | SPI_FIFOTRIG_RXLVL_NOTEMPTY); + + /* Enable generation of interrupts for selected FIFO trigger levels */ + + regval |= (SPI_FIFOTRIG_TXLVLENA | SPI_FIFOTRIG_RXLVLENA); + lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + + /* Set the delay configuration (not used) */ + + regval = (SPI_DLY_PRE_DELAY(0) | SPI_DLY_POST_DELAY(0) | SPI_DLY_FRAME_DELAY(0) | + SPI_DLY_TRANSFER_DELAY(0)); + lpc54_spi_putreg(priv, LPC54_SPI_DLY_OFFSET, regval); /* Select a default frequency of approx. 400KHz */ lpc54_spi_setfrequency((FAR struct spi_dev_s *)priv, 400000); - /* Initialize the SPI semaphore that enforces mutually exclusive access */ + /* Enable the SPI peripheral */ + + regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval |= SPI_CFG_ENABLE; + lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); - nxsem_init(&priv->exclsem, 0, 1); return &priv->dev; } diff --git a/arch/arm/src/lpc54xx/lpc54_spi_master.h b/arch/arm/src/lpc54xx/lpc54_spi_master.h index 376c3a6e768..12009872a77 100644 --- a/arch/arm/src/lpc54xx/lpc54_spi_master.h +++ b/arch/arm/src/lpc54xx/lpc54_spi_master.h @@ -109,45 +109,111 @@ extern "C" FAR struct spi_dev_s *lpc54_spibus_initialize(int port); /************************************************************************************ - * Name: lpc54_spiselect, lpc54_spistatus, and lpc54_spicmddata + * Name: lpc54_spiN_select, lpc54_spiN_status, and lpc54_spiN_cmddata * * Description: * These functions must be provided in your board-specific logic. The - * lpc54_spiselect function will perform chip selection and the lpc54_spistatus + * lpc54_spiN_select function will perform chip selection and the lpc54_spiN_status * will perform status operations using GPIOs in the way your board is configured. * * If CONFIG_SPI_CMDDATA is defined in the NuttX configuration, then - * lpc54_spicmddata must also be provided. This functions performs cmd/data + * lpc54_spiN_cmddata must also be provided. This functions performs cmd/data * selection operations using GPIOs in the way your board is configured. * ************************************************************************************/ -void lpc54_spiselect(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); -uint8_t lpc54_spistatus(FAR struct spi_dev_s *dev, uint32_t devid); +#ifdef CONFIG_LPC54_SPI0_MASTER +void lpc54_spi0_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi0_status(FAR struct spi_dev_s *dev, uint32_t devid); #ifdef CONFIG_SPI_CMDDATA -int lpc54_spicmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +int lpc54_spi0_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI1_MASTER +void lpc54_spi1_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi1_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi1_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI2_MASTER +void lpc54_spi2_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi2_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi2_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI3_MASTER +void lpc54_spi3_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi3_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi3_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI4_MASTER +void lpc54_spi4_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi4_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi4_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI5_MASTER +void lpc54_spi5_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi5_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi5_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI6_MASTER +void lpc54_spi6_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi6_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi6_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI7_MASTER +void lpc54_spi7_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi7_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi7_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI8_MASTER +void lpc54_spi8_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi8_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi8_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif +#endif + +#ifdef CONFIG_LPC54_SPI9_MASTER +void lpc54_spi9_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected); +uint8_t lpc54_spi9_status(FAR struct spi_dev_s *dev, uint32_t devid); + +#ifdef CONFIG_SPI_CMDDATA +int lpc54_spi9_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd); +#endif #endif /************************************************************************************ - * Name: spi_flush - * - * Description: - * Flush and discard any words left in the RX fifo. This can be called from - * spiselect after a device is deselected (if you worry about such things). - * - * Input Parameters: - * dev - Device-specific state data - * - * Returned Value: - * None - * - ************************************************************************************/ - -void spi_flush(FAR struct spi_dev_s *dev); - -/************************************************************************************ - * Name: lpc54_spi/spiregister + * Name: lpc54_spiN_register * * Description: * If the board supports a card detect callback to inform the SPI-based MMC/SD @@ -167,7 +233,36 @@ void spi_flush(FAR struct spi_dev_s *dev); ************************************************************************************/ #ifdef CONFIG_SPI_CALLBACK -int lpc54_spiregister(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#ifdef CONFIG_LPC54_SPI0_MASTER +int lpc54_spi0_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI1_MASTER +int lpc54_spi1_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI2_MASTER +int lpc54_spi2_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI3_MASTER +int lpc54_spi3_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI4_MASTER +int lpc54_spi4_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI5_MASTER +int lpc54_spi5_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI6_MASTER +int lpc54_spi6_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI7_MASTER +int lpc54_spi7_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI8_MASTER +int lpc54_spi8_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif +#ifdef CONFIG_LPC54_SPI9_MASTER +int lpc54_spi9_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); +#endif #endif #undef EXTERN diff --git a/sched/init/os_start.c b/sched/init/os_start.c index 93f5cf0f1e9..9033189e639 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -115,7 +115,7 @@ volatile dq_queue_t g_readytorun; * and * - Tasks/threads that have not been assigned to a CPU. * - * Otherwise, the TCB will be reatined in an assigned task list, + * Otherwise, the TCB will be retained in an assigned task list, * g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU * 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/ * threads would be assigned a particular CPU by one of two mechanisms: @@ -187,7 +187,7 @@ volatile dq_queue_t g_waitingforfill; volatile dq_queue_t g_inactivetasks; -/* These are lists of dayed memory deallocations that need to be handled +/* These are lists of delayed memory deallocations that need to be handled * within the IDLE loop or worker thread. These deallocations get queued * by sched_kufree and sched_kfree() if the OS needs to deallocate memory * while it is within an interrupt handler. From 8f94ce46f9875e127ec17629f10f2bf22341531f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 14 Jan 2018 12:09:26 -0600 Subject: [PATCH 07/16] arch/arm/src/lpc54xx: The basic SPI driver is code complete but still untested. This driver is 'basic' in that in only supports polled mode operations. --- arch/arm/src/lpc54xx/Kconfig | 18 + arch/arm/src/lpc54xx/chip/lpc54_spi.h | 89 +- arch/arm/src/lpc54xx/lpc54_spi_master.c | 1027 +++++++++++++++++++---- arch/arm/src/lpc54xx/lpc54_spi_master.h | 2 +- configs/lpcxpresso-lpc54628/README.txt | 19 +- include/nuttx/spi/spi.h | 4 +- 6 files changed, 968 insertions(+), 191 deletions(-) diff --git a/arch/arm/src/lpc54xx/Kconfig b/arch/arm/src/lpc54xx/Kconfig index bc77fb07199..947350c7733 100644 --- a/arch/arm/src/lpc54xx/Kconfig +++ b/arch/arm/src/lpc54xx/Kconfig @@ -667,6 +667,24 @@ endif # LPC54_EMC_DYNAMIC endmenu # EMC Configuration +menu "SPI Master configuration" + depends on LPC54_HAVE_SPI_MASTER + +config LPC54_SPI_WIDEDATA + bool "Enable wide data" + default n + ---help--- + The LPC54xxx SPI supports data widths from 4 through 16 bits. For + data from 4 through 8 bits; the receive and transmit data is + represented with a uint8_t type. For the wider data, data is + represented with a uint16_t. There is duplication of logic for this + different widths. By default, SPI wide data is disabled since that + is the less frequently used data type and disabling wide data can + result in some size reduction. Select this option if you need wide + SPI data. + +endmenu # SPI Master configuration + menu "Ethernet configuration" depends on LPC54_ETHERNET diff --git a/arch/arm/src/lpc54xx/chip/lpc54_spi.h b/arch/arm/src/lpc54xx/chip/lpc54_spi.h index 01e3a5830dd..21071fbb371 100644 --- a/arch/arm/src/lpc54xx/chip/lpc54_spi.h +++ b/arch/arm/src/lpc54xx/chip/lpc54_spi.h @@ -288,11 +288,18 @@ # define SPI_DLY_TRANSFER_DELAY(n) ((uint32_t)(n) << SPI_DLY_TRANSFER_DELAY_SHIFT) /* SPI Status register */ -#define SPI_STAT_ -/* SPI Interrupt Enable read and set */ -#define SPI_INTENSET_ -/* SPI Interrupt Enable Clear */ -#define SPI_INTENCLR_ + +#define SPI_STAT_SSA (1 << 4) /* Bit 4: Slave Select Assert */ +#define SPI_STAT_SSD (1 << 5) /* Bit 5: Slave Select Deassert */ +#define SPI_STAT_STALLED (1 << 6) /* Bit 6: Stalled status flag */ +#define SPI_STAT_ENDTRANSFER (1 << 7) /* Bit 7: End Transfer control bit */ +#define SPI_STAT_MSTIDLE (1 << 8) /* Bit 8: Master idle status flag */ + +/* SPI Interrupt Enable read and set, SPI Interrupt Enable Clear, and SPI Interrupt Status */ + +#define SPI_INT_SSA (1 << 4) /* Bit 4: Slave select assert interrupt */ +#define SPI_INT_SSD (1 << 5) /* Bit 5: Slave select deassert interrupt */ +#define SPI_INT_MSTIDLE (1 << 8) /* Bit 8: Master idle interrupt */ /* SPI clock Divider */ @@ -300,9 +307,6 @@ #define SPI_DIV_MASK (0xffff << SPI_DIV_SHIFT) # define SPI_DIV(n) ((uint32_t)((n)-1) << SPI_DIV_SHIFT) -/* SPI Interrupt Status */ -#define SPI_INTSTAT_ - /* FIFO configuration and enable register */ #define SPI_FIFOCFG_ENABLETX (1 << 0) /* Bit 0: Enable the transmit FIFO) */ @@ -318,12 +322,23 @@ #define SPI_FIFOCFG_EMPTYRX (1 << 17) /* Bit 17: Empty command for the receive FIFO) */ /* FIFO status register */ -#define SPI_FIFOSTAT_ + +#define SPI_FIFOSTAT_TXERR (1 << 0) /* Bit 0: TX FIFO error */ +#define SPI_FIFOSTAT_RXERR (1 << 1) /* Bit 1: RX FIFO error */ +#define SPI_FIFOSTAT_PERINT (1 << 3) /* Bit 3: Peripheral interrupt */ +#define SPI_FIFOSTAT_TXEMPTY (1 << 4) /* Bit 4: Transmit FIFO empty */ +#define SPI_FIFOSTAT_TXNOTFULL (1 << 5) /* Bit 5: Transmit FIFO not full */ +#define SPI_FIFOSTAT_RXNOTEMPTY (1 << 6) /* Bit 6: Receive FIFO not empty */ +#define SPI_FIFOSTAT_RXFULL (1 << 7) /* Bit 7: Receive FIFO full */ +#define SPI_FIFOSTAT_TXLVL_SHIFT (8) /* Bits 8-12: Transmit FIFO current level */ +#define SPI_FIFOSTAT_TXLVL_MASK (31 << SPI_FIFOSTAT_TXLVL_SHIFT) +#define SPI_FIFOSTAT_RXLVL_SHIFT (16) /* Bits 16-20: Receive FIFO current level */ +#define SPI_FIFOSTAT_RXLVL_MASK (31 << SPI_FIFOSTAT_RXLVL_SHIFT) /* FIFO trigger level settings for interrupt and DMA request */ -#define SPI_FIFOTRIG_TXLVLENA (1 << 0) /* Bit 0 Transmit FIFO level trigger enable */ -#define SPI_FIFOTRIG_RXLVLENA (1 << 1) /* Bit 1 Receive FIFO level trigger enable */ +#define SPI_FIFOTRIG_TXLVLENA (1 << 0) /* Bit 0: Transmit FIFO level trigger enable */ +#define SPI_FIFOTRIG_RXLVLENA (1 << 1) /* Bit 1: Receive FIFO level trigger enable */ #define SPI_FIFOTRIG_TXLVL_SHIFT (8) /* Bits 8-11: Transmit FIFO level trigger point */ #define SPI_FIFOTRIG_TXLVL_MASK (15 << SPI_FIFOTRIG_TXLVL_SHIFT) # define SPI_FIFOTRIG_TXLVL(n) ((uint32_t)(n) << SPI_FIFOTRIG_TXLVL_SHIFT) @@ -335,22 +350,28 @@ # define SPI_FIFOTRIG_RXLVL_NOTEMPTY (0 << SPI_FIFOTRIG_RXLVL_SHIFT) # define SPI_FIFOTRIG_RXLVL_FULL (7 << SPI_FIFOTRIG_RXLVL_SHIFT) -/* FIFO interrupt enable set (enable) and read register */ -#define SPI_FIFOINTENSET_ -/* FIFO interrupt enable clear (disable) and read register */ -#define SPI_FIFOINTENCLR_ -/* FIFO interrupt status register */ -#define SPI_FIFOINTSTAT_ +/* FIFO interrupt enable set (enable) and read register, FIFO interrupt enable clear (disable) + * and read register, and FIFO interrupt status register + */ + +#define SPI_FIFOINT_TXERR (1 << 0) /* Bit 0: Transmit error interrupt */ +#define SPI_FIFOINT_RXERR (1 << 1) /* Bit 1: Receive error interrupt */ +#define SPI_FIFOINT_TXLVL (1 << 2) /* Bit 2: Tx FIFO level reached interrupt */ +#define SPI_FIFOINT_RXLVL (1 << 3) /* Bit 3: Rx FIFO level reached interrupt */ +#define SPI_FIFOINTSTAT_PERINT (1 << 4) /* Bit 4: Peripheral interrupt (status only) */ /* FIFO write data */ #define SPI_FIFOWR_TXDATA_SHIFT (0) /* Bits 0-15: Transmit data to the FIFO */ #define SPI_FIFOWR_TXDATA_MASK (0xffff << SPI_FIFOWR_TXDATA_SHIFT) # define SPI_FIFOWR_TXDATA(n) ((uint32_t)(n) << SPI_FIFOWR_TXDATA_SHIFT) -#define SPI_FIFOWR_TXSSEL0_N (1 << 16) /* Bit 16: Transmit Slave Select */ -#define SPI_FIFOWR_TXSSEL1_N (1 << 17) /* Bit 17: Transmit Slave Select */ -#define SPI_FIFOWR_TXSSEL2_N (1 << 18) /* Bit 18: Transmit Slave Select */ -#define SPI_FIFOWR_TXSSEL3_N (1 << 19) /* Bit 19: Transmit Slave Select */ +#define SPI_FIFOWR_TXSSELN_SHIFT (16) /* Bits 16-19: Transmit Slave Selects */ +#define SPI_FIFOWR_TXSSELN_MASK (15 << SPI_FIFOWR_TXSSELN_SHIFT) +# define SPI_FIFOWR_TXSSELN_ALL (15 << SPI_FIFOWR_TXSSELN_SHIFT) +# define SPI_FIFOWR_TXSSEL0N (1 << 16) /* Bit 16: Transmit Slave Select */ +# define SPI_FIFOWR_TXSSEL1N (1 << 17) /* Bit 17: Transmit Slave Select */ +# define SPI_FIFOWR_TXSSEL2N (1 << 18) /* Bit 18: Transmit Slave Select */ +# define SPI_FIFOWR_TXSSEL3N (1 << 19) /* Bit 19: Transmit Slave Select */ #define SPI_FIFOWR_EOT (1 << 20) /* Bit 20: End of Transfer */ #define SPI_FIFOWR_EOF (1 << 21) /* Bit 21: End of Frame */ #define SPI_FIFOWR_RXIGNORE (1 << 22) /* Bit 22: Receive Ignore */ @@ -358,11 +379,27 @@ #define SPI_FIFOWR_LEN_MASK (15 << SPI_FIFOWR_LEN_SHIFT) # define SPI_FIFOWR_LEN(n) ((uint32_t)((n)-1) << SPI_FIFOWR_LEN_SHIFT) -/* FIFO read data */ -#define SPI_FIFORD_ -/* FIFO data read with no FIFO pop */ -#define SPI_FIFORDNOPOP_ +/* FIFO read data and FIFO data read with no FIFO pop */ + +#define SPI_FIFORD_RXDATA_SHIFT (0) /* Bits 0-15: Received data from the FIFO */ +#define SPI_FIFORD_RXDATA_MASK (0xffff << SPI_FIFORD_RXDATA_SHIFT) +#define SPI_FIFORD_RXSSELN_SHIFT (16) /* Bits 16-19: Slave Selects for receive */ +#define SPI_FIFORD_RXSSELN_MASK (15 << SPI_FIFORD_RXSSELN_SHIFT) +# define SPI_FIFORD_RXSSEL0N (1 << 16) /* Bit 16: Slave Select for receive */ +# define SPI_FIFORD_RXSSEL1N (1 << 17) /* Bit 17: Slave Select for receive */ +# define SPI_FIFORD_RXSSEL2N (1 << 18) /* Bit 18: Slave Select for receive */ +# define SPI_FIFORD_RXSSEL3N (1 << 19) /* Bit 19: Slave Select for receive */ +#define SPI_FIFORD_SOT (1 << 20) /* Bit 20: Start of Transfer flag */ + /* SPI module Identification */ -#define SPI_ID_ + +#define SPI_ID_APERTURE_SHIFT (0) /* Bits 0-7: Aperture encoded as (aperture size/4K) -1 */ +#define SPI_ID_APERTURE_MASK (0xff << SPI_ID_APERTURE_SHIFT) +#define SPI_ID_MINORREV_SHIFT (8) /* Bits 8-11: Minor revision of module implementation */ +#define SPI_ID_MINORREV_MASK (15 << SPI_ID_MINORREV_SHIFT) +#define SPI_ID_MAJORREV_SHIFT (12) /* Bits 12-15: Major revision of module implementation */ +#define SPI_ID_MAJORREV_MASK (15 << SPI_ID_MAJORREV_SHIFT) +#define SPI_ID_ID_SHIFT (15) /* Bits 16-31: Unique module identifier for this IP block */ +#define SPI_ID_ID_MASK (0xffff << SPI_ID_ID_SHIFT) #endif /* __ARCH_ARM_SRC_LPC54XX_CHIP_LPC54_SPI_H */ diff --git a/arch/arm/src/lpc54xx/lpc54_spi_master.c b/arch/arm/src/lpc54xx/lpc54_spi_master.c index 6189dc9135c..35dd60ed8f5 100644 --- a/arch/arm/src/lpc54xx/lpc54_spi_master.c +++ b/arch/arm/src/lpc54xx/lpc54_spi_master.c @@ -33,6 +33,16 @@ * ****************************************************************************/ +/* TODO: + * + * - There are no interrupt driven transfers, only polled. I don't + * consider this a significant problem because of the higher rate that + * would be necessary for interrupt driven transfers. + * - Integrate DMA transfers. This is fairly important because it can + * a) improve the data transfer rates and b) free the CPU when the + * SPI driver would otherwise be stuck in a tight polling loop. + */ + /**************************************************************************** * Included Files ****************************************************************************/ @@ -59,6 +69,7 @@ #include "chip/lpc54_spi.h" #include "lpc54_config.h" #include "lpc54_enableclk.h" +#include "lpc54_gpio.h" #include "lpc54_spi_master.h" #ifdef HAVE_SPI_MASTER_DEVICE @@ -67,7 +78,15 @@ * Pre-processor Definitions ****************************************************************************/ -#define SPI_DUMMYDATA 0xff +#define SPI_DUMMYDATA8 0xff +#define SPI_DUMMYDATA16 0xffff + +#define SPI_MINWIDTH 4 +#ifdef CONFIG_LPC54_SPI_WIDEDATA +# define SPI_MAXWIDTH 16 +#else +# define SPI_MAXWIDTH 8 +#endif /**************************************************************************** * Private Types @@ -77,22 +96,110 @@ struct lpc54_spidev_s { - struct spi_dev_s dev; /* Externally visible part of the SPI interface */ - uintptr_t base; /* Base address of Flexcomm registers */ - sem_t exclsem; /* Held while chip is selected for mutual exclusion */ - uint32_t fclock; /* Flexcomm function clock frequency */ - uint32_t frequency; /* Requested clock frequency */ - uint32_t actual; /* Actual clock frequency */ - uint16_t irq; /* Flexcomm IRQ number */ - uint8_t nbits; /* Width of word in bits (8 to 16) */ - uint8_t mode; /* Mode 0,1,2,3 */ + struct spi_dev_s dev; /* Externally visible part of the SPI interface */ + uintptr_t base; /* Base address of Flexcomm registers */ + sem_t exclsem; /* Held while chip is selected for mutual exclusion */ + uint32_t fclock; /* Flexcomm function clock frequency */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + uint16_t irq; /* Flexcomm IRQ number */ + uint8_t nbits; /* Width of word in bits (SPI_MINWIDTH to SPI_MAXWIDTH) */ + uint8_t mode; /* Mode 0,1,2,3 */ +}; + +/* These structures describes the Rx side of an 8- or 16-bit SPI data + * exchange. + */ + +struct lpc54_rxtransfer8_s +{ + FAR uint8_t *rxptr; /* Pointer into receive buffer */ + unsigned int remaining; /* Bytes remaining in the receive buffer */ + unsigned int expected; /* Bytes expected to be received */ +}; + +#ifdef CONFIG_LPC54_SPI_WIDEDATA +struct lpc54_rxtransfer16_s +{ + FAR uint16_t *rxptr; /* Pointer into receive buffer */ + unsigned int remaining; /* Hwords remaining in the receive buffer */ + unsigned int expected; /* Hwords expected to be received */ +}; +#endif + +/* These structures describes the Tx side of an 8- or 16-bit SPI data + * exchange. + */ + +struct lpc54_txtransfer8_s +{ + uint32_t txctrl; /* Tx control bits */ + FAR const uint8_t *txptr; /* Pointer into transmit buffer */ + unsigned int remaining; /* Bytes remaining in the transmit buffer */ +}; + +#ifdef CONFIG_LPC54_SPI_WIDEDATA +struct lpc54_txtransfer16_s +{ + uint32_t txctrl; /* Tx control bits */ + FAR const uint16_t *txptr; /* Pointer into transmit buffer */ + unsigned int remaining; /* Hwords remaining in the transmit buffer */ +}; +#endif + +struct lpc54_txdummy_s +{ + uint32_t txctrl; /* Tx control bits */ + unsigned int remaining; /* Bytes remaining in the transmit buffer */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -static inline bool lpc54_spi_16bitmode(FAR struct lpc54_spidev_s *priv); +/* Transfer helpers */ + +static inline unsigned int lpc54_spi_fifodepth(FAR struct lpc54_spidev_s *priv); +static inline bool lpc54_spi_txavailable(FAR struct lpc54_spidev_s *priv); +static inline bool lpc54_spi_rxavailable(FAR struct lpc54_spidev_s *priv); + +static void lpc54_spi_resetfifos(FAR struct lpc54_spidev_s *priv); +static void lpc54_spi_rxtransfer8(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_rxtransfer8_s *xfr); +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_rxtransfer16(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_rxtransfer16_s *xfr); +#endif +static bool lpc54_spi_txtransfer8(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_txtransfer8_s *xfr); +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static bool lpc54_spi_txtransfer16(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_txtransfer16_s *xfr); +#endif +static bool lpc54_spi_txdummy(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_txdummy_s *xfr); +#ifdef CONFIG_SPI_EXCHANGE +static void lpc54_spi_exchange8(FAR struct lpc54_spidev_s *priv, + FAR const void *txbuffer, FAR void *rxbuffer, + size_t nwords); +#ifdefCONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_exchange16(FAR struct lpc54_spidev_s *priv, + FAR const void *txbuffer, FAR void *rxbuffer, + size_t nwords); +#endif +#endif +static void lpc54_spi_sndblock8(FAR struct lpc54_spidev_s *priv, + FAR const void *buffer, size_t nwords); +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_sndblock16(FAR struct lpc54_spidev_s *priv, + FAR const void *buffer, size_t nwords); +#endif +static void lpc54_spi_recvblock8(FAR struct lpc54_spidev_s *priv, + FAR void *buffer, size_t nwords); +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_recvblock16(FAR struct lpc54_spidev_s *priv, + FAR void *buffer, size_t nwords); +#endif /* SPI methods */ @@ -103,20 +210,15 @@ static void lpc54_spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits); static uint16_t lpc54_spi_send(FAR struct spi_dev_s *dev, uint16_t ch); -#ifdef CONFIG_LPC54_SPI_MASTER_DMA -static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev, - FAR const void *txbuffer, FAR void *rxbuffer, - size_t nwords) -#endif +#ifdef CONFIG_SPI_EXCHANGE static void lpc54_spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, FAR void *rxbuffer, size_t nwords); -#ifndef CONFIG_SPI_EXCHANGE +#endif static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords); static void lpc54_spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords); -#endif /**************************************************************************** * Private Data @@ -475,25 +577,667 @@ static inline uint32_t lpc54_spi_getreg(struct lpc54_spidev_s *priv, } /**************************************************************************** - * Name: lpc54_spi_16bitmode + * Name: lpc54_spi_fifodepth * * Description: - * Check if the SPI is operating in > 8-bit mode (16-bit accesses) + * Return the depth of the SPI FIFOs. This is a constant value and could + * be hard coded. * * Input Parameters: * priv - Device-specific state data * * Returned Value: - * true: 16-bit mode, false: 8-bit mode + * The FIFO depth in words of the configured bit width. * ****************************************************************************/ -static inline bool lpc54_spi_16bitmode(FAR struct lpc54_spidev_s *priv) +static inline unsigned int lpc54_spi_fifodepth(FAR struct lpc54_spidev_s *priv) { -#warning Missing logic + uint32_t regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET); + return ((regval & SPI_FIFOCFG_SIZE_MASK) >> SPI_FIFOCFG_SIZE_SHIFT) << 3; +} + +/**************************************************************************** + * Name: lpc54_spi_txavailable + * + * Description: + * Return true if the Tx FIFO is not full. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * true: Tx FIFO is not full. + * + ****************************************************************************/ + +static inline bool lpc54_spi_txavailable(FAR struct lpc54_spidev_s *priv) +{ + uint32_t regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOSTAT_OFFSET); + return ((regval & SPI_FIFOSTAT_TXNOTFULL) != 0); +} + +/**************************************************************************** + * Name: lpc54_spi_rxavailable + * + * Description: + * Return true if the Rx FIFO is not empty. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * true: Rx FIFO is not empty. + * + ****************************************************************************/ + +static inline bool lpc54_spi_rxavailable(FAR struct lpc54_spidev_s *priv) +{ + uint32_t regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOSTAT_OFFSET); + return ((regval & SPI_FIFOSTAT_RXNOTEMPTY) != 0); +} + +/**************************************************************************** + * Name: lpc54_spi_rxdiscard + * + * Description: + * Read and discard the data until the Rx FIFO is empty. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void lpc54_spi_rxdiscard(FAR struct lpc54_spidev_s *priv) +{ + while (lpc54_spi_rxavailable(priv)) + { + (void)lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET); + } +} + +/**************************************************************************** + * Name: lpc54_spi_resetfifos + * + * Description: + * Clear Tx/Rx errors and empty FIFOs. + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void lpc54_spi_resetfifos(FAR struct lpc54_spidev_s *priv) +{ + uint32_t regval; + + /* Clear Tx/Rx errors and empty FIFOs */ + + regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET); + regval |= (SPI_FIFOCFG_EMPTYTX | SPI_FIFOCFG_EMPTYRX); + lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval); + + regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOSTAT_OFFSET); + regval |= (SPI_FIFOSTAT_TXERR | SPI_FIFOSTAT_RXERR); + lpc54_spi_putreg(priv, LPC54_SPI_FIFOSTAT_OFFSET, regval); +} + +/**************************************************************************** + * Name: lpc54_spi_rxtransfer8 and lpc54_spi_rxtransfer16 + * + * Description: + * Receive one 8- or 16-bit value from the selected SPI device. + * + * Input Parameters: + * priv - Device-specific state data + * xfr - Describes the Rx transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void lpc54_spi_rxtransfer8(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_rxtransfer8_s *xfr) +{ + /* Read one byte if available and expected */ + + if (lpc54_spi_rxavailable(priv)) + { + /* There is something in the Rx FIFO to be read. Are we expecting + * data in the Rx FIFO? Is there space available in the Rx buffer? + */ + + if (xfr->expected == 0 || xfr->remaining == 0) + { + /* No.. then just read and discard the data until the Rx FIFO is empty */ + + lpc54_spi_rxdiscard(priv); + xfr->expected = 0; + } + else + { + /* Read and transfer one byte */ + + *xfr->rxptr = lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET); + + /* Update pointers and counts */ + + xfr->rxptr++; + xfr->remaining--; + xfr->expected--; + } + } +} + +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_rxtransfer16(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_rxtransfer16_s *xfr) +{ + /* Read one HWord if available and expected */ + + if (lpc54_spi_rxavailable(priv)) + { + /* There is something in the Rx FIFO to be read. Are we expecting + * data in the Rx FIFO? Is there space available in the Rx buffer? + */ + + if (xfr->expected == 0 || xfr->remaining == 0) + { + /* No.. then just read and discard the data until the Rx FIFO + * is empty. + */ + + lpc54_spi_rxdiscard(priv); + xfr->expected = 0; + } + else + { + /* Read and transfer HWord */ + + *xfr->rxptr = lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET); + + /* Update pointers and counts */ + + xfr->rxptr++; + xfr->remaining--; + xfr->expected--; + } + } +} +#endif + +/**************************************************************************** + * Name: lpc54_spi_txtransfer8 and lpc54_spi_txtransfer16 + * + * Description: + * Send one 8- or 16-bit value to the selected SPI device. + * + * Input Parameters: + * priv - Device-specific state data + * xfr - Describes the Tx transfer + * + * Returned Value: + * true: The value was added to the TxFIFO + * + ****************************************************************************/ + +static bool lpc54_spi_txtransfer8(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_txtransfer8_s *xfr) +{ + uint32_t regval; + + /* Transmit if txFIFO is not full and there is more Tx data to be sent */ + + if (lpc54_spi_txavailable(priv) && xfr->remaining > 0) + { + /* Get the next byte to be sent */ + + regval = *xfr->txptr; + + /* And send it */ + + regval |= xfr->txctrl; + lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, regval); + + /* Update pointers and counts */ + + xfr->txptr++; + xfr->remaining--; + + return true; + } + return false; } +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static bool lpc54_spi_txtransfer16(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_txtransfer16_s *xfr) +{ + uint32_t regval; + + /* Transmit if txFIFO is not full and there is more Tx data to be sent */ + + if (lpc54_spi_txavailable(priv) && xfr->remaining > 0) + { + /* Get the next byte to be sent */ + + regval = *xfr->txptr; + + /* And send it */ + + regval |= xfr->txctrl; + lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, regval); + + /* Update pointers and counts */ + + xfr->txptr++; + xfr->remaining--; + + return true; + } + + return false; +} +#endif + +/**************************************************************************** + * Name: lpc54_spi_txdummy + * + * Description: + * Send dummy Tx data when we really only care about the Rx data. + * + * Input Parameters: + * priv - Device-specific state data + * xfr - Describes the Tx transfer + * + * Returned Value: + * true: The dummy value was added to the TxFIFO + * + ****************************************************************************/ + +static bool lpc54_spi_txdummy(FAR struct lpc54_spidev_s *priv, + FAR struct lpc54_txdummy_s *xfr) +{ + /* Transmit if txFIFO is not full and there is more Tx data to be sent */ + + if (lpc54_spi_txavailable(priv) && xfr->remaining > 0) + { + /* Send the dummy data */ + + lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, xfr->txctrl); + + /* Update counts */ + + xfr->remaining--; + return true; + } + + return false; +} + +/**************************************************************************** + * Name: lpc54_spi_exchange8 and lpc54_spi_exchange16 + * + * Description: + * Implements the SPI exchange method for the case of 8- and 16-bit transfers. + * + * Input Parameters: + * priv - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to a buffer in which to receive data + * nwords - the length of data to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_EXCHANGE +static void lpc54_spi_exchange8(FAR struct lpc54_spidev_s *priv, + FAR const void *txbuffer, FAR void *rxbuffer, + size_t nwords) +{ + struct lpc54_rxtransfer8_s rxtransfer; + struct lpc54_txtransfer8_s txtransfer; + unsigned int depth; + + DEBUGASSERT(rxbuffer != NULL && txbuffer != NULL); + + /* Get the FIFO depth */ + + depth = lpc54_spi_fifodepth(priv); + + /* Set up the transfer data */ + + txtransfer.txctrl = SPI_FIFOWR_LEN(priv->nbits) | SPI_FIFOWR_TXSSELN_ALL; + txtransfer.txptr = (FAR uint8_t *)txbuffer; + txtransfer.remaining = nwords; + rxtransfer.rxptr = (FAR uint8_t *)rxbuffer; + rxtransfer.remaining = nwords; + rxtransfer.expected = 0; + + /* Clear Tx/Rx errors and empty FIFOs */ + + lpc54_spi_resetfifos(priv); + + /* Loop until all Tx data has been sent and until all Rx data has been + * received. + */ + + while (txtransfer.remaining != 0 || rxtransfer.remaining != 0) + { + /* Transfer one byte from the Rx FIFO to the caller's Rx buffer */ + + lpc54_spi_rxtransfer8(priv, &rxtransfer); + + /* If sending another byte would exceed the capacity of the Rx FIFO + * then read-only until there space freed. + */ + + if (rxtransfer.expected < depth) + { + /* Attempt to transfer one byte from the caller's Tx buffer to + * the Tx FIFO. + */ + + if (lpc54_spi_txtransfer8(priv, &txtransfer)) + { + /* Increment the Rx expected count if successful */ + + rxtransfer.expected++; + } + } + } +} +#endif /* CONFIG_SPI_EXCHANGE */ + +#if defined(CONFIG_SPI_EXCHANGE) && defined(CONFIG_LPC54_SPI_WIDEDATA) +static void lpc54_spi_exchange16(FAR struct lpc54_spidev_s *priv, + FAR const void *txbuffer, FAR void *rxbuffer, + size_t nwords) +{ + struct lpc54_rxtransfer16_s rxtransfer; + struct lpc54_txtransfer16_s txtransfer; + uint32_t regval; + unsigned int depth; + + DEBUGASSERT(rxbuffer != NULL && ((uintptr_t)rxbuffer & 1) == 0); + DEBUGASSERT(txbuffer != NULL && ((uintptr_t)txbuffer & 1) == 0); + + /* Get the FIFO depth */ + + depth = lpc54_spi_fifodepth(priv); + + /* Set up the transfer data */ + + txtransfer.txctrl = SPI_FIFOWR_LEN(priv->nbits) | SPI_FIFOWR_TXSSELN_ALL; + txtransfer.txptr = (FAR uint16_t *)txbuffer; + txtransfer.remaining = nwords; + rxtransfer.rxptr = (FAR uint16_t *)rxbuffer; + rxtransfer.remaining = nwords; + rxtransfer.expected = 0; + + /* Clear Tx/Rx errors and empty FIFOs */ + + lpc54_spi_resetfifos(priv); + + /* Loop until all Tx data has been sent and until all Rx data has been + * received. + */ + + while (txtransfer.remaining || rxtransfer.remaining || rxtransfer.expected) + { + /* Transfer one HWord from the Rx FIFO to the caller's Rx buffer */ + + lpc54_spi_rxtransfer16(priv, &rxtransfer); + + /* If sending another byte would exceed the capacity of the Rx FIFO + * then read-only until there space freed. + */ + + if (rxtransfer.expected < depth) + { + /* Attempt to send one more byte */ + + if (lpc54_spi_txtransfer16(priv, &txtransfer)) + { + /* Increment the Rx expected count if successful */ + + rxtransfer.expected++; + } + } + } +} +#endif /* CONFIG_SPI_EXCHANGE && CONFIG_LPC54_SPI_WIDEDATA */ + +/**************************************************************************** + * Name: lpc54_spi_sndblock8 and lpc54_spi_sndblock16 + * + * Description: + * Implements the SPI sndblock method for the case of 8- and 16-bit + * transfers. + * + * Input Parameters: + * priv - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void lpc54_spi_sndblock8(FAR struct lpc54_spidev_s *priv, + FAR const void *buffer, size_t nwords) +{ + struct lpc54_txtransfer8_s txtransfer; + + DEBUGASSERT(buffer != NULL); + + /* Set up the transfer data. NOTE that we are ignoring returned Rx data */ + + txtransfer.txctrl = SPI_FIFOWR_RXIGNORE | SPI_FIFOWR_LEN(priv->nbits) | + SPI_FIFOWR_TXSSELN_ALL; + txtransfer.txptr = (FAR uint8_t *)buffer; + txtransfer.remaining = nwords; + + /* Clear Tx/Rx errors and empty FIFOs */ + + lpc54_spi_resetfifos(priv); + + /* Loop until all Tx data has been sent */ + + while (txtransfer.remaining != 0) + { + /* Attempt to transfer one byte from the caller's Tx buffer to the + * Tx FIFO. + */ + + (void)lpc54_spi_txtransfer8(priv, &txtransfer); + } +} + +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_sndblock16(FAR struct lpc54_spidev_s *priv, + FAR const void *buffer, size_t nwords) +{ + struct lpc54_txtransfer16_s txtransfer; + + DEBUGASSERT(buffer != NULL); + + /* Set up the transfer data. NOTE that we are ignoring returned Rx data */ + + txtransfer.txctrl = SPI_FIFOWR_RXIGNORE | SPI_FIFOWR_LEN(priv->nbits) | + SPI_FIFOWR_TXSSELN_ALL; + txtransfer.txptr = (FAR uint16_t *)buffer; + txtransfer.remaining = nwords; + + /* Clear Tx/Rx errors and empty FIFOs */ + + lpc54_spi_resetfifos(priv); + + /* Loop until all Tx data has been sent and until all Rx data has been + * received. + */ + + while (txtransfer.remaining != 0) + { + /* Attempt to transfer one byte from the caller's Tx buffer to the + * Tx FIFO. + */ + + lpc54_spi_txtransfer16(priv, &txtransfer); + } +} +#endif /*CONFIG_LPC54_SPI_WIDEDATA */ + +/**************************************************************************** + * Name: lpc54_spi_recvblock8 and lpc54_spi_recvblock16 + * + * Description: + * Implements the SPI recvblock method for the case of 8- and 16-bit + * transfers. + * + * Input Parameters: + * priv - Device-specific state data + * buffer - A pointer to the buffer in which to receive data + * nwords - the length of data that can be received in the buffer in + * number of words. The wordsize is determined by the number of + * bits-per-word selected for the SPI interface. If nbits <= 8, + * the data is packed into uint8_t's; if nbits >8, the data is + * packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void lpc54_spi_recvblock8(FAR struct lpc54_spidev_s *priv, + FAR void *buffer, size_t nwords) +{ + struct lpc54_rxtransfer8_s rxtransfer; + struct lpc54_txdummy_s txtransfer; + unsigned int depth; + + DEBUGASSERT(buffer != NULL); + + /* Get the FIFO depth */ + + depth = lpc54_spi_fifodepth(priv); + + /* Set up the transfer data */ + + txtransfer.txctrl = SPI_DUMMYDATA8 | SPI_FIFOWR_LEN(priv->nbits) | + SPI_FIFOWR_TXSSELN_ALL; + txtransfer.remaining = nwords; + rxtransfer.rxptr = (FAR uint8_t *)buffer; + rxtransfer.remaining = nwords; + rxtransfer.expected = 0; + + /* Clear Tx/Rx errors and empty FIFOs */ + + lpc54_spi_resetfifos(priv); + + /* Loop until all Tx data has been sent and until all Rx data has been + * received. + */ + + while (txtransfer.remaining != 0|| rxtransfer.remaining != 0) + { + /* Transfer one byte from the Rx FIFO to the caller's Rx buffer */ + + lpc54_spi_rxtransfer8(priv, &rxtransfer); + + /* If sending another byte would exceed the capacity of the Rx FIFO + * then read-only until there space freed. + */ + + if (rxtransfer.expected < depth) + { + /* Attempt to transfer one dummy byte to the Tx FIFO. */ + + if (lpc54_spi_txdummy(priv, &txtransfer)) + { + /* Increment the Rx expected count if successful */ + + rxtransfer.expected++; + } + } + } +} + +#ifdef CONFIG_LPC54_SPI_WIDEDATA +static void lpc54_spi_recvblock16(FAR struct lpc54_spidev_s *priv, + FAR void *buffer, size_t nwords) +{ + struct lpc54_rxtransfer16_s rxtransfer; + struct lpc54_txdummy_s txtransfer; + unsigned int depth; + + DEBUGASSERT(buffer != NULL); + + /* Get the FIFO depth */ + + depth = lpc54_spi_fifodepth(priv); + + /* Set up the transfer data */ + + txtransfer.txctrl = SPI_DUMMYDATA16 | SPI_FIFOWR_LEN(priv->nbits) | + SPI_FIFOWR_TXSSELN_ALL; + txtransfer.remaining = nwords; + rxtransfer.rxptr = (FAR uint16_t *)rxbuffer; + rxtransfer.remaining = nwords; + rxtransfer.expected = 0; + + /* Clear Tx/Rx errors and empty FIFOs */ + + lpc54_spi_resetfifos(priv); + + /* Loop until all Tx data has been sent and until all Rx data has been + * received. + */ + + while (txtransfer.remaining || rxtransfer.remaining || rxtransfer.expected) + { + /* Transfer one HWord from the Rx FIFO to the caller's Rx buffer */ + + lpc54_spi_rxtransfer16(priv, &rxtransfer); + + /* If sending another byte would exceed the capacity of the Rx FIFO + * then read-only until there space freed. + */ + + if (rxtransfer.expected < depth) + { + /* Attempt to transfer one dummy HWord to the Tx FIFO. */ + + if (lpc54_spi_txdummy(priv, &txtransfer)) + { + /* Increment the Rx expected count if successful */ + + rxtransfer.expected++; + } + } + } +} +#endif /* CONFIG_LPC54_SPI_WIDEDATA */ + /**************************************************************************** * Name: lpc54_spi_lock * @@ -686,11 +1430,11 @@ static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits) { FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; - /* The valid range of bit selections is 4 through 16 */ + /* The valid range of bit selections is SPI_MINWIDTH through SPI_MAXWIDTH */ - DEBUGASSERT(priv != NULL && nbits >=4 && nbits <= 16); + DEBUGASSERT(priv != NULL && nbits >= SPI_MINWIDTH && nbits <= SPI_MAXWIDTH); - if (nbits >= 4 && nbits <= 16) + if (nbits >= SPI_MINWIDTH && nbits <= SPI_MAXWIDTH) { /* Save the selection. It will be applied when data is transferred. */ @@ -716,28 +1460,46 @@ static void lpc54_spi_setbits(FAR struct spi_dev_s *dev, int nbits) static uint16_t lpc54_spi_send(FAR struct spi_dev_s *dev, uint16_t wd) { - uint16_t ret; + FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; + uint32_t regval; - /* Write the data to transmitted to the SPI Data Register */ -#warning Missing logic + DEBUGASSERT(priv != NULL); - /* Read the SPI Status Register again to clear the status bit */ -#warning Missing logic + /* Clear Tx/Rx errors and empty FIFOs */ - return ret; + lpc54_spi_resetfifos(priv); + + /* Send the word. Since we just reset the FIFOs, we assume that the Tx + * FIFO is not full and that the Rx FIFO is empty. + */ + + DEBUGASSERT(lpc54_spi_txavailable(priv) || !lpc54_spi_rxavailable(priv)); + + regval = wd | SPI_FIFOWR_LEN(priv->nbits) | SPI_FIFOWR_TXSSELN_ALL; + lpc54_spi_putreg(priv, LPC54_SPI_FIFOWR_OFFSET, regval); + + /* Wait for the Rx FIFO to become non-empty. */ + + while (!lpc54_spi_rxavailable(priv)) + { + } + + /* Then read and return the value from the Rx FIFO */ + + return (uint16_t)lpc54_spi_getreg(priv, LPC54_SPI_FIFORD_OFFSET); } /**************************************************************************** - * Name: lpc54_spi_exchange (no DMA). aka lpc54_spi_exchange_nodma + * Name: lpc54_spi_exchange * * Description: - * Exchange a block of data on SPI without using DMA + * Exchange a block of data on SPI * * Input Parameters: * dev - Device-specific state data * txbuffer - A pointer to the buffer of data to be sent * rxbuffer - A pointer to a buffer in which to receive data - * nwords - the length of data to be exchaned in units of words. + * nwords - the length of data to be exchanged in units of words. * The wordsize is determined by the number of bits-per-word * selected for the SPI interface. If nbits <= 8, the data is * packed into uint8_t's; if nbits >8, the data is packed into @@ -748,125 +1510,52 @@ static uint16_t lpc54_spi_send(FAR struct spi_dev_s *dev, uint16_t wd) * ****************************************************************************/ -#ifndef CONFIG_LPC54_SPI_MASTER_DMA -static void lpc54_spi_exchange(FAR struct spi_dev_s *dev, +#ifdef CONFIG_SPI_EXCHANGE +static void lpc54_spi_exchange(FAR struct lpc54_spidev_s *priv, FAR const void *txbuffer, FAR void *rxbuffer, size_t nwords) -#else -static void lpc54_spi_exchange_nodma(FAR struct spi_dev_s *dev, - FAR const void *txbuffer, - FAR void *rxbuffer, size_t nwords) -#endif { FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; - DEBUGASSERT(priv && priv->base); - spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", - txbuffer, rxbuffer, nwords); + DEBUGASSERT(priv != NULL); - /* 8- or 16-bit mode? */ + /* If there is no data sink, then handle this transfer with + * lpc54_spi_sndblock(). + */ - if (lpc54_spi_16bitmode(priv)) + if (rxbuffer == NULL) { - /* 16-bit mode */ - - FAR const uint16_t *src = (FAR const uint16_t *)txbuffer; - FAR uint16_t *dest = (FAR uint16_t *)rxbuffer; - uint16_t word; - - while (nwords-- > 0) - { - /* Get the next word to write. Is there a source buffer? */ - - if (src) - { - word = *src++; - } - else - { - word = 0xffff; - } - - /* Exchange one word */ - - word = lpc54_spi_send(dev, word); - - /* Is there a buffer to receive the return value? */ - - if (dest) - { - *dest++ = word; - } - } + lpc54_spi_sndblock(priv, txbuffer, nwords) } - else + + /* If there is no data source, then handle this transfer with + * lpc54_spi_recvblock(). + */ + + else if (txbuffer == NULL) { - /* 8-bit mode */ + lpc54_spi_recvblock(priv, rxbuffer, nwords) + } - FAR const uint8_t *src = (FAR const uint8_t *)txbuffer; - FAR uint8_t *dest = (FAR uint8_t *)rxbuffer; - uint8_t word; +#ifdef CONFIG_LPC54_SPI_WIDEDATA + /* If the data with is > 8-bits, then handle this transfer with + * lpc54_spi_exchange16(). + */ - while (nwords-- > 0) - { - /* Get the next word to write. Is there a source buffer? */ + else if (priv->nbits > 8) + { + lpc54_spi_exchange16(priv, txbuffer, rxbuffer, nwords); + } +#endif - if (src) - { - word = *src++; - } - else - { - word = 0xff; - } + /* Otherwise, let lpc54_spi_exchange8() do the job */ - /* Exchange one word */ - - word = (uint8_t)lpc54_spi_send(dev, (uint16_t)word); - - /* Is there a buffer to receive the return value? */ - - if (dest) - { - *dest++ = word; - } - } + else if (priv->nbits > 8) + { + lpc54_spi_exchange8(priv, txbuffer, rxbuffer, nwords); } } - -/**************************************************************************** - * Name: lpc54_spi_exchange (no DMA). aka lpc54_spi_exchange_nodma - * - * Description: - * Exchange a block of data on SPI without using DMA - * - * Input Parameters: - * dev - Device-specific state data - * txbuffer - A pointer to the buffer of data to be sent - * rxbuffer - A pointer to a buffer in which to receive data - * nwords - the length of data to be exchaned in units of words. - * The wordsize is determined by the number of bits-per-word - * selected for the SPI interface. If nbits <= 8, the data is - * packed into uint8_t's; if nbits >8, the data is packed into - * uint16_t's - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef CONFIG_LPC54_SPI_MASTER_DMA -static void lpc54_spi_exchange(FAR struct spi_dev_s *dev, - FAR const void *txbuffer, FAR void *rxbuffer, - size_t nwords) -{ - /* If the transfer is small, then perform the exchange without using DMA. */ -#warning Missing logic - - /* Otherwise, use DMA */ -#warning Missing logic -} -#endif /* CONFIG_LPC54_SPI_MASTER_DMA */ +#endif /* CONFIG_SPI_EXCHANGE */ /**************************************************************************** * Name: lpc54_spi_sndblock @@ -891,8 +1580,28 @@ static void lpc54_spi_exchange(FAR struct spi_dev_s *dev, static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords) { - spiinfo("txbuffer=%p nwords=%d\n", buffer, nwords); - return lpc54_spi_exchange(dev, buffer, NULL, nwords); + FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; + + spiinfo("buffer=%p nwords=%d\n", buffer, nwords); + DEBUGASSERT(priv != NULL && buffer != NULL); + +#ifdef CONFIG_LPC54_SPI_WIDEDATA + /* If the data with is > 8-bits, then handle this transfer with + * lpc54_spi_sndblock16(). + */ + + if (priv->nbits > 8) + { + lpc54_spi_sndblock16(priv, buffer, nwords); + } + + /* Otherwise, let lpc54_spi_sndblock8() do the job */ + + else if (priv->nbits > 8) +#endif + { + lpc54_spi_sndblock8(priv, buffer, nwords); + } } /**************************************************************************** @@ -903,7 +1612,7 @@ static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev, * * Input Parameters: * dev - Device-specific state data - * buffer - A pointer to the buffer in which to recieve data + * buffer - A pointer to the buffer in which to receive data * nwords - the length of data that can be received in the buffer in * number of words. The wordsize is determined by the number of * bits-per-word selected for the SPI interface. If nbits <= 8, @@ -918,8 +1627,28 @@ static void lpc54_spi_sndblock(FAR struct spi_dev_s *dev, static void lpc54_spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords) { - spiinfo("rxbuffer=%p nwords=%d\n", buffer, nwords); - return lpc54_spi_exchange(dev, NULL, buffer, nwords); + FAR struct lpc54_spidev_s *priv = (FAR struct lpc54_spidev_s *)dev; + + spiinfo("buffer=%p nwords=%d\n", buffer, nwords); + DEBUGASSERT(priv != NULL && buffer != NULL); + +#ifdef CONFIG_LPC54_SPI_WIDEDATA + /* If the data with is > 8-bits, then handle this transfer with + * lpc54_spi_recvblock16(). + */ + + if (priv->nbits > 8) + { + lpc54_spi_recvblock16(priv, buffer, nwords); + } + + /* Otherwise, let lpc54_spi_recvblock8() do the job */ + + else if (priv->nbits > 8) +#endif + { + lpc54_spi_recvblock8(priv, buffer, nwords); + } } /**************************************************************************** @@ -952,7 +1681,7 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) flags = enter_critical_section(); - /* Configure the requestin SPI peripheral */ + /* Configure the requested SPI peripheral */ /* NOTE: The basic FLEXCOMM initialization was performed in * lpc54_lowputc.c. */ @@ -1332,23 +2061,23 @@ FAR struct spi_dev_s *lpc54_spibus_initialize(int port) /* Enable FIFOs */ - regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET); regval |= (SPI_FIFOCFG_EMPTYTX | SPI_FIFOCFG_EMPTYRX); - lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval); regval |= (SPI_FIFOCFG_ENABLETX | SPI_FIFOCFG_ENABLERX); - lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval); /* Set FIFO trigger levels: Empty for Tx FIFO; 1 word for RxFIFO */ - regval = lpc54_spi_getreg(priv, LPC54_SPI_CFG_OFFSET); + regval = lpc54_spi_getreg(priv, LPC54_SPI_FIFOCFG_OFFSET); regval &= ~(SPI_FIFOTRIG_TXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK); regval |= (SPI_FIFOTRIG_TXLVL_EMPTY | SPI_FIFOTRIG_RXLVL_NOTEMPTY); /* Enable generation of interrupts for selected FIFO trigger levels */ regval |= (SPI_FIFOTRIG_TXLVLENA | SPI_FIFOTRIG_RXLVLENA); - lpc54_spi_putreg(priv, LPC54_SPI_CFG_OFFSET, regval); + lpc54_spi_putreg(priv, LPC54_SPI_FIFOCFG_OFFSET, regval); /* Set the delay configuration (not used) */ diff --git a/arch/arm/src/lpc54xx/lpc54_spi_master.h b/arch/arm/src/lpc54xx/lpc54_spi_master.h index 12009872a77..aba9a30e72d 100644 --- a/arch/arm/src/lpc54xx/lpc54_spi_master.h +++ b/arch/arm/src/lpc54xx/lpc54_spi_master.h @@ -263,7 +263,7 @@ int lpc54_spi8_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, v #ifdef CONFIG_LPC54_SPI9_MASTER int lpc54_spi9_register(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg); #endif -#endif +#endif /* CONFIG_SPI_CALLBACK */ #undef EXTERN #if defined(__cplusplus) diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt index 31a65ff18e3..926fc1bd9d9 100644 --- a/configs/lpcxpresso-lpc54628/README.txt +++ b/configs/lpcxpresso-lpc54628/README.txt @@ -86,20 +86,13 @@ STATUS of this writing. Also added the netnsh configuration will, eventually, be used to test the Ethernet driver. 2018-01-01: There Ethernet driver appears to be fully functional although - more testing is certainly needed. I believe that there is a memory - corruption issue in the current configuration that cause problems - occasionally. For example, after a longer Telnet session, I sometimes - see the following DEBUGASSERT after exiting the session from the host: + 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). - up_assert: Assertion failed at file:mm_heap/mm_free.c line: 129 - - which is a clear indication heap corruption. Increasing the size of some - stacks might correct this problem, but I have not yet experimented with - that. I have not seen the problem in any other context. - - There is still no support for the Accelerometer, SPIFI, or USB. There is a - complete but not-yet-functional SD card. There is a partial SPI driver, - but no on-board SPI devices to test it. + 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. Configurations ============== diff --git a/include/nuttx/spi/spi.h b/include/nuttx/spi/spi.h index 08b28e26255..b881e962571 100644 --- a/include/nuttx/spi/spi.h +++ b/include/nuttx/spi/spi.h @@ -70,8 +70,8 @@ * Name: SPI_LOCK * * Description: - * On SPI busses where there are multiple devices, it will be necessary to - * lock SPI to have exclusive access to the busses for a sequence of + * On SPI buses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the buses for a sequence of * transfers. The bus should be locked before the chip is selected. After * locking the SPI bus, the caller should then also call the setfrequency, * setbits, and setmode methods to make sure that the SPI is properly From fd5d811b0a4a6c3aae8a00ea246b37bc7e171b4e Mon Sep 17 00:00:00 2001 From: Mateusz Szafoni Date: Sun, 14 Jan 2018 19:00:18 +0000 Subject: [PATCH 08/16] Merged in raiden00/nuttx (pull request #569) Master * stm32f33xxx_hrtim.h: fix some definitions * stm32_hrtim: fix some bugs stm32_hrtim: fix deadtime configuration stm32_hrtim: add interface to change outputs SET/RST configuration Approved-by: Gregory Nutt --- arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h | 4 +- arch/arm/src/stm32/stm32_hrtim.c | 381 ++++++++++++++++++-- arch/arm/src/stm32/stm32_hrtim.h | 38 +- 3 files changed, 369 insertions(+), 54 deletions(-) diff --git a/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h b/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h index 0e962104f91..32dff07659b 100644 --- a/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h +++ b/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h @@ -447,8 +447,8 @@ # define HRTIM_TIMDT_DTPRSC_110 (6 << HRTIM_TIMDT_DTPRSC_SHIFT) # define HRTIM_TIMDT_DTPRSC_111 (7 << HRTIM_TIMDT_DTPRSC_SHIFT) #define HRTIM_TIMDT_DTRSLK (1 << 14) /* Bit 14: Deadtime Rising Sign Lock */ -#define HRTIM_TIMDT_DTRLK (1 << 14) /* Bit 15: Deadtime Rising Lock */ -#define HRTIM_TIMDT_DTF_SHIFT 0 /* Bits 16-24: Deadtime Falling Value */ +#define HRTIM_TIMDT_DTRLK (1 << 15) /* Bit 15: Deadtime Rising Lock */ +#define HRTIM_TIMDT_DTF_SHIFT 16 /* Bits 16-24: Deadtime Falling Value */ #define HRTIM_TIMDT_DTF_MASK (0x1ff << HRTIM_TIMDT_DTF_SHIFT) #define HRTIM_TIMDT_SDTF (1 << 25) /* Bit 25: Sign Deadtime Falling Value */ #define HRTIM_TIMDT_DTFSLK (1 << 30) /* Bit 30: Deadtime Falling Sign Lock */ diff --git a/arch/arm/src/stm32/stm32_hrtim.c b/arch/arm/src/stm32/stm32_hrtim.c index d064c8e1d3b..44f78bff6f6 100644 --- a/arch/arm/src/stm32/stm32_hrtim.c +++ b/arch/arm/src/stm32/stm32_hrtim.c @@ -317,10 +317,11 @@ struct stm32_hrtim_chopper_s #ifdef CONFIG_STM32_HRTIM_DEADTIME struct stm32_hrtim_deadtime_s { + uint8_t en:1; /* Enable deadtime for timer */ uint8_t fsign_lock:1; /* Deadtime falling sing lock */ uint8_t rsign_lock:1; /* Deadtime rising sing lock */ - uint8_t rising_lock:1; /* Deadtime rising value lock */ uint8_t falling_lock:1; /* Deadtime falling value lock */ + uint8_t rising_lock:1; /* Deadtime rising value lock */ uint8_t fsign:1; /* Deadtime falling sign */ uint8_t rsign:1; /* Deadtime rising sign */ uint8_t prescaler:3; /* Deadtime prescaler */ @@ -645,6 +646,10 @@ static int hrtim_synch_config(FAR struct stm32_hrtim_s *priv); static int hrtim_outputs_config(FAR struct stm32_hrtim_s *priv); static int hrtim_outputs_enable(FAR struct hrtim_dev_s *dev, uint16_t outputs, bool state); +static int hrtim_output_set_set(FAR struct hrtim_dev_s *dev, uint16_t output, + uint32_t set); +static int hrtim_output_rst_set(FAR struct hrtim_dev_s *dev, uint16_t output, + uint32_t rst); #endif #ifdef HRTIM_HAVE_ADC static int hrtim_adc_config(FAR struct stm32_hrtim_s *priv); @@ -658,13 +663,14 @@ static int hrtim_tim_dma_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer, uint16_t dma); #endif #ifdef CONFIG_STM32_HRTIM_DEADTIME -static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t dt, - uint16_t value) -static uint16_t hrtim_deadtime_get(FAR struct stm32_dev_s *dev, uint8_t dt); +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 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 #ifdef CONFIG_STM32_HRTIM_CHOPPER -static int hrtim_chopper_enable(FAR struct stm32_dev_s *dev, uint8_t timer, +static int hrtim_chopper_enable(FAR struct hrtim_dev_s *dev, uint8_t timer, uint8_t chan, bool state); static int hrtim_tim_chopper_cfg(FAR struct stm32_hrtim_s *priv, uint8_t timer); static int hrtim_chopper_config(FAR struct stm32_hrtim_s *priv); @@ -816,13 +822,14 @@ static struct stm32_hrtim_slave_priv_s g_tima_priv = #ifdef CONFIG_STM32_HRTIM_TIMA_DT .dt = { - .fsign_lock = HRTIM_TIMA_DT_RSLOCK, + .en = 1, + .fsign_lock = HRTIM_TIMA_DT_FSLOCK, .rsign_lock = HRTIM_TIMA_DT_RSLOCK, - .rising_lock = HRTIM_TIMA_DT_RVLOCK, .falling_lock = HRTIM_TIMA_DT_FVLOCK, + .rising_lock = HRTIM_TIMA_DT_RVLOCK, .fsign = HRTIM_TIMA_DT_FSIGN, .rsign = HRTIM_TIMA_DT_RSIGN, - .prescaler = HRTIM_TIMA_DT_PRESALER + .prescaler = HRTIM_TIMA_DT_PRESCALER } #endif }, @@ -911,13 +918,14 @@ static struct stm32_hrtim_slave_priv_s g_timb_priv = #ifdef CONFIG_STM32_HRTIM_TIMB_DT .dt = { - .fsign_lock = HRTIM_TIMB_DT_RSLOCK, + .en = 1, + .fsign_lock = HRTIM_TIMB_DT_FSLOCK, .rsign_lock = HRTIM_TIMB_DT_RSLOCK, - .rising_lock = HRTIM_TIMB_DT_RVLOCK, .falling_lock = HRTIM_TIMB_DT_FVLOCK, + .rising_lock = HRTIM_TIMB_DT_RVLOCK, .fsign = HRTIM_TIMB_DT_FSIGN, .rsign = HRTIM_TIMB_DT_RSIGN, - .prescaler = HRTIM_TIMB_DT_PRESALER + .prescaler = HRTIM_TIMB_DT_PRESCALER } #endif }, @@ -1006,13 +1014,14 @@ static struct stm32_hrtim_slave_priv_s g_timc_priv = #ifdef CONFIG_STM32_HRTIM_TIMC_DT .dt = { - .fsign_lock = HRTIM_TIMC_DT_RSLOCK, + .en = 1, + .fsign_lock = HRTIM_TIMC_DT_FSLOCK, .rsign_lock = HRTIM_TIMC_DT_RSLOCK, - .rising_lock = HRTIM_TIMC_DT_RVLOCK, .falling_lock = HRTIM_TIMC_DT_FVLOCK, + .rising_lock = HRTIM_TIMC_DT_RVLOCK, .fsign = HRTIM_TIMC_DT_FSIGN, .rsign = HRTIM_TIMC_DT_RSIGN, - .prescaler = HRTIM_TIMC_DT_PRESALER + .prescaler = HRTIM_TIMC_DT_PRESCALER } #endif }, @@ -1101,13 +1110,14 @@ static struct stm32_hrtim_slave_priv_s g_timd_priv = #ifdef CONFIG_STM32_HRTIM_TIMD_DT .dt = { - .fsign_lock = HRTIM_TIMD_DT_RSLOCK, + .en = 1, + .fsign_lock = HRTIM_TIMD_DT_FSLOCK, .rsign_lock = HRTIM_TIMD_DT_RSLOCK, - .rising_lock = HRTIM_TIMD_DT_RVLOCK, .falling_lock = HRTIM_TIMD_DT_FVLOCK, + .rising_lock = HRTIM_TIMD_DT_RVLOCK, .fsign = HRTIM_TIMD_DT_FSIGN, .rsign = HRTIM_TIMD_DT_RSIGN, - .prescaler = HRTIM_TIMD_DT_PRESALER + .prescaler = HRTIM_TIMD_DT_PRESCALER } #endif }, @@ -1196,13 +1206,14 @@ static struct stm32_hrtim_slave_priv_s g_time_priv = #ifdef CONFIG_STM32_HRTIM_TIME_DT .dt = { - .fsign_lock = HRTIM_TIME_DT_RSLOCK, + .en = 1, + .fsign_lock = HRTIM_TIME_DT_FSLOCK, .rsign_lock = HRTIM_TIME_DT_RSLOCK, - .rising_lock = HRTIM_TIME_DT_RVLOCK, .falling_lock = HRTIM_TIME_DT_FVLOCK, + .rising_lock = HRTIM_TIME_DT_RVLOCK, .fsign = HRTIM_TIME_DT_FSIGN, .rsign = HRTIM_TIME_DT_RSIGN, - .prescaler = HRTIM_TIME_DT_PRESALER + .prescaler = HRTIM_TIME_DT_PRESCALER } #endif }, @@ -1482,6 +1493,8 @@ static const struct stm32_hrtim_ops_s g_hrtim1ops = #endif #ifdef CONFIG_STM32_HRTIM_PWM .outputs_enable = hrtim_outputs_enable, + .output_rst_set = hrtim_output_rst_set, + .output_set_set = hrtim_output_set_set, #endif #ifdef CONFIG_STM32_HRTIM_BURST .burst_enable = hrtim_burst_enable, @@ -2151,6 +2164,10 @@ static int hrtim_tim_clock_config(FAR struct stm32_hrtim_s *priv, } } + /* Write prescaler configuration */ + + hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_CR_OFFSET, regval); + errout: return ret; } @@ -2637,9 +2654,8 @@ static int hrtim_tim_outputs_config(FAR struct stm32_hrtim_s *priv, uint8_t time { FAR struct stm32_hrtim_tim_s* tim; FAR struct stm32_hrtim_slave_priv_s* slave; - - int ret = OK; uint32_t regval = 0; + int ret = OK; /* Master Timer has no outputs */ @@ -2724,6 +2740,24 @@ static int hrtim_tim_outputs_config(FAR struct stm32_hrtim_s *priv, uint8_t time } #endif +#ifdef CONFIG_STM32_HRTIM_DEADTIME + if (slave->pwm.dt.en == 1) + { + regval = 0; + + /* Set deadtime enable */ + + regval |= HRTIM_TIMOUT_DTEN; + + /* TODO: deadtime upon burst mode Idle entry */ + + /* Write register */ + + hrtim_tim_modifyreg(priv, timer, STM32_HRTIM_TIM_OUTR_OFFSET, 0, + regval); + } +#endif + errout: return ret; } @@ -2841,6 +2875,243 @@ static int hrtim_outputs_enable(FAR struct hrtim_dev_s *dev, return OK; } + +/**************************************************************************** + * Name: output_tim_index_get + ****************************************************************************/ + +static uint8_t output_tim_index_get(uint16_t output) +{ + uint8_t timer = 0; + + switch(output) + { +#ifdef CONFIG_STM32_HRTIM_TIMA + case HRTIM_OUT_TIMA_CH1: + case HRTIM_OUT_TIMA_CH2: + { + timer = HRTIM_TIMER_TIMA; + break; + } +#endif + +#ifdef CONFIG_STM32_HRTIM_TIMB + case HRTIM_OUT_TIMB_CH1: + case HRTIM_OUT_TIMB_CH2: + { + timer = HRTIM_TIMER_TIMB; + break; + } +#endif + +#ifdef CONFIG_STM32_HRTIM_TIMC + case HRTIM_OUT_TIMC_CH1: + case HRTIM_OUT_TIMC_CH2: + { + timer = HRTIM_TIMER_TIMC; + break; + } +#endif + +#ifdef CONFIG_STM32_HRTIM_TIMD + case HRTIM_OUT_TIMD_CH1: + case HRTIM_OUT_TIMD_CH2: + { + timer = HRTIM_TIMER_TIMD; + break; + } +#endif + +#ifdef CONFIG_STM32_HRTIM_TIME + case HRTIM_OUT_TIME_CH1: + case HRTIM_OUT_TIME_CH2: + { + timer = HRTIM_TIMER_TIME; + break; + } +#endif + + default: + { + timer = 0; + break; + } + } + + return timer; +} + +/**************************************************************************** + * Name: output_tim_ch_get + ****************************************************************************/ + +static uint8_t output_tim_ch_get(uint16_t output) +{ + uint8_t ch = 0; + + switch (output) + { +#ifdef CONFIG_STM32_HRTIM_TIMA + case HRTIM_OUT_TIMA_CH1: +#endif +#ifdef CONFIG_STM32_HRTIM_TIMB + case HRTIM_OUT_TIMB_CH1: +#endif +#ifdef CONFIG_STM32_HRTIM_TIMC + case HRTIM_OUT_TIMC_CH1: +#endif +#ifdef CONFIG_STM32_HRTIM_TIMD + case HRTIM_OUT_TIMD_CH1: +#endif +#ifdef CONFIG_STM32_HRTIM_TIME + case HRTIM_OUT_TIME_CH1: +#endif + { + ch = HRTIM_OUT_CH1; + break; + } + +#ifdef CONFIG_STM32_HRTIM_TIMA + case HRTIM_OUT_TIMA_CH2: +#endif +#ifdef CONFIG_STM32_HRTIM_TIMB + case HRTIM_OUT_TIMB_CH2: +#endif +#ifdef CONFIG_STM32_HRTIM_TIMC + case HRTIM_OUT_TIMC_CH2: +#endif +#ifdef CONFIG_STM32_HRTIM_TIMD + case HRTIM_OUT_TIMD_CH2: +#endif +#ifdef CONFIG_STM32_HRTIM_TIME + case HRTIM_OUT_TIME_CH2: +#endif + { + ch = HRTIM_OUT_CH2; + break; + } + + default: + { + ch = 0; + break; + } + } + + return ch; +} + +/**************************************************************************** + * Name: hrtim_output_set_set + ****************************************************************************/ + +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; + + /* Get timer index from output */ + + timer = output_tim_index_get(output); + + /* 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; + + /* Set new SET value */ + + switch (output_tim_ch_get(output)) + { + case HRTIM_OUT_CH1: + { + slave->pwm.ch1.set = set; + hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_SET1R_OFFSET, set); + break; + } + + case HRTIM_OUT_CH2: + { + slave->pwm.ch2.set = set; + hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_SET2R_OFFSET, set); + break; + } + + default: + { + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: hrtim_output_rst_set + ****************************************************************************/ +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; + + /* Get timer index from output */ + + timer = output_tim_index_get(output); + + /* 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; + + /* Set new RST value */ + + switch (output_tim_ch_get(output)) + { + case HRTIM_OUT_CH1: + { + slave->pwm.ch1.rst = rst; + hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_RST1R_OFFSET, rst); + } + + case HRTIM_OUT_CH2: + { + slave->pwm.ch2.rst = rst; + hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_RST2R_OFFSET, rst); + } + + default: + { + ret = -EINVAL; + goto errout; + } + } + +errout: + return ret; +} + #endif /**************************************************************************** @@ -3069,7 +3340,7 @@ static int hrtim_dma_cfg(FAR struct stm32_hrtim_s *priv) * Name: hrtim_deadtime_update ****************************************************************************/ -static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t timer, +static int hrtim_deadtime_update(FAR struct hrtim_dev_s *dev, uint8_t timer, uint8_t dt, uint16_t value) { FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; @@ -3078,17 +3349,18 @@ static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t timer, uint32_t shift = 0; uint32_t mask = 0; - /* Sanity check */ + /* For safety reasons we saturate deadtime value if it exceeds + * the acceptable range. + */ if (value > 0x1FF) { - ret = -EINVAL; - goto errout; + value = 0x1FF; } /* Get shift value */ - switch (index) + switch (dt) { case HRTIM_DT_EDGE_RISING: { @@ -3115,7 +3387,7 @@ static int hrtim_deadtime_update(FAR struct stm32_dev_s *dev, uint8_t timer, /* Update register */ - hrtim_tim_modify(priv, timer, STM32_HRTIM_TIM_DTR_OFFSET, mask, regval); + hrtim_tim_modifyreg(priv, timer, STM32_HRTIM_TIM_DTR_OFFSET, mask, regval); errout: return ret; @@ -3125,7 +3397,7 @@ errout: * Name: hrtim_deadtime_get ****************************************************************************/ -static uint16_t hrtim_deadtime_get(FAR struct stm32_dev_s *dev, uint8_t dt) +static uint16_t hrtim_deadtime_get(FAR struct hrtim_dev_s *dev, uint8_t dt) { #warning missing logic } @@ -3134,20 +3406,36 @@ static uint16_t hrtim_deadtime_get(FAR struct stm32_dev_s *dev, uint8_t dt) * Name: hrtim_tim_deadtime_cfg ****************************************************************************/ -static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t index) +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 */ + if (timer == HRTIM_TIMER_MASTER) { 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 deadtime prescaler */ + + regval |= slave->pwm.dt.prescaler << HRTIM_TIMDT_DTPRSC_SHIFT; + /* Configure rising deadtime */ regval |= slave->pwm.dt.rising << HRTIM_TIMDT_DTR_SHIFT; @@ -3158,14 +3446,14 @@ static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t index) /* Configure falling deadtime sign */ - if (slave->pwm.dt.fsign == HRTIM_DT_SIGN_POSITIVE) + if (slave->pwm.dt.fsign == HRTIM_DT_SIGN_NEGATIVE) { regval |= HRTIM_TIMDT_SDTF; } /* Configure risign deadtime sign */ - if (slave->pwm.dt.rsign == HRTIM_DT_SIGN_POSITIVE) + if (slave->pwm.dt.rsign == HRTIM_DT_SIGN_NEGATIVE) { regval |= HRTIM_TIMDT_SDTR; } @@ -3198,6 +3486,12 @@ static int hrtim_tim_deadtime_cfg(FAR struct stm32_hrtim_s *priv, uint8_t index) regval |= HRTIM_TIMDT_DTFLK; } + /* TODO: configure default deadtime values */ + + /* Write register */ + + hrtim_tim_putreg(priv, timer, STM32_HRTIM_TIM_DTR_OFFSET, regval); + errout: return ret; } @@ -3210,31 +3504,31 @@ static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv) { /* Configure Timer A deadtime */ -#ifdef CONFIG_STM32_HRTIM_TIMA +#ifdef CONFIG_STM32_HRTIM_TIMA_DT hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMA); #endif /* Configure Timer B deadtime */ -#ifdef CONFIG_STM32_HRTIM_TIMB +#ifdef CONFIG_STM32_HRTIM_TIMB_DT hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMB); #endif /* Configure Timer C deadtime */ -#ifdef CONFIG_STM32_HRTIM_TIMC +#ifdef CONFIG_STM32_HRTIM_TIMC_DT hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMC); #endif /* Configure Timer D deadtime */ -#ifdef CONFIG_STM32_HRTIM_TIMD +#ifdef CONFIG_STM32_HRTIM_TIMD_DT hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIMD); #endif /* Configure Timer E deadtime */ -#ifdef CONFIG_STM32_HRTIM_TIME +#ifdef CONFIG_STM32_HRTIM_TIME_DT hrtim_tim_deadtime_cfg(priv, HRTIM_TIMER_TIME); #endif @@ -3260,7 +3554,7 @@ static int hrtim_deadtime_config(FAR struct stm32_hrtim_s *priv) * ****************************************************************************/ -static int hrtim_chopper_enable(FAR struct stm32_dev_s *dev, uint8_t timer, +static int hrtim_chopper_enable(FAR struct hrtim_dev_s *dev, uint8_t timer, uint8_t chan, bool state) { FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; @@ -4595,6 +4889,17 @@ static int stm32_hrtimconfig(FAR struct stm32_hrtim_s *priv) } #endif + /* Configure HRTIM outputs deadtime */ + +#if defined(CONFIG_STM32_HRTIM_DEADTIME) + ret = hrtim_deadtime_config(priv); + if (ret != OK) + { + tmrerr("ERROR: HRTIM deadtime configuration failed!\n"); + goto errout; + } +#endif + /* Configure HRTIM outputs GPIOs */ #if defined(CONFIG_STM32_HRTIM_PWM) diff --git a/arch/arm/src/stm32/stm32_hrtim.h b/arch/arm/src/stm32/stm32_hrtim.h index 1085951fb90..40ffe37b8dc 100644 --- a/arch/arm/src/stm32/stm32_hrtim.h +++ b/arch/arm/src/stm32/stm32_hrtim.h @@ -208,10 +208,12 @@ (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_OUTPUTS_ENABLE(hrtim, tim, state) \ - (hrtim)->hd_ops->outputs_enable(hrtim, tim, state) -#define HRTIM_OUTPUTS_ENABLE(hrtim, tim, state) \ - (hrtim)->hd_ops->outputs_enable(hrtim, tim, state) +#define HRTIM_OUTPUTS_ENABLE(hrtim, outputs, state) \ + (hrtim)->hd_ops->outputs_enable(hrtim, outputs, state) +#define HRTIM_OUTPUT_SET_SET(hrtim, output, set) \ + (hrtim)->hd_ops->output_set_set(hrtim, output, set) +#define HRTIM_OUTPUT_RST_SET(hrtim, output, rst) \ + (hrtim)->hd_ops->output_rst_set(hrtim, output, rst) #define HRTIM_BURST_CMP_SET(hrtim, cmp) \ (hrtim)->hd_ops->burst_cmp_set(hrtim, cmp) #define HRTIM_BURST_PER_SET(hrtim, per) \ @@ -220,6 +222,8 @@ (hrtim)->hd_ops->burst_pre_set(hrtim, pre) #define HRTIM_BURST_ENABLE(hrtim, state) \ (hrtim)->hd_ops->burst_enable(hrtim, state) +#define HRTIM_DEADTIME_UPDATE(hrtim, tim, dt, val) \ + (hrtim)->hd_ops->deadtime_update(hrtim, tim, dt, val) /************************************************************************************ * Public Types @@ -229,23 +233,23 @@ enum stm32_hrtim_tim_e { - HRTIM_TIMER_MASTER = 0, + HRTIM_TIMER_MASTER = (1<<0), #ifdef CONFIG_STM32_HRTIM_TIMA - HRTIM_TIMER_TIMA = 1, + HRTIM_TIMER_TIMA = (1<<1), #endif #ifdef CONFIG_STM32_HRTIM_TIMB - HRTIM_TIMER_TIMB = 2, + HRTIM_TIMER_TIMB = (1<<2), #endif #ifdef CONFIG_STM32_HRTIM_TIMC - HRTIM_TIMER_TIMC = 3, + HRTIM_TIMER_TIMC = (1<<3), #endif #ifdef CONFIG_STM32_HRTIM_TIMD - HRTIM_TIMER_TIMD = 4, + HRTIM_TIMER_TIMD = (1<<4), #endif #ifdef CONFIG_STM32_HRTIM_TIME - HRTIM_TIMER_TIME = 5, + HRTIM_TIMER_TIME = (1<<5), #endif - HRTIM_TIMER_COMMON = 6 + HRTIM_TIMER_COMMON = (1<<6) }; /* Source which can force the Tx1/Tx2 output to its inactive state */ @@ -571,7 +575,7 @@ enum stm32_outputs_e enum stm32_hrtim_deadtime_sign_e { HRTIM_DT_SIGN_POSITIVE = 0, - HRTIM_DT_DIGN_NEGATIVE = 1 + HRTIM_DT_SIGN_NEGATIVE = 1 }; /* HRTIM Deadtime types */ @@ -973,6 +977,10 @@ struct stm32_hrtim_ops_s #ifdef CONFIG_STM32_HRTIM_PWM int (*outputs_enable)(FAR struct hrtim_dev_s *dev, uint16_t outputs, bool state); + int (*output_set_set)(FAR struct hrtim_dev_s *dev, uint16_t output, + uint32_t set); + int (*output_rst_set)(FAR struct hrtim_dev_s *dev, uint16_t output, + uint32_t rst); #endif #ifdef CONFIG_STM32_HRTIM_BURST int (*burst_enable)(FAR struct hrtim_dev_s *dev, bool state); @@ -988,8 +996,10 @@ struct stm32_hrtim_ops_s uint8_t chan, bool state); #endif #ifdef CONFIG_STM32_HRTIM_DEADTIME - int (*deadtime_update)(FAR struct hrtim_dev_s *dev, uint8_t dt, uint16_t value); - uint16_t (*deadtime_get)(FAR struct hrtim_dev_s *dev, uint8_t dt); + int (*deadtime_update)(FAR struct hrtim_dev_s *dev, uint8_t timer, + uint8_t dt, uint16_t value); + uint16_t (*deadtime_get)(FAR struct hrtim_dev_s *dev, uint8_t timer, + uint8_t dt); #endif #ifdef CONFIG_STM32_HRTIM_CAPTURE uint16_t (*capture_get)(FAR struct hrtim_dev_s *dev, uint8_t timer, From 57b6dec74da8dcfd35f1500b259b8f6bdf0945d4 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso Date: Sun, 14 Jan 2018 17:09:23 -0600 Subject: [PATCH 09/16] If we want to open read-only in losetup.c, flags should be O_RDONLY not O_RDWR --- drivers/loop/losetup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/loop/losetup.c b/drivers/loop/losetup.c index 32c2f4d4374..0690776e230 100644 --- a/drivers/loop/losetup.c +++ b/drivers/loop/losetup.c @@ -440,7 +440,7 @@ int losetup(FAR const char *devname, FAR const char *filename, { /* If that fails, then try to open the device read-only */ - fd = open(filename, O_RDWR); + fd = open(filename, O_RDONLY); if (fd < 0) { ret = -get_errno(); From 0ecef4dbcbcfacc96a1a0a8e7b5244be31d17491 Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Mon, 15 Jan 2018 13:04:32 +0900 Subject: [PATCH 10/16] clock_systimer: Replace critical section APIs with spinlock APIs. (64bit only) If SMP=n or SMP=y && SPINLOCK_IRQ=n, this works in the same way as before. If SMP=y && SPINLOCK_IRQ=y, performance will be improved. Signed-off-by: Masayuki Ishikawa --- sched/clock/clock_systimer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sched/clock/clock_systimer.c b/sched/clock/clock_systimer.c index 1b134510922..288bcf66e7c 100644 --- a/sched/clock/clock_systimer.c +++ b/sched/clock/clock_systimer.c @@ -120,9 +120,9 @@ systime_t clock_systimer(void) /* 64-bit accesses are not atomic on most architectures. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(); sample = g_system_timer; - leave_critical_section(flags); + spin_unlock_irqrestore(flags); return sample; # else /* CONFIG_SYSTEM_TIME64 */ From e238c8b0904988b966c3b33e7df2ba3faba52e2b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 15 Jan 2018 11:05:45 -0600 Subject: [PATCH 11/16] sched/clock/clock_systimer.c: Change the way that the 64-bit time is sampled. Previously, we disabled interrupts before sampling the 64-bit timer since the uint64_t access is not atomic on most CPUs. However, disabling (local) interrupts does not work in the SMP case. In that case, the timer interrupt will be running on only one of the CPUs; disabling interrupts on a different CPU will provide no protection from timer rollover. To work around this, logic was added that samples 64-bit timer is sampled twice and if 32-bit rollover was detected between samples, then loops until there is no rollover. --- sched/clock/clock_systimer.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/sched/clock/clock_systimer.c b/sched/clock/clock_systimer.c index 288bcf66e7c..e1d4440ab11 100644 --- a/sched/clock/clock_systimer.c +++ b/sched/clock/clock_systimer.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/clock/clock_systimer.c * - * Copyright (C) 2011, 2014-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2014-2016, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -50,10 +50,15 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* See nuttx/clock.h */ #undef clock_systimer +/* 32-bit mask for 64-bit timer values */ + +#define TIMER_MASK32 0x00000000ffffffff + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -109,20 +114,34 @@ systime_t clock_systimer(void) /* Convert to a 64- then a 32-bit value */ tmp = USEC2TICK(1000000 * (uint64_t)ts.tv_sec + (uint64_t)ts.tv_nsec / 1000); - return (systime_t)(tmp & 0x00000000ffffffff); + return (systime_t)(tmp & TIMER_MASK32); # endif /* CONFIG_SYSTEM_TIME64 */ #else /* CONFIG_SCHED_TICKLESS */ # ifdef CONFIG_SYSTEM_TIME64 - irqstate_t flags; systime_t sample; + systime_t verify; - /* 64-bit accesses are not atomic on most architectures. */ + /* 64-bit accesses are not atomic on most architectures. The following + * loop samples the 64-bit timer twice and loops in the rare event that + * there was 32-bit rollover between samples. + * + * If there is no 32-bit rollover, then: + * + * - The MS 32-bits of each sample will be the same, and + * - The LS 32-bits of the second sample will be greater than or equal to + * the LS 32-bits for the first sample. + */ + + do + { + verify = g_system_timer; + sample = g_system_timer; + } + while ((sample & TIMER_MASK32) < (verify & TIMER_MASK32) || + (sample & ~TIMER_MASK32) != (verify & ~TIMER_MASK32)); - flags = spin_lock_irqsave(); - sample = g_system_timer; - spin_unlock_irqrestore(flags); return sample; # else /* CONFIG_SYSTEM_TIME64 */ From a30ccce7ced3732e0c9cac5b8fa66b94157fddc6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 15 Jan 2018 18:22:29 -0600 Subject: [PATCH 12/16] configs/nucleo-l432kc/src: Fix some bogus logic noted by Fanda. --- configs/nucleo-l432kc/src/stm32_userleds.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/configs/nucleo-l432kc/src/stm32_userleds.c b/configs/nucleo-l432kc/src/stm32_userleds.c index 0ff3ce66c86..8dec7afee3c 100644 --- a/configs/nucleo-l432kc/src/stm32_userleds.c +++ b/configs/nucleo-l432kc/src/stm32_userleds.c @@ -181,7 +181,7 @@ void board_userled_initialize(void) void board_userled(int led, bool ledon) { - if (led == 1) + if (led == BOARD_LD2) { stm32l4_gpiowrite(GPIO_LD2, ledon); } @@ -193,10 +193,7 @@ void board_userled(int led, bool ledon) void board_userled_all(uint8_t ledset) { - if (led == 1) - { - stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); - } + stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); } /**************************************************************************** From bb7703dc8c7fbb089768da38a56fc9029865b4d8 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 16 Jan 2018 07:17:35 -0600 Subject: [PATCH 13/16] fs/smartfs: Fix inverted ifdef for CONFIG_SMARTFS_USE_SECTOR_BUFFER in smartfs_extendfile() --- fs/smartfs/smartfs_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smartfs/smartfs_utils.c b/fs/smartfs/smartfs_utils.c index da37b922124..99bb8c16567 100644 --- a/fs/smartfs/smartfs_utils.c +++ b/fs/smartfs/smartfs_utils.c @@ -2072,7 +2072,7 @@ int smartfs_extendfile(FAR struct smartfs_mountpt_s *fs, ret = OK; errout_with_buffer: -#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER +#ifndef CONFIG_SMARTFS_USE_SECTOR_BUFFER /* Release the allocated buffer */ kmm_free(buffer); From 802f146781fed4018b3ebbaa269388d81e4ebf8a Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Tue, 16 Jan 2018 07:20:41 -0600 Subject: [PATCH 14/16] configs/nucleo-* and configs/stm32l476vg-disco: Fix more stm32_userleds.c bogus logic --- configs/nucleo-f072rb/src/stm32_userleds.c | 9 +++------ configs/nucleo-f091rc/src/stm32_userleds.c | 9 +++------ configs/nucleo-f410rb/src/stm32_userleds.c | 9 +++------ configs/nucleo-l452re/src/stm32_userleds.c | 9 +++------ configs/nucleo-l476rg/src/stm32_userleds.c | 11 ++++------- configs/stm32l476vg-disco/src/stm32_userleds.c | 4 ++-- 6 files changed, 18 insertions(+), 33 deletions(-) diff --git a/configs/nucleo-f072rb/src/stm32_userleds.c b/configs/nucleo-f072rb/src/stm32_userleds.c index 0b967fc662d..8febc96b467 100644 --- a/configs/nucleo-f072rb/src/stm32_userleds.c +++ b/configs/nucleo-f072rb/src/stm32_userleds.c @@ -181,9 +181,9 @@ void board_userled_initialize(void) void board_userled(int led, bool ledon) { - if (led == 1) + if (led == BOARD_LD2) { - stm32f0_gpiowrite(GPIO_LD2, ldeon); + stm32f0_gpiowrite(GPIO_LD2, ledon); } } @@ -193,10 +193,7 @@ void board_userled(int led, bool ledon) void board_userled_all(uint8_t ledset) { - if (led == 1) - { - stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); - } + stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); } /**************************************************************************** diff --git a/configs/nucleo-f091rc/src/stm32_userleds.c b/configs/nucleo-f091rc/src/stm32_userleds.c index b13c1882b73..f62e84a30e4 100644 --- a/configs/nucleo-f091rc/src/stm32_userleds.c +++ b/configs/nucleo-f091rc/src/stm32_userleds.c @@ -181,9 +181,9 @@ void board_userled_initialize(void) void board_userled(int led, bool ledon) { - if (led == 1) + if (led == BOARD_LD2) { - stm32f0_gpiowrite(GPIO_LD2, ldeon); + stm32f0_gpiowrite(GPIO_LD2, ledon); } } @@ -193,10 +193,7 @@ void board_userled(int led, bool ledon) void board_userled_all(uint8_t ledset) { - if (led == 1) - { - stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); - } + stm32f0_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); } /**************************************************************************** diff --git a/configs/nucleo-f410rb/src/stm32_userleds.c b/configs/nucleo-f410rb/src/stm32_userleds.c index bdd1be2b181..fb283a50cc7 100644 --- a/configs/nucleo-f410rb/src/stm32_userleds.c +++ b/configs/nucleo-f410rb/src/stm32_userleds.c @@ -181,9 +181,9 @@ void board_userled_initialize(void) void board_userled(int led, bool ledon) { - if (led == 1) + if (led == BOARD_LD2) { - stm32_gpiowrite(GPIO_LD2, ldeon); + stm32_gpiowrite(GPIO_LD2, ledon); } } @@ -193,10 +193,7 @@ void board_userled(int led, bool ledon) void board_userled_all(uint8_t ledset) { - if (led == 1) - { - stm32_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); - } + stm32_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); } /**************************************************************************** diff --git a/configs/nucleo-l452re/src/stm32_userleds.c b/configs/nucleo-l452re/src/stm32_userleds.c index 77ba277c342..4ed1b8d807e 100644 --- a/configs/nucleo-l452re/src/stm32_userleds.c +++ b/configs/nucleo-l452re/src/stm32_userleds.c @@ -181,9 +181,9 @@ void board_userled_initialize(void) void board_userled(int led, bool ledon) { - if (led == 1) + if (led == BOARD_LD2) { - stm32l4_gpiowrite(GPIO_LD2, ldeon); + stm32l4_gpiowrite(GPIO_LD2, ledon); } } @@ -193,10 +193,7 @@ void board_userled(int led, bool ledon) void board_userled_all(uint8_t ledset) { - if (led == 1) - { - stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); - } + stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); } /**************************************************************************** diff --git a/configs/nucleo-l476rg/src/stm32_userleds.c b/configs/nucleo-l476rg/src/stm32_userleds.c index 53d9193230a..9464a6ad341 100644 --- a/configs/nucleo-l476rg/src/stm32_userleds.c +++ b/configs/nucleo-l476rg/src/stm32_userleds.c @@ -172,7 +172,7 @@ void board_userled_initialize(void) { /* Configure LD2 GPIO for output */ - stm32_configgpio(GPIO_LD2); + stm32l4_configgpio(GPIO_LD2); } /**************************************************************************** @@ -181,9 +181,9 @@ void board_userled_initialize(void) void board_userled(int led, bool ledon) { - if (led == 1) + if (led == BOARD_LD2) { - stm32_gpiowrite(GPIO_LD2, ldeon); + stm32l4_gpiowrite(GPIO_LD2, ledon); } } @@ -193,10 +193,7 @@ void board_userled(int led, bool ledon) void board_userled_all(uint8_t ledset) { - if (led == 1) - { - stm32_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); - } + stm32l4_gpiowrite(GPIO_LD2, (ledset & BOARD_LD2_BIT) != 0); } /**************************************************************************** diff --git a/configs/stm32l476vg-disco/src/stm32_userleds.c b/configs/stm32l476vg-disco/src/stm32_userleds.c index 4bee92bde81..f1b27fb26f5 100644 --- a/configs/stm32l476vg-disco/src/stm32_userleds.c +++ b/configs/stm32l476vg-disco/src/stm32_userleds.c @@ -192,11 +192,11 @@ void board_userled(int led, bool ledon) switch (led) { case BOARD_LED_RED: - stm32l4_gpiowrite(GPIO_LED_RED, ldeon); + stm32l4_gpiowrite(GPIO_LED_RED, ledon); break; case BOARD_LED_GRN: - stm32l4_gpiowrite(GPIO_LED_GRN, ldeon); + stm32l4_gpiowrite(GPIO_LED_GRN, ledon); break; } } From c67de1f114ac1601707180b65420e27d6af08dae Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 16 Jan 2018 11:48:36 -0600 Subject: [PATCH 15/16] configs/lpcxpresso-lpc54628: Add pin definitions for USART, I2C, and SPI on the Arduino Uno connector. --- configs/lpcxpresso-lpc54628/README.txt | 6 +++ configs/lpcxpresso-lpc54628/include/board.h | 54 +++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt index 926fc1bd9d9..0f31315c946 100644 --- a/configs/lpcxpresso-lpc54628/README.txt +++ b/configs/lpcxpresso-lpc54628/README.txt @@ -24,6 +24,12 @@ README device functionality - 10/100Mbps Ethernet (RJ45 connector) +CONTENTS +======== + + - STATUS + - Configurations + STATUS ====== diff --git a/configs/lpcxpresso-lpc54628/include/board.h b/configs/lpcxpresso-lpc54628/include/board.h index 2ca923462a6..802d35575c0 100644 --- a/configs/lpcxpresso-lpc54628/include/board.h +++ b/configs/lpcxpresso-lpc54628/include/board.h @@ -306,7 +306,7 @@ /* Pin Disambiguation *******************************************************/ /* Flexcomm0/USART0 * - * USART0 connects to the serial bridge on LPC4322JET100 and is typlical used + * USART0 connects to the serial bridge on LPC4322JET100 and is typically used * for the serial console. * * BRIDGE_UART_RXD -> P0_29-ISP_FC0_RXD -> P0.29 GPIO_FC0_RXD_SDA_MOSI_2 @@ -316,6 +316,18 @@ #define GPIO_USART0_RXD (GPIO_FC0_RXD_SDA_MOSI_2 | GPIO_FILTER_OFF) #define GPIO_USART0_TXD (GPIO_FC0_TXD_SCL_MISO_2 | GPIO_FILTER_OFF) +/* An alternative for the serial console is a Arduino Uno compatible serial + * shield: + * + * Arduino Uno J13 Board Signal + * ----------- ------ ---------------- + * D0 RX Pin 15 P3_26-FC4_RXD + * D1 TX Pin 13 P3_27-FC4_TXD + */ + +#define GPIO_USART4_RXD (GPIO_FC4_RXD_SDA_MOSI_2 | GPIO_FILTER_OFF) +#define GPIO_USART4_TXD (GPIO_FC4_TXD_SCL_MISO_2 | GPIO_FILTER_OFF) + /* Flexcomm2/I2C * * For I2C: @@ -329,8 +341,14 @@ * Type I pins need for high speed I2C need: * GPIO_FILTER_OFF + GPIO_I2C_FILTER_OFF + GPIO_I2CDRIVE_HIGH * - * The touchscreen controller is on I2C2: SCL P3.24, SDA P3.23. These are - * both Type D/I pins. + * There are several on-board devices using I2C2: + * + * Codec I2C address: 0x1a + * Accel I2C address: 0x1d + * Touch panel I2C address: 0x38 + * + * In addition, these same I2C2 pins are brought out through D14 and D15 of + * the Arduino Uno connector. */ #if defined(CONFIG_LPC54_I2C_FAST) @@ -351,6 +369,35 @@ GPIO_FILTER_OFF | _I2CFILTER | \ _I2CDRIVE) +/* Flexcomm2/SPI + * + * There are no SPI devices on board the LPCXpresso-LPC54628. SPI is + * available on the Arduino Uno compatible connector, however: + * + * Arduino Uno J9 Board Signal Pin Type + * ----------- ------ ---------------- --------- + * D10 SSEL Pin 15 P3_20-FC9_SCK Type D + * D11 MOSI Pin 13 P3_21-FC9_MOSI Type A + * D12 MISO Pin 11 P3_22-FC9_MISO Type A + * D13 SCK Pin 9 P3_30-FC9_SSELn0 Type D + * + * For SPI: + * Type A & D pins need: + * GPIO_PUSHPULL (on outputs) + GPIO_SLEW_STANDARD (Type D) + + * GPIO_FILTER_OFF + * GPIO_SLEW_FAST is optional for high data rates (Type D). + * Type I need: + * GPIO_I2C_FILTER_OFF + GPIO_I2CDRIVE_LOW + GPIO_FILTER_OFF + + * GPIO_I2CSLEW_GPIO + */ + +#define GPIO_FC9_RXD_SDA_MOSI (GPIO_FC9_RXD_SDA_MOSI_1 | \ + GPIO_PUSHPULL | GPIO_FILTER_OFF) +#define GPIO_FC9_TXD_SCL_MISO (GPIO_FC9_TXD_SCL_MISO_1 | \ + GPIO_FILTER_OFF) +#define GPIO_FC9_SCK (GPIO_FC9_SCK_1 | GPIO_PUSHPULL | \ + GPIO_SLEW_STANDARD | GPIO_FILTER_OFF) + /* SD/MMC * * P2_10-SD_CDn @@ -412,7 +459,6 @@ * feature. */ - #define GPIO_ENET_MDIO GPIO_ENET_MDIO_2 /* P4.16 */ #define GPIO_ENET_MDC GPIO_ENET_MDC_2 /* P4.15 */ From 7d36a818061dd65ed49176633429c83535cb5113 Mon Sep 17 00:00:00 2001 From: Evgeniy Bobkov Date: Tue, 16 Jan 2018 12:41:02 -0600 Subject: [PATCH 16/16] Fixes two bugs in multi-block SD-card operations on the STM32F7 platform. arch/arm/src/stm32f7: DBLOCKSIZE must be the size of SD-card block, not the total amount of transferred bytes. drivers/mmcsd: respect SDIO_CAPS_DMABEFOREWRITE on CMD25. --- arch/arm/src/stm32f7/Kconfig | 2 + arch/arm/src/stm32f7/stm32_sdmmc.c | 76 +++++++++++++++++++++++------- drivers/mmcsd/mmcsd_sdio.c | 45 ++++++++++++++---- 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index 9e80a64934b..4f07188d097 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -1430,6 +1430,7 @@ config STM32F7_SDMMC1 select ARCH_HAVE_SDIO select ARCH_HAVE_SDIOWAIT_WRCOMPLETE select SDIO_PREFLIGHT + select SDIO_BLOCKSETUP config STM32F7_SDMMC2 bool "SDMMC2" @@ -1439,6 +1440,7 @@ config STM32F7_SDMMC2 select ARCH_HAVE_SDIO select ARCH_HAVE_SDIOWAIT_WRCOMPLETE select SDIO_PREFLIGHT + select SDIO_BLOCKSETUP config STM32F7_SPDIFRX bool "SPDIFRX" diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c index e6168ad6631..e5ac6632df6 100644 --- a/arch/arm/src/stm32f7/stm32_sdmmc.c +++ b/arch/arm/src/stm32f7/stm32_sdmmc.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_sdmmc.c * - * Copyright (C) 2009, 2011-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2009, 2011-2018 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * David Sidrane * @@ -388,6 +388,10 @@ struct stm32_dev_s bool dmamode; /* true: DMA mode transfer */ DMA_HANDLE dma; /* Handle for DMA channel */ #endif + + /* Misc */ + + uint32_t blocksize; /* Current block size */ }; /* Register logging support */ @@ -421,8 +425,8 @@ struct stm32_sampleregs_s /* Low-level helpers ********************************************************/ -static inline void sdmmc_putreg32(struct stm32_dev_s *priv, uint32_t value,\ - int offset); +static inline void sdmmc_putreg32(struct stm32_dev_s *priv, uint32_t value, + int offset); static inline uint32_t sdmmc_getreg32(struct stm32_dev_s *priv, int offset); static void stm32_takesem(struct stm32_dev_s *priv); #define stm32_givesem(priv) (nxsem_post(&priv->waitsem)) @@ -438,7 +442,7 @@ static inline uint32_t stm32_getpwrctrl(struct stm32_dev_s *priv); #ifdef CONFIG_STM32F7_SDMMC_XFRDEBUG static void stm32_sampleinit(void); static void stm32_sdiosample(struct stm32_dev_s *priv, - struct stm32_sdioregs_s *regs); + struct stm32_sdioregs_s *regs); static void stm32_sample(struct stm32_dev_s *priv, int index); static void stm32_sdiodump(struct stm32_sdioregs_s *regs, const char *msg); static void stm32_dumpsample(struct stm32_dev_s *priv, @@ -458,13 +462,15 @@ static void stm32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg); static uint8_t stm32_log2(uint16_t value); static void stm32_dataconfig(struct stm32_dev_s *priv, uint32_t timeout, - uint32_t dlen, uint32_t dctrl); + uint32_t dlen, uint32_t dctrl); static void stm32_datadisable(struct stm32_dev_s *priv); static void stm32_sendfifo(struct stm32_dev_s *priv); static void stm32_recvfifo(struct stm32_dev_s *priv); static void stm32_eventtimeout(int argc, uint32_t arg); -static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent); -static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent); +static void stm32_endwait(struct stm32_dev_s *priv, + sdio_eventset_t wkupevent); +static void stm32_endtransfer(struct stm32_dev_s *priv, + sdio_eventset_t wkupevent); /* Interrupt Handling *******************************************************/ @@ -495,6 +501,8 @@ static int stm32_attach(FAR struct sdio_dev_s *dev); static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg); +static void stm32_blocksetup(FAR struct sdio_dev_s *dev, + unsigned int blocksize, unsigned int nblocks); static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, size_t nbytes); static int stm32_sendsetup(FAR struct sdio_dev_s *dev, @@ -543,6 +551,7 @@ static void stm32_default(struct stm32_dev_s *priv); /**************************************************************************** * Private Data ****************************************************************************/ + #ifdef CONFIG_STM32F7_SDMMC1 struct stm32_dev_s g_sdmmcdev1 = { @@ -558,9 +567,7 @@ struct stm32_dev_s g_sdmmcdev1 = .clock = stm32_clock, .attach = stm32_attach, .sendcmd = stm32_sendcmd, -#ifdef CONFIG_SDIO_BLOCKSETUP - .blocksetup = stm32_blocksetup, /* Not implemented yet */ -#endif + .blocksetup = stm32_blocksetup, .recvsetup = stm32_recvsetup, .sendsetup = stm32_sendsetup, .cancel = stm32_cancel, @@ -620,9 +627,7 @@ struct stm32_dev_s g_sdmmcdev2 = .clock = stm32_clock, .attach = stm32_attach, .sendcmd = stm32_sendcmd, -#ifdef CONFIG_SDIO_BLOCKSETUP - .blocksetup = stm32_blocksetup, /* Not implemented yet */ -#endif + .blocksetup = stm32_blocksetup, .recvsetup = stm32_recvsetup, .sendsetup = stm32_sendsetup, .cancel = stm32_cancel, @@ -1433,6 +1438,19 @@ static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent) static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent) { + /* Disable the DTEN bit (it should not be left set after previous read when + * the next write initialization starts). + */ + +#if 1 + sdmmc_putreg32(priv, + sdmmc_getreg32(priv, STM32_SDMMC_DCTRL_OFFSET) & + ~STM32_SDMMC_DCTRL_DTEN, + STM32_SDMMC_DCTRL_OFFSET); +#else + stm32_datadisable(priv); +#endif + /* Disable all transfer related interrupts */ stm32_configxfrints(priv, 0); @@ -2057,6 +2075,30 @@ static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg) return OK; } +/**************************************************************************** + * Name: stm32_blocksetup + * + * Description: + * Configure block size and the number of blocks for next transfer. + * + * Input Parameters: + * dev - An instance of the SDIO device interface. + * blocksize - The selected block size. + * nblocks - The number of blocks to transfer. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocksize, + unsigned int nblocks) +{ + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + + priv->blocksize = blocksize; +} + /**************************************************************************** * Name: stm32_recvsetup * @@ -2103,7 +2145,7 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* Then set up the SDIO data path */ - dblocksize = stm32_log2(nbytes) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, nbytes, dblocksize | STM32_SDMMC_DCTRL_DTDIR); @@ -2158,7 +2200,7 @@ static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const /* Then set up the SDIO data path */ - dblocksize = stm32_log2(nbytes) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, nbytes, dblocksize); /* Enable TX interrupts */ @@ -2882,7 +2924,7 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* Then set up the SDIO data path */ - dblocksize = stm32_log2(buflen) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, buflen, dblocksize | STM32_SDMMC_DCTRL_DTDIR); @@ -2975,7 +3017,7 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, /* Then set up the SDIO data path */ - dblocksize = stm32_log2(buflen) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, buflen, dblocksize); /* Configure the TX DMA */ diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 3d890287010..9cb491feb7d 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -1895,6 +1895,25 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, } } + /* If Controller does not need DMA setup before the write then send CMD25 + * now. + */ + + if ((priv->caps & SDIO_CAPS_DMABEFOREWRITE) == 0) + { + /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status + * is returned + */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); + ret = mmcsd_recvR1(priv, MMCSD_CMD25); + if (ret != OK) + { + ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret); + return ret; + } + } + /* Configure SDIO controller hardware for the write transfer */ SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks); @@ -1923,24 +1942,30 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, priv->wrbusy = true; - /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status - * is returned - */ + /* If Controller needs DMA setup before write then only send CMD25 now. */ - mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); - ret = mmcsd_recvR1(priv, MMCSD_CMD25); - if (ret != OK) + if ((priv->caps & SDIO_CAPS_DMABEFOREWRITE) != 0) { - ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret); - return ret; + /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status + * is returned + */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); + ret = mmcsd_recvR1(priv, MMCSD_CMD25); + if (ret != OK) + { + ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret); + return ret; + } } /* Wait for the transfer to complete */ - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_WDATADELAY); + ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, + nblocks * MMCSD_BLOCK_WDATADELAY); if (ret != OK) { - ferr("ERROR: CMD18 transfer failed: %d\n", ret); + ferr("ERROR: CMD25 transfer failed: %d\n", ret); return ret; }