forked from esp8266/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathhspi_slave.c
169 lines (144 loc) · 5.19 KB
/
hspi_slave.c
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
/*
SPISlave library for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hspi_slave.h"
#include "esp8266_peri.h"
#include "ets_sys.h"
static void (*_hspi_slave_rx_data_cb)(void * arg, uint8_t * data, uint8_t len) = NULL;
static void (*_hspi_slave_tx_data_cb)(void * arg) = NULL;
static void (*_hspi_slave_rx_status_cb)(void * arg, uint32_t data) = NULL;
static void (*_hspi_slave_tx_status_cb)(void * arg) = NULL;
static uint8_t _hspi_slave_buffer[33];
void ICACHE_RAM_ATTR _hspi_slave_isr_handler(void *arg, void *frame)
{
(void) frame;
uint32_t status;
uint32_t istatus;
istatus = SPIIR;
if(istatus & (1 << SPII1)) { //SPI1 ISR
status = SPI1S;
SPI1S &= ~(0x3E0);//disable interrupts
SPI1S |= SPISSRES;//reset
SPI1S &= ~(0x1F);//clear interrupts
SPI1S |= (0x3E0);//enable interrupts
if((status & SPISRBIS) != 0 && (_hspi_slave_tx_data_cb)) {
_hspi_slave_tx_data_cb(arg);
}
if((status & SPISRSIS) != 0 && (_hspi_slave_tx_status_cb)) {
_hspi_slave_tx_status_cb(arg);
}
if((status & SPISWSIS) != 0 && (_hspi_slave_rx_status_cb)) {
uint32_t s = SPI1WS;
_hspi_slave_rx_status_cb(arg, s);
}
if((status & SPISWBIS) != 0 && (_hspi_slave_rx_data_cb)) {
uint8_t i;
uint32_t data;
_hspi_slave_buffer[32] = 0;
for(i=0; i<8; i++) {
data=SPI1W(i);
_hspi_slave_buffer[i<<2] = data & 0xff;
_hspi_slave_buffer[(i<<2)+1] = (data >> 8) & 0xff;
_hspi_slave_buffer[(i<<2)+2] = (data >> 16) & 0xff;
_hspi_slave_buffer[(i<<2)+3] = (data >> 24) & 0xff;
}
_hspi_slave_rx_data_cb(arg, &_hspi_slave_buffer[0], 32);
}
} else if(istatus & (1 << SPII0)) { //SPI0 ISR
SPI0S &= ~(0x3ff);//clear SPI ISR
} else if(istatus & (1 << SPII2)) {} //I2S ISR
}
void hspi_slave_begin(uint8_t status_len, void * arg)
{
if(status_len > 4) {
status_len = 4; //max 32 bits
}
else if(status_len == 0) {
status_len = 1; //min 8 bits
}
pinMode(SS, SPECIAL);
pinMode(SCK, SPECIAL);
pinMode(MISO, SPECIAL);
pinMode(MOSI, SPECIAL);
SPI1S = SPISE | SPISBE | SPISTRIE | SPISWBIE | SPISRSIE | SPISWSIE | SPISRBIE; //(0x63E0)
//setting config bits in SPI_SLAVE_REG, defined in "esp8266_peri.h" :
//SPISE - spi slave enable
//SPISBE - allows work (read/write) with buffer, without this only? status available
//SPISTRIE - enables TRANS?? interrupt
//other SPISxxIE - enables corresponding interrupts (read(R)/write(W) status(S) and buffer(B))
SPI1U = SPIUMISOH | SPIUCOMMAND | SPIUSSE; // SPI_USER_REG
SPI1CLK = 0;
SPI1U2 = (7 << SPILCOMMAND); // SPI_USER2_REG
SPI1S1 = (((status_len * 8) - 1) << SPIS1LSTA) | (0xff << SPIS1LBUF) | (7 << SPIS1LWBA) | (7 << SPIS1LRBA) | SPIS1RSTA; // SPI_SLAVE1_REG
SPI1P = (1 << 19);
SPI1CMD = SPIBUSY;
// Setting SPIC2MISODM_S makes slave to change MISO value on falling edge on CLK signal as is required for SPIMode 1
// Setting SPIC2MOSIDN_S is probably not critical, all tests run fine with this setting
SPI1C2 = (0x2 << SPIC2MOSIDN_S) | (0x1 << SPIC2MISODM_S);
ETS_SPI_INTR_ATTACH(_hspi_slave_isr_handler,arg);
ETS_SPI_INTR_ENABLE();
}
void hspi_slave_end()
{
ETS_SPI_INTR_DISABLE();
ETS_SPI_INTR_ATTACH(NULL, NULL);
pinMode(SS, INPUT);
pinMode(SCK, INPUT);
pinMode(MISO, INPUT);
pinMode(MOSI, INPUT);
// defaults
SPI1S = 0;
SPI1U = SPIUSSE | SPIUCOMMAND;
SPI1S1 = 0;
SPI1P = B110;
}
void ICACHE_RAM_ATTR hspi_slave_setStatus(uint32_t status)
{
SPI1WS = status;
}
void hspi_slave_setData(uint8_t *data, uint8_t len)
{
uint8_t i;
uint32_t out = 0;
uint8_t bi = 0;
uint8_t wi = 8;
for(i=0; i<32; i++) {
out |= (i<len)?(data[i] << (bi * 8)):0;
bi++;
bi &= 3;
if(!bi) {
SPI1W(wi) = out;
out = 0;
wi++;
}
}
}
void hspi_slave_onData(void (*rxd_cb)(void *, uint8_t *, uint8_t))
{
_hspi_slave_rx_data_cb = rxd_cb;
}
void hspi_slave_onDataSent(void (*txd_cb)(void *))
{
_hspi_slave_tx_data_cb = txd_cb;
}
void hspi_slave_onStatus(void (*rxs_cb)(void *, uint32_t))
{
_hspi_slave_rx_status_cb = rxs_cb;
}
void hspi_slave_onStatusSent(void (*txs_cb)(void *))
{
_hspi_slave_tx_status_cb = txs_cb;
}