-
Notifications
You must be signed in to change notification settings - Fork 9
/
SPISlave.h
84 lines (67 loc) · 1.9 KB
/
SPISlave.h
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
#ifndef SPI_SLAVE_H
#define SPI_SLAVE_H
#include <tonc.h>
#include "Utils.h"
#define SPI_BIT_CLOCK 0
#define SPI_BIT_SI 2
#define SPI_BIT_SO 3
#define SPI_BIT_START 7
#define SPI_BIT_LENGTH 12
#define SPI_BIT_IRQ 14
class SPISlave {
public:
SPISlave() { start(); }
ALWAYS_INLINE void start() {
setNormalMode();
set32BitPackets();
setSlaveMode();
disableTransfer();
}
ALWAYS_INLINE u32 transfer(u32 value) {
return transfer(
value, []() { return false; }, NULL);
}
template <typename F>
ALWAYS_INLINE u32 transfer(u32 value, F needsBreak, bool* breakFlag) {
setData(value);
enableTransfer();
startTransfer();
while (!isReady()) {
if (needsBreak()) {
setData(0xffffffff);
disableTransfer();
*breakFlag = true;
return 0;
}
}
disableTransfer();
u32 data = getData();
return data;
}
ALWAYS_INLINE void stop() {
stopTransfer();
disableTransfer();
BIT_SET_LOW(REG_SIOCNT, SPI_BIT_IRQ);
BIT_SET_HIGH(REG_SIOCNT, SPI_BIT_IRQ);
// (
// This doesn't make any sense, but it somehow fixes a ~random~ CPU crash
// when using DMA1 for audio and SPI transfers. Source: experimentation.
// )
}
private:
void setNormalMode() {
REG_RCNT = 0;
REG_SIOCNT = 0;
}
void setData(u32 data) { REG_SIODATA32 = data; }
u32 getData() { return REG_SIODATA32; }
void enableTransfer() { BIT_SET_LOW(REG_SIOCNT, SPI_BIT_SO); }
void disableTransfer() { BIT_SET_HIGH(REG_SIOCNT, SPI_BIT_SO); }
void startTransfer() { BIT_SET_HIGH(REG_SIOCNT, SPI_BIT_START); }
void stopTransfer() { BIT_SET_LOW(REG_SIOCNT, SPI_BIT_START); }
bool isReady() { return !BIT_IS_HIGH(REG_SIOCNT, SPI_BIT_START); }
void set32BitPackets() { BIT_SET_HIGH(REG_SIOCNT, SPI_BIT_LENGTH); }
void setSlaveMode() { BIT_SET_LOW(REG_SIOCNT, SPI_BIT_CLOCK); }
};
extern SPISlave* spiSlave;
#endif // SPI_SLAVE_H