From 66ccaed5ce268f985cefa5c32e74bab2335f8ace Mon Sep 17 00:00:00 2001 From: Rodrigo Sim Date: Sat, 11 Nov 2023 16:44:03 -0300 Subject: [PATCH] stm32f4/stm32f401rc-rs485: add support to userleds --- .../stm32/stm32f401rc-rs485/include/board.h | 23 +- .../stm32f401rc-rs485/src/CMakeLists.txt | 4 + .../arm/stm32/stm32f401rc-rs485/src/Make.defs | 4 + .../stm32f401rc-rs485/src/stm32_bringup.c | 14 ++ .../stm32f401rc-rs485/src/stm32_userleds.c | 214 ++++++++++++++++++ .../stm32f401rc-rs485/src/stm32f401rc-rs485.h | 14 +- 6 files changed, 262 insertions(+), 11 deletions(-) create mode 100644 boards/arm/stm32/stm32f401rc-rs485/src/stm32_userleds.c diff --git a/boards/arm/stm32/stm32f401rc-rs485/include/board.h b/boards/arm/stm32/stm32f401rc-rs485/include/board.h index 947d49d8bc..da9a00b7ae 100644 --- a/boards/arm/stm32/stm32f401rc-rs485/include/board.h +++ b/boards/arm/stm32/stm32f401rc-rs485/include/board.h @@ -36,9 +36,8 @@ /* Clocking *****************************************************************/ -/* The STM32F401RC-RS485 supports both HSE and LSE crystals (X2 and X3). - * However, as shipped, the X2 and X3 crystals are not populated. - * Therefore the Nucleo-F401RE will need to run off the 16MHz HSI clock. +/* The STM32F401RC-RS485 uses an external 32kHz cristal (X2) to enable HSE + * clock. * * System Clock source : PLL (HSI) * SYSCLK(Hz) : 84000000 Determined by PLL @@ -335,22 +334,26 @@ extern "C" /* LEDs * - * The Nucleo F401RE and F411RE boards provide a single user LED, LD2. LD2 - * is the green LED connected to Arduino signal D13 corresponding to MCU I/O - * PA5 (pin 21) or PB13 (pin 34) depending on the STM32 target. - * + * The STM32F401RC-RS485 boards provide 4 blue user LEDs. LD1, LD2, LD3 + * and LD4 that are connected to MCU I/O pins PC0, PC1, PC2 and PC3. * - When the I/O is HIGH value, the LED is on. * - When the I/O is LOW, the LED is off. */ /* LED index values for use with board_userled() */ -#define BOARD_LD2 0 -#define BOARD_NLEDS 1 +#define BOARD_LD1 0 +#define BOARD_LD2 1 +#define BOARD_LD3 2 +#define BOARD_LD4 3 +#define BOARD_NLEDS 4 /* LED bits for use with board_userled_all() */ -#define BOARD_LD2_BIT (1 << BOARD_LD2) +#define BOARD_LED1_BIT (1 << BOARD_LD1) +#define BOARD_LED2_BIT (1 << BOARD_LD2) +#define BOARD_LED3_BIT (1 << BOARD_LD3) +#define BOARD_LED4_BIT (1 << BOARD_LD4) /* These LEDs are not used by the board port unless CONFIG_ARCH_LEDS is * defined. In that case, the usage by the board port is defined in diff --git a/boards/arm/stm32/stm32f401rc-rs485/src/CMakeLists.txt b/boards/arm/stm32/stm32f401rc-rs485/src/CMakeLists.txt index 9162a3204b..249619b5f7 100644 --- a/boards/arm/stm32/stm32f401rc-rs485/src/CMakeLists.txt +++ b/boards/arm/stm32/stm32f401rc-rs485/src/CMakeLists.txt @@ -24,6 +24,10 @@ if(CONFIG_ARCH_LEDS) list(APPEND SRCS stm32_autoleds.c) endif() +if(CONFIG_USERLED) + list(APPEND SRCS stm32_userleds.c) +endif() + if(CONFIG_BOARDCTL) list(APPEND SRCS stm32_appinit.c) endif() diff --git a/boards/arm/stm32/stm32f401rc-rs485/src/Make.defs b/boards/arm/stm32/stm32f401rc-rs485/src/Make.defs index ba63091126..d7a3d689cf 100644 --- a/boards/arm/stm32/stm32f401rc-rs485/src/Make.defs +++ b/boards/arm/stm32/stm32f401rc-rs485/src/Make.defs @@ -27,6 +27,10 @@ ifeq ($(CONFIG_ARCH_LEDS),y) CSRCS += stm32_autoleds.c endif +ifeq ($(CONFIG_USERLED),y) +CSRCS += stm32_userleds.c +endif + ifeq ($(CONFIG_BOARDCTL),y) CSRCS += stm32_appinit.c endif diff --git a/boards/arm/stm32/stm32f401rc-rs485/src/stm32_bringup.c b/boards/arm/stm32/stm32f401rc-rs485/src/stm32_bringup.c index 0baef6aae3..f14e2504e7 100644 --- a/boards/arm/stm32/stm32f401rc-rs485/src/stm32_bringup.c +++ b/boards/arm/stm32/stm32f401rc-rs485/src/stm32_bringup.c @@ -35,6 +35,10 @@ #include +#ifdef CONFIG_USERLED +# include +#endif + #include "stm32f401rc-rs485.h" #include @@ -61,5 +65,15 @@ int stm32_bringup(void) { int ret = OK; +#ifdef CONFIG_USERLED + /* Register the LED driver */ + + ret = userled_lower_initialize("/dev/userleds"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: userled_lower_initialize() failed: %d\n", ret); + } +#endif + return ret; } diff --git a/boards/arm/stm32/stm32f401rc-rs485/src/stm32_userleds.c b/boards/arm/stm32/stm32f401rc-rs485/src/stm32_userleds.c new file mode 100644 index 0000000000..83e1cabd79 --- /dev/null +++ b/boards/arm/stm32/stm32f401rc-rs485/src/stm32_userleds.c @@ -0,0 +1,214 @@ +/**************************************************************************** + * boards/arm/stm32/stm32f401rc-rs485/src/stm32_userleds.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "chip.h" +#include "arm_internal.h" +#include "stm32.h" +#include "stm32f401rc-rs485.h" + +#ifndef CONFIG_ARCH_LEDS + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This array maps an LED number to GPIO pin configuration */ + +static uint32_t g_ledcfg[BOARD_NLEDS] = +{ + GPIO_LED1, GPIO_LED2, GPIO_LED3, GPIO_LED4 +}; + +/**************************************************************************** + * Private Function Protototypes + ****************************************************************************/ + +/* LED Power Management */ + +#ifdef CONFIG_PM +static void led_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +static int led_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_PM +static struct pm_callback_s g_ledscb = +{ + .notify = led_pm_notify, + .prepare = led_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: led_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void led_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Restore normal LEDs operation */ + } + break; + + case(PM_IDLE): + { + /* Entering IDLE mode - Turn leds off */ + } + break; + + case(PM_STANDBY): + { + /* Entering STANDBY mode - Logic for PM_STANDBY goes here */ + } + break; + + case(PM_SLEEP): + { + /* Entering SLEEP mode - Logic for PM_SLEEP goes here */ + } + break; + + default: + { + /* Should not get here */ + } + break; + } +} +#endif + +/**************************************************************************** + * Name: led_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int led_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* No preparation to change power modes is required by the LEDs driver. + * We always accept the state change by returning OK. + */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_userled_initialize + ****************************************************************************/ + +uint32_t board_userled_initialize(void) +{ + /* Configure LED1-4 GPIOs for output */ + + stm32_configgpio(GPIO_LED1); + stm32_configgpio(GPIO_LED2); + stm32_configgpio(GPIO_LED3); + stm32_configgpio(GPIO_LED4); + return BOARD_NLEDS; +} + +/**************************************************************************** + * Name: board_userled + ****************************************************************************/ + +void board_userled(int led, bool ledon) +{ + if ((unsigned)led < BOARD_NLEDS) + { + stm32_gpiowrite(g_ledcfg[led], ledon); + } +} + +/**************************************************************************** + * Name: board_userled_all + ****************************************************************************/ + +void board_userled_all(uint32_t ledset) +{ + stm32_gpiowrite(GPIO_LED1, (ledset & BOARD_LED1_BIT) != 0); + stm32_gpiowrite(GPIO_LED2, (ledset & BOARD_LED2_BIT) != 0); + stm32_gpiowrite(GPIO_LED3, (ledset & BOARD_LED3_BIT) != 0); + stm32_gpiowrite(GPIO_LED4, (ledset & BOARD_LED4_BIT) != 0); +} + +/**************************************************************************** + * Name: stm32_led_pminitialize + ****************************************************************************/ + +#ifdef CONFIG_PM +void stm32_led_pminitialize(void) +{ + /* Register to receive power management callbacks */ + + int ret = pm_register(&g_ledscb); + if (ret != OK) + { + board_autoled_on(LED_ASSERTION); + } +} +#endif /* CONFIG_PM */ + +#endif /* !CONFIG_ARCH_LEDS */ diff --git a/boards/arm/stm32/stm32f401rc-rs485/src/stm32f401rc-rs485.h b/boards/arm/stm32/stm32f401rc-rs485/src/stm32f401rc-rs485.h index d720588b08..1ba37d46c2 100644 --- a/boards/arm/stm32/stm32f401rc-rs485/src/stm32f401rc-rs485.h +++ b/boards/arm/stm32/stm32f401rc-rs485/src/stm32f401rc-rs485.h @@ -51,7 +51,19 @@ */ #define GPIO_LED1 \ - (GPIO_PORTC | GPIO_PIN0 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | GPIO_PULLUP | \ + (GPIO_PORTC | GPIO_PIN0 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | \ + GPIO_SPEED_50MHz) + +#define GPIO_LED2 \ + (GPIO_PORTC | GPIO_PIN1 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | \ + GPIO_SPEED_50MHz) + +#define GPIO_LED3 \ + (GPIO_PORTC | GPIO_PIN2 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | \ + GPIO_SPEED_50MHz) + +#define GPIO_LED4 \ + (GPIO_PORTC | GPIO_PIN3 | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT | \ GPIO_SPEED_50MHz) /* Buttons