This repository has been archived by the owner on Jan 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 39
/
spi_master.hpp.in
162 lines (136 loc) · 4.21 KB
/
spi_master.hpp.in
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// coding: utf-8
/* Copyright (c) 2013, Roboterclub Aachen e.V.
* All Rights Reserved.
*
* The file is part of the xpcc library and is released under the 3-clause BSD
* license. See the file `LICENSE` for the full license governing this code.
*/
// ----------------------------------------------------------------------------
{{ generation_block }}
#ifndef XPCC_{{target.family | upper}}_SPI_MASTER_HPP
#define XPCC_{{target.family | upper}}_SPI_MASTER_HPP
#include <xpcc/architecture/interface/spi_master.hpp>
#include "type_ids.hpp"
#include "spi.hpp"
namespace xpcc
{
namespace {{target.family}}
{
/**
* Implementation of the SimpleSpi.
*
* The fast SPI clock speeds make it unreasonable to use an interrupt
* based approach to shifting out each byte of the data, since the interrupt
* handling might decrease performance over busy waiting especially for
* targets operating at low CPU frequencies.
* Therefore the asynchronous methods are implemented synchronously.
*
* @warning When the !SS pin is configured in input mode and pulled low, the
* hardware will switch into SPI slave mode. It is therefore necessary
* to configure the pin either in output mode or to pull it high.
*
* @ingroup {{target.string}}_spi
* @author Niklas Hauser
*/
class SpiMaster : public ::xpcc::SpiMaster, private Spi
{
static uint8_t state;
static void *context;
static ConfigurationHandler configuration;
public:
static const TypeId::SpiMasterMosi Mosi;
static const TypeId::SpiMasterMiso Miso;
static const TypeId::SpiMasterSck Sck;
static const TypeId::SpiMasterSs Ss;
/// Spi Data Mode, Mode0 is the most common mode
enum class
DataMode : uint8_t
{
Mode0 = 0, ///< clock normal, sample on rising edge
Mode1 = (1 << CPOL), ///< clock normal, sample on falling edge
Mode2 = (1 << CPHA), ///< clock inverted, sample on rising edge
Mode3 = (1 << CPOL) | (1 << CPHA), ///< clock inverted, sample on falling edge
};
public:
// start documentation inherited
template< class SystemClock, uint32_t baudrate,
uint16_t tolerance = xpcc::Tolerance::FivePercent >
static inline void
initialize()
{
// calculate the nearest prescaler from the baudrate
constexpr float desired = float(SystemClock::Spi) / baudrate;
constexpr uint8_t nearest = (
(desired >= ( 64 * 4.f/3)) ? 128 : (
(desired >= ( 32 * 4.f/3)) ? 64 : (
(desired >= ( 16 * 4.f/3)) ? 32 : (
(desired >= ( 8 * 4.f/3)) ? 16 : (
(desired >= ( 4 * 4.f/3)) ? 8 : (
(desired >= ( 2 * 4.f/3)) ? 4 :
2
))))));
// check if we found a prescaler which generates a baudrate within the tolerance
assertBaudrateInTolerance<
SystemClock::Spi / nearest,
baudrate,
tolerance >();
// translate the prescaler into the bitmapping
constexpr Prescaler prescaler = (
(nearest >= 128) ? Prescaler::Div128 : (
(nearest >= 64) ? Prescaler::Div64 : (
(nearest >= 32) ? Prescaler::Div32 : (
(nearest >= 16) ? Prescaler::Div16 : (
(nearest >= 8) ? Prescaler::Div8 : (
(nearest >= 4) ? Prescaler::Div4 :
Prescaler::Div2
))))));
initialize(prescaler);
}
static void
setDataMode(DataMode mode)
{
SPCR = (SPCR & ~((1 << CPOL) | (1 << CPHA))) | static_cast<uint8_t>(mode);
}
static void
setDataOrder(DataOrder order)
{
if (order == DataOrder::LsbFirst) {
SPCR |= (1 << DORD);
} else {
SPCR &= ~(1 << DORD);
}
}
static uint8_t
acquire(void *ctx, ConfigurationHandler handler = nullptr);
static uint8_t
release(void *ctx);
static uint8_t
transferBlocking(uint8_t data)
{
%% if parameters.busywait
return transfer(data).getResult();
%% else
return RF_CALL_BLOCKING(transfer(data));
%% endif
}
static void
transferBlocking(uint8_t *tx, uint8_t *rx, std::size_t length)
{
%% if parameters.busywait
transfer(tx, rx, length);
%% else
RF_CALL_BLOCKING(transfer(tx, rx, length));
%% endif
}
static xpcc::ResumableResult<uint8_t>
transfer(uint8_t data);
static xpcc::ResumableResult<void>
transfer(uint8_t *tx, uint8_t *rx, std::size_t length);
// end documentation inherited
protected:
static void
initialize(Prescaler prescaler);
};
} // namespace {{target.family}}
} // namespace xpcc
#endif // XPCC_{{target.family | upper}}_SPI_MASTER_HPP