Commit fde87b75 authored by Christos Gentsos's avatar Christos Gentsos

Doc: start documenting the firmware

parent 35ccc3b9
......@@ -3,9 +3,14 @@
#define FLASH_ROW_SIZE 256
/*! This struct defines 256 bytes of user data, stored in non-volatile
* memory, including a special 4-byte word which is used to turn on
* remote programming.
*/
typedef struct {
//! check if we want to enable the remote programming functionality
uint32_t copy_fw;
//! provide some (optional) user data storage
uint8_t user_data[252];
} user_flash_t;
......
......@@ -26,18 +26,28 @@ enum QUERY_RET_VALS {
QUERY_FMT_NAN = 0x1c};
typedef const struct {
//! CMD code
const uint8_t addr;
//! transaction length for this command
int8_t *const data_len;
//! pointer to data
uint8_t *const data_pnt;
//! invoked when accessing the command, before any data transfer
const fp_t a_callback;
//! invoked after writing data
const fp_t w_callback;
//! invoked after reading data
const fp_t r_callback;
//! data for the query command
const uint8_t query_byte;
//! always disable PEC for this command if non-zero
const uint8_t wr_pec_disabled;
} cmd_t;
typedef const struct {
//! holds number of commands implemented
const uint8_t n_cmds;
//! where the command structure list is stored
cmd_t *const cmds;
} cmd_space_t;
......
......@@ -43,8 +43,11 @@ int16_t in_addr_space(cmd_space_t *addr_space, uint8_t addr)
return -1;
}
/*! \defgroup I2C_int_handlers Command space integrating interrupt handlers
* @{
*/
/* we get here every time we get a byte from the master */
/*! we get here every time we get a byte from the master */
static void __xMR I2C_slave_rx_complete_int(const struct i2c_s_async_descriptor *const descr)
{
if (last_byte_read_got_nack) {
......@@ -197,8 +200,8 @@ static void __xMR I2C_slave_rx_complete_int(const struct i2c_s_async_descriptor
}
}
/* we get here when a master read transaction expects another byte (we
* haven't terminated it using CMD=2 */
/*! we get here when a master read transaction expects another byte (we
* haven't terminated it using CMD=2 */
static void __xMR I2C_slave_tx_pending_int(const struct i2c_s_async_descriptor *const descr)
{
if (last_byte_read_got_nack) {
......@@ -265,20 +268,23 @@ static void __xMR I2C_slave_tx_pending_int(const struct i2c_s_async_descriptor *
}
/* we get here when a byte has been sent to the master */
/*! we get here when a byte has been sent to the master */
static void __xMR I2C_slave_tx_complete_int(const struct i2c_s_async_descriptor *const descr)
{
last_byte_read_got_nack = hri_sercomi2cs_get_STATUS_RXNACK_bit(descr->device.hw);
}
/* we get here when something bad has happened */
/*! we get here when something bad has happened */
static void __xMR I2C_slave_error_int(const struct i2c_s_async_descriptor *const descr)
{
set_cmd(descr, 2);
}
/*! @} */
/*! this configures the I2C interrupt handlers with the PMBus and
extended command structures */
void setup_I2C_slave(cmd_space_t *impl_cmds, cmd_space_t *impl_ext_cmds)
{
cmds = impl_cmds;
......
......@@ -12,7 +12,7 @@ BUILDDIR = build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
.PHONY: help doxygen Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
......@@ -32,6 +32,7 @@ doxygen:
ifeq ($(TARGET),clean)
@rm -rf build/doxygen-xml-common build/doxygen-xml-main build/doxygen-xml-testmaster
else
mkdir -p build
doxygen doxygen-config-common
doxygen doxygen-config-main
doxygen doxygen-config-testmaster
......
......@@ -87,4 +87,4 @@ import subprocess, os
read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True'
if read_the_docs_build:
subprocess.call('make doxygen', shell=True)
subprocess.call('cd .. ; make doxygen', shell=True)
......@@ -4,24 +4,138 @@ Firmware
The project's fitmware is split in three parts: the bootloader, the
main firmware and the test firmware.
PMBus command infrastructure
----------------------------
A common command handling infrastructure has been put in place, such
that both the main firmware and the bootloader can easily implement
different subsets of PMBus and extended commands. The basic construct
of this implementation is the :code:`cmd_t` structure:
.. doxygenstruct:: cmd_t
:project: common
:members:
An array of these structs makes up a command space:
.. doxygenstruct:: cmd_space_t
:project: common
:members:
From the user's point of view, these structures are defined and used
just once, in the function
.. doxygenfunction:: setup_I2C_slave
:project: common
:outline:
This function will configure the inturrupt handlers, below, with the
command spaces defined in the specific user implementation (main
firmware or bootloader). From that point on, the only interaction will
be through the user-defined callbacks.
.. doxygengroup:: I2C_int_handlers
:project: common
:outline:
:content-only:
Bootloader
----------
The bootloader checks a certain word in the flash storage and,
depending on the value, either hands control to the main FW, or enters
remote programming mode.
The bootloader, after bringing up the device, will check for the
special word :code:`0xBEC0ABCD` in the flash storage (see struct
below) and, depending on the value, will either hand control to the
main FW, or enter remote programming mode.
.. doxygenstruct:: user_flash_t
:project: common
:members:
Main firmware
-------------
PMBus and extended commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The PMBus and extended command spaces are:
.. doxygenvariable:: cmds
.. doxygenvariable:: ext_cmds
Fan control PID
~~~~~~~~~~~~~~~
When the fans connected provide a tachometer output, fan speed control
can be enabled. This is implemented using PID controllers, with each
fan having its own instance. The main data structure of the PID
implementation is
.. doxygenstruct:: pid_cntrl_t
:members:
This is used by the main software to set the PID setpoint, and by the
PID controller to hold integration data. The main function that has to
be called every timestep is described below:
.. doxygenfunction:: pid_compute
Test firmware
-------------
To help with development, a test firmware has been written for a
`Feather M0 Basic <https://www.adafruit.com/product/2772>`_ minimal
development board.
Mitigation measures
-------------------
The MoniMod will be used in radiation environments. Although its
function is not critical and it can be remotely reset upon loss of
communication, some measures have been taken to minimize interruptions
and data corruption, improving QoS.
TMR using COAST
~~~~~~~~~~~~~~~
The `COAST <https://github.com/byuccl/coast>`_ LLVM passes are used to
automatically implement TMR to important variables.
NOPs and trampolines
~~~~~~~~~~~~~~~~~~~~
The Program Counter is also sensitive to SEUs; in fact, execution can
sometimes jump to an invalid address. To help mitigate failures owed
to this mechanism, any region of unused memory space has been filled
with :code:`NOP` instructions, and a small trampoline function as an
epilogue that will reset the stack pointer and jump to the device
initialization code. Furthermore, the instruction that comprises the
main loop has been placed at a "strategic" location, aligned by
:code:`0x8000`: that way, a bit-flip in any of the lower bits will
send execution to the upper memory region, filled with the NOPs and
concluding at the trampoline.
Watchdog
~~~~~~~~
Short description of the watchdog peripheral and the use we make of
it.
Toolchains
----------
Can be built with GCC and Clang / LLVM compilers; TMR only works with
Clang.
......@@ -7,17 +7,24 @@
// #define DEBUG_PID
typedef struct {
//! controller setpoint
float setpoint;
//! the input of the last timestep
float last_input;
//! storage for integration
float output_sum;
#ifdef DEBUG_PID
float p_factor;
float i_factor;
float d_factor;
#endif
//! timestep counter
uint16_t id_cnt;
} pid_cntrl_t;
/*! use this function with a PID structure and an input to calculate
* the output for each timestep.
*/
float pid_compute(pid_cntrl_t *pid_inst, float input);
#endif
......@@ -14,7 +14,9 @@ __DEFAULT_NO_xMR
#define PWM_CC 1.041
/* #define PWM_CC 1.0 */
//! PMBus commmands structure
extern cmd_space_t cmds;
//! Our custom commmands structure
extern cmd_space_t ext_cmds;
uint16_t temps_lin[3];
......
......@@ -19,6 +19,11 @@ const float pid_outMax = 500;
const float pid_ifMax = 50;
/*! Compute the PID output for the next timestep
* \param pid_inst struct that holds the PID controller's configuration
* \param input the current input to the PID controller
* \return the PID controller output
*/
float __xMR pid_compute(pid_cntrl_t *pid_inst, float input)
{
/*Compute all the working error variables*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment