SatCat5
port_serial.cc
1 // Copyright 2021-2023 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/port_serial.h>
7 #include <satcat5/utils.h>
8 
9 namespace port = satcat5::port;
10 namespace util = satcat5::util;
11 
12 // Duplicate definitions required for C++0x11 compatibility, fixed in 0x17.
13 // See also: https://en.cppreference.com/w/cpp/language/static
14 #if __cplusplus < 201703L
15  constexpr u8 port::SerialAuto::MODE_AUTO;
16  constexpr u8 port::SerialAuto::MODE_SPI;
17  constexpr u8 port::SerialAuto::MODE_UART1;
18  constexpr u8 port::SerialAuto::MODE_UART2;
19 #endif
20 
21 // Generators for commonly-used command formats:
22 inline u32 cmd_uart(u32 ref, u32 baud, bool ignore_cts) {
23  static const u32 CTS_OVERRIDE = (1u << 31);
24  u32 flags = (ignore_cts ? CTS_OVERRIDE : 0);
25  return util::div_round_u32(ref, baud) | flags;
26 }
27 inline u32 cmd_i2c_controller(u32 ref, u32 baud, u32 devaddr) {
28  u32 clkdiv = util::div_ceil_u32(ref, 4*baud) - 1;
29  return (devaddr << 16) | clkdiv;
30 }
31 inline u32 cmd_i2c_peripheral(u32 devaddr) {
32  return (devaddr << 16);
33 }
34 inline u32 cmd_spi_controller(u32 ref, u32 baud, u32 mode) {
35  u32 clkdiv = util::div_ceil_u32(ref, 2*baud);
36  return (mode << 8) | clkdiv;
37 }
38 inline u32 cmd_spi_peripheral(u32 mode, u32 gfilt) {
39  return (mode << 8) | gfilt;
40 }
41 
42 // Most ports use the same set of control registers:
43 static const unsigned REGADDR_STATUS = 0; // Port status (interpretation varies)
44 static const unsigned REGADDR_CLKREF = 1; // Reference clock frequency, in Hz
45 static const unsigned REGADDR_CTRL0 = 2; // Main control register
46 static const unsigned REGADDR_CTRL1 = 3; // Aux control register, if applicable
47 static const unsigned REGADDR_MODE = 4; // Mode/autodetect register, if applicable
48 
50  satcat5::cfg::ConfigBus* cfg, unsigned devaddr)
51  : m_ctrl(cfg->get_register(devaddr))
52 {
53  // No other initialization required.
54 }
55 
57  return (u8)m_ctrl[REGADDR_STATUS];
58 }
59 
61  m_ctrl[REGADDR_MODE] = (u32)mode;
62 }
63 
64 void port::SerialAuto::config_spi(u8 mode, u8 gfilt) {
65  m_ctrl[REGADDR_CTRL1] = cmd_spi_peripheral(mode, gfilt);
66 }
67 
68 void port::SerialAuto::config_uart(unsigned baud, bool ignore_cts) {
69  u32 clk_hz = m_ctrl[REGADDR_CLKREF];
70  m_ctrl[REGADDR_CTRL0] = cmd_uart(clk_hz, baud, ignore_cts);
71 }
72 
74  return (u8)m_ctrl[REGADDR_MODE];
75 }
76 
77 void port::SerialI2cController::config_i2c(const util::I2cAddr& devaddr, unsigned baud) {
78  u32 clk_hz = m_ctrl[REGADDR_CLKREF];
79  m_ctrl[REGADDR_CTRL0] = cmd_i2c_controller(clk_hz, baud, devaddr.m_addr);
80 }
81 
83  m_ctrl[REGADDR_CTRL0] = cmd_i2c_peripheral(devaddr.m_addr);
84 }
85 
86 void port::SerialSpiController::config_spi(unsigned baud, u8 mode) {
87  u32 clk_hz = m_ctrl[REGADDR_CLKREF];
88  m_ctrl[REGADDR_CTRL0] = cmd_spi_controller(clk_hz, baud, mode);
89 }
90 
91 void port::SerialSpiPeripheral::config_spi(u8 mode, u8 gfilt) {
92  m_ctrl[REGADDR_CTRL0] = cmd_spi_peripheral(mode, gfilt);
93 }
94 
95 void port::SerialUart::config_uart(unsigned baud, bool ignore_cts) {
96  u32 clk_hz = m_ctrl[REGADDR_CLKREF];
97  m_ctrl[REGADDR_CTRL0] = cmd_uart(clk_hz, baud, ignore_cts);
98 }
Generic ConfigBus API.
Definition: cfgbus_core.h:124
static constexpr u8 MODE_AUTO
Constants for config_mode() and read_mode().
Definition: port_serial.h:64
static constexpr u8 MODE_UART1
Constants for config_mode() and read_mode().
Definition: port_serial.h:66
static constexpr u8 MODE_SPI
Constants for config_mode() and read_mode().
Definition: port_serial.h:65
static constexpr u8 MODE_UART2
Constants for config_mode() and read_mode().
Definition: port_serial.h:67
void config_spi(u8 mode, u8 gfilt=1)
Set the SPI clock mode (0/1/2/3) and glitch-filter parameters.
Definition: port_serial.cc:64
void config_mode(u8 mode)
Manually select auto/SPI/UART mode.
Definition: port_serial.cc:60
u8 read_mode()
Report the current mode (auto/SPI/UART).
Definition: port_serial.cc:73
void config_uart(unsigned baud, bool ignore_cts=false)
Set the UART baud rate and flow-control options.
Definition: port_serial.cc:68
u8 status()
Read the port-status register.
Definition: port_serial.cc:56
SerialGeneric(satcat5::cfg::ConfigBus *cfg, unsigned devaddr)
Link this object to a specific ConfigBus address.
Definition: port_serial.cc:49
void config_i2c(const satcat5::util::I2cAddr &devaddr, unsigned baud=100000)
Configure the remote I2C address and baud rate.
Definition: port_serial.cc:77
void config_i2c(const satcat5::util::I2cAddr &devaddr)
Configure the local I2C address.
Definition: port_serial.cc:82
void config_spi(unsigned baud, u8 mode)
Set the SPI baud-rate and clock mode (0/1/2/3).
Definition: port_serial.cc:86
void config_spi(u8 mode, u8 gfilt=1)
Set the SPI clock mode (0/1/2/3) and glitch-filter parameters.
Definition: port_serial.cc:91
void config_uart(unsigned baud, bool ignore_cts=false)
Set the UART baud rate and flow-control options.
Definition: port_serial.cc:95
Configuration for the various Ethernet-over-Serial ports.
Conversion function for I2C device addresses.
Definition: cfg_i2c.h:30
const u16 m_addr
Native internal address representation.
Definition: cfg_i2c.h:67
Miscellaneous mathematical utility functions.
constexpr u32 div_round_u32(u32 a, u32 b)
Integer division functions with various rounding options:
Definition: utils.h:272
constexpr u32 div_ceil_u32(u32 a, u32 b)
Integer division functions with various rounding options:
Definition: utils.h:276