Compare commits

...

27 commits

Author SHA1 Message Date
Mike.
93af2c0480
Merge a90f05ecf3 into 63c8de5f03 2025-01-12 16:17:54 +08:00
Leo Chung
63c8de5f03 sim: Fixes the linker 'noexecstack' warning
Signed-off-by: Leo Chung <gewalalb@gmail.com>
2025-01-12 16:17:52 +08:00
yaojiaqi
43797ea6cc drivers/timers/watchdog: add watchdog timer notifier chain
Add support for watchdog timer notifer chain so that users
can customize the callback function when the watchdog timer
times out which enabled by Auto-monitor

Signed-off-by: yaojiaqi <yaojiaqi@lixiang.com>
2025-01-12 11:15:42 +08:00
wangmingrong1
aa0aecbd80 mempool: addbacktrace should be before kasan_unpoison
If thread 1 is executing kasan_unpoison but a scheduling occurs and the block is trampled upon, the displayed backtracking may still be from the previously allocated backtracking

Signed-off-by: wangmingrong1 <wangmingrong1@xiaomi.com>
2025-01-12 01:29:14 +08:00
rongyichang
39780fdae1 drivers/vhost-rng: fix compile error in vhost-rng.
vhost/vhost-rng.c:154:9: error: too few arguments to function 'virtio_create_virtqueues'
  154 |   ret = vhost_create_virtqueues(hdev, 0, 1, vqnames, callback);

Signed-off-by: rongyichang <rongyichang@xiaomi.com>
2025-01-12 00:06:12 +08:00
rongyichang
ee2f3df2ff drivers/vhost: fix compile error while get vhost status.
vhost/vhost.c: In function 'vhost_status_driver_ok':
vhost/vhost.c:86:20: error: too few arguments to function 'virtio_get_status'
   86 |   uint8_t status = vhost_get_status(hdev);

Signed-off-by: rongyichang <rongyichang@xiaomi.com>
2025-01-12 00:06:12 +08:00
Yanfeng Liu
ff488133c9 qemu-armv7a: allows ELF_EXECUTABLE
This allows using BINFMT_ELF_EXECUTABLE for qemu-armv7a target.

Signed-off-by: Yanfeng Liu <p-liuyanfeng9@xiaomi.com>
2025-01-11 18:54:36 +08:00
Yanfeng Liu
48846954d8 arm/Toolchain.defs: skip -r for ELF_EXECUTABLE
This avoids using `-r` option when linking executable programs.

Signed-off-by: Yanfeng Liu <p-liuyanfeng9@xiaomi.com>
2025-01-11 18:54:36 +08:00
Yanfeng Liu
657247bda8 libc/modlib: preprocess gnu-elf.ld
This generates gnu-elf.ld via preprocessing of gnu-elf.ld.in so
that to reduce board specific app linker scripts in kernel mode
when BINFMT_ELF_EXECUTABLE is enabled.

Signed-off-by: Yanfeng Liu <p-liuyanfeng9@xiaomi.com>
2025-01-11 18:54:36 +08:00
Yanfeng Liu
be40c01ddd nuttx/addrenv.h: revise assembly guard
This allows the header file to be useful from non-C sources such as
assembly code or linker scripts.

Signed-off-by: Yanfeng Liu <p-liuyanfeng9@xiaomi.com>
2025-01-11 18:54:36 +08:00
wangmingrong1
91c71ed00a mm: Add mm_lock_irq, mm_unlock_iq
Signed-off-by: wangmingrong1 <wangmingrong1@xiaomi.com>
2025-01-11 12:28:30 +08:00
wangmingrong1
1d8ce18d7f macro/align: Fix ALIGN_UP and ALIGN_DOWN
Signed-off-by: wangmingrong1 <wangmingrong1@xiaomi.com>
2025-01-11 12:13:10 +08:00
Kyle Wilson
558fe83f6d Add Timer Support to STM32H5 ADC Driver
Added support for using timers with ADCs. Updated Kconfig to support TRGO2, although driver support for TRGO and TRGO2 not developed yet. Updated hardware/stm32_tim.h with missing CCER bits needed for compilation.
2025-01-11 12:04:48 +08:00
wangmingrong1
7c7a64c84c kconfiglib/mark: It should use pip instead of apt install
Signed-off-by: wangmingrong1 <wangmingrong1@xiaomi.com>
2025-01-10 15:27:06 -03:00
Huang Qi
f2a88059e7 tools/nxstyle.c: Add missing zlib function names to white list
The zlib compression functions are used in network utilities
for compression/decompression. These functions need to be added to
the nxstyle white list to prevent style checking errors since they
follow the zlib naming convention rather than NuttX's style guide.

Specifically, these functions are used in:
- apps/netutils/telnetc/telnetc.c for compressed data handling

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
2025-01-10 15:26:39 -03:00
hujun5
4bd8d9eac7 sched: remove spin_lock_irqsave(NULL) support
Signed-off-by: hujun5 <hujun5@xiaomi.com>
2025-01-10 22:35:14 +08:00
hujun5
69ee240b45 rp2040_pio: remove spin_lock_irqsave(NULL) in arch/arm/src/rp2040/rp2040_pio.c
Signed-off-by: hujun5 <hujun5@xiaomi.com>
2025-01-10 22:35:14 +08:00
wangzhi16
b9837bed08 use small lock to protect g_ram_vectors, involving armv6-m, armv7-m, armv8-m.
Signed-off-by: wangzhi16 <wangzhi16@xiaomi.com>
2025-01-10 21:33:23 +08:00
wangzhi16
d84ba608a1 use small lock in following files:
arch/arm/src/am335x/am335x_can.c
    arch/arm/src/am335x/am335x_gpio.c
    arch/arm/src/am335x/am335x_i2c.c
    arch/arm/src/am335x/am335x_irq.c
    arch/arm/src/am335x/am335x_serial.c
    arch/arm64/src/imx9/imx9_gpio.c
    arch/arm64/src/imx9/imx9_lpi2c.c
    arch/arm64/src/imx9/imx9_lpspi.c
    arch/arm64/src/imx9/imx9_usbdev.c
    arch/x86_64/src/intel64/intel64_tsc_tickless.c

Signed-off-by: wangzhi16 <wangzhi16@xiaomi.com>
2025-01-10 21:32:23 +08:00
Huang Qi
58c95f5d85 armv7-a/Toolchain.defs: Update LLVM arch type to thumbv7a
Changed the LLVM architecture type from thumbv7 to thumbv7a in
Toolchain.defs to better match the ARMv7-A architecture specification.

This change ensures proper code generation and optimization for
Cortex-A series processors when using the Thumb instruction set.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
2025-01-10 21:21:26 +08:00
wangzhi16
f179cb81b5 use small lock to protect register about l2cc, involving the following files:
arch/arm/src/armv7-a/arm_l2cc_pl310.c
arch/arm/src/armv7-r/arm_l2cc_pl310.c
arch/arm/src/armv8-r/arm_l2cc_pl310.c

Signed-off-by: wangzhi16 <wangzhi16@xiaomi.com>
2025-01-10 21:20:52 +08:00
Jukka Laitinen
575c608be8 drivers/usbdev/cdcacm.c: Fix a crash in cdcacm if usbdev gets unregistered while client calls close for the tty
Make sure that the cdcacm is disconnected before the usbdev gets unregistered.

Also, check if the device is connected or not in cdcuart_txempty (uart_txempty). Otherwise there may be a crash during uart_tcdrain, called in tty close path, if the usbdev unregistration happens during the loop.

This issue can be triggered by monitoring the cable connection status in one thread, sending BOARDIOC_USBDEV_DISCONNECT if the usb cable is detached. In another thread close the ttyACM.

Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
2025-01-10 21:14:55 +08:00
Eren Terzioglu
af6147fb2c esp32[c6]: Fix misconfigured pin functions for esp32c6-devkitm 2025-01-10 21:13:26 +08:00
YAMAMOTO Takashi
b2735751d1 rv-virt:citest64: Bump CONFIG_SYSTEM_POPEN_STACKSIZE
With today's master, according to up_check_tcbstack(),
the thread consumes 2432 bytes with examples/popen.
2025-01-10 21:12:12 +08:00
Huang Qi
6dbdfb3cd5 arch/arm: Add LLVM configuration to CMake
Added LLVM-specific configuration variables to ARM architecture CMake files:
- LLVM_ARCHTYPE for architecture variant (thumbv6m, thumbv7a, etc)
- LLVM_CPUTYPE for CPU target (cortex-m0, cortex-a5, etc)
- LLVM_ABITYPE for ABI (eabi/eabihf)

These changes enable LLVM/Clang toolchain support while maintaining
compatibility with existing GCC configurations. The LLVM variables
are set based on the same architecture/CPU/FPU configurations used
for GCC flags.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
2025-01-10 16:58:01 +08:00
Huang Qi
f2934935d0 armv7-a.cmake: Improve FPU options table formatting and readability
Reformatted the FPU options table to use a clearer markdown-style table format
with proper alignment and column headers. Added visual separators (~~~) to make
the table stand out from surrounding code. Improved consistency in column widths
and fixed line wrapping for better readability.

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
2025-01-10 16:58:01 +08:00
Kyle Wilson
9783c88425 Initial STM32H5 Timers Commit
Used the STM32H7 as a reference.

Removed APB enabling from stm32h5xx_rcc.c. This is done in timer initialization, like STM32H7.

Also removed LPTIM. Will add later.

tim_lowerhalf: Timers 9, 10, and 11 removed. Timers 15,16, and 17 added.

Removed low-power timers from Kconfig. Not implemented yet.

Style Updates

Added stm32_tim_enable and stm32_tim_disable to Timer operations.
2025-01-10 09:40:10 +01:00
58 changed files with 7361 additions and 418 deletions

View file

@ -87,7 +87,7 @@ find_program(KCONFIGLIB olddefconfig)
if(NOT KCONFIGLIB)
message(
FATAL_ERROR "Kconfig environment depends on kconfiglib, Please install:
$ sudo apt install python3-kconfiglib")
$ sudo pip3 install kconfiglib")
endif()
# BOARD CONFIG can be set to directory path, or <board-name>[/:]<config-name>
@ -727,6 +727,7 @@ else()
OUTPUT nuttx.rel
COMMAND
${CMAKE_C_COMPILER} ARGS -r $<$<BOOL:${CONFIG_SIM_M32}>:-m32>
$<$<BOOL:${CONFIG_HOST_LINUX}>:-Wl,-z,noexecstack>
$<TARGET_OBJECTS:sim_head> $<$<NOT:$<BOOL:${APPLE}>>:-Wl,--start-group>
${nuttx_libs_paths} $<$<NOT:$<BOOL:${APPLE}>>:-Wl,--end-group> -o
nuttx.rel

View file

@ -27,9 +27,11 @@
#include <nuttx/config.h>
#include <assert.h>
#include <sched.h>
#include <arch/board/board.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/arch.h>
#include <nuttx/can/can.h>
@ -205,6 +207,8 @@ static struct can_dev_s g_can1dev =
};
#endif
static spinlock_t g_can_lock = SP_UNLOCKED;
/****************************************************************************
* Private Functions
****************************************************************************/
@ -1079,7 +1083,8 @@ struct can_dev_s *am335x_can_initialize(int port)
syslog(LOG_DEBUG, "CAN%d\n", port);
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_can_lock);
sched_lock();
#ifdef CONFIG_AM335X_CAN0
if (port == 0)
@ -1109,11 +1114,13 @@ struct can_dev_s *am335x_can_initialize(int port)
{
canerr("Unsupported port: %d\n", port);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_can_lock, flags);
sched_unlock();
return NULL;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_can_lock, flags);
sched_unlock();
return candev;
}
@ -1124,7 +1131,8 @@ void am335x_can_uninitialize(struct can_dev_s *dev)
DEBUGASSERT(dev);
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_can_lock);
sched_lock();
#ifdef CONFIG_AM335X_CAN0
if (dev == &g_can0dev)
@ -1151,7 +1159,8 @@ void am335x_can_uninitialize(struct can_dev_s *dev)
canerr("Not a CAN device: %p\n", dev);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_can_lock, flags);
sched_unlock();
}
#endif

View file

@ -31,6 +31,7 @@
#include <errno.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "chip.h"
#include "arm_internal.h"
@ -219,6 +220,8 @@ static const uint8_t *g_gpio_padctl[AM335X_GPIO_NPORTS] =
g_gpio3_padctl, /* GPIO3 */
};
static spinlock_t g_gpio_lock = SP_UNLOCKED;
/****************************************************************************
* Private Functions
****************************************************************************/
@ -364,7 +367,7 @@ int am335x_gpio_config(gpio_pinset_t pinset)
/* Configure the pin as an input initially to avoid any spurious outputs */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
/* Configure based upon the pin mode */
@ -407,7 +410,7 @@ int am335x_gpio_config(gpio_pinset_t pinset)
break;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
return ret;
}
@ -425,9 +428,9 @@ void am335x_gpio_write(gpio_pinset_t pinset, bool value)
int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
int pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
am335x_gpio_setoutput(port, pin, value);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
}
/****************************************************************************
@ -445,9 +448,9 @@ bool am335x_gpio_read(gpio_pinset_t pinset)
int pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
bool value;
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
value = am335x_gpio_getinput(port, pin);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
return value;
}

View file

@ -37,6 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/clock.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
@ -185,6 +186,7 @@ struct am335x_i2c_priv_s
int refs; /* Reference count */
mutex_t lock; /* Mutual exclusion mutex */
spinlock_t spinlock; /* Spinlock */
#ifndef CONFIG_I2C_POLLED
sem_t sem_isr; /* Interrupt wait semaphore */
#endif
@ -317,6 +319,7 @@ static struct am335x_i2c_priv_s am335x_i2c0_priv =
.config = &am335x_i2c0_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -352,6 +355,7 @@ static struct am335x_i2c_priv_s am335x_i2c1_priv =
.config = &am335x_i2c1_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -387,6 +391,7 @@ static struct am335x_i2c_priv_s am335x_i2c2_priv =
.config = &am335x_i2c2_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -492,7 +497,7 @@ static inline int am335x_i2c_sem_waitdone(struct am335x_i2c_priv_s *priv)
uint32_t regval;
int ret;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
/* Enable Interrupts when master mode */
@ -529,6 +534,8 @@ static inline int am335x_i2c_sem_waitdone(struct am335x_i2c_priv_s *priv)
*/
priv->intstate = INTSTATE_WAITING;
spin_unlock_irqrestore(&priv->spinlock, flags);
do
{
/* Wait until either the transfer is complete or the timeout expires */
@ -551,6 +558,8 @@ static inline int am335x_i2c_sem_waitdone(struct am335x_i2c_priv_s *priv)
}
}
flags = spin_lock_irqsave(&priv->spinlock);
/* Loop until the interrupt level transfer is complete. */
while (priv->intstate != INTSTATE_DONE);
@ -563,7 +572,7 @@ static inline int am335x_i2c_sem_waitdone(struct am335x_i2c_priv_s *priv)
am335x_i2c_putreg(priv, AM335X_I2C_IRQ_EN_CLR_OFFSET, I2C_ICR_CLEARMASK);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return ret;
}
#else
@ -992,7 +1001,7 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv)
*/
#ifdef CONFIG_I2C_POLLED
irqstate_t flags = enter_critical_section();
irqstate_t flags = spin_lock_irqsave(&priv->spinlock);
#endif
/* Transmit a byte */
@ -1001,7 +1010,7 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv)
priv->dcnt--;
#ifdef CONFIG_I2C_POLLED
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
#endif
if ((priv->dcnt == 0) && ((priv->flags & I2C_M_NOSTOP) == 0))
{
@ -1026,7 +1035,7 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv)
*/
#ifdef CONFIG_I2C_POLLED
irqstate_t flags = enter_critical_section();
irqstate_t flags = spin_lock_irqsave(&priv->spinlock);
#endif
/* Receive a byte */
@ -1036,7 +1045,7 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv)
priv->dcnt--;
#ifdef CONFIG_I2C_POLLED
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
#endif
if ((priv->msgc <= 0) && (priv->dcnt == 0))
{
@ -1100,7 +1109,7 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv)
*/
#ifdef CONFIG_I2C_POLLED
irqstate_t flags = enter_critical_section();
irqstate_t flags = spin_lock_irqsave(&priv->spinlock);
#endif
/* Transmit a byte */
@ -1109,7 +1118,7 @@ static int am335x_i2c_isr_process(struct am335x_i2c_priv_s *priv)
priv->dcnt--;
#ifdef CONFIG_I2C_POLLED
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
#endif
if ((priv->dcnt == 0) && ((priv->flags & I2C_M_NOSTOP) == 0))
{

View file

@ -29,6 +29,7 @@
#include <assert.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "sctlr.h"
@ -36,6 +37,13 @@
#include "am335x_gpio.h"
#include "am335x_irq.h"
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_ARCH_IRQPRIO
static spinlock_t g_irq_lock = SP_UNLOCKED;
#endif
/****************************************************************************
* Public Data
****************************************************************************/
@ -328,7 +336,7 @@ int up_prioritize_irq(int irq, int priority)
{
/* These operations must be atomic */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_irq_lock);
#if 0 // TODO
/* Set the new priority */
@ -340,7 +348,7 @@ int up_prioritize_irq(int irq, int priority)
putreg32(regval, regaddr);
#endif
leave_critical_section(flags);
spin_unlock_irqrestore(&g_irq_lock, flags);
return OK;
}

View file

@ -39,6 +39,7 @@
#endif
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
@ -76,13 +77,14 @@
struct up_dev_s
{
uint32_t uartbase; /* Base address of UART registers */
uint32_t baud; /* Configured baud */
uint32_t ier; /* Saved IER value */
uint8_t irq; /* IRQ associated with this UART */
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (7 or 8) */
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
uint32_t uartbase; /* Base address of UART registers */
uint32_t baud; /* Configured baud */
uint32_t ier; /* Saved IER value */
uint8_t irq; /* IRQ associated with this UART */
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (7 or 8) */
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
spinlock_t spinlock; /* Spinlock */
};
/****************************************************************************
@ -169,6 +171,7 @@ static struct up_dev_s g_uart0priv =
.parity = CONFIG_UART0_PARITY,
.bits = CONFIG_UART0_BITS,
.stopbits2 = CONFIG_UART0_2STOP,
.spinlock = SP_UNLOCKED,
};
static uart_dev_t g_uart0port =
@ -200,6 +203,7 @@ static struct up_dev_s g_uart1priv =
.parity = CONFIG_UART1_PARITY,
.bits = CONFIG_UART1_BITS,
.stopbits2 = CONFIG_UART1_2STOP,
.spinlock = SP_UNLOCKED,
};
static uart_dev_t g_uart1port =
@ -230,6 +234,7 @@ static struct up_dev_s g_uart2priv =
.parity = CONFIG_UART2_PARITY,
.bits = CONFIG_UART2_BITS,
.stopbits2 = CONFIG_UART2_2STOP,
.spinlock = SP_UNLOCKED,
};
static uart_dev_t g_uart2port =
@ -260,6 +265,7 @@ static struct up_dev_s g_uart3priv =
.parity = CONFIG_UART3_PARITY,
.bits = CONFIG_UART3_BITS,
.stopbits2 = CONFIG_UART3_2STOP,
.spinlock = SP_UNLOCKED,
};
static uart_dev_t g_uart3port =
@ -290,6 +296,7 @@ static struct up_dev_s g_uart4priv =
.parity = CONFIG_UART4_PARITY,
.bits = CONFIG_UART4_BITS,
.stopbits2 = CONFIG_UART4_2STOP,
.spinlock = SP_UNLOCKED,
};
static uart_dev_t g_uart4port =
@ -320,6 +327,7 @@ static struct up_dev_s g_uart5priv =
.parity = CONFIG_UART5_PARITY,
.bits = CONFIG_UART5_BITS,
.stopbits2 = CONFIG_UART5_2STOP,
.spinlock = SP_UNLOCKED,
};
static uart_dev_t g_uart5port =
@ -484,6 +492,10 @@ static uart_dev_t g_uart5port =
# define UART5_ASSIGNED 1
#endif
/* Spinlock */
static spinlock_t g_gpio_lock = SP_UNLOCKED;
/****************************************************************************
* Inline Functions
****************************************************************************/
@ -567,7 +579,7 @@ static inline void am335x_uart0config(void)
/* Step 1: Enable power to UART0 */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
#warning Missing logic
/* Step 2: Enable clocking to UART0 */
@ -577,7 +589,7 @@ static inline void am335x_uart0config(void)
am335x_gpio_config(GPIO_UART0_TXD);
am335x_gpio_config(GPIO_UART0_RXD);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
};
#endif
@ -588,7 +600,7 @@ static inline void am335x_uart1config(void)
/* Step 1: Enable power to UART1 */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
#warning Missing logic
/* Step 2: Enable clocking to UART1 */
@ -598,7 +610,7 @@ static inline void am335x_uart1config(void)
am335x_gpio_config(GPIO_UART1_TXD);
am335x_gpio_config(GPIO_UART1_RXD);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
};
#endif
@ -609,7 +621,7 @@ static inline void am335x_uart2config(void)
/* Step 1: Enable power to UART2 */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
#warning Missing logic
/* Step 2: Enable clocking on UART2 */
@ -619,7 +631,7 @@ static inline void am335x_uart2config(void)
am335x_gpio_config(GPIO_UART2_TXD);
am335x_gpio_config(GPIO_UART2_RXD);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
};
#endif
@ -630,7 +642,7 @@ static inline void am335x_uart3config(void)
/* Step 1: Enable power to UART3 */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
#warning Missing logic
/* Step 2: Enable clocking to UART3 */
@ -640,7 +652,7 @@ static inline void am335x_uart3config(void)
am335x_gpio_config(GPIO_UART3_TXD);
am335x_gpio_config(GPIO_UART3_RXD);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
};
#endif
@ -651,7 +663,7 @@ static inline void am335x_uart4config(void)
/* Step 1: Enable power to UART4 */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
#warning Missing logic
/* Step 2: Enable clocking to UART4 */
@ -661,7 +673,7 @@ static inline void am335x_uart4config(void)
am335x_gpio_config(GPIO_UART4_TXD);
am335x_gpio_config(GPIO_UART4_RXD);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
};
#endif
@ -672,7 +684,7 @@ static inline void am335x_uart5config(void)
/* Step 1: Enable power to UART5 */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
#warning Missing logic
/* Step 2: Enable clocking to UART5 */
@ -682,7 +694,7 @@ static inline void am335x_uart5config(void)
am335x_gpio_config(GPIO_UART5_TXD);
am335x_gpio_config(GPIO_UART5_RXD);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
};
#endif
@ -1029,18 +1041,18 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */
{
irqstate_t flags = enter_critical_section();
irqstate_t flags = spin_lock_irqsave(&priv->spinlock);
up_enablebreaks(priv, true);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
break;
case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */
{
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
up_enablebreaks(priv, false);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
break;
@ -1204,13 +1216,15 @@ static void up_txint(struct uart_dev_s *dev, bool enable)
struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
if (enable)
{
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
priv->ier |= UART_IER_THR;
up_serialout(priv, AM335X_UART_IER_OFFSET, priv->ier);
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Fake a TX interrupt here by just calling uart_xmitchars() with
* interrupts disabled (note this may recurse).
*/
@ -1222,9 +1236,9 @@ static void up_txint(struct uart_dev_s *dev, bool enable)
{
priv->ier &= ~UART_IER_THR;
up_serialout(priv, AM335X_UART_IER_OFFSET, priv->ier);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
}
/****************************************************************************

View file

@ -31,11 +31,18 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "ram_vectors.h"
#ifdef CONFIG_ARCH_RAMVECTORS
/****************************************************************************
* Private Data
****************************************************************************/
static spinlock_t g_ramvec_lock = SP_UNLOCKED;
/****************************************************************************
* Public Functions
****************************************************************************/
@ -68,7 +75,7 @@ int arm_ramvec_attach(int irq, up_vector_t vector)
* common exception handler.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_ramvec_lock);
if (vector == NULL)
{
/* Disable the interrupt if we can before detaching it. We might
@ -87,7 +94,7 @@ int arm_ramvec_attach(int irq, up_vector_t vector)
/* Save the new vector in the vector table */
g_ram_vectors[irq] = vector;
leave_critical_section(flags);
spin_unlock_irqrestore(&g_ramvec_lock, flags);
ret = OK;
}

View file

@ -35,7 +35,7 @@ else ifeq ($(CONFIG_ARCH_CORTEXA9),y)
endif
ifeq ($(CONFIG_ARM_THUMB),y)
LLVM_ARCHTYPE := thumbv7
LLVM_ARCHTYPE := thumbv7a
else
LLVM_ARCHTYPE := armv7a
endif

View file

@ -38,6 +38,7 @@
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "barriers.h"
@ -225,6 +226,12 @@
#define PL310_GULP_SIZE 4096
/****************************************************************************
* Private Data
****************************************************************************/
static spinlock_t g_l2cc_lock = SP_UNLOCKED;
/****************************************************************************
* Private Functions
****************************************************************************/
@ -262,6 +269,66 @@ static void pl310_flush_all(void)
putreg32(0, L2CC_CSR);
}
/****************************************************************************
* Name: l2cc_disable_nolock
*
* Description:
* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR)
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void l2cc_disable_nolock(void)
{
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
pl310_flush_all();
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
putreg32(0, L2CC_CR);
ARM_DSB();
ARM_ISB();
}
/****************************************************************************
* Name: l2cc_invalidate_all_nolock
*
* Description:
* Invalidate all ways using the Invalidate Way Register (IWR).
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void l2cc_invalidate_all_nolock(void)
{
/* Invalidate all ways by writing the bit mask of ways to be invalidated
* the Invalidate Way Register (IWR).
*/
putreg32(PL310_WAY_MASK, L2CC_IWR);
/* Wait for cache operation by way to complete */
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
putreg32(0, L2CC_CSR);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -457,18 +524,18 @@ void l2cc_enable(void)
/* Invalidate and enable the cache (must be disabled to do this!) */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
if ((getreg32(L2CC_CR) & L2CC_CR_L2CEN) != 0)
{
l2cc_disable();
l2cc_disable_nolock();
}
l2cc_invalidate_all();
l2cc_invalidate_all_nolock();
putreg32(L2CC_CR_L2CEN, L2CC_CR);
ARM_DSB();
ARM_ISB();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -489,17 +556,11 @@ void l2cc_disable(void)
{
irqstate_t flags;
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
flags = spin_lock_irqsave(&g_l2cc_lock);
flags = enter_critical_section();
pl310_flush_all();
l2cc_disable_nolock();
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
putreg32(0, L2CC_CR);
ARM_DSB();
ARM_ISB();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -525,9 +586,9 @@ void l2cc_sync(void)
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -548,27 +609,11 @@ void l2cc_invalidate_all(void)
{
irqstate_t flags;
/* Invalidate all ways */
flags = spin_lock_irqsave(&g_l2cc_lock);
flags = enter_critical_section();
l2cc_invalidate_all_nolock();
/* Invalidate all ways by writing the bit mask of ways to be invalidated
* the Invalidate Way Register (IWR).
*/
putreg32(PL310_WAY_MASK, L2CC_IWR);
/* Wait for cache operation by way to complete */
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -595,7 +640,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Check if the start address is aligned with a cacheline */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
if ((startaddr & PL310_CACHE_LINE_MASK) != 0)
{
/* No.. align down and flush the cache line by writing the address to
@ -622,7 +667,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
putreg32(endaddr, L2CC_CIPALR);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
/* Loop, invalidated the address range by cache line. Interrupts are re-
* enabled momentarily every PL310_GULP_SIZE bytes.
@ -640,7 +685,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Disable interrupts and invalidate the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Invalidate the cache line by writing the address to the
@ -656,16 +701,16 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -690,7 +735,7 @@ void l2cc_clean_all(void)
* Ways Register (CWR).
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(PL310_WAY_MASK, L2CC_CWR);
/* Wait for cache operation by way to complete */
@ -702,7 +747,7 @@ void l2cc_clean_all(void)
*/
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -758,7 +803,7 @@ void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
/* Disable interrupts and clean the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Clean the cache line by writing the address to the Clean
@ -774,16 +819,16 @@ void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -806,9 +851,9 @@ void l2cc_flush_all(void)
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
pl310_flush_all();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -864,7 +909,7 @@ void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
/* Disable interrupts and flush the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Flush the cache line by writing the address to the Clean
@ -880,16 +925,16 @@ void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
#endif /* CONFIG_ARMV7A_L2CC_PL310 */

View file

@ -31,11 +31,18 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "ram_vectors.h"
#ifdef CONFIG_ARCH_RAMVECTORS
/****************************************************************************
* Private Data
****************************************************************************/
static spinlock_t g_ramvec_lock = SP_UNLOCKED;
/****************************************************************************
* Public Functions
****************************************************************************/
@ -68,7 +75,7 @@ int arm_ramvec_attach(int irq, up_vector_t vector)
* common exception handler.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_ramvec_lock);
if (vector == NULL)
{
/* Disable the interrupt if we can before detaching it. We might
@ -87,7 +94,7 @@ int arm_ramvec_attach(int irq, up_vector_t vector)
/* Save the new vector in the vector table */
g_ram_vectors[irq] = vector;
leave_critical_section(flags);
spin_unlock_irqrestore(&g_ramvec_lock, flags);
ret = OK;
}

View file

@ -38,6 +38,7 @@
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "barriers.h"
@ -225,6 +226,12 @@
#define PL310_GULP_SIZE 4096
/****************************************************************************
* Private Data
****************************************************************************/
static volatile spinlock_t g_l2cc_lock = SP_UNLOCKED;
/****************************************************************************
* Private Functions
****************************************************************************/
@ -262,6 +269,66 @@ static void pl310_flush_all(void)
putreg32(0, L2CC_CSR);
}
/****************************************************************************
* Name: l2cc_disable_nolock
*
* Description:
* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR)
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void l2cc_disable_nolock(void)
{
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
pl310_flush_all();
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
putreg32(0, L2CC_CR);
ARM_DSB();
ARM_ISB();
}
/****************************************************************************
* Name: l2cc_invalidate_all_nolock
*
* Description:
* Invalidate all ways using the Invalidate Way Register (IWR).
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void l2cc_invalidate_all_nolock(void)
{
/* Invalidate all ways by writing the bit mask of ways to be invalidated
* the Invalidate Way Register (IWR).
*/
putreg32(PL310_WAY_MASK, L2CC_IWR);
/* Wait for cache operation by way to complete */
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
putreg32(0, L2CC_CSR);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -457,18 +524,18 @@ void l2cc_enable(void)
/* Invalidate and enable the cache (must be disabled to do this!) */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
if ((getreg32(L2CC_CR) & L2CC_CR_L2CEN) != 0)
{
l2cc_disable();
l2cc_disable_nolock();
}
l2cc_invalidate_all();
l2cc_invalidate_all_nolock();
putreg32(L2CC_CR_L2CEN, L2CC_CR);
ARM_DSB();
ARM_ISB();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -489,17 +556,11 @@ void l2cc_disable(void)
{
irqstate_t flags;
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
flags = spin_lock_irqsave(&g_l2cc_lock);
flags = enter_critical_section();
pl310_flush_all();
l2cc_disable_nolock();
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
putreg32(0, L2CC_CR);
ARM_DSB();
ARM_ISB();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -525,9 +586,9 @@ void l2cc_sync(void)
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -548,27 +609,11 @@ void l2cc_invalidate_all(void)
{
irqstate_t flags;
/* Invalidate all ways */
flags = spin_lock_irqsave(&g_l2cc_lock);
flags = enter_critical_section();
l2cc_invalidate_all_nolock();
/* Invalidate all ways by writing the bit mask of ways to be invalidated
* the Invalidate Way Register (IWR).
*/
putreg32(PL310_WAY_MASK, L2CC_IWR);
/* Wait for cache operation by way to complete */
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -595,7 +640,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Check if the start address is aligned with a cacheline */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
if ((startaddr & PL310_CACHE_LINE_MASK) != 0)
{
/* No.. align down and flush the cache line by writing the address to
@ -622,7 +667,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
putreg32(endaddr, L2CC_CIPALR);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
/* Loop, invalidated the address range by cache line. Interrupts are re-
* enabled momentarily every PL310_GULP_SIZE bytes.
@ -640,7 +685,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Disable interrupts and invalidate the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Invalidate the cache line by writing the address to the
@ -656,16 +701,16 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -690,7 +735,7 @@ void l2cc_clean_all(void)
* Ways Register (CWR).
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(PL310_WAY_MASK, L2CC_CWR);
/* Wait for cache operation by way to complete */
@ -702,7 +747,7 @@ void l2cc_clean_all(void)
*/
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -758,7 +803,7 @@ void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
/* Disable interrupts and clean the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Clean the cache line by writing the address to the Clean
@ -774,16 +819,16 @@ void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -806,9 +851,9 @@ void l2cc_flush_all(void)
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
pl310_flush_all();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -864,7 +909,7 @@ void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
/* Disable interrupts and flush the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Flush the cache line by writing the address to the Clean
@ -880,16 +925,16 @@ void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
#endif /* CONFIG_ARMV7R_L2CC_PL310 */

View file

@ -31,11 +31,18 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include "ram_vectors.h"
#ifdef CONFIG_ARCH_RAMVECTORS
/****************************************************************************
* Private Data
****************************************************************************/
static spinlock_t g_ramvec_lock = SP_UNLOCKED;
/****************************************************************************
* Public Functions
****************************************************************************/
@ -68,7 +75,7 @@ int arm_ramvec_attach(int irq, up_vector_t vector)
* common exception handler.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_ramvec_lock);
if (vector == NULL)
{
/* Disable the interrupt if we can before detaching it. We might
@ -87,7 +94,7 @@ int arm_ramvec_attach(int irq, up_vector_t vector)
/* Save the new vector in the vector table */
g_ram_vectors[irq] = vector;
leave_critical_section(flags);
spin_unlock_irqrestore(&g_ramvec_lock, flags);
ret = OK;
}

View file

@ -38,6 +38,7 @@
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include "arm_internal.h"
#include "barriers.h"
@ -225,6 +226,12 @@
#define PL310_GULP_SIZE 4096
/****************************************************************************
* Private Data
****************************************************************************/
static volatile spinlock_t g_l2cc_lock = SP_UNLOCKED;
/****************************************************************************
* Private Functions
****************************************************************************/
@ -262,6 +269,66 @@ static void pl310_flush_all(void)
putreg32(0, L2CC_CSR);
}
/****************************************************************************
* Name: l2cc_disable_nolock
*
* Description:
* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR)
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void l2cc_disable_nolock(void)
{
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
pl310_flush_all();
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
putreg32(0, L2CC_CR);
ARM_DSB();
ARM_ISB();
}
/****************************************************************************
* Name: l2cc_invalidate_all_nolock
*
* Description:
* Invalidate all ways using the Invalidate Way Register (IWR).
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void l2cc_invalidate_all_nolock(void)
{
/* Invalidate all ways by writing the bit mask of ways to be invalidated
* the Invalidate Way Register (IWR).
*/
putreg32(PL310_WAY_MASK, L2CC_IWR);
/* Wait for cache operation by way to complete */
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
putreg32(0, L2CC_CSR);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -457,18 +524,18 @@ void l2cc_enable(void)
/* Invalidate and enable the cache (must be disabled to do this!) */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
if ((getreg32(L2CC_CR) & L2CC_CR_L2CEN) != 0)
{
l2cc_disable();
l2cc_disable_nolock();
}
l2cc_invalidate_all();
l2cc_invalidate_all_nolock();
putreg32(L2CC_CR_L2CEN, L2CC_CR);
ARM_DSB();
ARM_ISB();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -489,17 +556,11 @@ void l2cc_disable(void)
{
irqstate_t flags;
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
flags = spin_lock_irqsave(&g_l2cc_lock);
flags = enter_critical_section();
pl310_flush_all();
l2cc_disable_nolock();
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
putreg32(0, L2CC_CR);
ARM_DSB();
ARM_ISB();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -525,9 +586,9 @@ void l2cc_sync(void)
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -548,27 +609,11 @@ void l2cc_invalidate_all(void)
{
irqstate_t flags;
/* Invalidate all ways */
flags = spin_lock_irqsave(&g_l2cc_lock);
flags = enter_critical_section();
l2cc_invalidate_all_nolock();
/* Invalidate all ways by writing the bit mask of ways to be invalidated
* the Invalidate Way Register (IWR).
*/
putreg32(PL310_WAY_MASK, L2CC_IWR);
/* Wait for cache operation by way to complete */
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -595,7 +640,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Check if the start address is aligned with a cacheline */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
if ((startaddr & PL310_CACHE_LINE_MASK) != 0)
{
/* No.. align down and flush the cache line by writing the address to
@ -622,7 +667,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
putreg32(endaddr, L2CC_CIPALR);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
/* Loop, invalidated the address range by cache line. Interrupts are re-
* enabled momentarily every PL310_GULP_SIZE bytes.
@ -640,7 +685,7 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Disable interrupts and invalidate the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Invalidate the cache line by writing the address to the
@ -656,16 +701,16 @@ void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -690,7 +735,7 @@ void l2cc_clean_all(void)
* Ways Register (CWR).
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(PL310_WAY_MASK, L2CC_CWR);
/* Wait for cache operation by way to complete */
@ -702,7 +747,7 @@ void l2cc_clean_all(void)
*/
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -758,7 +803,7 @@ void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
/* Disable interrupts and clean the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Clean the cache line by writing the address to the Clean
@ -774,16 +819,16 @@ void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -806,9 +851,9 @@ void l2cc_flush_all(void)
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
pl310_flush_all();
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/****************************************************************************
@ -864,7 +909,7 @@ void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
/* Disable interrupts and flush the gulp */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
while (startaddr < gulpend)
{
/* Flush the cache line by writing the address to the Clean
@ -880,16 +925,16 @@ void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
/* Enable interrupts momentarily */
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
* EB, are empty.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_l2cc_lock);
putreg32(0, L2CC_CSR);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_l2cc_lock, flags);
}
#endif /* CONFIG_ARMV8R_L2CC_PL310 */

View file

@ -21,3 +21,8 @@
# ##############################################################################
add_compile_options(-mcpu=cortex-m0 -mthumb -mfloat-abi=soft)
# LLVM Configuration
set(LLVM_ARCHTYPE thumbv6m)
set(LLVM_ABITYPE eabi)
set(LLVM_CPUTYPE cortex-m0)

View file

@ -24,24 +24,43 @@ set(PLATFORM_FLAGS)
if(CONFIG_ARCH_CORTEXA5)
list(APPEND PLATFORM_FLAGS -mcpu=cortex-a5)
set(LLVM_CPUTYPE cortex-a5)
elseif(CONFIG_ARCH_CORTEXA7)
list(APPEND PLATFORM_FLAGS -mcpu=cortex-a7)
set(LLVM_CPUTYPE cortex-a7)
elseif(CONFIG_ARCH_CORTEXA8)
list(APPEND PLATFORM_FLAGS -mcpu=cortex-a8)
set(LLVM_CPUTYPE cortex-a8)
elseif(CONFIG_ARCH_CORTEXA9)
list(APPEND PLATFORM_FLAGS -mcpu=cortex-a9)
set(LLVM_CPUTYPE cortex-a9)
endif()
if(CONFIG_ARM_THUMB)
set(LLVM_ARCHTYPE thumbv7a)
else()
set(LLVM_ARCHTYPE armv7-a)
endif()
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
if(NOT CONFIG_ARM_DPFPU32)
set(ARCHFPUD16 -d16)
endif()
# Cortex-A5 | -mfpu=vfpv4-fp16 | -mfpu=vfpv4-d16-fp16 | -mfpu=neon-fp16
# Cortex-A7 | -mfpu=vfpv4 | -mfpu=vfpv4-d16 | -mfpu=neon-vfpv4
# Cortex-A8 | -mfpu=vfpv3 | | -mfpu=neon (alias for
# neon-vfpv3) Cortex-A9 | -mfpu=vfpv3-fp16 | -mfpu=vfpv3-d16-fp16 |
# -mfpu=neon-fp16 Cortex-A15 | -mfpu=vfpv4 | |
# -mfpu=neon-vfpv4
# ~~~
# | Cortex | FPU Option 1 | FPU Option 2 | FPU Option 3 |
# |--------|--------------------|------------------------|-----------------------|
# | A5 | -mfpu=vfpv4-fp16 | -mfpu=vfpv4-d16-fp16 | -mfpu=neon-fp16 |
# | A7 | -mfpu=vfpv4 | -mfpu=vfpv4-d16 | -mfpu=neon-vfpv4 |
# | A8 | -mfpu=vfpv3 | | -mfpu=neon (alias for neon-vfpv3) |
# | A9 | -mfpu=vfpv3-fp16 | -mfpu=vfpv3-d16-fp16 | -mfpu=neon-fp16 |
# | A15 | -mfpu=vfpv4 | | -mfpu=neon-vfpv4 |
# ~~~
if(CONFIG_ARCH_FPU)
if(CONFIG_ARM_FPU_ABI_SOFT)

View file

@ -38,4 +38,23 @@ else() # gcc
set(TOOLCHAIN_ARCH_FILE armv7-m_gcc)
endif()
# LLVM Configuration
if(CONFIG_ARCH_CORTEXM3)
set(LLVM_ARCHTYPE thumbv7m)
set(LLVM_CPUTYPE cortex-m3)
else()
set(LLVM_ARCHTYPE thumbv7em)
if(CONFIG_ARCH_CORTEXM4)
set(LLVM_CPUTYPE cortex-m4)
elseif(CONFIG_ARCH_CORTEXM7)
set(LLVM_CPUTYPE cortex-m7)
endif()
endif()
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
include(${TOOLCHAIN_ARCH_FILE})

View file

@ -22,6 +22,31 @@
set(PLATFORM_FLAGS)
# LLVM Configuration
if(CONFIG_ARCH_CORTEXM23)
set(LLVM_ARCHTYPE thumbv8m.base)
set(LLVM_CPUTYPE cortex-m23)
elseif(CONFIG_ARCH_CORTEXM33)
set(LLVM_ARCHTYPE thumbv8m.main)
set(LLVM_CPUTYPE cortex-m33)
elseif(CONFIG_ARCH_CORTEXM35P)
set(LLVM_ARCHTYPE thumbv8m.main)
set(LLVM_CPUTYPE cortex-m35p)
elseif(CONFIG_ARCH_CORTEXM55)
set(LLVM_ARCHTYPE thumbv8.1m.main)
set(LLVM_CPUTYPE cortex-m55)
elseif(CONFIG_ARCH_CORTEXM85)
set(LLVM_ARCHTYPE thumbv8.1m.main)
set(LLVM_CPUTYPE cortex-m85)
endif()
# Set ABI type based on FPU configuration
if(CONFIG_ARCH_FPU)
set(LLVM_ABITYPE eabihf)
else()
set(LLVM_ABITYPE eabi)
endif()
if(CONFIG_ARM_DSP)
set(EXTCPUFLAGS +dsp)
endif()

View file

@ -546,7 +546,9 @@ ifeq ($(CONFIG_PIC),y)
# Generate an executable elf, need to ignore undefined symbols
LDELFFLAGS += --unresolved-symbols=ignore-in-object-files --emit-relocs
else
LDELFFLAGS += -r
ifneq ($(CONFIG_BINFMT_ELF_EXECUTABLE),y)
LDELFFLAGS += -r
endif
endif
LDELFFLAGS += -e main -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)modlib$(DELIM)gnu-elf.ld)

View file

@ -15,6 +15,7 @@ config ARCH_CHIP_QEMU_CORTEXA7
bool "Qemu virtual Processor (cortex-a7)"
select ARCH_CORTEXA7
select ARCH_HAVE_ADDRENV
select ARCH_HAVE_ELF_EXECUTABLE
select ARCH_HAVE_LOWVECTORS
select ARCH_HAVE_MULTICPU
select ARCH_NEED_ADDRENV_MAPPING

View file

@ -59,8 +59,8 @@
#define hw_claim_lock() spin_lock_irqsave(&pio_lock)
#define hw_claim_unlock(save) spin_unlock_irqrestore(&pio_lock, save)
#else
#define hw_claim_lock() spin_lock_irqsave(NULL)
#define hw_claim_unlock(save) spin_unlock_irqrestore(NULL, save)
#define hw_claim_lock() up_irq_save()
#define hw_claim_unlock(save) up_irq_restore(save)
#endif
/****************************************************************************

File diff suppressed because it is too large Load diff

View file

@ -43,7 +43,7 @@ CHIP_CSRCS += stm32_idle.c
endif
ifeq ($(CONFIG_TIMER),y)
CHIP_CSRCS += stm32h5_tim_lowerhalf.c
CHIP_CSRCS += stm32_tim_lowerhalf.c
endif
ifeq ($(CONFIG_STM32H5_I2C),y)
@ -66,6 +66,10 @@ ifeq ($(CONFIG_STM32H5_QSPI1),y)
CHIP_CSRCS += stm32_qspi.c
endif
ifeq ($(CONFIG_STM32H5_TIM),y)
CHIP_CSRCS += stm32_tim.c
endif
# Required chip type specific files
ifeq ($(CONFIG_STM32H5_STM32H5XXXX),y)

View file

@ -363,6 +363,26 @@
#define STM32_TIM16_DCR (STM32_TIM16_BASE+STM32_GTIM_DCR_OFFSET)
#define STM32_TIM16_DMAR (STM32_TIM16_BASE+STM32_GTIM_DMAR_OFFSET)
#define STM32_TIM17_CR1 (STM32_TIM17_BASE+STM32_GTIM_CR1_OFFSET)
#define STM32_TIM17_CR2 (STM32_TIM17_BASE+STM32_GTIM_CR2_OFFSET)
#define STM32_TIM17_DIER (STM32_TIM17_BASE+STM32_GTIM_DIER_OFFSET)
#define STM32_TIM17_SR (STM32_TIM17_BASE+STM32_GTIM_SR_OFFSET)
#define STM32_TIM17_EGR (STM32_TIM17_BASE+STM32_GTIM_EGR_OFFSET)
#define STM32_TIM17_CCMR1 (STM32_TIM17_BASE+STM32_GTIM_CCMR1_OFFSET)
#define STM32_TIM17_CCER (STM32_TIM17_BASE+STM32_GTIM_CCER_OFFSET)
#define STM32_TIM17_CNT (STM32_TIM17_BASE+STM32_GTIM_CNT_OFFSET)
#define STM32_TIM17_PSC (STM32_TIM17_BASE+STM32_GTIM_PSC_OFFSET)
#define STM32_TIM17_ARR (STM32_TIM17_BASE+STM32_GTIM_ARR_OFFSET)
#define STM32_TIM17_RCR (STM32_TIM17_BASE+STM32_GTIM_RCR_OFFSET)
#define STM32_TIM17_CCR1 (STM32_TIM17_BASE+STM32_GTIM_CCR1_OFFSET)
#define STM32_TIM17_BDTR (STM32_TIM17_BASE+STM32_GTIM_BDTR_OFFSET)
#define STM32_TIM17_DTR2 (STM32_TIM17_BASE+STM32_GTIM_DTR2_OFFSET)
#define STM32_TIM17_TISEL (STM32_TIM17_BASE+STM32_GTIM_TISEL_OFFSET)
#define STM32_TIM17_AF1 (STM32_TIM17_BASE+STM32_GTIM_AF1_OFFSET)
#define STM32_TIM17_AF2 (STM32_TIM17_BASE+STM32_GTIM_AF2_OFFSET)
#define STM32_TIM17_DCR (STM32_TIM17_BASE+STM32_GTIM_DCR_OFFSET)
#define STM32_TIM17_DMAR (STM32_TIM17_BASE+STM32_GTIM_DMAR_OFFSET)
/* Register Bitfield Definitions ********************************************/
/* Basic Timers - TIM6 and TIM7 */
@ -764,6 +784,12 @@
#define ATIM_CCER_CC4E (1 << 12) /* Bit 12: Capture/Compare 4 output enable */
#define ATIM_CCER_CC4P (1 << 13) /* Bit 13: Capture/Compare 4 output Polarity */
#define ATIM_CCER_CC4NE (1 << 14) /* Bit 14: Capture/compare 4 Complementary output enable */
#define ATIM_CCER_CC4NP (1 << 15) /* Bit 15: Capture/Compare 4 Complementary output polarity */
#define ATIM_CCER_CC5E (1 << 16) /* Bit 16: Capture/Compare 5 output enable */
#define ATIM_CCER_CC5P (1 << 17) /* Bit 17: Capture/Compare 5 output Polarity */
#define ATIM_CCER_CC6E (1 << 20) /* Bit 20: Capture/Compare 6 output enable */
#define ATIM_CCER_CC6P (1 << 21) /* Bit 21: Capture/Compare 6 output Polarity */
#define ATIM_CCER_CCXBASE(ch) ((ch) << 2) /* Each channel uses 4-bits */
/* Counter Register */

View file

@ -47,6 +47,7 @@
#include "chip.h"
#include "stm32_adc.h"
#include "stm32_tim.h"
#include "stm32_rcc.h"
#ifdef CONFIG_ADC
@ -166,6 +167,16 @@ static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value);
static void adc_modifyreg(struct stm32_dev_s *priv, int offset,
uint32_t clrbits, uint32_t setbits);
#ifdef ADC_HAVE_TIMER
static uint16_t tim_getreg(struct stm32_dev_s *priv, int offset);
static void tim_putreg(struct stm32_dev_s *priv, int offset,
uint16_t value);
static void tim_modifyreg(struct stm32_dev_s *priv, int offset,
uint16_t clrbits, uint16_t setbits);
static void tim_dumpregs(struct stm32_dev_s *priv,
const char *msg);
#endif
/* ADC Miscellaneous Helpers */
static void adc_rccreset(struct stm32_dev_s *priv, bool reset);
@ -178,6 +189,11 @@ static bool adc_internal(struct stm32_dev_s * priv, uint32_t *adc_ccr);
static void adc_startconv(struct stm32_dev_s *priv, bool enable);
static void adc_wdog_enable(struct stm32_dev_s *priv);
#ifdef ADC_HAVE_TIMER
static void adc_timstart(struct stm32_dev_s *priv, bool enable);
static int adc_timinit(struct stm32_dev_s *priv);
#endif
/* ADC Interrupt Handler */
static int adc_interrupt(struct adc_dev_s *dev, uint32_t regval);
@ -220,6 +236,15 @@ static struct stm32_dev_s g_adcpriv1 =
.base = STM32_ADC1_BASE,
.mbase = STM32_ADC1_BASE,
.initialized = false,
#ifdef ADC1_HAVE_TIMER
.trigger = CONFIG_STM32H5_ADC1_TIMTRIG,
.tbase = ADC1_TIMER_BASE,
.trcc_enr = ADC1_TIMER_RCC_ENR,
.trcc_en = ADC1_TIMER_RCC_EN,
.extsel = ADC1_EXTSEL_VALUE,
.pclck = ADC1_TIMER_PCLK_FREQUENCY,
.freq = CONFIG_STM32H5_ADC1_SAMPLE_FREQUENCY,
#endif
};
static struct adc_dev_s g_adcdev1 =
@ -240,6 +265,15 @@ static struct stm32_dev_s g_adcpriv2 =
.base = STM32_ADC2_BASE,
.mbase = STM32_ADC2_BASE,
.initialized = false,
#ifdef ADC2_HAVE_TIMER
.trigger = CONFIG_STM32H5_ADC2_TIMTRIG,
.tbase = ADC2_TIMER_BASE,
.trcc_enr = ADC2_TIMER_RCC_ENR,
.trcc_en = ADC2_TIMER_RCC_EN,
.extsel = ADC2_EXTSEL_VALUE,
.pclck = ADC2_TIMER_PCLK_FREQUENCY,
.freq = CONFIG_STM32H5_ADC2_SAMPLE_FREQUENCY,
#endif
};
static struct adc_dev_s g_adcdev2 =
@ -1212,7 +1246,7 @@ static int adc_interrupt(struct adc_dev_s *dev, uint32_t adcisr)
if ((adcisr & ADC_INT_EOC) != 0)
{
/* Read from the ADC_DR register until 8 stage FIFO is empty.
* The FIFO is first mentioned in STM32H7 Reference Manual
* The FIFO is first mentioned in STM32H5 Reference Manual
* rev. 7, though, not yet indicated in the block diagram!
*/
@ -1307,6 +1341,521 @@ static int adc12_interrupt(int irq, void *context, void *arg)
}
#endif
/****************************************************************************
* Name: tim_getreg
*
* Description:
* Read the value of an ADC timer register.
*
* Input Parameters:
* priv - A reference to the ADC block status
* offset - The offset to the register to read
*
* Returned Value:
* The current contents of the specified register
*
****************************************************************************/
#ifdef ADC_HAVE_TIMER
static uint16_t tim_getreg(struct stm32_dev_s *priv, int offset)
{
return getreg16(priv->tbase + offset);
}
#endif
/****************************************************************************
* Name: tim_putreg
*
* Description:
* Write a value to an ADC timer register.
*
* Input Parameters:
* priv - A reference to the ADC block status
* offset - The offset to the register to write to
* value - The value to write to the register
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef ADC_HAVE_TIMER
static void tim_putreg(struct stm32_dev_s *priv, int offset,
uint16_t value)
{
putreg16(value, priv->tbase + offset);
}
#endif
/****************************************************************************
* Name: tim_modifyreg
*
* Description:
* Modify the value of an ADC timer register (not atomic).
*
* Input Parameters:
* priv - A reference to the ADC block status
* offset - The offset to the register to modify
* clrbits - The bits to clear
* setbits - The bits to set
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef ADC_HAVE_TIMER
static void tim_modifyreg(struct stm32_dev_s *priv, int offset,
uint16_t clrbits, uint16_t setbits)
{
tim_putreg(priv, offset, (tim_getreg(priv, offset) & ~clrbits) | setbits);
}
#endif
/****************************************************************************
* Name: tim_dumpregs
*
* Description:
* Dump all timer registers.
*
* Input Parameters:
* priv - A reference to the ADC block status
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef ADC_HAVE_TIMER
static void tim_dumpregs(struct stm32_dev_s *priv, const char *msg)
{
ainfo("%s:\n", msg);
ainfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n",
tim_getreg(priv, STM32_GTIM_CR1_OFFSET),
tim_getreg(priv, STM32_GTIM_CR2_OFFSET),
tim_getreg(priv, STM32_GTIM_SMCR_OFFSET),
tim_getreg(priv, STM32_GTIM_DIER_OFFSET));
ainfo(" SR: %04x EGR: 0000 CCMR1: %04x CCMR2: %04x\n",
tim_getreg(priv, STM32_GTIM_SR_OFFSET),
tim_getreg(priv, STM32_GTIM_CCMR1_OFFSET),
tim_getreg(priv, STM32_GTIM_CCMR2_OFFSET));
ainfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n",
tim_getreg(priv, STM32_GTIM_CCER_OFFSET),
tim_getreg(priv, STM32_GTIM_CNT_OFFSET),
tim_getreg(priv, STM32_GTIM_PSC_OFFSET),
tim_getreg(priv, STM32_GTIM_ARR_OFFSET));
ainfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n",
tim_getreg(priv, STM32_GTIM_CCR1_OFFSET),
tim_getreg(priv, STM32_GTIM_CCR2_OFFSET),
tim_getreg(priv, STM32_GTIM_CCR3_OFFSET),
tim_getreg(priv, STM32_GTIM_CCR4_OFFSET));
if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE)
{
ainfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n",
tim_getreg(priv, STM32_ATIM_RCR_OFFSET),
tim_getreg(priv, STM32_ATIM_BDTR_OFFSET),
tim_getreg(priv, STM32_ATIM_DCR_OFFSET),
tim_getreg(priv, STM32_ATIM_DMAR_OFFSET));
}
else
{
ainfo(" DCR: %04x DMAR: %04x\n",
tim_getreg(priv, STM32_GTIM_DCR_OFFSET),
tim_getreg(priv, STM32_GTIM_DMAR_OFFSET));
}
}
#endif
/****************************************************************************
* Name: adc_timstart
*
* Description:
* Start (or stop) the timer counter
*
* Input Parameters:
* priv - A reference to the ADC block status
* enable - True: Start conversion
*
* Returned Value:
*
****************************************************************************/
#ifdef ADC_HAVE_TIMER
static void adc_timstart(struct stm32_dev_s *priv, bool enable)
{
ainfo("enable: %d\n", enable ? 1 : 0);
if (enable)
{
/* Start the counter */
tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN);
}
else
{
/* Disable the counter */
tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0);
}
}
#endif
/****************************************************************************
* Name: adc_timinit
*
* Description:
* Initialize the timer that drivers the ADC sampling for this channel
* using the pre-calculated timer divider definitions.
*
* Input Parameters:
* priv - A reference to the ADC block status
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
#ifdef ADC_HAVE_TIMER
static int adc_timinit(struct stm32_dev_s *priv)
{
uint32_t prescaler;
uint32_t reload;
uint32_t timclk;
uint16_t clrbits = 0;
uint16_t setbits = 0;
uint16_t cr2;
uint16_t ccmr1;
uint16_t ccmr2;
uint16_t ocmode1;
uint16_t ocmode2;
uint16_t ccenable;
uint16_t ccer;
uint16_t egr;
/* If the timer base address is zero, then this ADC was not configured to
* use a timer.
*/
if (priv->tbase == 0)
{
return ERROR;
}
/* EXTSEL selection: These bits select the external event used to trigger
* the start of conversion of a regular group. NOTE:
*
* - The position with of the EXTSEL field varies from one STM32 MCU
* to another.
* - The width of the EXTSEL field varies from one STM32 MCU to another.
* - The value in priv->extsel is already shifted into the correct bit
* position.
*/
ainfo("Initializing timers extsel = 0x%08" PRIx32 "\n", priv->extsel);
adc_modifyreg(priv, STM32_ADC_CFGR_OFFSET,
ADC_CFGR_EXTEN_MASK | ADC_CFGR_EXTSEL_MASK,
ADC_CFGR_EXTEN_RISING | priv->extsel);
/* Configure the timer channel to drive the ADC */
/* Enable Timer clocking */
modifyreg32(priv->trcc_enr, 0, priv->trcc_en);
/* Calculate optimal values for the timer prescaler and for the timer
* reload register. If freq is the desired frequency, then
*
* reload = timclk / freq
* reload = (pclck / prescaler) / freq
*
* There are many solutions to do this, but the best solution will be the
* one that has the largest reload value and the smallest prescaler value.
* That is the solution that should give us the most accuracy in the timer
* control. Subject to:
*
* 0 <= prescaler <= 65536
* 1 <= reload <= 65535
*
* So ( prescaler = pclck / 65535 / freq ) would be optimal.
*/
prescaler = (priv->pclck / priv->freq + 65534) / 65535;
/* We need to decrement the prescaler value by one, but only, the value
* does not underflow.
*/
if (prescaler < 1)
{
awarn("WARNING: Prescaler underflowed.\n");
prescaler = 1;
}
/* Check for overflow */
else if (prescaler > 65536)
{
awarn("WARNING: Prescaler overflowed.\n");
prescaler = 65536;
}
timclk = priv->pclck / prescaler;
reload = timclk / priv->freq;
if (reload < 1)
{
awarn("WARNING: Reload value underflowed.\n");
reload = 1;
}
else if (reload > 65535)
{
awarn("WARNING: Reload value overflowed.\n");
reload = 65535;
}
/* Disable the timer until we get it configured */
adc_timstart(priv, false);
/* Set up the timer CR1 register.
*
* Select the Counter Mode == count up:
*
* ATIM_CR1_EDGE: The counter counts up or down depending on the
* direction bit(DIR).
* ATIM_CR1_DIR: 0: count up, 1: count down
*
* Set the clock division to zero for all
*/
clrbits = GTIM_CR1_DIR | GTIM_CR1_CMS_MASK | GTIM_CR1_CKD_MASK;
setbits = GTIM_CR1_EDGE;
tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, clrbits, setbits);
/* Set the reload and prescaler values */
tim_putreg(priv, STM32_GTIM_PSC_OFFSET, prescaler - 1);
tim_putreg(priv, STM32_GTIM_ARR_OFFSET, reload);
/* Clear the advanced timers repetition counter in TIM1 */
if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE)
{
tim_putreg(priv, STM32_ATIM_RCR_OFFSET, 0);
tim_putreg(priv, STM32_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE); /* Check me */
}
/* TIMx event generation: Bit 0 UG: Update generation */
tim_putreg(priv, STM32_GTIM_EGR_OFFSET, GTIM_EGR_UG);
/* Handle channel specific setup */
ocmode1 = 0;
ocmode2 = 0;
switch (priv->trigger)
{
case 0: /* TimerX CC1 event */
{
ccenable = ATIM_CCER_CC1E;
ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) |
(ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) |
ATIM_CCMR1_OC1PE;
/* Set the event CC1 */
egr = ATIM_EGR_CC1G;
/* Set the duty cycle by writing to the CCR register for this
* channel
*/
tim_putreg(priv, STM32_GTIM_CCR1_OFFSET, (uint16_t)(reload >> 1));
}
break;
case 1: /* TimerX CC2 event */
{
ccenable = ATIM_CCER_CC2E;
ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) |
(ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) |
ATIM_CCMR1_OC2PE;
/* Set the event CC2 */
egr = ATIM_EGR_CC2G;
/* Set the duty cycle by writing to the CCR register for this
* channel
*/
tim_putreg(priv, STM32_GTIM_CCR2_OFFSET, (uint16_t)(reload >> 1));
}
break;
case 2: /* TimerX CC3 event */
{
ccenable = ATIM_CCER_CC3E;
ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) |
(ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) |
ATIM_CCMR2_OC3PE;
/* Set the event CC3 */
egr = ATIM_EGR_CC3G;
/* Set the duty cycle by writing to the CCR register for this
* channel
*/
tim_putreg(priv, STM32_GTIM_CCR3_OFFSET, (uint16_t)(reload >> 1));
}
break;
case 3: /* TimerX CC4 event */
{
ccenable = ATIM_CCER_CC4E;
ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) |
(ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC4M_SHIFT) |
ATIM_CCMR2_OC4PE;
/* Set the event CC4 */
egr = ATIM_EGR_CC4G;
/* Set the duty cycle by writing to the CCR register for this
* channel
*/
tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1));
}
break;
case 4: /* TimerX TRGO event */
{
/* TODO: TRGO support not yet implemented */
/* Set the event TRGO */
ccenable = 0;
egr = GTIM_EGR_TG;
/* Set the duty cycle by writing to the CCR register for this
* channel
*/
tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1));
}
break;
case 5: /* TimerX TRGO2 event */
{
/* TODO: TRGO2 support not yet implemented */
/* Set the event TRGO2 */
ccenable = 0;
egr = GTIM_EGR_TG;
/* Set the duty cycle by writing to the CCR register for this
* channel
*/
tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1));
}
break;
default:
aerr("ERROR: No such trigger: %d\n", priv->trigger);
return -EINVAL;
}
/* Disable the Channel by resetting the CCxE Bit in the CCER register */
ccer = tim_getreg(priv, STM32_GTIM_CCER_OFFSET);
ccer &= ~ccenable;
tim_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer);
/* Fetch the CR2, CCMR1, and CCMR2 register (already have ccer) */
cr2 = tim_getreg(priv, STM32_GTIM_CR2_OFFSET);
ccmr1 = tim_getreg(priv, STM32_GTIM_CCMR1_OFFSET);
ccmr2 = tim_getreg(priv, STM32_GTIM_CCMR2_OFFSET);
/* Reset the Output Compare Mode Bits and set the select output compare
* mode
*/
ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE |
ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE);
ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE |
ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE);
ccmr1 |= ocmode1;
ccmr2 |= ocmode2;
/* Reset the output polarity level of all channels (selects high
* polarity)
*/
ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P |
ATIM_CCER_CC3P | ATIM_CCER_CC4P);
/* Enable the output state of the selected channel (only) */
ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E |
ATIM_CCER_CC3E | ATIM_CCER_CC4E);
ccer |= ccenable;
if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE)
{
/* Reset output N polarity level, output N state, output compare state,
* output compare N idle state.
*/
ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP |
ATIM_CCER_CC2NE | ATIM_CCER_CC2NP |
ATIM_CCER_CC3NE | ATIM_CCER_CC3NP |
ATIM_CCER_CC4NP);
/* Reset the output compare and output compare N IDLE State */
cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N |
ATIM_CR2_OIS2 | ATIM_CR2_OIS2N |
ATIM_CR2_OIS3 | ATIM_CR2_OIS3N |
ATIM_CR2_OIS4);
}
else
{
ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP);
}
/* Save the modified register values */
tim_putreg(priv, STM32_GTIM_CR2_OFFSET, cr2);
tim_putreg(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1);
tim_putreg(priv, STM32_GTIM_CCMR2_OFFSET, ccmr2);
tim_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer);
tim_putreg(priv, STM32_GTIM_EGR_OFFSET, egr);
/* Set the ARR Preload Bit */
tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_ARPE);
/* Enable the timer counter */
adc_timstart(priv, true);
tim_dumpregs(priv, "After starting timers");
return OK;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -1368,4 +1917,5 @@ struct adc_dev_s *stm32h5_adc_initialize(int intf,
return dev;
}
#endif /* CONFIG_STM32H5_ADC1 || CONFIG_STM32H5_ADC2 */
#endif /* CONFIG_ADC */
#endif /* CONFIG_ADC */

View file

@ -38,6 +38,462 @@
#if defined(CONFIG_STM32H5_ADC1) || defined(CONFIG_STM32H5_ADC2)
/* Configuration ************************************************************/
/* Timer devices may be used for different purposes. One special purpose is
* to control periodic ADC sampling. If CONFIG_STM32H5_TIMn is defined then
* CONFIG_STM32H5_TIMn_ADC must also be defined to indicate that timer "n"
* is intended to be used for that purpose. Timers 1,2,3,6 and 15 may be
* used on STM32H5X3, while STM32H5X6 adds support for timers 4 and 8 as
* well.
*/
#ifndef CONFIG_STM32H5_TIM1
# undef CONFIG_STM32H5_TIM1_ADC
# undef CONFIG_STM32H5_TIM1_ADC1
# undef CONFIG_STM32H5_TIM1_ADC2
# undef CONFIG_STM32H5_TIM1_ADC3
#endif
#ifndef CONFIG_STM32H5_TIM2
# undef CONFIG_STM32H5_TIM2_ADC
# undef CONFIG_STM32H5_TIM2_ADC1
# undef CONFIG_STM32H5_TIM2_ADC2
# undef CONFIG_STM32H5_TIM2_ADC3
#endif
#ifndef CONFIG_STM32H5_TIM3
# undef CONFIG_STM32H5_TIM3_ADC
# undef CONFIG_STM32H5_TIM3_ADC1
# undef CONFIG_STM32H5_TIM3_ADC2
# undef CONFIG_STM32H5_TIM3_ADC3
#endif
#ifndef CONFIG_STM32H5_TIM4
# undef CONFIG_STM32H5_TIM4_ADC
# undef CONFIG_STM32H5_TIM4_ADC1
# undef CONFIG_STM32H5_TIM4_ADC2
# undef CONFIG_STM32H5_TIM4_ADC3
#endif
#ifndef CONFIG_STM32H5_TIM6
# undef CONFIG_STM32H5_TIM6_ADC
# undef CONFIG_STM32H5_TIM6_ADC1
# undef CONFIG_STM32H5_TIM6_ADC2
# undef CONFIG_STM32H5_TIM6_ADC3
#endif
#ifndef CONFIG_STM32H5_TIM8
# undef CONFIG_STM32H5_TIM8_ADC
# undef CONFIG_STM32H5_TIM8_ADC1
# undef CONFIG_STM32H5_TIM8_ADC2
# undef CONFIG_STM32H5_TIM8_ADC3
#endif
#ifndef CONFIG_STM32H5_TIM15
# undef CONFIG_STM32H5_TIM15_ADC
# undef CONFIG_STM32H5_TIM15_ADC1
# undef CONFIG_STM32H5_TIM15_ADC2
# undef CONFIG_STM32H5_TIM15_ADC3
#endif
/* Timer configuration: If a timer trigger is specified, then get
* information about the timer.
*/
#if defined(CONFIG_STM32H5_TIM1_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM1_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM1_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB2ENR
# define ADC1_TIMER_RCC_EN RCC_APB2ENR_TIM1EN
#elif defined(CONFIG_STM32H5_TIM2_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM2_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM2_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC1_TIMER_RCC_EN RCC_APB1LENR_TIM2EN
#elif defined(CONFIG_STM32H5_TIM3_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM3_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM3_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC1_TIMER_RCC_EN RCC_APB1LENR_TIM3EN
#elif defined(CONFIG_STM32H5_TIM4_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM4_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM4_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC1_TIMER_RCC_EN RCC_APB1LENR_TIM4EN
#elif defined(CONFIG_STM32H5_TIM6_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM6_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM6_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC1_TIMER_RCC_EN RCC_APB1LENR_TIM6EN
#elif defined(CONFIG_STM32H5_TIM8_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM8_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB2ENR
# define ADC1_TIMER_RCC_EN RCC_APB2ENR_TIM8EN
#elif defined(CONFIG_STM32H5_TIM15_ADC1)
# define ADC1_HAVE_TIMER 1
# define ADC1_TIMER_BASE STM32_TIM15_BASE
# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM15_CLKIN
# define ADC1_TIMER_RCC_ENR STM32_RCC_APB2ENR
# define ADC1_TIMER_RCC_EN RCC_APB2ENR_TIM15EN
#else
# undef ADC1_HAVE_TIMER
#endif
#ifdef ADC1_HAVE_TIMER
# ifndef CONFIG_STM32H5_ADC1_SAMPLE_FREQUENCY
# error "CONFIG_STM32H5_ADC1_SAMPLE_FREQUENCY not defined"
# endif
# ifndef CONFIG_STM32H5_ADC1_TIMTRIG
# error "CONFIG_STM32H5_ADC1_TIMTRIG not defined"
# warning "Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO"
# endif
#endif
#if defined(CONFIG_STM32H5_TIM1_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM1_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM1_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB2ENR
# define ADC2_TIMER_RCC_EN RCC_APB2ENR_TIM1EN
#elif defined(CONFIG_STM32H5_TIM2_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM2_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM2_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC2_TIMER_RCC_EN RCC_APB1LENR_TIM2EN
#elif defined(CONFIG_STM32H5_TIM3_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM3_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM3_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC2_TIMER_RCC_EN RCC_APB1LENR_TIM3EN
#elif defined(CONFIG_STM32H5_TIM4_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM4_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM4_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC2_TIMER_RCC_EN RCC_APB1LENR_TIM4EN
#elif defined(CONFIG_STM32H5_TIM6_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM6_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM6_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB1LENR
# define ADC2_TIMER_RCC_EN RCC_APB1LENR_TIM6EN
#elif defined(CONFIG_STM32H5_TIM8_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM8_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB2ENR
# define ADC2_TIMER_RCC_EN RCC_APB2ENR_TIM8EN
#elif defined(CONFIG_STM32H5_TIM15_ADC2)
# define ADC2_HAVE_TIMER 1
# define ADC2_TIMER_BASE STM32_TIM15_BASE
# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM15_CLKIN
# define ADC2_TIMER_RCC_ENR STM32_RCC_APB2ENR
# define ADC2_TIMER_RCC_EN RCC_APB2ENR_TIM15EN
#else
# undef ADC2_HAVE_TIMER
#endif
#ifdef ADC2_HAVE_TIMER
# ifndef CONFIG_STM32H5_ADC2_SAMPLE_FREQUENCY
# error "CONFIG_STM32H5_ADC2_SAMPLE_FREQUENCY not defined"
# endif
# ifndef CONFIG_STM32H5_ADC2_TIMTRIG
# error "CONFIG_STM32H5_ADC2_TIMTRIG not defined"
# warning "Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO"
# endif
#endif
#if defined(ADC1_HAVE_TIMER) || defined(ADC2_HAVE_TIMER)
# define ADC_HAVE_TIMER 1
#else
# undef ADC_HAVE_TIMER
#endif
/* Timer 1 */
#define ADC1_EXTSEL_T1CC1 ADC_CFGR_EXTSEL_T1CC1
#define ADC1_EXTSEL_T1CC2 ADC_CFGR_EXTSEL_T1CC2
#define ADC1_EXTSEL_T1CC3 ADC_CFGR_EXTSEL_T1CC3
#define ADC1_EXTSEL_T1CC4 ADC_CFGR_EXTSEL_T1CC4
#define ADC1_EXTSEL_T1TRGO ADC_CFGR_EXTSEL_T1TRGO
#define ADC1_EXTSEL_T1TRGO2 ADC_CFGR_EXTSEL_T1TRGO2
#define ADC2_EXTSEL_T1CC1 ADC_CFGR_EXTSEL_T1CC1
#define ADC2_EXTSEL_T1CC2 ADC_CFGR_EXTSEL_T1CC2
#define ADC2_EXTSEL_T1CC3 ADC_CFGR_EXTSEL_T1CC3
#define ADC2_EXTSEL_T1CC4 ADC_CFGR_EXTSEL_T1CC4
#define ADC2_EXTSEL_T1TRGO ADC_CFGR_EXTSEL_T1TRGO
#define ADC2_EXTSEL_T1TRGO2 ADC_CFGR_EXTSEL_T1TRGO2
/* Timer 2 */
#define ADC1_EXTSEL_T2CC2 ADC_CFGR_EXTSEL_T2CC2
#define ADC1_EXTSEL_T2TRGO ADC_CFGR_EXTSEL_T2TRGO
#define ADC2_EXTSEL_T2CC2 ADC_CFGR_EXTSEL_T2CC2
#define ADC2_EXTSEL_T2TRGO ADC_CFGR_EXTSEL_T2TRGO
/* Timer 3 */
#define ADC1_EXTSEL_T3CC4 ADC_CFGR_EXTSEL_T3CC4
#define ADC1_EXTSEL_T3TRGO ADC_CFGR_EXTSEL_T3TRGO
#define ADC2_EXTSEL_T3CC4 ADC_CFGR_EXTSEL_T3CC4
#define ADC2_EXTSEL_T3TRGO ADC_CFGR_EXTSEL_T3TRGO
/* Timer 4 */
#define ADC1_EXTSEL_T4CC4 ADC_CFGR_EXTSEL_T4CC4
#define ADC1_EXTSEL_T4TRGO ADC_CFGR_EXTSEL_T4TRGO
#define ADC2_EXTSEL_T4CC4 ADC_CFGR_EXTSEL_T4CC4
#define ADC2_EXTSEL_T4TRGO ADC_CFGR_EXTSEL_T4TRGO
/* Timer 6 */
#define ADC1_EXTSEL_T6TRGO ADC_CFGR_EXTSEL_T6TRGO
#define ADC2_EXTSEL_T6TRGO ADC_CFGR_EXTSEL_T6TRGO
/* Timer 8 */
#define ADC1_EXTSEL_T8TRGO ADC_CFGR_EXTSEL_T8TRGO
#define ADC1_EXTSEL_T8TRGO2 ADC_CFGR_EXTSEL_T8TRGO2
#define ADC2_EXTSEL_T8TRGO ADC_CFGR_EXTSEL_T8TRGO
#define ADC2_EXTSEL_T8TRGO2 ADC_CFGR_EXTSEL_T8TRGO2
/* Timer 15 */
#define ADC1_EXTSEL_T15TRGO ADC_CFGR_EXTSEL_T15TRGO
#define ADC2_EXTSEL_T15TRGO ADC_CFGR_EXTSEL_T15TRGO
#if defined(CONFIG_STM32H5_TIM1_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC2
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC3
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC4
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1TRGO2
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM1)"
# endif
#elif defined(CONFIG_STM32H5_TIM2_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2CC2
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T2TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM2)"
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM2)"
# endif
#elif defined(CONFIG_STM32H5_TIM3_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3CC4
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T3TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM3)"
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM3)"
# endif
#elif defined(CONFIG_STM32H5_TIM4_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4CC4
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T4TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM4)"
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM4)"
# endif
#elif defined(CONFIG_STM32H5_TIM6_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T6TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM6)"
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM6)"
# endif
#elif defined(CONFIG_STM32H5_TIM8_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T8TRGO2
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM8)"
# endif
#elif defined(CONFIG_STM32H5_TIM15_ADC1)
# if CONFIG_STM32H5_ADC1_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 4
# define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T15TRGO
# elif CONFIG_STM32H5_ADC1_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC1_TIMTRIG is invalid (TIM15)"
# else
# error "CONFIG_STM32H5_ADC1_TIMTRIG is out of range (TIM15)"
# endif
#endif
#if defined(CONFIG_STM32H5_TIM1_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC1
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC2
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC3
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC4
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1TRGO2
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM1)"
# endif
#elif defined(CONFIG_STM32H5_TIM2_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2CC2
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T2TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM2)"
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM2)"
# endif
#elif defined(CONFIG_STM32H5_TIM3_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3CC4
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T3TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM3)"
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM3)"
# endif
#elif defined(CONFIG_STM32H5_TIM4_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4CC4
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T4TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM4)"
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM4)"
# endif
#elif defined(CONFIG_STM32H5_TIM6_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T6TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM6)"
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM6)"
# endif
#elif defined(CONFIG_STM32H5_TIM8_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM8)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T8TRGO2
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM8)"
# endif
#elif defined(CONFIG_STM32H5_TIM15_ADC2)
# if CONFIG_STM32H5_ADC2_TIMTRIG == 0
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 1
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 2
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 3
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 4
# define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T15TRGO
# elif CONFIG_STM32H5_ADC2_TIMTRIG == 5
# error "CONFIG_STM32H5_ADC2_TIMTRIG is invalid (TIM15)"
# else
# error "CONFIG_STM32H5_ADC2_TIMTRIG is out of range (TIM15)"
# endif
#endif
/****************************************************************************
* Public Types
****************************************************************************/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,223 @@
/****************************************************************************
* arch/arm/src/stm32h5/stm32_tim.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_STM32H5_STM32_TIM_H
#define __ARCH_ARM_SRC_STM32H5_STM32_TIM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "chip.h"
#include "hardware/stm32_tim.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Helpers ******************************************************************/
#define STM32_TIM_ENABLE(d) ((d)->ops->enable(d))
#define STM32_TIM_DISABLE(d) ((d)->ops->disable(d))
#define STM32_TIM_SETMODE(d,mode) ((d)->ops->setmode(d,mode))
#define STM32_TIM_SETCLOCK(d,freq) ((d)->ops->setclock(d,freq))
#define STM32_TIM_SETPERIOD(d,period) ((d)->ops->setperiod(d,period))
#define STM32_TIM_GETCOUNTER(d) ((d)->ops->getcounter(d))
#define STM32_TIM_SETCOUNTER(d,c) ((d)->ops->setcounter(d,c))
#define STM32_TIM_GETWIDTH(d) ((d)->ops->getwidth(d))
#define STM32_TIM_SETCHANNEL(d,ch,mode) ((d)->ops->setchannel(d,ch,mode))
#define STM32_TIM_SETCOMPARE(d,ch,comp) ((d)->ops->setcompare(d,ch,comp))
#define STM32_TIM_GETCAPTURE(d,ch) ((d)->ops->getcapture(d,ch))
#define STM32_TIM_SETISR(d,hnd,arg,s) ((d)->ops->setisr(d,hnd,arg,s))
#define STM32_TIM_ENABLEINT(d,s) ((d)->ops->enableint(d,s))
#define STM32_TIM_DISABLEINT(d,s) ((d)->ops->disableint(d,s))
#define STM32_TIM_ACKINT(d,s) ((d)->ops->ackint(d,s))
#define STM32_TIM_CHECKINT(d,s) ((d)->ops->checkint(d,s))
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/* TIM Device Structure */
struct stm32_tim_dev_s
{
struct stm32_tim_ops_s *ops;
};
/* TIM Modes of Operation */
typedef enum
{
STM32_TIM_MODE_UNUSED = -1,
/* One of the following */
STM32_TIM_MODE_MASK = 0x0310,
STM32_TIM_MODE_DISABLED = 0x0000,
STM32_TIM_MODE_UP = 0x0100,
STM32_TIM_MODE_DOWN = 0x0110,
STM32_TIM_MODE_UPDOWN = 0x0200,
STM32_TIM_MODE_PULSE = 0x0300,
/* One of the following */
STM32_TIM_MODE_CK_INT = 0x0000,
#if 0
STM32_TIM_MODE_CK_INT_TRIG = 0x0400,
STM32_TIM_MODE_CK_EXT = 0x0800,
STM32_TIM_MODE_CK_EXT_TRIG = 0x0c00,
/* Clock sources, OR'ed with CK_EXT */
STM32_TIM_MODE_CK_CHINVALID = 0x0000,
STM32_TIM_MODE_CK_CH1 = 0x0001,
STM32_TIM_MODE_CK_CH2 = 0x0002,
STM32_TIM_MODE_CK_CH3 = 0x0003,
STM32_TIM_MODE_CK_CH4 = 0x0004
#endif
/* Todo: external trigger block */
} stm32_tim_mode_t;
/* TIM Channel Modes */
typedef enum
{
STM32_TIM_CH_DISABLED = 0x00,
/* Common configuration */
STM32_TIM_CH_POLARITY_POS = 0x00,
STM32_TIM_CH_POLARITY_NEG = 0x01,
/* MODES: */
STM32_TIM_CH_MODE_MASK = 0x0e,
/* Output Compare Modes */
/* Enable standard PWM mode, active high when counter < compare */
STM32_TIM_CH_OUTPWM = 0x04,
/* Toggle TIM_CHx output on UEV */
STM32_TIM_CH_OUTTOGGLE = 0x08,
#if 0
STM32_TIM_CH_OUTCOMPARE = 0x06,
/* TODO other modes ... as PWM capture, ENCODER and Hall Sensor */
STM32_TIM_CH_INCAPTURE = 0x10,
STM32_TIM_CH_INPWM = 0x20
STM32_TIM_CH_DRIVE_OC - open collector mode
#endif
} stm32_tim_channel_t;
/* TIM Operations */
struct stm32_tim_ops_s
{
/* Basic Timers */
void (*enable)(struct stm32_tim_dev_s *dev);
void (*disable)(struct stm32_tim_dev_s *dev);
int (*setmode)(struct stm32_tim_dev_s *dev, stm32_tim_mode_t mode);
int (*setclock)(struct stm32_tim_dev_s *dev, uint32_t freq);
void (*setperiod)(struct stm32_tim_dev_s *dev, uint32_t period);
uint32_t (*getcounter)(struct stm32_tim_dev_s *dev);
void (*setcounter)(struct stm32_tim_dev_s *dev, uint32_t count);
/* General and Advanced Timers Adds */
int (*getwidth)(struct stm32_tim_dev_s *dev);
int (*setchannel)(struct stm32_tim_dev_s *dev, uint8_t channel,
stm32_tim_channel_t mode);
int (*setcompare)(struct stm32_tim_dev_s *dev, uint8_t channel,
uint32_t compare);
int (*getcapture)(struct stm32_tim_dev_s *dev, uint8_t channel);
/* Timer interrupts */
int (*setisr)(struct stm32_tim_dev_s *dev, xcpt_t handler, void *arg,
int source);
void (*enableint)(struct stm32_tim_dev_s *dev, int source);
void (*disableint)(struct stm32_tim_dev_s *dev, int source);
void (*ackint)(struct stm32_tim_dev_s *dev, int source);
int (*checkint)(struct stm32_tim_dev_s *dev, int source);
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Power-up timer and get its structure */
struct stm32_tim_dev_s *stm32_tim_init(int timer);
/* Power-down timer, mark it as unused */
int stm32_tim_deinit(struct stm32_tim_dev_s *dev);
/****************************************************************************
* Name: stm32_timer_initialize
*
* Description:
* Bind the configuration timer to a timer lower half instance and
* register the timer drivers at 'devpath'
*
* Input Parameters:
* devpath - The full path to the timer device. This should be of the
* form /dev/timer0
* timer - the timer number.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
#ifdef CONFIG_TIMER
int stm32_timer_initialize(const char *devpath, int timer);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_STM32H5_STM32_TIM_H */

View file

@ -0,0 +1,586 @@
/****************************************************************************
* arch/arm/src/stm32h5/stm32_tim_lowerhalf.c
*
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-FileCopyrightText: 2023 Max Kriegleder. All rights reserved.
* SPDX-FileCopyrightText: 2015 Wail Khemir. All rights reserved.
* SPDX-FileCopyrightText: 2015 Omni Hoverboards Inc. All rights reserved.
* SPDX-FileContributor: Wail Khemir <khemirwail@gmail.com>
* SPDX-FileContributor: Paul Alexander Patience <paul-a.patience@polymtl.ca>
* SPDX-FileContributor: Max Kriegleder <max.kriegleder@gmail.com>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <nuttx/irq.h>
#include <nuttx/timers/timer.h>
#include <arch/board/board.h>
#include "stm32_tim.h"
#if defined(CONFIG_TIMER) && \
(defined(CONFIG_STM32H5_TIM1) || defined(CONFIG_STM32H5_TIM2) || \
defined(CONFIG_STM32H5_TIM3) || defined(CONFIG_STM32H5_TIM4) || \
defined(CONFIG_STM32H5_TIM5) || defined(CONFIG_STM32H5_TIM6) || \
defined(CONFIG_STM32H5_TIM7) || defined(CONFIG_STM32H5_TIM8) || \
defined(CONFIG_STM32H5_TIM12) || defined(CONFIG_STM32H5_TIM13) || \
defined(CONFIG_STM32H5_TIM14) || defined(CONFIG_STM32H5_TIM15) || \
defined(CONFIG_STM32H5_TIM16) || defined(CONFIG_STM32H5_TIM17))
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define STM32_TIM1_RES 16
#define STM32_TIM2_RES 32
#define STM32_TIM3_RES 16
#define STM32_TIM4_RES 16
#define STM32_TIM5_RES 32
#define STM32_TIM6_RES 16
#define STM32_TIM7_RES 16
#define STM32_TIM8_RES 16
#define STM32_TIM12_RES 16
#define STM32_TIM13_RES 16
#define STM32_TIM14_RES 16
#define STM32_TIM15_RES 16
#define STM32_TIM16_RES 16
#define STM32_TIM17_RES 16
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure provides the private representation of the "lower-half"
* driver state structure. This structure must be cast-compatible with the
* timer_lowerhalf_s structure.
*/
struct stm32_lowerhalf_s
{
const struct timer_ops_s *ops; /* Lower half operations */
struct stm32_tim_dev_s *tim; /* stm32 timer driver */
tccb_t callback; /* Current user interrupt callback */
void *arg; /* Argument passed to upper half callback */
bool started; /* True: Timer has been started */
const uint8_t resolution; /* Number of bits in the timer (16 or 32 bits) */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int stm32_timer_handler(int irq, void * context, void * arg);
/* "Lower half" driver methods **********************************************/
static int stm32_start(struct timer_lowerhalf_s *lower);
static int stm32_stop(struct timer_lowerhalf_s *lower);
static int stm32_settimeout(struct timer_lowerhalf_s *lower,
uint32_t timeout);
static void stm32_setcallback(struct timer_lowerhalf_s *lower,
tccb_t callback, void *arg);
/****************************************************************************
* Private Data
****************************************************************************/
/* "Lower half" driver methods */
static const struct timer_ops_s g_timer_ops =
{
.start = stm32_start,
.stop = stm32_stop,
.getstatus = NULL,
.settimeout = stm32_settimeout,
.setcallback = stm32_setcallback,
.ioctl = NULL,
};
#ifdef CONFIG_STM32H5_TIM1
static struct stm32_lowerhalf_s g_tim1_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM1_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM2
static struct stm32_lowerhalf_s g_tim2_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM2_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM3
static struct stm32_lowerhalf_s g_tim3_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM3_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM4
static struct stm32_lowerhalf_s g_tim4_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM4_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM5
static struct stm32_lowerhalf_s g_tim5_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM5_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM6
static struct stm32_lowerhalf_s g_tim6_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM6_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM7
static struct stm32_lowerhalf_s g_tim7_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM7_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM8
static struct stm32_lowerhalf_s g_tim8_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM8_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM12
static struct stm32_lowerhalf_s g_tim12_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM12_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM13
static struct stm32_lowerhalf_s g_tim13_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM13_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM14
static struct stm32_lowerhalf_s g_tim14_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM14_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM15
static struct stm32_lowerhalf_s g_tim15_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM15_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM16
static struct stm32_lowerhalf_s g_tim16_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM16_RES,
};
#endif
#ifdef CONFIG_STM32H5_TIM17
static struct stm32_lowerhalf_s g_tim17_lowerhalf =
{
.ops = &g_timer_ops,
.resolution = STM32_TIM17_RES,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_timer_handler
*
* Description:
* timer interrupt handler
*
* Input Parameters:
*
* Returned Value:
*
****************************************************************************/
static int stm32_timer_handler(int irq, void * context, void * arg)
{
struct stm32_lowerhalf_s *lower = (struct stm32_lowerhalf_s *) arg;
uint32_t next_interval_us = 0;
STM32_TIM_ACKINT(lower->tim, ATIM_DIER_UIE);
if (lower->callback(&next_interval_us, lower->arg))
{
if (next_interval_us > 0)
{
STM32_TIM_SETPERIOD(lower->tim, next_interval_us);
}
}
else
{
stm32_stop((struct timer_lowerhalf_s *)lower);
}
return OK;
}
/****************************************************************************
* Name: stm32_start
*
* Description:
* Start the timer, resetting the time to the current timeout,
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int stm32_start(struct timer_lowerhalf_s *lower)
{
struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
if (!priv->started)
{
STM32_TIM_SETMODE(priv->tim, STM32_TIM_MODE_UP);
if (priv->callback != NULL)
{
STM32_TIM_SETISR(priv->tim, stm32_timer_handler, priv, 0);
STM32_TIM_ENABLEINT(priv->tim, ATIM_DIER_UIE);
}
priv->started = true;
return OK;
}
/* Return EBUSY to indicate that the timer was already running */
return -EBUSY;
}
/****************************************************************************
* Name: stm32_stop
*
* Description:
* Stop the timer
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int stm32_stop(struct timer_lowerhalf_s *lower)
{
struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
if (priv->started)
{
STM32_TIM_SETMODE(priv->tim, STM32_TIM_MODE_DISABLED);
STM32_TIM_DISABLEINT(priv->tim, ATIM_DIER_UIE);
STM32_TIM_SETISR(priv->tim, NULL, NULL, 0);
priv->started = false;
return OK;
}
/* Return ENODEV to indicate that the timer was not running */
return -ENODEV;
}
/****************************************************************************
* Name: stm32_settimeout
*
* Description:
* Set a new timeout value (and reset the timer)
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
* timeout - The new timeout value in microseconds.
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
static int stm32_settimeout(struct timer_lowerhalf_s *lower,
uint32_t timeout)
{
struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
uint64_t maxtimeout;
if (priv->started)
{
return -EPERM;
}
maxtimeout = (1 << priv->resolution) - 1;
if (timeout > maxtimeout)
{
uint64_t freq = (maxtimeout * 1000000) / timeout;
STM32_TIM_SETCLOCK(priv->tim, freq);
STM32_TIM_SETPERIOD(priv->tim, maxtimeout);
}
else
{
STM32_TIM_SETCLOCK(priv->tim, 1000000);
STM32_TIM_SETPERIOD(priv->tim, timeout);
}
return OK;
}
/****************************************************************************
* Name: stm32_setcallback
*
* Description:
* Call this user provided timeout callback.
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
* callback - The new timer expiration function pointer. If this
* function pointer is NULL, then the reset-on-expiration
* behavior is restored,
* arg - Argument that will be provided in the callback
*
* Returned Value:
* The previous timer expiration function pointer or NULL is there was
* no previous function pointer.
*
****************************************************************************/
static void stm32_setcallback(struct timer_lowerhalf_s *lower,
tccb_t callback, void *arg)
{
struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower;
irqstate_t flags = enter_critical_section();
/* Save the new callback */
priv->callback = callback;
priv->arg = arg;
if (callback != NULL && priv->started)
{
STM32_TIM_SETISR(priv->tim, stm32_timer_handler, priv, 0);
STM32_TIM_ENABLEINT(priv->tim, ATIM_DIER_UIE);
}
else
{
STM32_TIM_DISABLEINT(priv->tim, ATIM_DIER_UIE);
STM32_TIM_SETISR(priv->tim, NULL, NULL, 0);
}
leave_critical_section(flags);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_timer_initialize
*
* Description:
* Bind the configuration timer to a timer lower half instance and
* register the timer drivers at 'devpath'
*
* Input Parameters:
* devpath - The full path to the timer device. This should be of the
* form /dev/timer0
* timer - the timer's number.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
int stm32_timer_initialize(const char *devpath, int timer)
{
struct stm32_lowerhalf_s *lower;
switch (timer)
{
#ifdef CONFIG_STM32H5_TIM1
case 1:
lower = &g_tim1_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM2
case 2:
lower = &g_tim2_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM3
case 3:
lower = &g_tim3_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM4
case 4:
lower = &g_tim4_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM5
case 5:
lower = &g_tim5_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM6
case 6:
lower = &g_tim6_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM7
case 7:
lower = &g_tim7_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM8
case 8:
lower = &g_tim8_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM12
case 12:
lower = &g_tim12_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM13
case 13:
lower = &g_tim13_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM14
case 14:
lower = &g_tim14_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM15
case 15:
lower = &g_tim15_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM16
case 16:
lower = &g_tim16_lowerhalf;
break;
#endif
#ifdef CONFIG_STM32H5_TIM17
case 17:
lower = &g_tim17_lowerhalf;
break;
#endif
default:
return -ENODEV;
}
/* Initialize the elements of lower half state structure */
lower->started = false;
lower->callback = NULL;
lower->tim = stm32_tim_init(timer);
if (lower->tim == NULL)
{
return -EINVAL;
}
/* Register the timer driver as /dev/timerX. The returned value from
* timer_register is a handle that could be used with timer_unregister().
* REVISIT: The returned handle is discard here.
*/
void *drvr = timer_register(devpath,
(struct timer_lowerhalf_s *)lower);
if (drvr == NULL)
{
/* The actual cause of the failure may have been a failure to allocate
* perhaps a failure to register the timer driver (such as if the
* 'depath' were not unique). We know here but we return EEXIST to
* indicate the failure (implying the non-unique devpath).
*/
return -EEXIST;
}
return OK;
}
#endif /* CONFIG_TIMER */

View file

@ -355,60 +355,6 @@ static inline void rcc_enableapb1l(void)
regval = getreg32(STM32_RCC_APB1LENR);
#ifdef CONFIG_STM32H5_TIM2
/* Bit 0: TIM2 clock enable */
regval |= RCC_APB1LENR_TIM2EN;
#endif
#ifdef CONFIG_STM32H5_TIM3
/* Bit 1: TIM3 clock enable */
regval |= RCC_APB1LENR_TIM3EN;
#endif
#ifdef CONFIG_STM32H5_TIM4
/* Bit 2: TIM4 clock enable */
regval |= RCC_APB1LENR_TIM4EN;
#endif
#ifdef CONFIG_STM32H5_TIM5
/* Bit 3: TIM5 clock enable */
regval |= RCC_APB1LENR_TIM5EN;
#endif
#ifdef CONFIG_STM32H5_TIM6
/* Bit 4: TIM6 clock enable */
regval |= RCC_APB1LENR_TIM6EN;
#endif
#ifdef CONFIG_STM32H5_TIM7
/* Bit 5: TIM7 clock enable */
regval |= RCC_APB1LENR_TIM7EN;
#endif
#ifdef CONFIG_STM32H5_TIM12
/* Bit 5: TIM12 clock enable */
regval |= RCC_APB1LENR_TIM12EN;
#endif
#ifdef CONFIG_STM32H5_TIM13
/* Bit 5: TIM13 clock enable */
regval |= RCC_APB1LENR_TIM13EN;
#endif
#ifdef CONFIG_STM32H5_TIM14
/* Bit 5: TIM14 clock enable */
regval |= RCC_APB1LENR_TIM14EN;
#endif
#ifdef CONFIG_STM32H5_SPI2
/* Bit 14: SPI2 clock enable */
@ -588,48 +534,18 @@ static inline void rcc_enableapb2(void)
regval = getreg32(STM32_RCC_APB2ENR);
#ifdef CONFIG_STM32H5_TIM1
/* TIM1 clock enable */
regval |= RCC_APB2ENR_TIM1EN;
#endif
#ifdef CONFIG_STM32H5_SPI1
/* SPI1 clock enable */
regval |= RCC_APB2ENR_SPI1EN;
#endif
#ifdef CONFIG_STM32H5_TIM8
/* TIM8 clock enable */
regval |= RCC_APB2ENR_TIM8EN;
#endif
#ifdef CONFIG_STM32H5_USART1
/* USART1 clock enable */
regval |= RCC_APB2ENR_USART1EN;
#endif
#ifdef CONFIG_STM32H5_TIM15
/* TIM15 clock enable */
regval |= RCC_APB2ENR_TIM15EN;
#endif
#ifdef CONFIG_STM32H5_TIM16
/* TIM16 clock enable */
regval |= RCC_APB2ENR_TIM16EN;
#endif
#ifdef CONFIG_STM32H5_TIM17
/* TIM17 clock enable */
regval |= RCC_APB2ENR_TIM17EN;
#endif
#ifdef CONFIG_STM32H5_SPI4
/* SPI4 clock enable */

View file

@ -33,6 +33,7 @@
#include <errno.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <imx9_gpiobase.c>
@ -45,6 +46,10 @@
* Private Functions
****************************************************************************/
/* Spinlock */
static spinlock_t g_gpio_lock = SP_UNLOCKED;
/****************************************************************************
* Name: imx9_gpio_dirout
****************************************************************************/
@ -174,7 +179,7 @@ int imx9_config_gpio(gpio_pinset_t pinset)
/* Configure the pin as an input initially to avoid any spurious outputs */
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
/* Configure based upon the pin mode */
@ -223,7 +228,7 @@ int imx9_config_gpio(gpio_pinset_t pinset)
break;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
return ret;
}
@ -243,9 +248,9 @@ void imx9_gpio_write(gpio_pinset_t pinset, bool value)
DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS);
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
imx9_gpio_setoutput(port, pin, value);
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
}
/****************************************************************************
@ -265,7 +270,7 @@ bool imx9_gpio_read(gpio_pinset_t pinset)
DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS);
flags = enter_critical_section();
flags = spin_lock_irqsave(&g_gpio_lock);
if ((pinset & (GPIO_OUTPUT)) == (GPIO_OUTPUT))
{
value = imx9_gpio_get_pinstatus(port, pin);
@ -275,6 +280,6 @@ bool imx9_gpio_read(gpio_pinset_t pinset)
value = imx9_gpio_getinput(port, pin);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&g_gpio_lock, flags);
return value;
}

View file

@ -2438,7 +2438,7 @@ int imx9_i2cbus_uninitialize(struct i2c_master_s *dev)
if (--priv->refs > 0)
{
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}

View file

@ -1798,8 +1798,6 @@ struct spi_dev_s *imx9_lpspibus_initialize(int bus)
{
struct imx9_lpspidev_s *priv = NULL;
irqstate_t flags = enter_critical_section();
#ifdef CONFIG_IMX9_LPSPI1
if (bus == 1)
{
@ -2017,7 +2015,6 @@ struct spi_dev_s *imx9_lpspibus_initialize(int bus)
else
#endif
{
leave_critical_section(flags);
spierr("ERROR: Unsupported SPI bus: %d\n", bus);
return NULL;
}
@ -2061,7 +2058,6 @@ struct spi_dev_s *imx9_lpspibus_initialize(int bus)
}
#endif
leave_critical_section(flags);
return (struct spi_dev_s *)priv;
}

View file

@ -2319,9 +2319,9 @@ static int imx9_epdisable(struct usbdev_ep_s *ep)
/* Cancel any ongoing activity */
spin_unlock_irqrestore(&privep->spinlock, flags);
imx9_cancelrequests(privep, -ESHUTDOWN);
leave_critical_section(flags);
spin_unlock_irqrestore(&privep->spinlock, flags);
return OK;
}

View file

@ -200,3 +200,7 @@ else()
add_link_options(-Wl,--gc-sections)
add_link_options(-Wl,-Ttext-segment=0x40000000)
endif()
if(CONFIG_HOST_LINUX)
add_link_options(-Wl,-z,noexecstack)
endif()

View file

@ -57,6 +57,7 @@
#include <nuttx/arch.h>
#include <nuttx/clock.h>
#include <nuttx/spinlock.h>
#ifdef CONFIG_SCHED_TICKLESS
@ -90,6 +91,7 @@ static uint32_t g_timer_active;
static irqstate_t g_tmr_sync_count;
static irqstate_t g_tmr_flags;
static spinlock_t g_tmr_lock = SP_UNLOCKED;
/****************************************************************************
* Private Functions
@ -161,7 +163,7 @@ static inline void up_tmr_sync_up(void)
{
if (!g_tmr_sync_count)
{
g_tmr_flags = enter_critical_section();
g_tmr_flags = spin_lock_irqsave(&g_tmr_lock);
}
g_tmr_sync_count++;
@ -171,7 +173,7 @@ static inline void up_tmr_sync_down(void)
{
if (g_tmr_sync_count == 1)
{
leave_critical_section(g_tmr_flags);
spin_unlock_irqrestore(&g_tmr_lock, g_tmr_flags);
}
if (g_tmr_sync_count > 0)

View file

@ -484,7 +484,7 @@ int esp_gpio_init(void)
/* Configure the pins that will be used as output */
esp_gpio_matrix_out(g_gpiooutputs[i], SIG_GPIO_OUT_IDX, 0, 0);
esp_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_1 | INPUT_FUNCTION_1);
esp_configgpio(g_gpiooutputs[i], OUTPUT_FUNCTION_2 | INPUT_FUNCTION_2);
esp_gpiowrite(g_gpiooutputs[i], 0);
pincount++;
@ -503,7 +503,7 @@ int esp_gpio_init(void)
/* Configure the pins that will be used as interrupt input */
esp_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_1 | PULLDOWN);
esp_configgpio(g_gpiointinputs[i], INPUT_FUNCTION_2 | PULLDOWN);
pincount++;
}

View file

@ -76,6 +76,7 @@ CONFIG_START_YEAR=2021
CONFIG_SYMTAB_ORDEREDBYNAME=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_POPEN=y
CONFIG_SYSTEM_POPEN_STACKSIZE=3072
CONFIG_TESTING_GETPRIME=y
CONFIG_TESTING_MM=y
CONFIG_TESTING_OSTEST=y

View file

@ -439,6 +439,14 @@ menuconfig WATCHDOG_AUTOMONITOR
if WATCHDOG_AUTOMONITOR
config WATCHDOG_TIMEOUT_NOTIFIER
bool "Enable watchdog timeout notifier"
default n
---help---
The watchdog timeout notifier chain mechanism supports users registering
custom callback functions, which will be called when the watchdog timer
managed by Auto-monitor times out.
choice
prompt "Auto-monitor keepalive by"
default WATCHDOG_AUTOMONITOR_BY_WDOG

View file

@ -71,6 +71,20 @@
# endif
#endif
#if defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_ONESHOT)
# define WATCHDOG_NOTIFIER_ACTION WATCHDOG_KEEPALIVE_BY_ONESHOT
#elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_TIMER)
# define WATCHDOG_NOTIFIER_ACTION WATCHDOG_KEEPALIVE_BY_TIMER
#elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_WDOG)
# define WATCHDOG_NOTIFIER_ACTION WATCHDOG_KEEPALIVE_BY_WDOG
#elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_WORKER)
# define WATCHDOG_NOTIFIER_ACTION WATCHDOG_KEEPALIVE_BY_WORKER
#elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_CAPTURE)
# define WATCHDOG_NOTIFIER_ACTION WATCHDOG_KEEPALIVE_BY_CAPTURE
#elif defined(CONFIG_WATCHDOG_AUTOMONITOR_BY_IDLE)
# define WATCHDOG_NOTIFIER_ACTION WATCHDOG_KEEPALIVE_BY_IDLE
#endif
/****************************************************************************
* Private Type Definitions
****************************************************************************/
@ -135,6 +149,10 @@ static const struct file_operations g_wdogops =
wdog_ioctl, /* ioctl */
};
#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
static ATOMIC_NOTIFIER_HEAD(g_watchdog_notifier_list);
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@ -699,6 +717,55 @@ static int wdog_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
* Public Functions
****************************************************************************/
#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
/****************************************************************************
* Name: watchdog_notifier_chain_register
*
* Description:
* Add notifier to the watchdog notifier chain
*
* Input Parameters:
* nb - New entry in notifier chain
*
****************************************************************************/
void watchdog_notifier_chain_register(FAR struct notifier_block *nb)
{
atomic_notifier_chain_register(&g_watchdog_notifier_list, nb);
}
/****************************************************************************
* Name: watchdog_notifier_chain_unregister
*
* Description:
* Remove notifier from the watchdog notifier chain
*
* Input Parameters:
* nb - Entry to remove from notifier chain
*
****************************************************************************/
void watchdog_notifier_chain_unregister(FAR struct notifier_block *nb)
{
atomic_notifier_chain_unregister(&g_watchdog_notifier_list, nb);
}
/****************************************************************************
* Name: watchdog_automonitor_timeout
*
* Description:
* This function can be called in the watchdog timeout interrupt handler.
* If so, callbacks on the watchdog timer notify chain are called when the
* watchdog timer times out.
*
****************************************************************************/
void watchdog_automonitor_timeout(void)
{
atomic_notifier_call_chain(&g_watchdog_notifier_list, action, data);
}
#endif /* CONFIG_WATCHDOG_TIMEOUT_NOTIFIER */
/****************************************************************************
* Name: watchdog_register
*

View file

@ -2618,6 +2618,13 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev)
#endif
flags = enter_critical_section();
if (dev->disconnected)
{
leave_critical_section(flags);
return true;
}
priv->ispolling = true;
EP_POLL(ep);
priv->ispolling = false;
@ -3012,6 +3019,10 @@ void cdcacm_uninitialize(FAR struct usbdevclass_driver_s *classdev)
char devname[CDCACM_DEVNAME_SIZE];
int ret;
/* Disconnect in case we are connected */
cdcacm_disconnect(classdev, priv->usbdev);
#ifndef CONFIG_CDCACM_COMPOSITE
usbdev_unregister(&drvr->drvr);
#endif

View file

@ -30,6 +30,7 @@
#include <stdlib.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spinlock.h>
#include <nuttx/vhost/vhost.h>
#include <nuttx/wqueue.h>
@ -151,7 +152,7 @@ static int vhost_rng_probe(FAR struct vhost_device *hdev)
vqnames[0] = "virtio_rng";
callback[0] = vhost_rng_handler;
ret = vhost_create_virtqueues(hdev, 0, 1, vqnames, callback);
ret = vhost_create_virtqueues(hdev, 0, 1, vqnames, callback, NULL);
if (ret < 0)
{
vhosterr("virtio_device_create_virtqueue failed, ret=%d\n", ret);

View file

@ -83,8 +83,15 @@ static struct vhost_bus_s g_vhost_bus =
static bool vhost_status_driver_ok(FAR struct vhost_device *hdev)
{
uint8_t status = vhost_get_status(hdev);
bool driver_ok = false;
uint8_t status;
int ret;
ret = vhost_get_status(hdev, &status);
if (ret)
{
return driver_ok;
}
/* Busy wait until the remote is ready */

View file

@ -29,6 +29,8 @@
#include <nuttx/config.h>
#ifndef __ASSEMBLY__
#ifdef CONFIG_BUILD_KERNEL
# include <signal.h>
#endif
@ -40,6 +42,8 @@
#include <arch/arch.h>
#endif /* __ASSEMBLY__ */
#ifdef CONFIG_ARCH_ADDRENV
/****************************************************************************
@ -241,6 +245,9 @@
(CONFIG_ARCH_PGPOOL_VBASE + CONFIG_ARCH_PGPOOL_SIZE)
#endif
#ifndef __ASSEMBLY__
/****************************************************************************
* Public Type Definitions
****************************************************************************/
@ -251,8 +258,6 @@ struct tcb_s; /* Forward reference to TCB */
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
struct addrenv_s
{
struct arch_addrenv_s addrenv; /* The address environment page directory */

View file

@ -48,7 +48,7 @@
#endif
#ifndef ALIGN_UP
# define ALIGN_UP(x,a) (((x) + ((a) - 1)) & ~((a) - 1))
# define ALIGN_UP(x,a) ((((x) + (a) - 1) / (a)) * (a))
#endif
#ifndef ALIGN_UP_MASK
@ -56,7 +56,7 @@
#endif
#ifndef ALIGN_DOWN
# define ALIGN_DOWN(x,a) ((x) & (~((a) - 1)))
# define ALIGN_DOWN(x,a) (((x) / (a)) * (a))
#endif
#ifndef ALIGN_DOWN_MASK

View file

@ -106,14 +106,6 @@ void sched_note_spinlock_unlock(FAR volatile spinlock_t *spinlock);
* Public Data Types
****************************************************************************/
/* Used for access control */
extern volatile spinlock_t g_irq_spin;
/* Handles nested calls to spin_lock_irqsave and spin_unlock_irqrestore */
extern volatile uint8_t g_irq_spin_count[CONFIG_SMP_NCPUS];
/****************************************************************************
* Name: up_testset
*
@ -448,26 +440,12 @@ static inline_function void spin_unlock(FAR volatile spinlock_t *lock)
static inline_function
irqstate_t spin_lock_irqsave_wo_note(FAR volatile spinlock_t *lock)
{
irqstate_t ret;
ret = up_irq_save();
irqstate_t flags;
flags = up_irq_save();
if (NULL == lock)
{
int me = this_cpu();
if (0 == g_irq_spin_count[me])
{
spin_lock_wo_note(&g_irq_spin);
}
spin_lock_wo_note(lock);
g_irq_spin_count[me]++;
DEBUGASSERT(0 != g_irq_spin_count[me]);
}
else
{
spin_lock_wo_note(lock);
}
return ret;
return flags;
}
#else
# define spin_lock_irqsave_wo_note(l) ((void)(l), up_irq_save())
@ -478,14 +456,7 @@ irqstate_t spin_lock_irqsave_wo_note(FAR volatile spinlock_t *lock)
*
* Description:
* If SMP is enabled:
* If the argument lock is not specified (i.e. NULL),
* disable local interrupts and take the global spinlock (g_irq_spin)
* if the call counter (g_irq_spin_count[cpu]) equals to 0. Then the
* counter on the CPU is incremented to allow nested calls and return
* the interrupt state.
*
* If the argument lock is specified,
* disable local interrupts and take the lock spinlock and return
* Disable local interrupts and take the lock spinlock and return
* the interrupt state.
*
* NOTE: This API is very simple to protect data (e.g. H/W register
@ -496,9 +467,7 @@ irqstate_t spin_lock_irqsave_wo_note(FAR volatile spinlock_t *lock)
* This function is equivalent to up_irq_save().
*
* Input Parameters:
* lock - Caller specific spinlock. If specified NULL, g_irq_spin is used
* and can be nested. Otherwise, nested call for the same lock
* would cause a deadlock
* lock - Caller specific spinlock. not NULL.
*
* Returned Value:
* An opaque, architecture-specific value that represents the state of
@ -618,21 +587,7 @@ static inline_function
void spin_unlock_irqrestore_wo_note(FAR volatile spinlock_t *lock,
irqstate_t flags)
{
if (NULL == lock)
{
int me = this_cpu();
DEBUGASSERT(0 < g_irq_spin_count[me]);
g_irq_spin_count[me]--;
if (0 == g_irq_spin_count[me])
{
spin_unlock_wo_note(&g_irq_spin);
}
}
else
{
spin_unlock_wo_note(lock);
}
spin_unlock_wo_note(lock);
up_irq_restore(flags);
}
@ -645,21 +600,14 @@ void spin_unlock_irqrestore_wo_note(FAR volatile spinlock_t *lock,
*
* Description:
* If SMP is enabled:
* If the argument lock is not specified (i.e. NULL),
* decrement the call counter (g_irq_spin_count[cpu]) and if it
* decrements to zero then release the spinlock (g_irq_spin) and
* restore the interrupt state as it was prior to the previous call to
* spin_lock_irqsave(NULL).
*
* If the argument lock is specified, release the lock and
* restore the interrupt state as it was prior to the previous call to
* spin_lock_irqsave(lock).
* Release the lock and restore the interrupt state as it was prior
* to the previous call to spin_lock_irqsave(lock).
*
* If SMP is not enabled:
* This function is equivalent to up_irq_restore().
*
* Input Parameters:
* lock - Caller specific spinlock. If specified NULL, g_irq_spin is used.
* lock - Caller specific spinlock. not NULL
*
* flags - The architecture-specific value that represents the state of
* the interrupts prior to the call to spin_lock_irqsave(lock);

View file

@ -31,6 +31,7 @@
#include <nuttx/compiler.h>
#include <nuttx/irq.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/notifier.h>
#ifdef CONFIG_WATCHDOG
@ -88,6 +89,35 @@
#define WDFLAGS_CAPTURE (1 << 2) /* 1=Call the user function when the
* watchdog timer expires */
/* Keepalive Actions ********************************************************/
/* According to the keepalive action specified by the Auto-monitor, callback
* functions registered on the watchdog notifier chain may take corresponding
* actions.
*
* These are detected and handled by the "upper half" watchdog timer driver.
*
* WATCHDOG_KEEPALIVE_BY_ONESHOT - The watchdog timer is keepalive by
* oneshot timer.
* WATCHDOG_KEEPALIVE_BY_TIMER - The watchdog timer is keepalive by
* timer.
* WATCHDOG_KEEPALIVE_BY_WDOG - The watchdog timer is keepalive by
* wdog.
* WATCHDOG_KEEPALIVE_BY_WORKER - The watchdog timer is keepalive by
* worker queue.
* WATCHDOG_KEEPALIVE_BY_CAPTURE - The watchdog timer is keepalive by
* capture.
* WATCHDOG_KEEPALIVE_BY_IDLE - The watchdog timer is keepalive by
* idle task.
*/
#define WATCHDOG_KEEPALIVE_BY_ONESHOT 0
#define WATCHDOG_KEEPALIVE_BY_TIMER 1
#define WATCHDOG_KEEPALIVE_BY_WDOG 2
#define WATCHDOG_KEEPALIVE_BY_WORKER 3
#define WATCHDOG_KEEPALIVE_BY_CAPTURE 4
#define WATCHDOG_KEEPALIVE_BY_IDLE 5
/****************************************************************************
* Public Types
****************************************************************************/
@ -197,6 +227,47 @@ extern "C"
#define EXTERN extern
#endif
#ifdef CONFIG_WATCHDOG_TIMEOUT_NOTIFIER
/****************************************************************************
* Name: watchdog_notifier_chain_register
*
* Description:
* Add notifier to the watchdog notifier chain
*
* Input Parameters:
* nb - New entry in notifier chain
*
****************************************************************************/
void watchdog_notifier_chain_register(FAR struct notifier_block *nb);
/****************************************************************************
* Name: watchdog_notifier_chain_unregister
*
* Description:
* Remove notifier from the watchdog notifier chain
*
* Input Parameters:
* nb - Entry to remove from notifier chain
*
****************************************************************************/
void watchdog_notifier_chain_unregister(FAR struct notifier_block *nb);
/****************************************************************************
* Name: watchdog_automonitor_timeout
*
* Description:
* This function can be called in the watchdog timeout interrupt handler.
* If so, callbacks on the watchdog timer notify chain are called when the
* watchdog timer times out.
*
****************************************************************************/
void watchdog_automonitor_timeout(void);
#endif /* CONFIG_WATCHDOG_TIMEOUT_NOTIFIER */
/****************************************************************************
* Name: watchdog_register
*

View file

@ -1,2 +1,3 @@
/exec_symtab.c
/modlib_symtab.c
modlib/gnu-elf.ld

View file

@ -183,6 +183,10 @@ context:: bin kbin
ifeq ($(CONFIG_LIBC_ZONEINFO_ROMFS),y)
$(Q) $(MAKE) -C zoneinfo context BIN=$(BIN)
endif
ifeq ($(CONFIG_LIBC_MODLIB),y)
$(Q) $(MAKE) -C modlib context
endif
# Dependencies
@ -210,6 +214,7 @@ depend:: .depend
clean::
$(Q) $(MAKE) -C zoneinfo clean BIN=$(BIN)
$(Q) $(MAKE) -C modlib clean
$(call DELFILE, $(BIN))
$(call DELFILE, $(KBIN))
$(call CLEAN)
@ -218,6 +223,7 @@ clean::
distclean:: clean
$(Q) $(MAKE) -C zoneinfo distclean BIN=$(BIN)
$(Q) $(MAKE) -C modlib distclean
$(call DELFILE, exec_symtab.c)
$(call DELFILE, .depend)
$(call DELDIR, bin)

40
libs/libc/modlib/Makefile Normal file
View file

@ -0,0 +1,40 @@
############################################################################
# libs/libc/modlib/Makefile
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(TOPDIR)/Make.defs
# Generate gnu-elf.ld from gnu-elf.ld.in
gnu-elf.ld: gnu-elf.ld.in
$(call PREPROCESS, $<, $@)
# Create initial context
context: gnu-elf.ld
.PHONY: context clean distclean
clean:
$(call CLEAN)
distclean: clean
$(call DELFILE, gnu-elf.ld)

View file

@ -1,5 +1,5 @@
/****************************************************************************
* libs/libc/modlib/gnu-elf.ld
* libs/libc/modlib/gnu-elf.ld.in
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -18,9 +18,23 @@
*
****************************************************************************/
#include <nuttx/config.h>
#if defined(CONFIG_BUILD_KERNEL) && defined(CONFIG_BINFMT_ELF_EXECUTABLE)
# define __ASSEMBLY__
# include <nuttx/addrenv.h>
# define TEXT CONFIG_ARCH_TEXT_VBASE
# define DATA CONFIG_ARCH_DATA_VBASE + ARCH_DATA_RESERVE_SIZE
#else
# define TEXT 0x0
# define DATA
#endif
SECTIONS
{
.text 0x00000000 :
.text TEXT :
{
_stext = . ;
*(.text)
@ -58,7 +72,7 @@ SECTIONS
_erodata = . ;
}
.data :
.data DATA :
{
_sdata = . ;
*(.data)

View file

@ -397,16 +397,17 @@ retry:
pool->nalloc++;
spin_unlock_irqrestore(&pool->lock, flags);
blk = kasan_unpoison(blk, pool->blocksize);
#ifdef CONFIG_MM_FILL_ALLOCATIONS
memset(blk, MM_ALLOC_MAGIC, pool->blocksize);
#endif
#if CONFIG_MM_BACKTRACE >= 0
mempool_add_backtrace(pool, (FAR struct mempool_backtrace_s *)
((FAR char *)blk + pool->blocksize));
#endif
blk = kasan_unpoison(blk, pool->blocksize);
#ifdef CONFIG_MM_FILL_ALLOCATIONS
memset(blk, MM_ALLOC_MAGIC, pool->blocksize);
#endif
return blk;
}

View file

@ -282,6 +282,8 @@ typedef CODE void (*mm_node_handler_t)(FAR struct mm_allocnode_s *node,
int mm_lock(FAR struct mm_heap_s *heap);
void mm_unlock(FAR struct mm_heap_s *heap);
irqstate_t mm_lock_irq(FAR struct mm_heap_s *heap);
void mm_unlock_irq(FAR struct mm_heap_s *heap, irqstate_t state);
/* Functions contained in mm_shrinkchunk.c **********************************/

View file

@ -49,7 +49,7 @@ static void add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem)
/* Delay the deallocation until a more appropriate time. */
flags = up_irq_save();
flags = mm_lock_irq(heap);
# ifdef CONFIG_DEBUG_ASSERTIONS
FAR struct mm_freenode_s *node;
@ -65,7 +65,7 @@ static void add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem)
heap->mm_delaycount[this_cpu()]++;
#endif
up_irq_restore(flags);
mm_unlock_irq(heap, flags);
#endif
}

View file

@ -117,3 +117,31 @@ void mm_unlock(FAR struct mm_heap_s *heap)
DEBUGVERIFY(nxmutex_unlock(&heap->mm_lock));
}
/****************************************************************************
* Name: mm_lock_irq
*
* Description:
* Locking by pausing interruption
*
****************************************************************************/
irqstate_t mm_lock_irq(FAR struct mm_heap_s *heap)
{
UNUSED(heap);
return up_irq_save();
}
/****************************************************************************
* Name: mm_unlock_irq
*
* Description:
* Release the lock by resuming the interrupt
*
****************************************************************************/
void mm_unlock_irq(FAR struct mm_heap_s *heap, irqstate_t state)
{
UNUSED(heap);
up_irq_restore(state);
}

View file

@ -65,7 +65,7 @@ static bool free_delaylist(FAR struct mm_heap_s *heap, bool force)
/* Move the delay list to local */
flags = up_irq_save();
flags = mm_lock_irq(heap);
tmp = heap->mm_delaylist[this_cpu()];
@ -74,7 +74,7 @@ static bool free_delaylist(FAR struct mm_heap_s *heap, bool force)
(!force &&
heap->mm_delaycount[this_cpu()] < CONFIG_MM_FREE_DELAYCOUNT_MAX))
{
up_irq_restore(flags);
mm_unlock_irq(heap, flags);
return false;
}
@ -83,7 +83,7 @@ static bool free_delaylist(FAR struct mm_heap_s *heap, bool force)
heap->mm_delaylist[this_cpu()] = NULL;
up_irq_restore(flags);
mm_unlock_irq(heap, flags);
/* Test if the delayed is empty */

View file

@ -181,6 +181,34 @@ static void mm_delayfree(struct mm_heap_s *heap, void *mem, bool delay);
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: mm_lock_irq
*
* Description:
* Locking by pausing interruption
*
****************************************************************************/
static irqstate_t mm_lock_irq(FAR struct mm_heap_s *heap)
{
UNUSED(heap);
return up_irq_save();
}
/****************************************************************************
* Name: mm_unlock_irq
*
* Description:
* Release the lock by resuming the interrupt
*
****************************************************************************/
static void mm_unlock_irq(FAR struct mm_heap_s *heap, irqstate_t state)
{
UNUSED(heap);
up_irq_restore(state);
}
static void memdump_allocnode(FAR void *ptr, size_t size)
{
#if CONFIG_MM_BACKTRACE < 0
@ -301,7 +329,7 @@ static void add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem)
/* Delay the deallocation until a more appropriate time. */
flags = up_irq_save();
flags = mm_lock_irq(heap);
tmp->flink = heap->mm_delaylist[this_cpu()];
heap->mm_delaylist[this_cpu()] = tmp;
@ -310,7 +338,7 @@ static void add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem)
heap->mm_delaycount[this_cpu()]++;
#endif
up_irq_restore(flags);
mm_unlock_irq(heap, flags);
#endif
}
@ -327,7 +355,7 @@ static bool free_delaylist(FAR struct mm_heap_s *heap, bool force)
/* Move the delay list to local */
flags = up_irq_save();
flags = mm_lock_irq(heap);
tmp = heap->mm_delaylist[this_cpu()];
@ -336,7 +364,7 @@ static bool free_delaylist(FAR struct mm_heap_s *heap, bool force)
(!force &&
heap->mm_delaycount[this_cpu()] < CONFIG_MM_FREE_DELAYCOUNT_MAX))
{
up_irq_restore(flags);
mm_unlock_irq(heap, flags);
return false;
}
@ -345,7 +373,7 @@ static bool free_delaylist(FAR struct mm_heap_s *heap, bool force)
heap->mm_delaylist[this_cpu()] = NULL;
up_irq_restore(flags);
mm_unlock_irq(heap, flags);
/* Test if the delayed is empty */

View file

@ -39,14 +39,6 @@
* Public Data
****************************************************************************/
/* Used for access control */
volatile spinlock_t g_irq_spin = SP_UNLOCKED;
/* Handles nested calls to spin_lock_irqsave and spin_unlock_irqrestore */
volatile uint8_t g_irq_spin_count[CONFIG_SMP_NCPUS];
/****************************************************************************
* Public Functions
****************************************************************************/

View file

@ -617,6 +617,17 @@ static const char *g_white_content_list[] =
"unzGetCurrentFileInfo64",
"unzGoToNextFile",
"unzGoToFirstFile",
/* Ref:
* apps/netutils/telnetc/telnetc.c
*/
"deflateInit",
"deflateEnd",
"inflateInit",
"inflateEnd",
"zError",
NULL
};