-
Notifications
You must be signed in to change notification settings - Fork 2
/
spi.yaml
124 lines (101 loc) · 4.61 KB
/
spi.yaml
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
115
116
117
118
119
120
121
122
123
124
---
# Name of the component
component: spi-e1800
# Which language backend to use
backend: c
# External .c source files to build
sources:
- example_spi.c
# .h headers to include
headers:
- e1800.h
- e1800_spi_priv.h
# The C struct declared in a header file used for the state of this component. It is passed as `self`
# in all callbacks.
struct: spi_state
# A C function (declared in a listed header file) called when this component is created
# (normally at boot). It would enable the SPI controller and clocks, etc.
on_begin: enable_spi(self)
# A C function called when this component is destroyed, disabling the SPI controller.
on_end: disable_spi(self)
# Arguments to the construction of the component. Values are bound to these arguments in the
# component that uses this one.
args_in:
# Pointer to the memory-mapped IO region for the hardware configuration registers for this instance
base: ptr
# The chip select pin
cs:
type: component(GPIO)
# The pin component defines actions `low` and `high`. Here we bind
actions:
# `low` and `high` are actions defined by the GPIO component. With `to_begin`, we name an
# autogenerated C function that will invoke this action on the `cs` GPIO component. When we
# call `cs_low` and `cs_high` below, the autogenerated function calls the `on_begin`
# code under the `low` and `high` actions in the GPIO component file.
low:
to_begin: cs_low
high:
to_begin: cs_high
# The SPI completion interrupt
isr:
type: component(ISR)
actions:
fire:
# When the ISR fires, this code is run. It calls an autogenerated `transfer_end` function
# named by the `transaction`.`to_end` line below, which calls the `on_end` handler configured
# by the component using this SPI controller. It passes the received byte, because `mi` is
# an out argument (in `args_out`) of the `transaction` event.
on_begin: |
transfer_end(self, self->spi->DATA);
# Defines the actions that this SPI controller supports
actions:
# The only top-level action of the SPI component is a SPI `transaction`
transaction:
# The arguments passed into a `transaction` when it begins
args_in:
# Clock speed, an integer
clock_speed:
type: int
# As subsequent transactions are likely to use the same clock speed, we use `configure` code
# to explicitly model the state variable.. Code using this component can declare ahead of
# time that a series of transactions will all use the same `clock_speed`, and this register
# will be written only once, instead of every transaction.
# `calculate_clock` is a hypothetical function in one of the header files, which calculates
# the register value based on the integer clock_speed
configure: self->SPI->CDIV = calculate_clock(clock_speed);
# Mode, an integer
mode:
type: int
configure: self->SPI->MODE = mode;
# When code using this component begins a transaction, this code is run. Because `on_begin` is
# defined, the component using this SPI controller decides when a transaction starts. It calls the
# autogenerated function `cs_low`, which makes the GPIO component set the CS pin low.
# Within the transaction, the `transfer` action defined in the actions section below is defined.
on_begin: |
cs_low(self);
# When code using this component ends a transaction, this code is run. It brings the CS pin high.
# Because `on_end` is defined, the component using this one gets to decide when a `transaction`
# ends.
on_end: |
cs_high(self);
# Defining the sub-actions within `transaction`
actions:
# Within a transaction, you can transfer a byte
transfer:
# The `mo` argument, a byte, is passed in by the component using this one when a `transfer`
# begins
args_in:
mo: byte
# The `mi` argument, a byte, is passed from this component to the component using this one
# when the `transfer` ends.
args_out:
mi: byte
# Because `on_begin` is defined, the component using this SPI controller can begin a transfer,
# which runs this action, passing in the `mo` byte. It makes the hardware transfer the byte
# by writing it to the transfer register.
on_begin: |
self->spi->DATA = mo;
# Because `to_end` is defined, this component determines when the transfer ends. The
# autogenerated function named here is called by the interrupt handler above when the
# transaction completes.
to_end: transfer_end