-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathsci_spi_io.hpp
233 lines (200 loc) · 5.78 KB
/
sci_spi_io.hpp
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#pragma once
//=========================================================================//
/*! @file
@brief RX グループ・SCI/SPI I/O 制御 @n
※現在、実装中で「未完」となっている。
@author 平松邦仁 ([email protected])
@copyright Copyright (C) 2018, 2022 Kunihito Hiramatsu @n
Released under the MIT license @n
https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=========================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"
/// F_PCLKB はボーレートパラメーター計算に必要で、設定が無いとエラーにします。
#ifndef F_PCLKB
# error "sci_spi_io.hpp requires F_PCLKB to be defined"
#endif
namespace device {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief SCI/SPI I/O 制御クラス
@param[in] SCI SCI 型
@param[in] RBF 受信バッファクラス
@param[in] SBF 送信バッファクラス
@param[in] PSEL ポート選択
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class SCI, class RBF, class SBF, port_map::ORDER PSEL = port_map::ORDER::FIRST>
class sci_spi_io {
static inline RBF recv_;
static inline SBF send_;
uint8_t level_;
// ※マルチタスクの場合適切な実装をする
void sleep_() noexcept { asm("nop"); }
#if 0
static INTERRUPT_FUNC void recv_task_()
{
bool err = false;
if(SCI::SSR.ORER()) { ///< 受信オーバランエラー状態確認
SCI::SSR.ORER = 0; ///< 受信オーバランエラークリア
err = true;
}
///< フレーミングエラー/パリティエラー状態確認
if(SCI::SSR() & (SCI::SSR.FER.b() | SCI::SSR.PER.b())) {
// エラーフラグの消去
SCI::SSR.FER = 0;
SCI::SSR.PER = 0;
err = true;
}
volatile uint8_t data = SCI::RDR();
if(!err) {
recv_.put(data);
}
}
static INTERRUPT_FUNC void send_task_()
{
#if defined(SIG_RX64M) || defined(SIG_RX71M) || defined(SIG_RX65N) || defined(SIG_RX651)
if(send_.length() > 0) {
SCI::TDR = send_.get();
}
if(send_.length() == 0) {
SCI::SCR.TIE = 0;
send_stall_ = true;
}
#else
SCI::TDR = send_.get();
if(send_.length() == 0) {
SCI::SCR.TEIE = 0;
}
#endif
}
void set_vector_(ICU::VECTOR rx_vec, ICU::VECTOR tx_vec) noexcept
{
if(level_) {
icu_mgr::set_task(rx_vec, recv_task_);
icu_mgr::set_task(tx_vec, send_task_);
} else {
icu_mgr::set_task(rx_vec, nullptr);
icu_mgr::set_task(tx_vec, nullptr);
}
}
void set_intr_() noexcept
{
#if defined(SIG_RX64M) || defined(SIG_RX71M) || defined(SIG_RX65N) || defined(SIG_RX651)
set_vector_(SCI::get_rx_vec(), SCI::get_tx_vec());
#else
set_vector_(SCI::get_rx_vec(), SCI::get_te_vec());
#endif
icu_mgr::set_level(SCI::PERIPHERAL, level_);
}
#endif
public:
//-----------------------------------------------------------------//
/*!
@brief コンストラクター
*/
//-----------------------------------------------------------------//
sci_spi_io() noexcept : level_(0) { }
//-----------------------------------------------------------------//
/*!
@brief 簡易 SPI を有効にする
@param[in] bps ビットレート
@param[in] level 割り込みレベル(0の場合ポーリング)
@return エラーなら「false」
*/
//-----------------------------------------------------------------//
bool start(uint32_t bps, uint8_t level = 0) noexcept
{
level_ = level;
power_mgr::turn(SCI::PERIPHERAL);
SCI::SCR = 0x00; // TE, RE disable.
uint32_t brr = F_PCLKB / bps / 2;
if(brr & 1) { brr >>= 1; ++brr; }
else { brr >>= 1; }
uint8_t cks = 0;
while(brr > 256) {
brr >>= 2;
++cks;
}
if(cks > 3 || brr > 256) return false;
set_intr_();
// LSB(0), MSB(1) first
SCI::SCMR.SDIR = 1;
SCI::SIMR1.IICM = 0;
SCI::SMR = cks | SCI::SMR.CM.b();
SCI::SPMR.SSE = 0; ///< SS 端子制御しない「0」
if(master) {
SCI::SPMR.MSS = 0;
} else {
SCI::SPMR.MSS = 1;
}
// クロックタイミング種別選択
SCI::SPMR.CKPOL = 0;
SCI::SPMR.CKPH = 0;
if(brr) --brr;
SCI::BRR = static_cast<uint8_t>(brr);
uint8_t scr = 0;
if(master) {
scr = SCI::SCR.CKE.b(0b01);
} else {
scr = SCI::SCR.CKE.b(0b10);
}
if(level_) {
SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
} else {
SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
}
return true;
}
//-----------------------------------------------------------------//
/*!
@brief 送受信(SPI)
@param[in] ch 送信データ
@return 受信データ
*/
//-----------------------------------------------------------------//
inline uint8_t xchg(uint8_t ch = 0xff) noexcept
{
if(level_) {
return 0;
} else {
SCI::TDR = ch;
while(recv_length() == 0) sleep_();
return SCI::RDR();
}
}
//-----------------------------------------------------------------//
/*!
@brief ブロック送信(SPI)
@param[in] src 送信ソース
@param[in] siz 送信サイズ
*/
//-----------------------------------------------------------------//
void send(const void* src, uint32_t siz) noexcept
{
const uint8_t* p = static_cast<const uint8_t*>(src);
auto end = p + siz;
while(p < end) {
xchg(*p);
++p;
}
}
//-----------------------------------------------------------------//
/*!
@brief ブロック受信(SPI)
@param[out] dst 受信先
@param[in] siz 受信サイズ
*/
//-----------------------------------------------------------------//
void recv(void* dst, uint32_t siz) noexcept
{
uint8_t* p = static_cast<uint8_t*>(dst);
auto end = p + siz;
while(p < end) {
*p = xchg();
++p;
}
}
};
}