Home2L - C/C++ API v1.4-0-g38cc (2024-05-25)
Smart Tools for a Private Home
|
Microcontroller firmware basic modules, relevant for implementing new features.
This module describes some internal interfaces of the Brownie firmware. They are relevant for extending the firmware by, for example, adding new feature modules.
To add a new feature module foobar, the following steps have to be done (replace foobar with the name of your module):
In the same directory, add a new file foobar.c with the following content:
The documentation of CoreInit() and friends describe what the interface functions must do.
In file configure.h, add a new section for the compile-time parameters of your module. At least one parameter, 'WITH_FOOBAR' must be defined. Other parameters must be prefixed with 'FOOBAR_'.
In the same file, please also extend the sections "Features: Auto-Completion", "Ports: Auto-Completion", "Ports: Checks", and "MCU: Reset Pin Configuration".
Classes | |
struct | SBrEeprom |
Structure to describe the complete EEPROM content. More... | |
Macros | |
#define | EMPTY_MODULE(NAME) |
Helper to declare an empty / deactivated module (see Microcontroller: API). | |
Memory and Registers ... | |
const __flash TBrFeatureRecord | brFeatureRecord |
The Brownie feature recourd. | |
#define | brConfigRecord ((const TBrConfigRecord) _brConfigRecord) |
The Brownie config recourd. | |
#define | RegGet(REG) (_regFile[REG]) |
Get a register value. | |
#define | RegSet(REG, VAL) do { _regFile[REG] = (VAL); } while (0) |
Set a register to a new value. | |
Persistent Storage (EEPROM) ... | |
struct SBrEeprom | brEeprom |
Complete EEPROM contents. | |
Change Reporting ... | |
uint8_t | chgShadow |
static void | ReportChange (uint8_t mask) |
Set (a) bit(s) in the BR_REG_CHANGED register. | |
void | ReportChangeAndNotify (uint8_t mask) |
Set (a) bit(s) in the BR_REG_CHANGED register and issue a TWI host notification. | |
Timer ... | |
uint16_t | TimerNow () |
Get current time in ticks. More... | |
Mini-Timer ... | |
8-bit counter with a cycle time of 8µs to be used locally in modules. Presently, the mini-timer is used by the ISRs of the UART and the 'temperature' modules. Minitimers must be used with interrupts disabled. Note: MinitimerReset() and MinitimerNow() are implemented as macros to ensure that they are inlined. Otherwise, ISRs may get a very long prologue saving many registers. This causes problems in 'TemperatureISR()' on the ATtiny861. | |
void | MinitimerStart (int clockScale) |
Start the minitimer (pass any MINI_CLOCK_SCALE_* constants) | |
void | MinitimerStop () |
Stop the minitimer. | |
void | MinitimerReset () |
Reset the minitimer. | |
uint8_t | MinitimerNow () |
Get the current minitimer value. | |
#define | MINITICKS_OF_US(X) (X * (BR_CPU_FREQ / 1000000) / 8) |
Number of 8-bit timer ticks of a microsecond value for a clock selection of clk_io/8. | |
#define | MINI_CLOCK_SCALE_1 |
Minitimer clock period of 1/BR_CPU_FREQ. | |
#define | MINI_CLOCK_SCALE_8 |
Minitimer clock period of 8 * 1/BR_CPU_FREQ. | |
#define | MINI_CLOCK_SCALE_64 |
Minitimer clock period of 64 * 1/BR_CPU_FREQ. | |
#define | MINI_CLOCK_SCALE_256 |
Minitimer clock period of 256 * 1/BR_CPU_FREQ. | |
#define | MINI_CLOCK_SCALE_1024 |
Minitimer clock period of 1024 * 1/BR_CPU_FREQ. | |
Interface Functions of the "core" Module ... | |
The feature modules (e.g. gpio.[hc], shades.[hc]) have a common set of interface functions. The following functions are the interface for the pseudo-module "core", which implements some core functionality. If you are developing a feature module: Never call these functions directly. They are only documented here in order to document the general module interface functions. | |
void | CoreInit () |
Initialize the module. More... | |
static void | CoreIterate () |
Iterate the module. More... | |
void | CoreOnRegRead (uint8_t reg) |
Update a register when it is read. More... | |
void | CoreOnRegWrite (uint8_t reg, uint8_t val) |
Write a register. More... | |
Basic Helpers ... | |
#define | INIT(NAME, VAL) if ((VAL) != 0) NAME = (VAL); |
Variable assignment for '*Init()' functions which are only called once on startup. More... | |
#define | LO(X) ((X) & 0xff) |
Get low byte of a 16-bit word-. | |
#define | HI(X) ((X) >> 8) |
Get high byte of a 16-bit word. | |
#define | HILO(H, L) ((((uint16_t) (H)) << 8) | (L)) |
Compose a 16-bit word from high and low byte. | |
#define | SHIFT_OF_MASK(X) |
Get the number of shifts to obtain a certain byte mask (inverse of '1 << N'). | |
MCU Port Access Macros ... | |
#define | P_A0 0x0001 |
#define | P_A1 0x0002 |
#define | P_A2 0x0004 |
#define | P_A3 0x0008 |
#define | P_A4 0x0010 |
#define | P_A5 0x0020 |
#define | P_A6 0x0040 |
#define | P_A7 0x0080 |
#define | P_B0 0x0100 |
#define | P_B1 0x0200 |
#define | P_B2 0x0400 |
#define | P_B3 0x0800 |
#define | P_B4 0x1000 |
#define | P_B5 0x2000 |
#define | P_B6 0x4000 |
#define | P_B7 0x8000 |
#define | P_IN(P) (LO(P) ? (PINA & LO(P)) : HI(P) ? (PINB & HI(P)) : 0) |
Read a single pin; result is either 0 or non-zero, depending on whether the pin is set. | |
#define | P_IN_MULTI(MASK) ((LO(MASK) ? (PINA & LO(MASK)) : 0) | (HI(MASK) ? ((uint16_t) (PINB & HI(MASK))) << 8 : 0)) |
Read multiple pins, selected by PMASK; result is 16-bit vector. | |
#define | P_OUT_0(P) do { if (LO(P)) PORTA &= ~LO(P); if (HI(P)) PORTB &= ~HI(P); } while(0) |
#define | P_OUT_1(P) do { if (LO(P)) PORTA |= LO(P); if (HI(P)) PORTB |= HI(P); } while(0) |
Set/reset pin(s). Usually, only a single bit should be passed here to make the compiler generate 'sbi' and 'cbi' instructions. | |
#define | P_OUT_MULTI(MASK, P) |
Set multiple pins, selected by 'MASK', to 'P'. | |
#define | P_DDR_IN(P) do { if (LO(P)) DDRA &= ~LO(P); if (HI(P)) DDRB &= ~HI(P); } while(0) |
Set port(s) as input. | |
#define | P_DDR_OUT(P) do { if (LO(P)) DDRA |= LO(P); if (HI(P)) DDRB |= HI(P); } while(0) |
Set port(s) as output. | |
MCU Types ... | |
#define | MCU_TYPE |
MCU type compiled for; is set to any 'BR_MCU_*' value (see BR_MCU_NONE and friends). | |
#define INIT | ( | NAME, | |
VAL | |||
) | if ((VAL) != 0) NAME = (VAL); |
uint16_t TimerNow | ( | ) |
Get current time in ticks.
One tick is approx. 1ms (1024µs for a calibrated clock). => Counter overflow is in approx. one minute (~65 seconds). This function never returns 0 (= BR_TICKS_NEVER) (if necessary by rounding away from that value).
void CoreInit | ( | ) |
Initialize the module.
In this case, the timers and the "changed" register logic are initialized.
|
inlinestatic |
void CoreOnRegRead | ( | uint8_t | reg | ) |
Update a register when it is read.
The ...OnRegRegRead() functions are called whenever the Brownie has received a "register read" request just before it is answered. The function must check if 'reg' references a register maintained by this module and may then update the register content. For example, the GPIO module reads the GPIO inputs then.
This function handles reads from the BR_REG_CHANGED register (i.e. auto-resets it on read) and reads from the timer registers (i.e. latches the 16-bit time value on access to BR_REG_TICKS_LO).
void CoreOnRegWrite | ( | uint8_t | reg, |
uint8_t | val | ||
) |
Write a register.
The ...OnRegRegWrite() functions are called whenever the Brownie has received a "register write" request. The function must check, if 'reg' references a register maintained by this module and perform the repective action. Also, the passed value must be written into the respective register.
This function handles writes to the BR_REG_CHANGED register.