Prusa MINI Firmware overview
pinsDebug_STM32duino.h
Go to the documentation of this file.
1 /**
2  * Marlin 3D Printer Firmware
3  * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 #pragma once
20 
21 #include <Arduino.h>
22 
23 #ifdef NUM_DIGITAL_PINS // Only in ST's Arduino core (STM32duino, STM32Core)
24 
25 /**
26  * Life gets complicated if you want an easy to use 'M43 I' output (in port/pin order)
27  * because the variants in this platform do not always define all the I/O port/pins
28  * that a CPU has.
29  *
30  * VARIABLES:
31  * Ard_num - Arduino pin number - defined by the platform. It is used by digitalRead and
32  * digitalWrite commands and by M42.
33  * - does not contain port/pin info
34  * - is not in port/pin order
35  * - typically a variant will only assign Ard_num to port/pins that are actually used
36  * Index - M43 counter - only used to get Ard_num
37  * x - a parameter/argument used to search the pin_array to try to find a signal name
38  * associated with a Ard_num
39  * Port_pin - port number and pin number for use with CPU registers and printing reports
40  *
41  * Since M43 uses digitalRead and digitalWrite commands, only the Port_pins with an Ard_num
42  * are accessed and/or displayed.
43  *
44  * Three arrays are used.
45  *
46  * digitalPin[] is provided by the platform. It consists of the Port_pin numbers in
47  * Arduino pin number order.
48  *
49  * pin_array is a structure generated by the pins/pinsDebug.h header file. It is generated by
50  * the preprocessor. Only the signals associated with enabled options are in this table.
51  * It contains:
52  * - name of the signal
53  * - the Ard_num assigned by the pins_YOUR_BOARD.h file using the platform defines.
54  * EXAMPLE: "#define KILL_PIN PB1" results in Ard_num of 57. 57 is then used as an
55  * index into digitalPin[] to get the Port_pin number
56  * - if it is a digital or analog signal. PWMs are considered digital here.
57  *
58  * pin_xref is a structure generated by this header file. It is generated by the
59  * preprocessor. It is in port/pin order. It contains just the port/pin numbers defined by the
60  * platform for this variant.
61  * - Ard_num
62  * - printable version of Port_pin
63  *
64  * Routines with an "x" as a parameter/argument are used to search the pin_array to try to
65  * find a signal name associated with a port/pin.
66  *
67  * NOTE - the Arduino pin number is what is used by the M42 command, NOT the port/pin for that
68  * signal. The Arduino pin number is listed by the M43 I command.
69  */
70 
71 extern const PinName digitalPin[]; // provided by the platform
72 
73 ////////////////////////////////////////////////////////
74 //
75 // make a list of the Arduino pin numbers in the Port/Pin order
76 //
77 
78 #define _PIN_ADD_2(NAME_ALPHA, ARDUINO_NUM) { {NAME_ALPHA}, ARDUINO_NUM },
79 #define _PIN_ADD(NAME_ALPHA, ARDUINO_NUM) { NAME_ALPHA, ARDUINO_NUM },
80 #define PIN_ADD(NAME) _PIN_ADD(#NAME, NAME)
81 
82 typedef struct {
83  char Port_pin_alpha[5];
84  pin_t Ard_num;
85 } XrefInfo;
86 
87 const XrefInfo pin_xref[] PROGMEM = {
88  #include "pins_Xref.h"
89 };
90 
91 ////////////////////////////////////////////////////////////
92 
93 #define MODE_PIN_INPUT 0 // Input mode (reset state)
94 #define MODE_PIN_OUTPUT 1 // General purpose output mode
95 #define MODE_PIN_ALT 2 // Alternate function mode
96 #define MODE_PIN_ANALOG 3 // Analog mode
97 
98 #define PIN_NUM(P) (P & 0x000F)
99 #define PIN_NUM_ALPHA_LEFT(P) (((P & 0x000F) < 10) ? ('0' + (P & 0x000F)) : '1')
100 #define PIN_NUM_ALPHA_RIGHT(P) (((P & 0x000F) > 9) ? ('0' + (P & 0x000F) - 10) : 0 )
101 #define PORT_NUM(P) ((P >> 4) & 0x0007)
102 #define PORT_ALPHA(P) ('A' + (P >> 4))
103 
104 /**
105  * Translation of routines & variables used by pinsDebug.h
106  */
107 #define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS
108 #define VALID_PIN(ANUM) ((ANUM) >= 0 && (ANUM) < NUMBER_PINS_TOTAL)
109 #define digitalRead_mod(Ard_num) extDigitalRead(Ard_num) // must use Arduino pin numbers when doing reads
110 #define PRINT_PIN(Q)
111 #define PRINT_PORT(ANUM) port_print(ANUM)
112 #define DIGITAL_PIN_TO_ANALOG_PIN(ANUM) -1 // will report analog pin number in the print port routine
113 #define GET_PIN_MAP_PIN_M43(Index) pin_xref[Index].Ard_num
114 
115 // x is a variable used to search pin_array
116 #define GET_ARRAY_IS_DIGITAL(x) ((bool) pin_array[x].is_digital)
117 #define GET_ARRAY_PIN(x) ((pin_t) pin_array[x].pin)
118 #define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0)
119 #define MULTI_NAME_PAD 33 // space needed to be pretty if not first name assigned to a pin
120 
121 #ifndef M43_NEVER_TOUCH
122  #define _M43_NEVER_TOUCH(Index) (Index >= 9 && Index <= 12) // SERIAL/USB pins: PA9(TX) PA10(RX) PA11(USB_DM) PA12(USB_DP)
123  #ifdef KILL_PIN
124  #define M43_NEVER_TOUCH(Index) m43_never_touch(Index)
125 
126  bool m43_never_touch(const pin_t Index) {
127  static pin_t M43_kill_index = -1;
128  if (M43_kill_index < 0)
129  for (M43_kill_index = 0; M43_kill_index < NUMBER_PINS_TOTAL; M43_kill_index++)
130  if (KILL_PIN == GET_PIN_MAP_PIN_M43(M43_kill_index)) break;
131  return _M43_NEVER_TOUCH(Index) || Index == M43_kill_index; // KILL_PIN and SERIAL/USB
132  }
133  #else
134  #define M43_NEVER_TOUCH(Index) _M43_NEVER_TOUCH(Index)
135  #endif
136 #endif
137 
138 uint8_t get_pin_mode(const pin_t Ard_num) {
139  uint32_t mode_all = 0;
140  const PinName dp = digitalPin[Ard_num];
141  switch (PORT_ALPHA(dp)) {
142  case 'A' : mode_all = GPIOA->MODER; break;
143  case 'B' : mode_all = GPIOB->MODER; break;
144  case 'C' : mode_all = GPIOC->MODER; break;
145  case 'D' : mode_all = GPIOD->MODER; break;
146  #ifdef PE_0
147  case 'E' : mode_all = GPIOE->MODER; break;
148  #elif defined(PF_0)
149  case 'F' : mode_all = GPIOF->MODER; break;
150  #elif defined(PG_0)
151  case 'G' : mode_all = GPIOG->MODER; break;
152  #elif defined(PH_0)
153  case 'H' : mode_all = GPIOH->MODER; break;
154  #elif defined(PI_0)
155  case 'I' : mode_all = GPIOI->MODER; break;
156  #elif defined(PJ_0)
157  case 'J' : mode_all = GPIOJ->MODER; break;
158  #elif defined(PK_0)
159  case 'K' : mode_all = GPIOK->MODER; break;
160  #elif defined(PL_0)
161  case 'L' : mode_all = GPIOL->MODER; break;
162  #endif
163  }
164  return (mode_all >> (2 * uint8_t(PIN_NUM(dp)))) & 0x03;
165 }
166 
167 bool GET_PINMODE(const pin_t Ard_num) {
168  const uint8_t pin_mode = get_pin_mode(Ard_num);
169  return pin_mode == MODE_PIN_OUTPUT || pin_mode == MODE_PIN_ALT; // assume all alt definitions are PWM
170 }
171 
172 int8_t digital_pin_to_analog_pin(pin_t Ard_num) {
173  Ard_num -= NUM_ANALOG_FIRST;
174  return (Ard_num >= 0 && Ard_num < NUM_ANALOG_INPUTS) ? Ard_num : -1;
175 }
176 
177 bool IS_ANALOG(const pin_t Ard_num) {
178  return get_pin_mode(Ard_num) == MODE_PIN_ANALOG;
179 }
180 
181 bool is_digital(const pin_t x) {
182  const uint8_t pin_mode = get_pin_mode(pin_array[x].pin);
183  return pin_mode == MODE_PIN_INPUT || pin_mode == MODE_PIN_OUTPUT;
184 }
185 
186 void port_print(const pin_t Ard_num) {
187  char buffer[16];
188  pin_t Index;
189  for (Index = 0; Index < NUMBER_PINS_TOTAL; Index++)
190  if (Ard_num == GET_PIN_MAP_PIN_M43(Index)) break;
191 
192  const char * ppa = pin_xref[Index].Port_pin_alpha;
193  sprintf_P(buffer, PSTR("%s"), ppa);
194  SERIAL_ECHO(buffer);
195  if (ppa[3] == '\0') SERIAL_CHAR(' ');
196 
197  // print analog pin number
198  const int8_t Port_pin = digital_pin_to_analog_pin(Ard_num);
199  if (Port_pin >= 0) {
200  sprintf_P(buffer, PSTR(" (A%d) "), Port_pin);
201  SERIAL_ECHO(buffer);
202  if (Port_pin < 10) SERIAL_CHAR(' ');
203  }
204  else
205  SERIAL_ECHO_SP(7);
206 
207  // Print number to be used with M42
208  sprintf_P(buffer, PSTR(" M42 P%d "), Ard_num);
209  SERIAL_ECHO(buffer);
210  if (Ard_num < 10) SERIAL_CHAR(' ');
211  if (Ard_num < 100) SERIAL_CHAR(' ');
212 }
213 
214 bool pwm_status(const pin_t Ard_num) {
215  return get_pin_mode(Ard_num) == MODE_PIN_ALT;
216 }
217 
218 void pwm_details(const pin_t Ard_num) {
219  if (pwm_status(Ard_num)) {
220  uint32_t alt_all = 0;
221  const PinName dp = digitalPin[Ard_num];
222  pin_t pin_number = uint8_t(PIN_NUM(dp));
223  const bool over_7 = pin_number >= 8;
224  const uint8_t ind = over_7 ? 1 : 0;
225  switch (PORT_ALPHA(dp)) { // get alt function
226  case 'A' : alt_all = GPIOA->AFR[ind]; break;
227  case 'B' : alt_all = GPIOB->AFR[ind]; break;
228  case 'C' : alt_all = GPIOC->AFR[ind]; break;
229  case 'D' : alt_all = GPIOD->AFR[ind]; break;
230  #ifdef PE_0
231  case 'E' : alt_all = GPIOE->AFR[ind]; break;
232  #elif defined (PF_0)
233  case 'F' : alt_all = GPIOF->AFR[ind]; break;
234  #elif defined (PG_0)
235  case 'G' : alt_all = GPIOG->AFR[ind]; break;
236  #elif defined (PH_0)
237  case 'H' : alt_all = GPIOH->AFR[ind]; break;
238  #elif defined (PI_0)
239  case 'I' : alt_all = GPIOI->AFR[ind]; break;
240  #elif defined (PJ_0)
241  case 'J' : alt_all = GPIOJ->AFR[ind]; break;
242  #elif defined (PK_0)
243  case 'K' : alt_all = GPIOK->AFR[ind]; break;
244  #elif defined (PL_0)
245  case 'L' : alt_all = GPIOL->AFR[ind]; break;
246  #endif
247  }
248  if (over_7) pin_number -= 8;
249 
250  uint8_t alt_func = (alt_all >> (4 * pin_number)) & 0x0F;
251  SERIAL_ECHOPAIR("Alt Function: ", alt_func);
252  if (alt_func < 10) SERIAL_CHAR(' ');
253  SERIAL_ECHOPGM(" - ");
254  switch (alt_func) {
255  case 0 : SERIAL_ECHOPGM("system (misc. I/O)"); break;
256  case 1 : SERIAL_ECHOPGM("TIM1/TIM2 (probably PWM)"); break;
257  case 2 : SERIAL_ECHOPGM("TIM3..5 (probably PWM)"); break;
258  case 3 : SERIAL_ECHOPGM("TIM8..11 (probably PWM)"); break;
259  case 4 : SERIAL_ECHOPGM("I2C1..3"); break;
260  case 5 : SERIAL_ECHOPGM("SPI1/SPI2"); break;
261  case 6 : SERIAL_ECHOPGM("SPI3"); break;
262  case 7 : SERIAL_ECHOPGM("USART1..3"); break;
263  case 8 : SERIAL_ECHOPGM("USART4..6"); break;
264  case 9 : SERIAL_ECHOPGM("CAN1/CAN2, TIM12..14 (probably PWM)"); break;
265  case 10 : SERIAL_ECHOPGM("OTG"); break;
266  case 11 : SERIAL_ECHOPGM("ETH"); break;
267  case 12 : SERIAL_ECHOPGM("FSMC, SDIO, OTG"); break;
268  case 13 : SERIAL_ECHOPGM("DCMI"); break;
269  case 14 : SERIAL_ECHOPGM("unused (shouldn't see this)"); break;
270  case 15 : SERIAL_ECHOPGM("EVENTOUT"); break;
271  }
272  }
273 } // pwm_details
274 
275 #endif // NUM_DIGITAL_PINS
SERIAL_CHAR
#define SERIAL_CHAR(x)
Definition: serial.h:69
SERIAL_ECHO
#define SERIAL_ECHO(x)
Definition: serial.h:70
get_pin_mode
int8_t get_pin_mode(pin_t pin)
Definition: pinsDebug.h:44
PROGMEM
#define PROGMEM
Definition: pgmspace.h:29
IS_ANALOG
#define IS_ANALOG(P)
Definition: pinsDebug.h:59
PinName
PinName
Definition: PinNames.h:11
SERIAL_ECHOPAIR
#define SERIAL_ECHOPAIR(V...)
Definition: serial.h:114
NUM_ANALOG_FIRST
#define NUM_ANALOG_FIRST
Definition: variant.h:216
pwm_details
void pwm_details(int32_t pin)
Definition: pinsDebug.h:47
sprintf_P
#define sprintf_P(s,...)
Definition: pgmspace.h:72
SERIAL_ECHO_SP
#define SERIAL_ECHO_SP(C)
Definition: serial.h:186
pin_t
int8_t pin_t
Definition: HAL.h:65
pins_Xref.h
PSTR
#define PSTR(str)
Definition: pgmspace.h:31
NUMBER_PINS_TOTAL
#define NUMBER_PINS_TOTAL
Definition: pinsDebug.h:27
GET_PINMODE
bool GET_PINMODE(int8_t pin)
Definition: pinsDebug.h:49
SERIAL_ECHOPGM
#define SERIAL_ECHOPGM(S)
Definition: serial.h:173
uint8_t
const uint8_t[]
Definition: 404_html.c:3
NUM_ANALOG_INPUTS
constexpr uint8_t NUM_ANALOG_INPUTS
Definition: pinmapping.h:33
KILL_PIN
#define KILL_PIN
Definition: pins_CHEAPTRONICv2.h:106
digitalPin
const PinName digitalPin[]
Definition: variant.cpp:40
pwm_status
#define pwm_status(pin)
Definition: pinsDebug.h:30