forked from ahessling/RFM69-STM32
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spiL1.cpp
158 lines (136 loc) · 3 KB
/
spiL1.cpp
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
/**
* @file spiL1.cpp
* @brief STM32L1 SPI class.
* @date January 2015
* @author André Heßling
*
* Class for communicating with other SPI devices using the STM32L1 controller.
*/
/** @addtogroup SPI
* @{
*/
#include "spiL1.hpp"
/**
* Initialize the peripheral clocks needed for SPI transfers.
*
* @return true if OK, else false.
*/
bool SPI::initClock()
{
bool clockEnabled = true;
// init clocks
if (_spi == SPI1)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
}
else if (_spi == SPI2)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
}
else if (_spi == SPI3)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
}
else
{
clockEnabled = false;
}
return clockEnabled;
}
/**
* Init SPI peripheral.
*
* @return true if OK, else false
*/
bool SPI::init()
{
// deinit before init
if (true == _init)
deinit();
// enable peripheral clock
if (false == initClock())
return false;
// configure SPI
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = (_bits == 8) ? SPI_DataSize_8b : SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = _cpol ? SPI_CPOL_High : SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = _cpha ? SPI_CPHA_2Edge : SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = _prescaler;
SPI_InitStructure.SPI_FirstBit = _firstBitLSB ? SPI_FirstBit_LSB : SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(_spi, &SPI_InitStructure);
// enable SPI
SPI_Cmd(_spi, ENABLE);
_init = true;
return _init;
}
/**
* Deinit the SPI peripheral.
*/
void SPI::deinit()
{
// fixme: check if transfer is pending
SPI_I2S_DeInit(_spi);
_init = false;
}
/**
* SPI read/write.
*
* Depending on the number of bits per transfer unit,
* 8 or 16 bits are read/written.
*
* @param data Data to be sent
* @return Data received
*/
uint16_t SPI::transfer(uint16_t data)
{
// truncate data if necessary
if (8 == _bits)
data &= 0xff;
// SPI must be init'd
if (false == _init)
return 0;
// wait for TX buffer empty (transfer finished)
while ((_spi->SR & SPI_I2S_FLAG_TXE) == RESET);
// transfer
_spi->DR = data;
// wait for RX buffer full (transfer finished)
while ((_spi->SR & SPI_I2S_FLAG_RXNE) == RESET);
// get received data
data = _spi->DR;
// truncate data if necessary
if (8 == _bits)
return data & 0xff;
else
return data;
}
/**
* Select the device.
*
* Can be used if only one device shall be addressed.
*
* @note Can only be used if configureCS() has been called before.
*/
void SPI::select()
{
if (_csGPIO != 0)
_csGPIO->BSRRH = _csPin;
}
/**
* Release the device.
*
* Can be used if only one device shall be addressed.
*
* @note Can only be used if configureCS() has been called before.
*/
void SPI::unselect()
{
if (_csGPIO != 0)
_csGPIO->BSRRL = _csPin;
}
/** @}
*
*/