implementare RS485
On this page
Uno dei protocolli fisici più utilizzati in campo industriale è RS485,
che permette di creare un bus di comunicazione tra molteplici dispositivi
con solo 2 cavi ed è adatto alla comunicazione su lunghe distanze.
Nel kernel linux è già implementata la logica del driver per poter gestire
periferiche rs485, ma questo non è sufficiente.
È necessario un componente che permetta di pilotare
la nostra periferica hardware a partire dai comandi ricevuti dal kernel.
Facendola breve, possiamo utilizzare una semplice porta UART,
ma è necessario che sia disponibile un pin che segnali
quando il nostro dispositivo ha intenzione di comunicare.
Il microprocessore stm32mp2xx contiene molte periferiche,
ma non dispone direttamente di una rs485.
Dal datasheet
possiamo vedere che sono presenti 9 UART
e che tutte permettono di pilotare un pin di flow control durante la trasmissione.
STM32MP25xC/F devices embed four USART and five UART (see Table 8. USART/UART features for feature
summary).
They provide hardware management of CTS and RTS signals, and RS485 driver enable.
They can communicate at speeds of up to 12 Mbit/s.
All USARTs provide smartcard mode (ISO 7816 compliant) and SPI-like communication capability.
All USARTs can be served by the DMA controller.Andiamo quindi a vedere come abilitare
la nostra scheda per il RS485,
che ci permetterà di implementare in seguito
protocolli come Modbus o altri.
DTS
Ispezionando i device tree forniti da st
1// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
2/*
3 * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
4 * Author: Alexandre Torgue <[email protected]> for STMicroelectronics.
5 */
6
7/dts-v1/;
8
9#include <dt-bindings/gpio/gpio.h>
10#include <dt-bindings/input/input.h>
11#include <dt-bindings/leds/common.h>
12#include <dt-bindings/rtc/rtc-stm32.h>
13#include "stm32mp257.dtsi"
14#include "stm32mp25xf.dtsi"
15#include "stm32mp25-pinctrl.dtsi"
16#include "stm32mp25xxak-pinctrl.dtsi"
17#include "stm32mp257f-dk-resmem.dtsi"
18
19/ {
20 model = "STMicroelectronics STM32MP257F-DK Discovery Board";
21 compatible = "st,stm32mp257f-dk", "st,stm32mp257";
22
23 aliases {
24 serial0 = &usart2;
25 serial1 = &usart6;
26 serial2 = &usart1;
27 ethernet0 = ð1;
28 };843/* Bluetooth */
844&usart1 {
845 pinctrl-names = "default", "sleep", "idle";
846 pinctrl-0 = <&usart1_pins_a>;
847 pinctrl-1 = <&usart1_sleep_pins_a>;
848 pinctrl-2 = <&usart1_idle_pins_a>;
849 uart-has-rtscts;
850 status = "okay";
851
852 bluetooth {
853 shutdown-gpios = <&gpiog 4 GPIO_ACTIVE_HIGH>;
854 compatible = "brcm,bcm43438-bt";
855 clocks = <&rtc>;
856 clock-names = "lpo";
857 max-speed = <2000000>;
858 vbat-supply = <&scmi_v3v3>;
859 vddio-supply = <&scmi_v3v3>;
860 };
861};
862
863&usart2 {
864 bootph-all;
865 pinctrl-names = "default", "idle", "sleep";
866 pinctrl-0 = <&usart2_pins_a>;
867 pinctrl-1 = <&usart2_idle_pins_a>;
868 pinctrl-2 = <&usart2_sleep_pins_a>;
869 /delete-property/dmas;
870 /delete-property/dma-names;
871 status = "okay";
872};
873
874&usart2_pins_a {
875 bootph-all;
876 pins1 {
877 bootph-all;
878 };
879 pins2 {
880 bootph-all;
881 };
882};
883
884&usart6 {
885 pinctrl-names = "default", "idle", "sleep";
886 pinctrl-0 = <&usart6_pins_a>;
887 pinctrl-1 = <&usart6_idle_pins_a>;
888 pinctrl-2 = <&usart6_sleep_pins_a>;
889 uart-has-rtscts;
890 status = "disabled";
891};Notiamo che sono già configurate 3 UART.
usart1è dedicata ad una periferica bluetoothusart2è abilitata già al boot e potrebbe essere la porta seriale di defaultusart6è disabilitata e presenta un parametrouart-has-rtsctsche suggerisce la presenza di un flow control
Esplorando anche i file dtsi che vengono inclusi nel dts:
1117usart6: serial@40220000 {
1118 compatible = "st,stm32h7-uart";
1119 reg = <0x40220000 0x400>;
1120 interrupts-extended = <&exti1 29 IRQ_TYPE_LEVEL_HIGH>;
1121 clocks = <&rcc CK_KER_USART6>;
1122 dmas = <&hpdma 19 0x20 0x10012>,
1123 <&hpdma 20 0x20 0x3021>;
1124 dma-names = "rx", "tx";
1125 access-controllers = <&rifsc 36>;
1126 power-domains = <&d1_pd>;
1127 wakeup-source;
1128 status = "disabled";
1129 };1#include <dt-bindings/pinctrl/stm32-pinfunc.h>875usart6_pins_a: usart6-0 {
876 pins1 {
877 pinmux = <STM32_PINMUX('F', 13, AF3)>, /* USART6_TX */
878 <STM32_PINMUX('G', 5, AF3)>; /* USART6_RTS */
879 bias-disable;
880 drive-push-pull;
881 slew-rate = <0>;
882 };
883 pins2 {
884 pinmux = <STM32_PINMUX('F', 14, AF3)>, /* USART6_RX */
885 <STM32_PINMUX('F', 15, AF3)>; /* USART6_CTS_NSS */
886 bias-pull-up;
887 };
888 };
889
890 usart6_idle_pins_a: usart6-idle-0 {
891 pins1 {
892 pinmux = <STM32_PINMUX('F', 13, ANALOG)>, /* USART6_TX */
893 <STM32_PINMUX('F', 15, ANALOG)>; /* USART6_CTS_NSS */
894 };
895 pins2 {
896 pinmux = <STM32_PINMUX('G', 5, AF3)>; /* USART6_RTS */
897 bias-disable;
898 drive-push-pull;
899 slew-rate = <0>;
900 };
901 pins3 {
902 pinmux = <STM32_PINMUX('F', 14, AF3)>; /* USART6_RX */
903 bias-pull-up;
904 };
905 };
906
907 usart6_sleep_pins_a: usart6-sleep-0 {
908 pins {
909 pinmux = <STM32_PINMUX('F', 13, ANALOG)>, /* USART6_TX */
910 <STM32_PINMUX('G', 5, ANALOG)>, /* USART6_RTS */
911 <STM32_PINMUX('F', 15, ANALOG)>, /* USART6_CTS_NSS */
912 <STM32_PINMUX('F', 14, ANALOG)>; /* USART6_RX */
913 };
914 };Per capire come i parametri presenti nel device-tree
vengono interpretati dobbiamo analizzare il campo compatible,
in quanto il suo valore ci indica quale driver sarà associato.
1118compatible = "st,stm32h7-uart";E cercando la stringa st,stm32h7-uart nella cartella drivers otteniamo:
0grep -r "st,stm32h7-uart" drivers0drivers/tty/serial/stm32-usart.cE all’interno di stm32-usart.c vediamo che il codice
si occupa di configurare struct serial_rs485,
che è il compito richiesto ad un driver rs485.
Quindi questo è il kernel driver che ci interessa
e corrisponde alle seguenti stringhe compatible:
2017#ifdef CONFIG_OF
2018static const struct of_device_id stm32_match[] = {
2019 { .compatible = "st,stm32-uart", .data = &stm32f4_info},
2020 { .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
2021 { .compatible = "st,stm32h7-uart", .data = &stm32h7_info},
2022 {},
2023};
2024
2025MODULE_DEVICE_TABLE(of, stm32_match);
2026#endifPer
rs485
