[136] | 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"
|
---|
[224] | 15 | #include <Arduino.h>
|
---|
[136] | 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 |
|
---|
[224] | 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 |
|
---|
[136] | 55 | void SPIClass::end()
|
---|
| 56 | {
|
---|
| 57 | _p_sercom->resetSPI();
|
---|
| 58 | }
|
---|
| 59 |
|
---|
[224] | 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 |
|
---|
[136] | 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 |
|
---|
[224] | 132 | void SPIClass::setClockDivider(uint16_t div)
|
---|
[136] | 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 |
|
---|
[224] | 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 |
|
---|
[136] | 246 | void SPIClass::attachInterrupt() {
|
---|
| 247 | // Should be enableInterrupt()
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 | void SPIClass::detachInterrupt() {
|
---|
| 251 | // Should be disableInterrupt()
|
---|
| 252 | }
|
---|
| 253 |
|
---|
[224] | 254 | SPIClass SPI(&sercom4, 18, 20, 21);
|
---|