Skip to content

Commit

Permalink
Merge pull request #3 from Zubax/gpio
Browse files Browse the repository at this point in the history
CLI GPIO
  • Loading branch information
j3qq4hch authored Feb 20, 2019
2 parents beec0ed + f026a51 commit d121430
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 7 deletions.
59 changes: 53 additions & 6 deletions docs/datasheet/Zubax_Babel_Datasheet.tex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
%
% Copyright (c) 2017 Zubax Robotics OU <info@zubax.com>
% Copyright (c) 2017-2019 Zubax Robotics <info@zubax.com>
%
% Distributed under BY-NC-ND (attribution required, non-commercial use only, no derivatives).
%
Expand Down Expand Up @@ -405,6 +405,7 @@ \subsection{SMD pads}\label{sec:smd_pads}
\item CAN development board.
Standard 2.54\,mm connectors can be soldered to the SMD pads in order to make the device compatible with
standard prototyping breadboards.
\item Generic USB/UART GPIO controller (section \ref{sec:cli_gpio}).
\end{itemize}

Information about the use of Babel in OEM applications is provided in the section \ref{sec:oem_applications}.
Expand All @@ -416,6 +417,7 @@ \subsection{SMD pads}\label{sec:smd_pads}
& High-level input voltage & 2.1 & 3.3 & 5.5 & V \\
& Low-level output voltage & 0 & 0 & 0.5 & V \\
& High-level output voltage & 2.8 & 3.3 & 3.4 & V \\
& Pull-down or pull-up resistance & 25 & 40 & 55 & $\text{k}\Omega$ \\
& Source/sink current (magnitude) & & & 10 & mA \\
\end{ZubaxSimpleTable}

Expand Down Expand Up @@ -500,6 +502,13 @@ \section{Start up and initialization}
the bootloader starts the application.
If no valid application is found in the ROM, the bootloader will wait for commands forever.

\section{GPIO pins}\label{sec:principles_gpio}

The device allows the user to control some of its SMD-exposed GPIO pins via CLI (section \ref{sec:cli_gpio}).
The specified GPIO configuration survives until the device is restarted.
Upon restart, the default configuration is applied, which is identical for all GPIO pins:
discrete input with pull-down.

\section{LED indicators}

\newcommand{\LEDX}{{\rule{0.4em}{0.8em}}}
Expand Down Expand Up @@ -985,18 +994,18 @@ \subsubsection{cfg}

Syntax:
\begin{itemize}
\item \verb|cfg list| - list all configuration parameters, their current values,
\item \verb|cfg list| --- list all configuration parameters, their current values,
acceptable value intervals, and default values.

\item \verb|cfg save| - save the current configuration into the non-volatile storage.
\item \verb|cfg save| --- save the current configuration into the non-volatile storage.
This command is redundant and normally need not be used,
because firmware revisions starting from v1.1 commit all configuration
into the non-volatile storage automatically upon modification.

\item \verb|cfg erase| - erase the current configuration and reset the non-volatile memory to
\item \verb|cfg erase| --- erase the current configuration and reset the non-volatile memory to
the factory defaults.

\item \verb|cfg set <name> <value>| - assign the configuration parameter named \verb|<name>| the value
\item \verb|cfg set <name> <value>| --- assign the configuration parameter named \verb|<name>| the value
\verb|<value>|. For example: \verb|cfg set foo 42|.
The non-volatile storage will be updated automatically.
\end{itemize}
Expand Down Expand Up @@ -1165,6 +1174,44 @@ \subsubsection{reboot}

Unconditionally reboots the device.

\subsubsection{gpio}\label{sec:cli_gpio}

Controls the GPIO pins exposed on the SMD pads.
This command is available since firmware v1.2.

Syntax:

\begin{itemize}
\item \verb|gpio <pin>| --- read the current status of the pin without changing its mode.
\item \verb|gpio <pin> <mode>| --- apply the specified mode and then read the status of the pin.
\end{itemize}

Where \verb|pin| can be one of the following (see the pinout diagram \ref{fig:pinout}) (case sensitive):

\begin{itemize}
\item \verb|pa4|
\item \verb|pa5|
\item \verb|pa6|
\item \verb|pb0|
\item \verb|pb6|
\item \verb|pb7|
\end{itemize}

The \verb|mode| argument, if specified, can be one of the following (case sensitive):

\begin{itemize}
\item \verb|oh| --- discrete output at high level.
\item \verb|ol| --- discrete output at low level.
\item \verb|ih| --- discrete input with pull-up.
\item \verb|il| --- discrete input with pull-down.
\end{itemize}

Upon successful execution, the command returns either \verb|h| or \verb|l| (lowercase Latin L),
depending on the current logical level of the selected pin.

The specified GPIO configuration survives until the device is restarted.
After restart, the default GPIO configuration will be applied, as specified in the section \ref{sec:principles_gpio}.

\chapter{OEM applications}\label{sec:oem_applications}

Besides its primary role of a USB-CAN or UART-CAN adapter tool,
Expand Down Expand Up @@ -1374,7 +1421,7 @@ \section{State machine}\label{sec:bootloader_state_machine}
2 & BootCancelled & There is a valid application to boot; however,
booting was canceled by an external command.\\

3 & AppUpgradeinProgress & The application is currently being updated.
3 & AppUpgradeInProgress & The application is currently being updated.
If interrupted, the bootloader will switch into
\textbf{NoAppToBoot} or \textbf{BootCancelled}.\\

Expand Down
2 changes: 1 addition & 1 deletion firmware/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ PROJECT = com.zubax.babel

HW_VERSION_MAJOR = 1
FW_VERSION_MAJOR = 1
FW_VERSION_MINOR = 1
FW_VERSION_MINOR = 2

#
# Application
Expand Down
89 changes: 89 additions & 0 deletions firmware/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,91 @@ class CommandProcessor
os::requestReboot();
}

void cmdGPIO(int argc, char** argv)
{
// Examples:
// gpio pa5
// gpio pb0 <oh|ol|ih|il>
// Upon success, the command returns the logical level of the pin: either "l" or "h".
if ((argc < 2) || (argc > 3))
{
std::puts("ERROR: bad arguments");
return;
}

/*
* Parse the pin specifier.
*/
stm32_gpio_t* port = nullptr;
std::uint8_t pin = 0;
{
const char* const pin_specifier = argv[1];
if ((pin_specifier[0] != 'p') ||
(pin_specifier[1] == '\0') ||
(pin_specifier[2] == '\0') ||
(pin_specifier[3] != '\0'))
{
std::puts("ERROR: malformed pin spec");
return;
}

static const std::tuple<const char*, stm32_gpio_t*, std::uint8_t> Map[] =
{
{"pa4", GPIOA, 4},
{"pa5", GPIOA, 5},
{"pa6", GPIOA, 6},
{"pb0", GPIOB, 0},
{"pb6", GPIOB, 6},
{"pb7", GPIOB, 7},
};

for (auto& m : Map)
{
if (startsWith(pin_specifier, std::get<0>(m)))
{
port = std::get<1>(m);
pin = std::get<2>(m);
break;
}
}
}

if (port == nullptr)
{
std::puts("ERROR: unknown pin");
return;
}

/*
* If target state is provided, parse and execute.
*/
if (argc > 2)
{
const char* const state_specifier = argv[2];
if (state_specifier[0] == 'o') // Output
{
const bool level = state_specifier[1] == 'h';
palWritePad(port, pin, std::uint8_t(level));
palSetPadMode(port, pin, PAL_MODE_OUTPUT_PUSHPULL);
}
else if (state_specifier[0] == 'i') // Input
{
const auto mode = (state_specifier[1] == 'h') ? PAL_MODE_INPUT_PULLUP : PAL_MODE_INPUT_PULLDOWN;
palSetPadMode(port, pin, mode);
}
else
{
std::puts("ERROR: invalid mode");
return;
}
}

/*
* Unconditional readback.
*/
std::puts(palReadPad(port, pin) ? "h" : "l");
}

static bool startsWith(const char* const str, const char* const prefix)
{
return std::strncmp(prefix, str, std::strlen(prefix)) == 0;
Expand Down Expand Up @@ -753,6 +838,10 @@ class CommandProcessor
{
return processComplexCommand(cmd, &CommandProcessor::cmdReboot);
}
else if (startsWith(cmd, "gpio"))
{
return processComplexCommand(cmd, &CommandProcessor::cmdGPIO);
}
else
{
; // No handler
Expand Down

0 comments on commit d121430

Please sign in to comment.