1 | /*
|
---|
2 | * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
---|
3 | * SPI Master library for arduino.
|
---|
4 | *
|
---|
5 | * This file is free software; you can redistribute it and/or modify
|
---|
6 | * it under the terms of either the GNU General Public License version 2
|
---|
7 | * or the GNU Lesser General Public License version 2.1, both as
|
---|
8 | * published by the Free Software Foundation.
|
---|
9 | */
|
---|
10 |
|
---|
11 | #include "SPI.h"
|
---|
12 | #include "wiring_digital.h"
|
---|
13 | #include "assert.h"
|
---|
14 | #include "variant.h"
|
---|
15 | #include <Arduino.h>
|
---|
16 |
|
---|
17 | SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI)
|
---|
18 | {
|
---|
19 | assert(p_sercom != NULL );
|
---|
20 | _p_sercom = p_sercom;
|
---|
21 |
|
---|
22 | _uc_pinMiso = uc_pinMISO;
|
---|
23 | _uc_pinSCK = uc_pinSCK;
|
---|
24 | _uc_pinMosi = uc_pinMOSI;
|
---|
25 | }
|
---|
26 |
|
---|
27 | void SPIClass::begin()
|
---|
28 | {
|
---|
29 | // PIO init
|
---|
30 | pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
|
---|
31 | pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
|
---|
32 | pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);
|
---|
33 |
|
---|
34 | // Default speed set to 4Mhz, SPI mode set to MODE 0 and Bit order set to MSB first.
|
---|
35 | _p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, MSB_FIRST);
|
---|
36 | _p_sercom->initSPIClock(SERCOM_SPI_MODE_0, 4000000);
|
---|
37 |
|
---|
38 | _p_sercom->enableSPI();
|
---|
39 | }
|
---|
40 |
|
---|
41 |
|
---|
42 | void SPIClass::beginSlave()
|
---|
43 | {
|
---|
44 | // PIO init
|
---|
45 | pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
|
---|
46 | pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
|
---|
47 | pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);
|
---|
48 |
|
---|
49 | // Default speed set to 4Mhz, SPI mode set to MODE 0 and Bit order set to MSB first.
|
---|
50 | _p_sercom->initSPIslave(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, MSB_FIRST);
|
---|
51 |
|
---|
52 | _p_sercom->enableSPI();
|
---|
53 | }
|
---|
54 |
|
---|
55 | void SPIClass::end()
|
---|
56 | {
|
---|
57 | _p_sercom->resetSPI();
|
---|
58 | }
|
---|
59 |
|
---|
60 |
|
---|
61 | void SPIClass::beginTransaction(SPISettings settings)
|
---|
62 | {
|
---|
63 | SercomDataOrder bitOrder;
|
---|
64 | SercomSpiClockMode SpiClockMode;
|
---|
65 |
|
---|
66 | interruptSave = intStatus();
|
---|
67 | noInterrupts();
|
---|
68 |
|
---|
69 |
|
---|
70 | if(settings.bit_order==LSBFIRST) bitOrder = LSB_FIRST;
|
---|
71 | else if(settings.bit_order==MSBFIRST) bitOrder = MSB_FIRST;
|
---|
72 | else;
|
---|
73 |
|
---|
74 | if(settings.data_mode==SPI_MODE0) SpiClockMode = SERCOM_SPI_MODE_0;
|
---|
75 | else if(settings.data_mode==SPI_MODE1) SpiClockMode = SERCOM_SPI_MODE_1;
|
---|
76 | else if(settings.data_mode==SPI_MODE2) SpiClockMode = SERCOM_SPI_MODE_2;
|
---|
77 | else if(settings.data_mode==SPI_MODE3) SpiClockMode = SERCOM_SPI_MODE_3;
|
---|
78 | else;
|
---|
79 |
|
---|
80 | end();
|
---|
81 |
|
---|
82 | pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
|
---|
83 | pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
|
---|
84 | pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);
|
---|
85 |
|
---|
86 | _p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, bitOrder);
|
---|
87 | _p_sercom->initSPIClock(SpiClockMode, settings.interface_clock);
|
---|
88 |
|
---|
89 | _p_sercom->enableSPI();
|
---|
90 | inTransactionFlag=1;
|
---|
91 | }
|
---|
92 |
|
---|
93 | void SPIClass::endTransaction(void)
|
---|
94 | {
|
---|
95 | inTransactionFlag=0;
|
---|
96 | interrupts();
|
---|
97 | }
|
---|
98 |
|
---|
99 | void SPIClass::setBitOrder(BitOrder order)
|
---|
100 | {
|
---|
101 | if(order == LSBFIRST)
|
---|
102 | _p_sercom->setDataOrderSPI(LSB_FIRST);
|
---|
103 | else
|
---|
104 | _p_sercom->setDataOrderSPI(MSB_FIRST);
|
---|
105 | }
|
---|
106 |
|
---|
107 | void SPIClass::setDataMode(uint8_t mode)
|
---|
108 | {
|
---|
109 | switch(mode)
|
---|
110 | {
|
---|
111 | case SPI_MODE0:
|
---|
112 | _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_0);
|
---|
113 | break;
|
---|
114 |
|
---|
115 | case SPI_MODE1:
|
---|
116 | _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_1);
|
---|
117 | break;
|
---|
118 |
|
---|
119 | case SPI_MODE2:
|
---|
120 | _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_2);
|
---|
121 | break;
|
---|
122 |
|
---|
123 | case SPI_MODE3:
|
---|
124 | _p_sercom->setClockModeSPI(SERCOM_SPI_MODE_3);
|
---|
125 | break;
|
---|
126 |
|
---|
127 | default:
|
---|
128 | break;
|
---|
129 | }
|
---|
130 | }
|
---|
131 |
|
---|
132 | void SPIClass::setClockDivider(uint16_t div)
|
---|
133 | {
|
---|
134 | _p_sercom->setBaudrateSPI(div);
|
---|
135 | }
|
---|
136 |
|
---|
137 | byte SPIClass::transfer(uint8_t data)
|
---|
138 | {
|
---|
139 | //Writing the data
|
---|
140 | _p_sercom->writeDataSPI(data);
|
---|
141 |
|
---|
142 | //Read data
|
---|
143 | return _p_sercom->readDataSPI();
|
---|
144 | }
|
---|
145 |
|
---|
146 | byte SPIClass::read()
|
---|
147 | {
|
---|
148 | return _p_sercom->readDataSPI();
|
---|
149 | }
|
---|
150 |
|
---|
151 | void SPIClass::usingInterrupt(uint8_t intNum)
|
---|
152 | {
|
---|
153 | uint8_t irestore;
|
---|
154 | uint32_t mask;
|
---|
155 |
|
---|
156 | irestore=intStatus();
|
---|
157 | noInterrupts();
|
---|
158 | if(intNum > 13)
|
---|
159 | {
|
---|
160 | //Interrupts();
|
---|
161 | return;
|
---|
162 | }
|
---|
163 | else
|
---|
164 | {
|
---|
165 | //Pio *pio=g_APinDescription[intNum].ulPort;
|
---|
166 | mask=g_APinDescription[intNum].ulPin;
|
---|
167 | interruptMode=1;
|
---|
168 | interruptMask=mask;
|
---|
169 | }
|
---|
170 | if (irestore) interrupts();
|
---|
171 | }
|
---|
172 |
|
---|
173 | void SPIClass::write(uint8_t data)
|
---|
174 | {
|
---|
175 | //Writing the data
|
---|
176 | _p_sercom->writeDataSPI(data);
|
---|
177 | }
|
---|
178 |
|
---|
179 | void SPIClass::transfer(void *data, size_t count)
|
---|
180 | {
|
---|
181 | uint8_t *p;
|
---|
182 | //int i=0;
|
---|
183 | //Serial.println("dentro transfer");
|
---|
184 | if(count==0) return;
|
---|
185 | p=(uint8_t *)data;
|
---|
186 | _p_sercom->writeDataSPI(*p); //scrittura primo dato
|
---|
187 |
|
---|
188 | while(--count > 0)
|
---|
189 | {
|
---|
190 | //Serial.println("dentro while");
|
---|
191 | uint8_t out=*(p+1); //copio in out il prossimo dato
|
---|
192 | uint8_t in = _p_sercom->readDataSPI(); //leggo dato da SPI
|
---|
193 | //Serial.println("UNO");
|
---|
194 | //while(!(SERCOM4->SPI.INTFLAG.bit.RXC)); // controllo trasferimento //vedere se necessario
|
---|
195 | //Serial.println("DUE");
|
---|
196 | //Serial.println(out);
|
---|
197 | _p_sercom->writeDataSPI(out); //scrivo il out su SPI
|
---|
198 | *p++=in; //metto in p il dato letto da spi
|
---|
199 | }
|
---|
200 | while(!(SERCOM4->SPI.INTFLAG.bit.TXC)); // controllo trasferimrnto
|
---|
201 | //Serial.print("*p: ");
|
---|
202 | //Serial.println(*p);
|
---|
203 | *p = _p_sercom->readDataSPI();
|
---|
204 |
|
---|
205 |
|
---|
206 |
|
---|
207 | }
|
---|
208 |
|
---|
209 | uint16_t SPIClass::transfer16(uint16_t data)
|
---|
210 | {
|
---|
211 | union{
|
---|
212 | uint16_t value;
|
---|
213 | struct{
|
---|
214 | uint8_t lsb;
|
---|
215 | uint8_t msb;
|
---|
216 | };
|
---|
217 | }in, out;
|
---|
218 |
|
---|
219 | in.value = data;
|
---|
220 |
|
---|
221 | if(SERCOM4->SPI.CTRLA.bit.DORD==0)
|
---|
222 | {
|
---|
223 | _p_sercom->writeDataSPI(in.msb);
|
---|
224 | while(!(SERCOM4->SPI.INTFLAG.bit.TXC));
|
---|
225 | out.msb = _p_sercom->readDataSPI();
|
---|
226 | //while(!(SERCOM4->SPI.INTFLAG.bit.RXC));
|
---|
227 | _p_sercom->writeDataSPI(in.lsb);
|
---|
228 | while(!(SERCOM4->SPI.INTFLAG.bit.TXC));
|
---|
229 | out.lsb = _p_sercom->readDataSPI();
|
---|
230 | }
|
---|
231 |
|
---|
232 | else
|
---|
233 | {
|
---|
234 | _p_sercom->writeDataSPI(in.lsb);
|
---|
235 | while(!(SERCOM4->SPI.INTFLAG.bit.TXC));
|
---|
236 | out.lsb = _p_sercom->readDataSPI();
|
---|
237 | //while(!(SERCOM4->SPI.INTFLAG.bit.RXC));
|
---|
238 | _p_sercom->writeDataSPI(in.msb);
|
---|
239 | while(!(SERCOM4->SPI.INTFLAG.bit.TXC));
|
---|
240 | out.msb = _p_sercom->readDataSPI();
|
---|
241 | }
|
---|
242 |
|
---|
243 | return out.value;
|
---|
244 | }
|
---|
245 |
|
---|
246 | void SPIClass::attachInterrupt() {
|
---|
247 | // Should be enableInterrupt()
|
---|
248 | }
|
---|
249 |
|
---|
250 | void SPIClass::detachInterrupt() {
|
---|
251 | // Should be disableInterrupt()
|
---|
252 | }
|
---|
253 |
|
---|
254 | SPIClass SPI(&sercom4, 18, 20, 21);
|
---|