Skip to content

Commit 3246565

Browse files
authored
Merge pull request sipeed#8 from ReinForce-II/add_spi_com
add SPI lib
2 parents 252dfbb + 5524103 commit 3246565

File tree

7 files changed

+473
-85
lines changed

7 files changed

+473
-85
lines changed

cores/arduino/Common.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#include "Arduino.h"
55

6-
76
#ifdef __cplusplus
87
extern "C"{
98
#endif

libraries/SPI/keywords.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#######################################
2+
# Syntax Coloring Map SPI
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
SPI KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
begin KEYWORD2
15+
end KEYWORD2
16+
beginTransaction KEYWORD2
17+
endTransaction KEYWORD2
18+
transfer KEYWORD2
19+
setBitOrder KEYWORD2
20+
setDataMode KEYWORD2
21+
setFrequency KEYWORD2
22+
23+
#######################################
24+
# Constants (LITERAL1)
25+
#######################################
26+
SPI_MODE0 LITERAL1
27+
SPI_MODE1 LITERAL1
28+
SPI_MODE2 LITERAL1
29+
SPI_MODE3 LITERAL1

libraries/SPI/library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=SPI
2+
version=0.1
3+
author=Reinforce-II
4+
maintainer=Longduino
5+
sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus.
6+
paragraph=SPI is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. It uses three lines common to all devices (MISO, MOSI and SCK) and one specific for each device.
7+
category=Communication
8+
url=http://arduino.cc/en/Reference/SPI
9+
architectures=gd32v

libraries/SPI/src/SPI.cpp

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
#include "SPI.h"
2+
#include <gd32vf103.h>
3+
#include "Common.h"
4+
5+
SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel)
6+
: _dev(0)
7+
, _dev_clk(RCU_SPI0)
8+
, _mosi_bank(0)
9+
, _miso_bank(0)
10+
, _sclk_bank(0)
11+
, _ssel_bank(0)
12+
, _mosi_bit(0)
13+
, _miso_bit(0)
14+
, _sclk_bit(0)
15+
, _ssel_bit(0)
16+
, _mosi_bank_clk(RCU_GPIOA)
17+
, _miso_bank_clk(RCU_GPIOA)
18+
, _sclk_bank_clk(RCU_GPIOA)
19+
, _ssel_bank_clk(RCU_GPIOA) {
20+
if (mosi < VARIANT_GPIO_NUM && digitalPinSPIAvailiable(mosi)) {
21+
_dev = digitalPinToSPIDevice(mosi);
22+
_dev_clk = digitalPinToSPIClockId(mosi);
23+
_mosi_bank = digitalPinToPort(mosi);
24+
_mosi_bit = digitalPinToBitMask(mosi);
25+
_mosi_bank_clk = digitalPinToClkid(mosi);
26+
}
27+
if (miso < VARIANT_GPIO_NUM && digitalPinSPIAvailiable(miso)) {
28+
_dev = digitalPinToSPIDevice(miso);
29+
_dev_clk = digitalPinToSPIClockId(miso);
30+
_miso_bank = digitalPinToPort(miso);
31+
_miso_bit = digitalPinToBitMask(miso);
32+
_miso_bank_clk = digitalPinToClkid(miso);
33+
}
34+
if (sclk < VARIANT_GPIO_NUM && digitalPinSPIAvailiable(sclk)) {
35+
_sclk_bank = digitalPinToPort(sclk);
36+
_sclk_bit = digitalPinToBitMask(sclk);
37+
_sclk_bank_clk = digitalPinToClkid(sclk);
38+
}
39+
if (ssel < VARIANT_GPIO_NUM) {}
40+
_ssel_bank = digitalPinToPort(ssel);
41+
_ssel_bit = digitalPinToBitMask(ssel);
42+
_ssel_bank_clk = digitalPinToClkid(ssel);
43+
if (digitalPinSPIAvailiable(ssel)) {
44+
_ssel_hard = 1;
45+
}
46+
}
47+
48+
void SPIClass::begin() {
49+
if (_dev == 0) {
50+
return;
51+
}
52+
if (_mosi_bank != 0) {
53+
rcu_periph_clock_enable((rcu_periph_enum)_mosi_bank_clk);
54+
gpio_init(_mosi_bank, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, _mosi_bit);
55+
}
56+
if (_miso_bank != 0) {
57+
rcu_periph_clock_enable((rcu_periph_enum)_miso_bank_clk);
58+
gpio_init(
59+
_miso_bank, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, _miso_bit);
60+
}
61+
if (_sclk_bank != 0) {
62+
rcu_periph_clock_enable((rcu_periph_enum)_sclk_bank_clk);
63+
gpio_init(_sclk_bank, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, _sclk_bit);
64+
}
65+
if (_ssel_bank != 0) {
66+
rcu_periph_clock_enable((rcu_periph_enum)_ssel_bank_clk);
67+
gpio_init(_ssel_bank, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, _ssel_bit);
68+
if (_ssel_hard == 0) {
69+
gpio_bit_set(_ssel_bank, _ssel_bit);
70+
}
71+
}
72+
rcu_periph_clock_enable((rcu_periph_enum)_dev_clk);
73+
spi_i2s_deinit((uint32_t)_dev);
74+
}
75+
76+
void SPIClass::end() {
77+
if (_dev == 0) {
78+
return;
79+
}
80+
if (_mosi_bank != 0) {
81+
gpio_init(_mosi_bank, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, _mosi_bit);
82+
}
83+
if (_miso_bank != 0) {
84+
gpio_init(_miso_bank, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, _miso_bit);
85+
}
86+
if (_sclk_bank != 0) {
87+
gpio_init(_sclk_bank, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, _sclk_bit);
88+
}
89+
if (_ssel_bank != 0) {
90+
gpio_init(_ssel_bank, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, _ssel_bit);
91+
}
92+
spi_i2s_deinit((uint32_t)_dev);
93+
rcu_periph_clock_disable((rcu_periph_enum)_dev_clk);
94+
}
95+
96+
void SPIClass::beginTransaction(SPISettings settings) {
97+
if (_dev == 0) {
98+
return;
99+
}
100+
if (settings._freq == 0) {
101+
return;
102+
}
103+
if (_dev == SPI0 && settings._freq > rcu_clock_freq_get(CK_APB2)) {
104+
return;
105+
}
106+
else if (settings._freq > rcu_clock_freq_get(CK_APB1)) {
107+
return;
108+
}
109+
_dataMode = settings._dataMode;
110+
_bitOrder = settings._bitOrder;
111+
_freq = settings._freq;
112+
beginTransaction();
113+
}
114+
115+
void SPIClass::endTransaction() {
116+
if (_dev == 0) {
117+
return;
118+
}
119+
spi_disable(_dev);
120+
}
121+
122+
void SPIClass::transfer(uint8_t* data, uint32_t size, uint32_t timeout) {
123+
if (_dev == 0 || data == nullptr) {
124+
return;
125+
}
126+
uint64_t startT = millis();
127+
128+
if (_ssel_hard == 0 && _ssel_bank != 0) {
129+
gpio_bit_reset(_ssel_bank, _ssel_bit);
130+
}
131+
132+
for (size_t i = 0; i < size; i++) {
133+
while (!spi_i2s_flag_get(_dev, SPI_FLAG_TBE)) {
134+
if (millis() > startT + timeout) {
135+
if (_ssel_hard == 0 && _ssel_bank != 0) {
136+
gpio_bit_set(_ssel_bank, _ssel_bit);
137+
}
138+
return;
139+
}
140+
}
141+
spi_i2s_data_transmit(_dev, *data);
142+
data++;
143+
}
144+
145+
if (_ssel_hard == 0 && _ssel_bank != 0) {
146+
gpio_bit_set(_ssel_bank, _ssel_bit);
147+
}
148+
}
149+
150+
void SPIClass::transfer(
151+
uint8_t* txdata, uint8_t* rxdata, uint32_t size, uint32_t timeout) {
152+
if (_dev == 0 || txdata == nullptr || rxdata == nullptr) {
153+
return;
154+
}
155+
uint64_t startT = millis();
156+
157+
if (_ssel_hard == 0 && _ssel_bank != 0) {
158+
gpio_bit_reset(_ssel_bank, _ssel_bit);
159+
}
160+
161+
for (size_t i = 0; i < size; i++) {
162+
while (!spi_i2s_flag_get(_dev, SPI_FLAG_TBE)) {
163+
if (millis() > startT + timeout) {
164+
if (_ssel_hard == 0 && _ssel_bank != 0) {
165+
gpio_bit_set(_ssel_bank, _ssel_bit);
166+
}
167+
return;
168+
}
169+
}
170+
spi_i2s_data_transmit(_dev, *txdata);
171+
txdata++;
172+
while (!spi_i2s_flag_get(_dev, SPI_FLAG_RBNE)) {
173+
if (millis() > startT + timeout) {
174+
if (_ssel_hard == 0 && _ssel_bank != 0) {
175+
gpio_bit_set(_ssel_bank, _ssel_bit);
176+
}
177+
return;
178+
}
179+
}
180+
*rxdata = spi_i2s_data_receive(_dev);
181+
rxdata++;
182+
}
183+
184+
if (_ssel_hard == 0 && _ssel_bank != 0) {
185+
gpio_bit_set(_ssel_bank, _ssel_bit);
186+
}
187+
}
188+
189+
void SPIClass::setBitOrder(uint8_t bitOrder) {
190+
_bitOrder = bitOrder;
191+
beginTransaction();
192+
}
193+
194+
void SPIClass::setDataMode(uint8_t dataMode) {
195+
_dataMode = dataMode;
196+
beginTransaction();
197+
}
198+
199+
void SPIClass::setFrequency(uint32_t freq) {
200+
if (_dev == 0) {
201+
return;
202+
}
203+
if (freq == 0) {
204+
return;
205+
}
206+
if (_dev == SPI0 && freq > rcu_clock_freq_get(CK_APB2)) {
207+
return;
208+
}
209+
else if (freq > rcu_clock_freq_get(CK_APB1)) {
210+
return;
211+
}
212+
_freq = freq;
213+
beginTransaction();
214+
}
215+
216+
void SPIClass::beginTransaction() {
217+
if (_dev == 0) {
218+
return;
219+
}
220+
spi_parameter_struct param;
221+
switch (_dataMode) {
222+
case SPI_MODE0:
223+
param.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
224+
break;
225+
case SPI_MODE1:
226+
param.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE;
227+
break;
228+
case SPI_MODE2:
229+
param.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
230+
break;
231+
case SPI_MODE3:
232+
param.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
233+
break;
234+
default:
235+
return;
236+
}
237+
param.device_mode = SPI_MASTER;
238+
param.endian = _bitOrder == MSBFIRST ? SPI_ENDIAN_MSB : SPI_ENDIAN_LSB;
239+
param.frame_size = SPI_FRAMESIZE_8BIT;
240+
param.nss = _ssel_hard ? SPI_NSS_HARD : SPI_NSS_SOFT;
241+
uint32_t prescale = 0;
242+
if (_dev == SPI0) {
243+
prescale = rcu_clock_freq_get(CK_APB2) / _freq - 1;
244+
}
245+
else {
246+
prescale = rcu_clock_freq_get(CK_APB1) / _freq - 1;
247+
}
248+
param.prescale = prescale;
249+
param.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
250+
spi_init(_dev, &param);
251+
spi_enable(_dev);
252+
}

libraries/SPI/src/SPI.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#ifndef __LIB_SPI_H__
2+
#define __LIB_SPI_H__
3+
4+
#include "stdint.h"
5+
6+
#define SPI_LSBFIRST 0
7+
#define SPI_MSBFIRST 1
8+
9+
#define SPI_MODE0 0
10+
#define SPI_MODE1 1
11+
#define SPI_MODE2 2
12+
#define SPI_MODE3 3
13+
14+
15+
class SPISettings {
16+
public:
17+
SPISettings()
18+
: _freq(1000000)
19+
, _bitOrder(SPI_MSBFIRST)
20+
, _dataMode(SPI_MODE0) {}
21+
SPISettings(uint32_t freq, uint8_t bitOrder, uint8_t dataMode);
22+
uint32_t _freq;
23+
uint8_t _bitOrder;
24+
uint8_t _dataMode;
25+
};
26+
27+
class SPIClass {
28+
private:
29+
uint32_t _dev;
30+
uint32_t _dev_clk;
31+
uint32_t _mosi_bank;
32+
uint32_t _miso_bank;
33+
uint32_t _sclk_bank;
34+
uint32_t _ssel_bank;
35+
uint32_t _mosi_bit;
36+
uint32_t _miso_bit;
37+
uint32_t _sclk_bit;
38+
uint32_t _ssel_bit;
39+
uint32_t _mosi_bank_clk;
40+
uint32_t _miso_bank_clk;
41+
uint32_t _sclk_bank_clk;
42+
uint32_t _ssel_bank_clk;
43+
uint8_t _dataMode;
44+
uint8_t _bitOrder;
45+
uint32_t _freq;
46+
uint8_t _ssel_hard;
47+
48+
void beginTransaction();
49+
50+
public:
51+
SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel = -1);
52+
void begin();
53+
void end();
54+
55+
void beginTransaction(SPISettings settings);
56+
void endTransaction();
57+
58+
// timeout in ms
59+
void transfer(uint8_t* data, uint32_t size, uint32_t timeout = 1);
60+
void transfer(
61+
uint8_t* txdata, uint8_t* rxdata, uint32_t size, uint32_t timeout = 1);
62+
63+
void setBitOrder(uint8_t bitOrder);
64+
void setDataMode(uint8_t dataMode);
65+
void setFrequency(uint32_t freq);
66+
};
67+
68+
extern SPIClass SPI;
69+
70+
71+
#endif //__LIB_SPI_H__

0 commit comments

Comments
 (0)