-
Notifications
You must be signed in to change notification settings - Fork 3
/
README
114 lines (90 loc) · 4.24 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
libperipha (lib peripheral access) is a collection of headers and
definitions to access internal registers of various hardware components.
License
-------
libperipha consists of number of components, developed by project
contributors, collected from existing projects, or imported from
vendor releases. All components of libperipha are released under
well-known liberal Open Source licenses (such as BSD or MIT), or
are in public domain. Please consult each individual file for
licensing/copyright terms applying to it. Following provides
(possibly incomplete) information for major libperihpa components:
1. Default libperipha license unless otherwise specified: 3-clause BSD.
If you contribute materials of which you are copyright holder, please
consider using this license to minimize complexity and confusion.
2. scripts/ subdirectory: It's common practice in Open Source community
to release development and support tools on stricter freedom and
community protecting license, like GPL. However, to minimize confusion
and to keep automatic licensing scanners happy, libperipha adopts to use
same 3-clause BSD license for support scripts.
3. arm/cortex-m/arm-cmsis/ subdir: CMSIS library, copyrighted by ARM Ltd.
and released under 3-clause BSD license.
Downloading
-----------
libperipha is distributed via git repository. To checkout:
git clone --recursive https://github.com/pfalcon/libperipha.git
If you cloned without --recursive, run:
git submodule update --init --recursive
Interface/API
-------------
There're a few well-known ways to define hardware registers and access
them:
1. Define iomem addresses of registers, and provide functions/macros
to access them. E.g.:
#define REG_DATA 0x40
#define READ_R8(addr) ...
#define WRITE_R8(addr, val) ...
uint8_t v = READ_R8(REG_DATA);
WRITE_R8(REG_DATA, 'a');
2. Define registers as "virtual variables", so they can be read/written
directly. This is really a variation of the previous method, where
register symbol is defined to a dereferenced pointer to an address:
#define _REG_DATA 0x40
#define R8(addr) (*(volatile uint8_t*)(addr))
#define REG_DATA R8(_REG_DATA)
uint8_t v = REG_DATA;
REG_DATA = 'a';
3. More complex hardware may have number of similar blocks, so instead
of using just scalar address with method 1, separate block base address
and in-block register offsets are defines, with corresponding accessors:
#define BLOCK1 0x10
#define BLOCK2 0x20
#define REG_DATA 0x00
#define REG_CTRL 0x02
#define READ_R16(base, offset) ...
#define WRITE_R16(base, offset, val) ...
uint16_t v = READ_R16(BLOCK1, REG_DATA);
WRITE_R16(BLOCK2, REG_DATA, 0xaa55);
4. Generalization of method 2 to a repeating blocks is using structures
to define block register layouts, then defining block symbols as structure
pointers using block base addresses:
struct BLOCK {
uint16_t REG_DATA;
uint16_t REG_CTRL;
};
#define _BLOCK1 0x10
#define _BLOCK2 0x20
#define BLOCK1 ((volatile struct BLOCK*)_BLOCK1)
#define BLOCK2 (*(volatile struct BLOCK*)_BLOCK1)
uint16_t v = BLOCK1->REG_DATA;
BLOCK1->REG_DATA = 0xaa55;
BLOCK2.REG_CTRL = CMD_RESET;
It's hard to say that one method is "better" than another, each of them has
its pros and cons. For example, for simple hardware, it makes no sense
to mandate usage of extra parameters in accessor methods or define
structures, methods 1 & 2 work pretty well. Methods 2 & 4 are more
concise, but require registers to be memory-mapped (or special pointer
types support from compiler).
So, libperipha doesn't try to postulate any of these as primary, but
embraces them all. It is however recommended to whenever possible support
all of them. It's not as hard as it seems, methods 1 & 2 have basically
the same underlying definitions (register addresses as scalar), and from
4 to 3 it is possible to go with offsetof macro. All these cases can be
covered by simple codegeneration script. Going from method 3 to 4 is more
complicated, but a tool to layout structures based on register offsets
and sizes is just a bit more complicated than trivial.
(Re)generating headers from YAML descriptions
---------------------------------------------
libperipha favors declaritive descriptions encoded in easy to understand YAML
files. To generate headers from .yaml files, run scripts/yaml2h.py tool
in a directory with such files.