1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-12-02 13:24:12 +01:00

Merge pull request #2365 from cmaglie/ide-1.0.x-spi-transaction

[IDE 1.0.x (backport from 1.5.x)] SPI Transactions
This commit is contained in:
Cristian Maglie 2014-12-02 22:24:51 +01:00
commit 1be99c3a1d
45 changed files with 1071 additions and 456 deletions

View File

@ -2,12 +2,16 @@
ARDUINO 1.0.7 ARDUINO 1.0.7
[libraries] [libraries]
* Backported GSM from IDE 1.5.x * Backported SPI Transaction API from IDE 1.5.x (Paul Stoffregen)
* EthernetClien: use IANA recommended ephemeral port range, 49152-65535 (Jack Christensen, cifer-lee) * Backported GSM from IDE 1.5.x: fix build regression
* Backported Ethernet from IDE 1.5.x
* Backported SD from IDE 1.5.x
* Backported SPI from IDE 1.5.x
* EthernetClient: use IANA recommended ephemeral port range, 49152-65535 (Jack Christensen, cifer-lee)
[core] [core]
* Fixed missing NOT_AN_INTERRUPT constant in digitalPinToInterrupt() macro * Fixed missing NOT_AN_INTERRUPT constant in digitalPinToInterrupt() macro
* Fixed regression in HardwareSerial::available() introduced with https://github.com/arduino/Arduino/pull/2057 * Fixed performance regression in HardwareSerial::available() introduced with https://github.com/arduino/Arduino/pull/2057
ARDUINO 1.0.6 - 2014.09.16 ARDUINO 1.0.6 - 2014.09.16

View File

@ -34,6 +34,8 @@
extern "C"{ extern "C"{
#endif #endif
void yield(void);
#define HIGH 0x1 #define HIGH 0x1
#define LOW 0x0 #define LOW 0x0

View File

@ -0,0 +1,31 @@
/*
Copyright (c) 2012 Arduino. All right reserved.
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
*/
/**
* Empty yield() hook.
*
* This function is intended to be used by library writers to build
* libraries or sketches that supports cooperative threads.
*
* Its defined as a weak symbol and it can be redefined to implement a
* real cooperative scheduler.
*/
static void __empty() {
// Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));

View File

@ -111,6 +111,7 @@ void delay(unsigned long ms)
uint16_t start = (uint16_t)micros(); uint16_t start = (uint16_t)micros();
while (ms > 0) { while (ms > 0) {
yield();
if (((uint16_t)micros() - start) >= 1000) { if (((uint16_t)micros() - start) >= 1000) {
ms--; ms--;
start += 1000; start += 1000;

4
libraries/Ethernet/Dhcp.cpp Executable file → Normal file
View File

@ -1,13 +1,13 @@
// DHCP Library v0.3 - April 25, 2009 // DHCP Library v0.3 - April 25, 2009
// Author: Jordan Terrell - blog.jordanterrell.com // Author: Jordan Terrell - blog.jordanterrell.com
#include "w5100.h" #include "utility/w5100.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "Dhcp.h" #include "Dhcp.h"
#include "Arduino.h" #include "Arduino.h"
#include "util.h" #include "utility/util.h"
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
{ {

0
libraries/Ethernet/Dhcp.h Executable file → Normal file
View File

View File

@ -2,9 +2,9 @@
// (c) Copyright 2009-2010 MCQN Ltd. // (c) Copyright 2009-2010 MCQN Ltd.
// Released under Apache License, version 2.0 // Released under Apache License, version 2.0
#include "w5100.h" #include "utility/w5100.h"
#include "EthernetUdp.h" #include "EthernetUdp.h"
#include "util.h" #include "utility/util.h"
#include "Dns.h" #include "Dns.h"
#include <string.h> #include <string.h>

View File

@ -1,4 +1,4 @@
#include "w5100.h" #include "utility/w5100.h"
#include "Ethernet.h" #include "Ethernet.h"
#include "Dhcp.h" #include "Dhcp.h"
@ -16,8 +16,10 @@ int EthernetClass::begin(uint8_t *mac_address)
// Initialise the basic info // Initialise the basic info
W5100.init(); W5100.init();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.setMACAddress(mac_address); W5100.setMACAddress(mac_address);
W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); W5100.setIPAddress(IPAddress(0,0,0,0).raw_address());
SPI.endTransaction();
// Now try to get our config info from a DHCP server // Now try to get our config info from a DHCP server
int ret = _dhcp->beginWithDHCP(mac_address); int ret = _dhcp->beginWithDHCP(mac_address);
@ -25,9 +27,11 @@ int EthernetClass::begin(uint8_t *mac_address)
{ {
// We've successfully found a DHCP server and got our configuration info, so set things // We've successfully found a DHCP server and got our configuration info, so set things
// accordingly // accordingly
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); W5100.setIPAddress(_dhcp->getLocalIp().raw_address());
W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address());
W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address());
SPI.endTransaction();
_dnsServerAddress = _dhcp->getDnsServerIp(); _dnsServerAddress = _dhcp->getDnsServerIp();
} }
@ -61,10 +65,12 @@ void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dn
void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet)
{ {
W5100.init(); W5100.init();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.setMACAddress(mac); W5100.setMACAddress(mac);
W5100.setIPAddress(local_ip._address); W5100.setIPAddress(local_ip.raw_address());
W5100.setGatewayIp(gateway._address); W5100.setGatewayIp(gateway.raw_address());
W5100.setSubnetMask(subnet._address); W5100.setSubnetMask(subnet.raw_address());
SPI.endTransaction();
_dnsServerAddress = dns_server; _dnsServerAddress = dns_server;
} }
@ -80,9 +86,11 @@ int EthernetClass::maintain(){
case DHCP_CHECK_RENEW_OK: case DHCP_CHECK_RENEW_OK:
case DHCP_CHECK_REBIND_OK: case DHCP_CHECK_REBIND_OK:
//we might have got a new IP. //we might have got a new IP.
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); W5100.setIPAddress(_dhcp->getLocalIp().raw_address());
W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address());
W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address());
SPI.endTransaction();
_dnsServerAddress = _dhcp->getDnsServerIp(); _dnsServerAddress = _dhcp->getDnsServerIp();
break; break;
default: default:
@ -96,21 +104,27 @@ int EthernetClass::maintain(){
IPAddress EthernetClass::localIP() IPAddress EthernetClass::localIP()
{ {
IPAddress ret; IPAddress ret;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.getIPAddress(ret.raw_address()); W5100.getIPAddress(ret.raw_address());
SPI.endTransaction();
return ret; return ret;
} }
IPAddress EthernetClass::subnetMask() IPAddress EthernetClass::subnetMask()
{ {
IPAddress ret; IPAddress ret;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.getSubnetMask(ret.raw_address()); W5100.getSubnetMask(ret.raw_address());
SPI.endTransaction();
return ret; return ret;
} }
IPAddress EthernetClass::gatewayIP() IPAddress EthernetClass::gatewayIP()
{ {
IPAddress ret; IPAddress ret;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.getGatewayIp(ret.raw_address()); W5100.getGatewayIp(ret.raw_address());
SPI.endTransaction();
return ret; return ret;
} }

View File

@ -1,5 +1,5 @@
#include "w5100.h" #include "utility/w5100.h"
#include "socket.h" #include "utility/socket.h"
extern "C" { extern "C" {
#include "string.h" #include "string.h"
@ -40,7 +40,7 @@ int EthernetClient::connect(IPAddress ip, uint16_t port) {
return 0; return 0;
for (int i = 0; i < MAX_SOCK_NUM; i++) { for (int i = 0; i < MAX_SOCK_NUM; i++) {
uint8_t s = W5100.readSnSR(i); uint8_t s = socketStatus(i);
if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) {
_sock = i; _sock = i;
break; break;
@ -88,7 +88,7 @@ size_t EthernetClient::write(const uint8_t *buf, size_t size) {
int EthernetClient::available() { int EthernetClient::available() {
if (_sock != MAX_SOCK_NUM) if (_sock != MAX_SOCK_NUM)
return W5100.getRXReceivedSize(_sock); return recvAvailable(_sock);
return 0; return 0;
} }
@ -120,8 +120,7 @@ int EthernetClient::peek() {
} }
void EthernetClient::flush() { void EthernetClient::flush() {
while (available()) ::flush(_sock);
read();
} }
void EthernetClient::stop() { void EthernetClient::stop() {
@ -154,7 +153,7 @@ uint8_t EthernetClient::connected() {
uint8_t EthernetClient::status() { uint8_t EthernetClient::status() {
if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED;
return W5100.readSnSR(_sock); return socketStatus(_sock);
} }
// the next function allows us to use the client returned by // the next function allows us to use the client returned by

View File

@ -1,5 +1,5 @@
#include "w5100.h" #include "utility/w5100.h"
#include "socket.h" #include "utility/socket.h"
extern "C" { extern "C" {
#include "string.h" #include "string.h"
} }

View File

@ -26,8 +26,8 @@
* bjoern@cs.stanford.edu 12/30/2008 * bjoern@cs.stanford.edu 12/30/2008
*/ */
#include "w5100.h" #include "utility/w5100.h"
#include "socket.h" #include "utility/socket.h"
#include "Ethernet.h" #include "Ethernet.h"
#include "Udp.h" #include "Udp.h"
#include "Dns.h" #include "Dns.h"
@ -41,7 +41,7 @@ uint8_t EthernetUDP::begin(uint16_t port) {
return 0; return 0;
for (int i = 0; i < MAX_SOCK_NUM; i++) { for (int i = 0; i < MAX_SOCK_NUM; i++) {
uint8_t s = W5100.readSnSR(i); uint8_t s = socketStatus(i);
if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
_sock = i; _sock = i;
break; break;
@ -120,7 +120,7 @@ int EthernetUDP::parsePacket()
// discard any remaining bytes in the last packet // discard any remaining bytes in the last packet
flush(); flush();
if (W5100.getRXReceivedSize(_sock) > 0) if (recvAvailable(_sock) > 0)
{ {
//HACK - hand-parse the UDP packet using TCP recv method //HACK - hand-parse the UDP packet using TCP recv method
uint8_t tmpBuf[8]; uint8_t tmpBuf[8];

View File

@ -29,10 +29,11 @@
// assign a MAC address for the ethernet controller. // assign a MAC address for the ethernet controller.
// fill in your address here: // fill in your address here:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
// assign an IP address for the controller: // assign an IP address for the controller:
IPAddress ip(192,168,1,20); IPAddress ip(192, 168, 1, 20);
IPAddress gateway(192,168,1,1); IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0); IPAddress subnet(255, 255, 255, 0);
@ -85,7 +86,7 @@ void setup() {
void loop() { void loop() {
// check for a reading no more than once a second. // check for a reading no more than once a second.
if (millis() - lastReadingTime > 1000){ if (millis() - lastReadingTime > 1000) {
// if there's a reading ready, read it: // if there's a reading ready, read it:
// don't do anything until the data ready pin is high: // don't do anything until the data ready pin is high:
if (digitalRead(dataReadyPin) == HIGH) { if (digitalRead(dataReadyPin) == HIGH) {
@ -115,7 +116,7 @@ void getData() {
//Read the pressure data lower 16 bits: //Read the pressure data lower 16 bits:
unsigned int pressureDataLow = readRegister(0x20, 2); unsigned int pressureDataLow = readRegister(0x20, 2);
//combine the two parts into one 19-bit number: //combine the two parts into one 19-bit number:
pressure = ((pressureDataHigh << 16) | pressureDataLow)/4; pressure = ((pressureDataHigh << 16) | pressureDataLow) / 4;
Serial.print("Temperature: "); Serial.print("Temperature: ");
Serial.print(temperature); Serial.print(temperature);
@ -210,10 +211,10 @@ unsigned int readRegister(byte registerName, int numBytes) {
result = inByte; result = inByte;
// if there's more than one byte returned, // if there's more than one byte returned,
// shift the first byte then get the second byte: // shift the first byte then get the second byte:
if (numBytes > 1){ if (numBytes > 1) {
result = inByte << 8; result = inByte << 8;
inByte = SPI.transfer(0x00); inByte = SPI.transfer(0x00);
result = result |inByte; result = result | inByte;
} }
// take the chip select high to de-select: // take the chip select high to de-select:
digitalWrite(chipSelectPin, HIGH); digitalWrite(chipSelectPin, HIGH);

View File

@ -24,9 +24,10 @@
// The IP address will be dependent on your local network. // The IP address will be dependent on your local network.
// gateway and subnet are optional: // gateway and subnet are optional:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
IPAddress ip(192,168,1, 177); };
IPAddress gateway(192,168,1, 1); IPAddress ip(192, 168, 1, 177);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0); IPAddress subnet(255, 255, 0, 0);

View File

@ -20,7 +20,8 @@
// Enter a MAC address for your controller below. // Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield // Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { byte mac[] = {
0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02
};
// Initialize the Ethernet client library // Initialize the Ethernet client library
// with the IP address and port of the server // with the IP address and port of the server
@ -39,7 +40,7 @@ void setup() {
if (Ethernet.begin(mac) == 0) { if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP"); Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore: // no point in carrying on, so do nothing forevermore:
for(;;) for (;;)
; ;
} }
// print your local IP address: // print your local IP address:

View File

@ -25,9 +25,10 @@
// The IP address will be dependent on your local network. // The IP address will be dependent on your local network.
// gateway and subnet are optional: // gateway and subnet are optional:
byte mac[] = { byte mac[] = {
0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02
IPAddress ip(192,168,1, 177); };
IPAddress gateway(192,168,1, 1); IPAddress ip(192, 168, 1, 177);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0); IPAddress subnet(255, 255, 0, 0);
// telnet defaults to port 23 // telnet defaults to port 23

View File

@ -24,11 +24,12 @@
// Enter a MAC address and IP address for your controller below. // Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network: // The IP address will be dependent on your local network:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
IPAddress ip(192,168,1,177); };
IPAddress ip(192, 168, 1, 177);
// Enter the IP address of the server you're connecting to: // Enter the IP address of the server you're connecting to:
IPAddress server(1,1,1,1); IPAddress server(1, 1, 1, 1);
// Initialize the Ethernet client library // Initialize the Ethernet client library
// with the IP address and port of the server // with the IP address and port of the server
@ -84,7 +85,7 @@ void loop()
Serial.println("disconnecting."); Serial.println("disconnecting.");
client.stop(); client.stop();
// do nothing: // do nothing:
while(true); while (true);
} }
} }

View File

@ -21,7 +21,8 @@
// Enter a MAC address and IP address for your controller below. // Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network: // The IP address will be dependent on your local network:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 177); IPAddress ip(192, 168, 1, 177);
unsigned int localPort = 8888; // local port to listen on unsigned int localPort = 8888; // local port to listen on
@ -35,7 +36,7 @@ EthernetUDP Udp;
void setup() { void setup() {
// start the Ethernet and UDP: // start the Ethernet and UDP:
Ethernet.begin(mac,ip); Ethernet.begin(mac, ip);
Udp.begin(localPort); Udp.begin(localPort);
Serial.begin(9600); Serial.begin(9600);
@ -44,13 +45,13 @@ void setup() {
void loop() { void loop() {
// if there's data available, read a packet // if there's data available, read a packet
int packetSize = Udp.parsePacket(); int packetSize = Udp.parsePacket();
if(packetSize) if (packetSize)
{ {
Serial.print("Received packet of size "); Serial.print("Received packet of size ");
Serial.println(packetSize); Serial.println(packetSize);
Serial.print("From "); Serial.print("From ");
IPAddress remote = Udp.remoteIP(); IPAddress remote = Udp.remoteIP();
for (int i =0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
Serial.print(remote[i], DEC); Serial.print(remote[i], DEC);
if (i < 3) if (i < 3)
@ -62,7 +63,7 @@ void loop() {
Serial.println(Udp.remotePort()); Serial.println(Udp.remotePort());
// read the packet into packetBufffer // read the packet into packetBufffer
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE); Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:"); Serial.println("Contents:");
Serial.println(packetBuffer); Serial.println(packetBuffer);

View File

@ -7,13 +7,6 @@
For more on NTP time servers and the messages needed to communicate with them, For more on NTP time servers and the messages needed to communicate with them,
see http://en.wikipedia.org/wiki/Network_Time_Protocol see http://en.wikipedia.org/wiki/Network_Time_Protocol
Warning: NTP Servers are subject to temporary failure or IP address change.
Plese check
http://tf.nist.gov/tf-cgi/servers.cgi
if the time server used in the example didn't work.
created 4 Sep 2010 created 4 Sep 2010
by Michael Margolis by Michael Margolis
modified 9 Apr 2012 modified 9 Apr 2012
@ -30,15 +23,14 @@
// Enter a MAC address for your controller below. // Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield // Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
unsigned int localPort = 8888; // local port to listen for UDP packets unsigned int localPort = 8888; // local port to listen for UDP packets
IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov NTP server char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server
// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov NTP server
// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov NTP server
const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
@ -58,7 +50,7 @@ void setup()
if (Ethernet.begin(mac) == 0) { if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP"); Serial.println("Failed to configure Ethernet using DHCP");
// no point in carrying on, so do nothing forevermore: // no point in carrying on, so do nothing forevermore:
for(;;) for (;;)
; ;
} }
Udp.begin(localPort); Udp.begin(localPort);
@ -72,7 +64,7 @@ void loop()
delay(1000); delay(1000);
if ( Udp.parsePacket() ) { if ( Udp.parsePacket() ) {
// We've received a packet, read the data from it // We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes, //the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words: // or two words, long. First, esxtract the two words:
@ -109,14 +101,14 @@ void loop()
// In the first 10 seconds of each minute, we'll want a leading '0' // In the first 10 seconds of each minute, we'll want a leading '0'
Serial.print('0'); Serial.print('0');
} }
Serial.println(epoch %60); // print the second Serial.println(epoch % 60); // print the second
} }
// wait ten seconds before asking for the time again // wait ten seconds before asking for the time again
delay(10000); delay(10000);
} }
// send an NTP request to the time server at the given address // send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) unsigned long sendNTPpacket(char* address)
{ {
// set all bytes in the buffer to 0 // set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE); memset(packetBuffer, 0, NTP_PACKET_SIZE);
@ -135,7 +127,7 @@ unsigned long sendNTPpacket(IPAddress& address)
// all NTP fields have been given values, now // all NTP fields have been given values, now
// you can send a packet requesting a timestamp: // you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123 Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE); Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket(); Udp.endPacket();
} }

View File

@ -26,7 +26,7 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server[] = "www.google.com"; // name address for Google (using DNS) char server[] = "www.google.com"; // name address for Google (using DNS)
// Set the static IP address to use if the DHCP fails to assign // Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192,168,0,177); IPAddress ip(192, 168, 0, 177);
// Initialize the Ethernet client library // Initialize the Ethernet client library
// with the IP address and port of the server // with the IP address and port of the server
@ -82,7 +82,7 @@ void loop()
client.stop(); client.stop();
// do nothing forevermore: // do nothing forevermore:
while(true); while (true);
} }
} }

View File

@ -14,6 +14,8 @@
created 19 Apr 2012 created 19 Apr 2012
by Tom Igoe by Tom Igoe
modified 21 Jan 2014
by Federico Vanzati
http://arduino.cc/en/Tutorial/WebClientRepeating http://arduino.cc/en/Tutorial/WebClientRepeating
This code is in the public domain. This code is in the public domain.
@ -26,26 +28,32 @@
// assign a MAC address for the ethernet controller. // assign a MAC address for the ethernet controller.
// fill in your address here: // fill in your address here:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
// fill in an available IP address on your network here, // fill in an available IP address on your network here,
// for manual configuration: // for manual configuration:
IPAddress ip(10,0,0,20); IPAddress ip(192, 168, 1, 177);
// fill in your Domain Name Server address here: // fill in your Domain Name Server address here:
IPAddress myDns(1,1,1,1); IPAddress myDns(1, 1, 1, 1);
// initialize the library instance: // initialize the library instance:
EthernetClient client; EthernetClient client;
char server[] = "www.arduino.cc"; char server[] = "www.arduino.cc";
//IPAddress server(64,131,82,241);
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
boolean lastConnected = false; // state of the connection last time through the main loop const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds
const unsigned long postingInterval = 60*1000; // delay between updates, in milliseconds // the "L" is needed to use long type numbers
void setup() { void setup() {
// start serial port: // start serial port:
Serial.begin(9600); Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// give the ethernet module time to boot up: // give the ethernet module time to boot up:
delay(1000); delay(1000);
// start the Ethernet connection using a fixed IP address and DNS server: // start the Ethernet connection using a fixed IP address and DNS server:
@ -61,29 +69,23 @@ void loop() {
// purposes only: // purposes only:
if (client.available()) { if (client.available()) {
char c = client.read(); char c = client.read();
Serial.print(c); Serial.write(c);
} }
// if there's no net connection, but there was one last time // if ten seconds have passed since your last connection,
// through the loop, then stop the client: // then connect again and send data:
if (!client.connected() && lastConnected) { if (millis() - lastConnectionTime > postingInterval) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
}
// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
httpRequest(); httpRequest();
} }
// store the state of the connection for next time through
// the loop:
lastConnected = client.connected();
} }
// this method makes a HTTP connection to the server: // this method makes a HTTP connection to the server:
void httpRequest() { void httpRequest() {
// close any connection before send a new request.
// This will free the socket on the WiFi shield
client.stop();
// if there's a successful connection: // if there's a successful connection:
if (client.connect(server, 80)) { if (client.connect(server, 80)) {
Serial.println("connecting..."); Serial.println("connecting...");
@ -100,11 +102,7 @@ void httpRequest() {
else { else {
// if you couldn't make a connection: // if you couldn't make a connection:
Serial.println("connection failed"); Serial.println("connection failed");
Serial.println("disconnecting.");
client.stop();
} }
} }

View File

@ -21,8 +21,9 @@
// Enter a MAC address and IP address for your controller below. // Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network: // The IP address will be dependent on your local network:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
IPAddress ip(192,168,1,177); };
IPAddress ip(192, 168, 1, 177);
// Initialize the Ethernet server library // Initialize the Ethernet server library
// with the IP address and port you want to use // with the IP address and port you want to use

View File

@ -1,5 +1,5 @@
#include "w5100.h" #include "utility/w5100.h"
#include "socket.h" #include "utility/socket.h"
static uint16_t local_port; static uint16_t local_port;
@ -12,6 +12,7 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE)) if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE))
{ {
close(s); close(s);
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.writeSnMR(s, protocol | flag); W5100.writeSnMR(s, protocol | flag);
if (port != 0) { if (port != 0) {
W5100.writeSnPORT(s, port); W5100.writeSnPORT(s, port);
@ -22,7 +23,7 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
} }
W5100.execCmdSn(s, Sock_OPEN); W5100.execCmdSn(s, Sock_OPEN);
SPI.endTransaction();
return 1; return 1;
} }
@ -30,13 +31,24 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
} }
uint8_t socketStatus(SOCKET s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
uint8_t status = W5100.readSnSR(s);
SPI.endTransaction();
return status;
}
/** /**
* @brief This function close the socket and parameter is "s" which represent the socket number * @brief This function close the socket and parameter is "s" which represent the socket number
*/ */
void close(SOCKET s) void close(SOCKET s)
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.execCmdSn(s, Sock_CLOSE); W5100.execCmdSn(s, Sock_CLOSE);
W5100.writeSnIR(s, 0xFF); W5100.writeSnIR(s, 0xFF);
SPI.endTransaction();
} }
@ -46,9 +58,13 @@ void close(SOCKET s)
*/ */
uint8_t listen(SOCKET s) uint8_t listen(SOCKET s)
{ {
if (W5100.readSnSR(s) != SnSR::INIT) SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
if (W5100.readSnSR(s) != SnSR::INIT) {
SPI.endTransaction();
return 0; return 0;
}
W5100.execCmdSn(s, Sock_LISTEN); W5100.execCmdSn(s, Sock_LISTEN);
SPI.endTransaction();
return 1; return 1;
} }
@ -70,9 +86,11 @@ uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
return 0; return 0;
// set destination IP // set destination IP
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.writeSnDIPR(s, addr); W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port); W5100.writeSnDPORT(s, port);
W5100.execCmdSn(s, Sock_CONNECT); W5100.execCmdSn(s, Sock_CONNECT);
SPI.endTransaction();
return 1; return 1;
} }
@ -85,7 +103,9 @@ uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
*/ */
void disconnect(SOCKET s) void disconnect(SOCKET s)
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.execCmdSn(s, Sock_DISCON); W5100.execCmdSn(s, Sock_DISCON);
SPI.endTransaction();
} }
@ -107,17 +127,21 @@ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len)
// if freebuf is available, start. // if freebuf is available, start.
do do
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
freesize = W5100.getTXFreeSize(s); freesize = W5100.getTXFreeSize(s);
status = W5100.readSnSR(s); status = W5100.readSnSR(s);
SPI.endTransaction();
if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT))
{ {
ret = 0; ret = 0;
break; break;
} }
yield();
} }
while (freesize < ret); while (freesize < ret);
// copy data // copy data
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.send_data_processing(s, (uint8_t *)buf, ret); W5100.send_data_processing(s, (uint8_t *)buf, ret);
W5100.execCmdSn(s, Sock_SEND); W5100.execCmdSn(s, Sock_SEND);
@ -127,12 +151,17 @@ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len)
/* m2008.01 [bj] : reduce code */ /* m2008.01 [bj] : reduce code */
if ( W5100.readSnSR(s) == SnSR::CLOSED ) if ( W5100.readSnSR(s) == SnSR::CLOSED )
{ {
SPI.endTransaction();
close(s); close(s);
return 0; return 0;
} }
SPI.endTransaction();
yield();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
} }
/* +2008.01 bj */ /* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK); W5100.writeSnIR(s, SnIR::SEND_OK);
SPI.endTransaction();
return ret; return ret;
} }
@ -146,6 +175,7 @@ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len)
int16_t recv(SOCKET s, uint8_t *buf, int16_t len) int16_t recv(SOCKET s, uint8_t *buf, int16_t len)
{ {
// Check how much data is available // Check how much data is available
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
int16_t ret = W5100.getRXReceivedSize(s); int16_t ret = W5100.getRXReceivedSize(s);
if ( ret == 0 ) if ( ret == 0 )
{ {
@ -172,6 +202,16 @@ int16_t recv(SOCKET s, uint8_t *buf, int16_t len)
W5100.recv_data_processing(s, buf, ret); W5100.recv_data_processing(s, buf, ret);
W5100.execCmdSn(s, Sock_RECV); W5100.execCmdSn(s, Sock_RECV);
} }
SPI.endTransaction();
return ret;
}
int16_t recvAvailable(SOCKET s)
{
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
int16_t ret = W5100.getRXReceivedSize(s);
SPI.endTransaction();
return ret; return ret;
} }
@ -183,8 +223,9 @@ int16_t recv(SOCKET s, uint8_t *buf, int16_t len)
*/ */
uint16_t peek(SOCKET s, uint8_t *buf) uint16_t peek(SOCKET s, uint8_t *buf)
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.recv_data_processing(s, buf, 1, 1); W5100.recv_data_processing(s, buf, 1, 1);
SPI.endTransaction();
return 1; return 1;
} }
@ -213,6 +254,7 @@ uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint1
} }
else else
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.writeSnDIPR(s, addr); W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port); W5100.writeSnDPORT(s, port);
@ -227,12 +269,17 @@ uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint1
{ {
/* +2008.01 [bj]: clear interrupt */ /* +2008.01 [bj]: clear interrupt */
W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */ W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */
SPI.endTransaction();
return 0; return 0;
} }
SPI.endTransaction();
yield();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
} }
/* +2008.01 bj */ /* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK); W5100.writeSnIR(s, SnIR::SEND_OK);
SPI.endTransaction();
} }
return ret; return ret;
} }
@ -252,11 +299,12 @@ uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t
if ( len > 0 ) if ( len > 0 )
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
ptr = W5100.readSnRX_RD(s); ptr = W5100.readSnRX_RD(s);
switch (W5100.readSnMR(s) & 0x07) switch (W5100.readSnMR(s) & 0x07)
{ {
case SnMR::UDP : case SnMR::UDP :
W5100.read_data(s, (uint8_t *)ptr, head, 0x08); W5100.read_data(s, ptr, head, 0x08);
ptr += 8; ptr += 8;
// read peer's IP address, port number. // read peer's IP address, port number.
addr[0] = head[0]; addr[0] = head[0];
@ -268,14 +316,14 @@ uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t
data_len = head[6]; data_len = head[6];
data_len = (data_len << 8) + head[7]; data_len = (data_len << 8) + head[7];
W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy. W5100.read_data(s, ptr, buf, data_len); // data copy.
ptr += data_len; ptr += data_len;
W5100.writeSnRX_RD(s, ptr); W5100.writeSnRX_RD(s, ptr);
break; break;
case SnMR::IPRAW : case SnMR::IPRAW :
W5100.read_data(s, (uint8_t *)ptr, head, 0x06); W5100.read_data(s, ptr, head, 0x06);
ptr += 6; ptr += 6;
addr[0] = head[0]; addr[0] = head[0];
@ -285,19 +333,19 @@ uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t
data_len = head[4]; data_len = head[4];
data_len = (data_len << 8) + head[5]; data_len = (data_len << 8) + head[5];
W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy. W5100.read_data(s, ptr, buf, data_len); // data copy.
ptr += data_len; ptr += data_len;
W5100.writeSnRX_RD(s, ptr); W5100.writeSnRX_RD(s, ptr);
break; break;
case SnMR::MACRAW: case SnMR::MACRAW:
W5100.read_data(s,(uint8_t*)ptr,head,2); W5100.read_data(s, ptr, head, 2);
ptr+=2; ptr+=2;
data_len = head[0]; data_len = head[0];
data_len = (data_len<<8) + head[1] - 2; data_len = (data_len<<8) + head[1] - 2;
W5100.read_data(s,(uint8_t*) ptr,buf,data_len); W5100.read_data(s, ptr, buf, data_len);
ptr += data_len; ptr += data_len;
W5100.writeSnRX_RD(s, ptr); W5100.writeSnRX_RD(s, ptr);
break; break;
@ -306,14 +354,20 @@ uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t
break; break;
} }
W5100.execCmdSn(s, Sock_RECV); W5100.execCmdSn(s, Sock_RECV);
SPI.endTransaction();
} }
return data_len; return data_len;
} }
/**
* @brief Wait for buffered transmission to complete.
*/
void flush(SOCKET s) {
// TODO
}
uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
{ {
uint8_t status=0;
uint16_t ret=0; uint16_t ret=0;
if (len > W5100.SSIZE) if (len > W5100.SSIZE)
@ -324,28 +378,34 @@ uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
if (ret == 0) if (ret == 0)
return 0; return 0;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.send_data_processing(s, (uint8_t *)buf, ret); W5100.send_data_processing(s, (uint8_t *)buf, ret);
W5100.execCmdSn(s, Sock_SEND); W5100.execCmdSn(s, Sock_SEND);
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
{ {
status = W5100.readSnSR(s);
if (W5100.readSnIR(s) & SnIR::TIMEOUT) if (W5100.readSnIR(s) & SnIR::TIMEOUT)
{ {
/* in case of igmp, if send fails, then socket closed */ /* in case of igmp, if send fails, then socket closed */
/* if you want change, remove this code. */ /* if you want change, remove this code. */
SPI.endTransaction();
close(s); close(s);
return 0; return 0;
} }
SPI.endTransaction();
yield();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
} }
W5100.writeSnIR(s, SnIR::SEND_OK); W5100.writeSnIR(s, SnIR::SEND_OK);
SPI.endTransaction();
return ret; return ret;
} }
uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len)
{ {
uint16_t ret =0; uint16_t ret =0;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
if (len > W5100.getTXFreeSize(s)) if (len > W5100.getTXFreeSize(s))
{ {
ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size.
@ -355,6 +415,7 @@ uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len)
ret = len; ret = len;
} }
W5100.send_data_processing_offset(s, offset, buf, ret); W5100.send_data_processing_offset(s, offset, buf, ret);
SPI.endTransaction();
return ret; return ret;
} }
@ -370,14 +431,17 @@ int startUDP(SOCKET s, uint8_t* addr, uint16_t port)
} }
else else
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.writeSnDIPR(s, addr); W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port); W5100.writeSnDPORT(s, port);
SPI.endTransaction();
return 1; return 1;
} }
} }
int sendUDP(SOCKET s) int sendUDP(SOCKET s)
{ {
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
W5100.execCmdSn(s, Sock_SEND); W5100.execCmdSn(s, Sock_SEND);
/* +2008.01 bj */ /* +2008.01 bj */
@ -387,12 +451,17 @@ int sendUDP(SOCKET s)
{ {
/* +2008.01 [bj]: clear interrupt */ /* +2008.01 [bj]: clear interrupt */
W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT));
SPI.endTransaction();
return 0; return 0;
} }
SPI.endTransaction();
yield();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
} }
/* +2008.01 bj */ /* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK); W5100.writeSnIR(s, SnIR::SEND_OK);
SPI.endTransaction();
/* Sent ok */ /* Sent ok */
return 1; return 1;

5
libraries/Ethernet/utility/socket.h Executable file → Normal file
View File

@ -1,18 +1,21 @@
#ifndef _SOCKET_H_ #ifndef _SOCKET_H_
#define _SOCKET_H_ #define _SOCKET_H_
#include "w5100.h" #include "utility/w5100.h"
extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode) extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode)
extern uint8_t socketStatus(SOCKET s);
extern void close(SOCKET s); // Close socket extern void close(SOCKET s); // Close socket
extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection) extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection)
extern void disconnect(SOCKET s); // disconnect the connection extern void disconnect(SOCKET s); // disconnect the connection
extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection) extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection)
extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP) extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP)
extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len); // Receive data (TCP) extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len); // Receive data (TCP)
extern int16_t recvAvailable(SOCKET s);
extern uint16_t peek(SOCKET s, uint8_t *buf); extern uint16_t peek(SOCKET s, uint8_t *buf);
extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW) extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW)
extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW) extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW)
extern void flush(SOCKET s); // Wait for transmission to complete
extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len); extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len);

View File

@ -1,7 +1,8 @@
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) #define htons(x) ( ((x)<< 8 & 0xFF00) | \
((x)>> 8 & 0x00FF) )
#define ntohs(x) htons(x) #define ntohs(x) htons(x)
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \

View File

@ -9,9 +9,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <avr/interrupt.h>
#include "w5100.h" #include "utility/w5100.h"
// W5100 controller instance // W5100 controller instance
W5100Class W5100; W5100Class W5100;
@ -29,10 +28,11 @@ void W5100Class::init(void)
SPI.begin(); SPI.begin();
initSS(); initSS();
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
writeMR(1<<RST); writeMR(1<<RST);
writeTMSR(0x55); writeTMSR(0x55);
writeRMSR(0x55); writeRMSR(0x55);
SPI.endTransaction();
for (int i=0; i<MAX_SOCK_NUM; i++) { for (int i=0; i<MAX_SOCK_NUM; i++) {
SBASE[i] = TXBUF_BASE + SSIZE * i; SBASE[i] = TXBUF_BASE + SSIZE * i;
@ -98,7 +98,7 @@ void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uin
{ {
uint16_t ptr; uint16_t ptr;
ptr = readSnRX_RD(s); ptr = readSnRX_RD(s);
read_data(s, (uint8_t *)ptr, data, len); read_data(s, ptr, data, len);
if (!peek) if (!peek)
{ {
ptr += len; ptr += len;
@ -106,13 +106,13 @@ void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uin
} }
} }
void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len) void W5100Class::read_data(SOCKET s, volatile uint16_t src, volatile uint8_t *dst, uint16_t len)
{ {
uint16_t size; uint16_t size;
uint16_t src_mask; uint16_t src_mask;
uint16_t src_ptr; uint16_t src_ptr;
src_mask = (uint16_t)src & RMASK; src_mask = src & RMASK;
src_ptr = RBASE[s] + src_mask; src_ptr = RBASE[s] + src_mask;
if( (src_mask + len) > RSIZE ) if( (src_mask + len) > RSIZE )

6
libraries/Ethernet/utility/w5100.h Executable file → Normal file
View File

@ -10,9 +10,10 @@
#ifndef W5100_H_INCLUDED #ifndef W5100_H_INCLUDED
#define W5100_H_INCLUDED #define W5100_H_INCLUDED
#include <avr/pgmspace.h>
#include <SPI.h> #include <SPI.h>
#define SPI_ETHERNET_SETTINGS SPISettings(4000000, MSBFIRST, SPI_MODE0)
#define MAX_SOCK_NUM 4 #define MAX_SOCK_NUM 4
typedef uint8_t SOCKET; typedef uint8_t SOCKET;
@ -138,7 +139,7 @@ public:
* the data from Receive buffer. Here also take care of the condition while it exceed * the data from Receive buffer. Here also take care of the condition while it exceed
* the Rx memory uper-bound of socket. * the Rx memory uper-bound of socket.
*/ */
void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len); void read_data(SOCKET s, volatile uint16_t src, volatile uint8_t * dst, uint16_t len);
/** /**
* @brief This function is being called by send() and sendto() function also. * @brief This function is being called by send() and sendto() function also.
@ -340,7 +341,6 @@ private:
inline static void setSS() { PORTB &= ~_BV(2); }; inline static void setSS() { PORTB &= ~_BV(2); };
inline static void resetSS() { PORTB |= _BV(2); }; inline static void resetSS() { PORTB |= _BV(2); };
#endif #endif
}; };
extern W5100Class W5100; extern W5100Class W5100;

View File

@ -550,9 +550,9 @@ boolean SDClass::mkdir(char *filepath) {
boolean SDClass::rmdir(char *filepath) { boolean SDClass::rmdir(char *filepath) {
/* /*
Makes a single directory or a heirarchy of directories. Remove a single directory or a heirarchy of directories.
A rough equivalent to `mkdir -p`. A rough equivalent to `rm -rf`.
*/ */
return walkPath(filepath, root, callback_rmdir); return walkPath(filepath, root, callback_rmdir);

View File

@ -19,7 +19,8 @@
modified 9 Apr 2012 modified 9 Apr 2012
by Tom Igoe by Tom Igoe
*/ */
// include the SD library: // include the SD library:
#include <SPI.h>
#include <SD.h> #include <SD.h>
// set up variables using the SD utility library functions: // set up variables using the SD utility library functions:
@ -64,7 +65,7 @@ void setup()
// print the type of card // print the type of card
Serial.print("\nCard type: "); Serial.print("\nCard type: ");
switch(card.type()) { switch (card.type()) {
case SD_CARD_TYPE_SD1: case SD_CARD_TYPE_SD1:
Serial.println("SD1"); Serial.println("SD1");
break; break;

View File

@ -20,6 +20,7 @@
*/ */
#include <SPI.h>
#include <SD.h> #include <SD.h>
// On the Ethernet Shield, CS is pin 4. Note that even if it's not // On the Ethernet Shield, CS is pin 4. Note that even if it's not

View File

@ -20,6 +20,7 @@
*/ */
#include <SPI.h>
#include <SD.h> #include <SD.h>
// On the Ethernet Shield, CS is pin 4. Note that even if it's not // On the Ethernet Shield, CS is pin 4. Note that even if it's not

View File

@ -17,6 +17,7 @@
This example code is in the public domain. This example code is in the public domain.
*/ */
#include <SPI.h>
#include <SD.h> #include <SD.h>
File myFile; File myFile;
@ -67,7 +68,7 @@ void setup()
Serial.println("Removing example.txt..."); Serial.println("Removing example.txt...");
SD.remove("example.txt"); SD.remove("example.txt");
if (SD.exists("example.txt")){ if (SD.exists("example.txt")) {
Serial.println("example.txt exists."); Serial.println("example.txt exists.");
} }
else { else {

View File

@ -18,6 +18,7 @@
*/ */
#include <SPI.h>
#include <SD.h> #include <SD.h>
File myFile; File myFile;

View File

@ -21,6 +21,7 @@
This example code is in the public domain. This example code is in the public domain.
*/ */
#include <SPI.h>
#include <SD.h> #include <SD.h>
File root; File root;

View File

@ -90,7 +90,7 @@ struct partitionTable {
uint32_t firstSector; uint32_t firstSector;
/** Length of the partition, in blocks. */ /** Length of the partition, in blocks. */
uint32_t totalSectors; uint32_t totalSectors;
}; } __attribute__((packed));
/** Type name for partitionTable */ /** Type name for partitionTable */
typedef struct partitionTable part_t; typedef struct partitionTable part_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -114,7 +114,7 @@ struct masterBootRecord {
uint8_t mbrSig0; uint8_t mbrSig0;
/** Second MBR signature byte. Must be 0XAA */ /** Second MBR signature byte. Must be 0XAA */
uint8_t mbrSig1; uint8_t mbrSig1;
}; } __attribute__((packed));
/** Type name for masterBootRecord */ /** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t; typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -236,7 +236,7 @@ struct biosParmBlock {
* should always set all of the bytes of this field to 0. * should always set all of the bytes of this field to 0.
*/ */
uint8_t fat32Reserved[12]; uint8_t fat32Reserved[12];
}; } __attribute__((packed));
/** Type name for biosParmBlock */ /** Type name for biosParmBlock */
typedef struct biosParmBlock bpb_t; typedef struct biosParmBlock bpb_t;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -271,7 +271,7 @@ struct fat32BootSector {
uint8_t bootSectorSig0; uint8_t bootSectorSig0;
/** must be 0XAA */ /** must be 0XAA */
uint8_t bootSectorSig1; uint8_t bootSectorSig1;
}; } __attribute__((packed));
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// End Of Chain values for FAT entries // End Of Chain values for FAT entries
/** FAT16 end of chain value used by Microsoft. */ /** FAT16 end of chain value used by Microsoft. */
@ -366,7 +366,7 @@ struct directoryEntry {
uint16_t firstClusterLow; uint16_t firstClusterLow;
/** 32-bit unsigned holding this file's size in bytes. */ /** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize; uint32_t fileSize;
}; } __attribute__((packed));
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Definitions for directory entries // Definitions for directory entries
// //

View File

@ -17,20 +17,34 @@
* along with the Arduino Sd2Card Library. If not, see * along with the Arduino Sd2Card Library. If not, see
* <http://www.gnu.org/licenses/>. * <http://www.gnu.org/licenses/>.
*/ */
#define USE_SPI_LIB
#include <Arduino.h> #include <Arduino.h>
#include "Sd2Card.h" #include "Sd2Card.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#ifndef SOFTWARE_SPI #ifndef SOFTWARE_SPI
#ifdef USE_SPI_LIB
#include <SPI.h>
static SPISettings settings;
#endif
// functions for hardware SPI // functions for hardware SPI
/** Send a byte to the card */ /** Send a byte to the card */
static void spiSend(uint8_t b) { static void spiSend(uint8_t b) {
#ifndef USE_SPI_LIB
SPDR = b; SPDR = b;
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
#else
SPI.transfer(b);
#endif
} }
/** Receive a byte from the card */ /** Receive a byte from the card */
static uint8_t spiRec(void) { static uint8_t spiRec(void) {
#ifndef USE_SPI_LIB
spiSend(0XFF); spiSend(0XFF);
return SPDR; return SPDR;
#else
return SPI.transfer(0xFF);
#endif
} }
#else // SOFTWARE_SPI #else // SOFTWARE_SPI
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -112,7 +126,8 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
spiSend(crc); spiSend(crc);
// wait for response // wait for response
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++)
;
return status_; return status_;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -142,11 +157,25 @@ uint32_t Sd2Card::cardSize(void) {
} }
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static uint8_t chip_select_asserted = 0;
void Sd2Card::chipSelectHigh(void) { void Sd2Card::chipSelectHigh(void) {
digitalWrite(chipSelectPin_, HIGH); digitalWrite(chipSelectPin_, HIGH);
#ifdef USE_SPI_LIB
if (chip_select_asserted) {
chip_select_asserted = 0;
SPI.endTransaction();
}
#endif
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void Sd2Card::chipSelectLow(void) { void Sd2Card::chipSelectLow(void) {
#ifdef USE_SPI_LIB
if (!chip_select_asserted) {
chip_select_asserted = 1;
SPI.beginTransaction(settings);
}
#endif
digitalWrite(chipSelectPin_, LOW); digitalWrite(chipSelectPin_, LOW);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -219,12 +248,15 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
// set pin modes // set pin modes
pinMode(chipSelectPin_, OUTPUT); pinMode(chipSelectPin_, OUTPUT);
chipSelectHigh(); digitalWrite(chipSelectPin_, HIGH);
#ifndef USE_SPI_LIB
pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MISO_PIN, INPUT);
pinMode(SPI_MOSI_PIN, OUTPUT); pinMode(SPI_MOSI_PIN, OUTPUT);
pinMode(SPI_SCK_PIN, OUTPUT); pinMode(SPI_SCK_PIN, OUTPUT);
#endif
#ifndef SOFTWARE_SPI #ifndef SOFTWARE_SPI
#ifndef USE_SPI_LIB
// SS must be in output mode even it is not chip select // SS must be in output mode even it is not chip select
pinMode(SS_PIN, OUTPUT); pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
@ -232,10 +264,20 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
// clear double speed // clear double speed
SPSR &= ~(1 << SPI2X); SPSR &= ~(1 << SPI2X);
#else // USE_SPI_LIB
SPI.begin();
settings = SPISettings(250000, MSBFIRST, SPI_MODE0);
#endif // USE_SPI_LIB
#endif // SOFTWARE_SPI #endif // SOFTWARE_SPI
// must supply min of 74 clock cycles with CS high. // must supply min of 74 clock cycles with CS high.
#ifdef USE_SPI_LIB
SPI.beginTransaction(settings);
#endif
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
#ifdef USE_SPI_LIB
SPI.endTransaction();
#endif
chipSelectLow(); chipSelectLow();
@ -360,18 +402,21 @@ uint8_t Sd2Card::readData(uint32_t block,
// skip data before offset // skip data before offset
for (;offset_ < offset; offset_++) { for (;offset_ < offset; offset_++) {
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
SPDR = 0XFF; SPDR = 0XFF;
} }
// transfer data // transfer data
n = count - 1; n = count - 1;
for (uint16_t i = 0; i < n; i++) { for (uint16_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
dst[i] = SPDR; dst[i] = SPDR;
SPDR = 0XFF; SPDR = 0XFF;
} }
// wait for last byte // wait for last byte
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
dst[n] = SPDR; dst[n] = SPDR;
#else // OPTIMIZE_HARDWARE_SPI #else // OPTIMIZE_HARDWARE_SPI
@ -406,11 +451,13 @@ void Sd2Card::readEnd(void) {
// optimize skip for hardware // optimize skip for hardware
SPDR = 0XFF; SPDR = 0XFF;
while (offset_++ < 513) { while (offset_++ < 513) {
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
SPDR = 0XFF; SPDR = 0XFF;
} }
// wait for last crc byte // wait for last crc byte
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
#else // OPTIMIZE_HARDWARE_SPI #else // OPTIMIZE_HARDWARE_SPI
while (offset_++ < 514) spiRec(); while (offset_++ < 514) spiRec();
#endif // OPTIMIZE_HARDWARE_SPI #endif // OPTIMIZE_HARDWARE_SPI
@ -456,6 +503,7 @@ uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
error(SD_CARD_ERROR_SCK_RATE); error(SD_CARD_ERROR_SCK_RATE);
return false; return false;
} }
#ifndef USE_SPI_LIB
// see avr processor datasheet for SPI register bit definitions // see avr processor datasheet for SPI register bit definitions
if ((sckRateID & 1) || sckRateID == 6) { if ((sckRateID & 1) || sckRateID == 6) {
SPSR &= ~(1 << SPI2X); SPSR &= ~(1 << SPI2X);
@ -465,6 +513,17 @@ uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
SPCR &= ~((1 <<SPR1) | (1 << SPR0)); SPCR &= ~((1 <<SPR1) | (1 << SPR0));
SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0) SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
| (sckRateID & 2 ? (1 << SPR0) : 0); | (sckRateID & 2 ? (1 << SPR0) : 0);
#else // USE_SPI_LIB
switch (sckRateID) {
case 0: settings = SPISettings(25000000, MSBFIRST, SPI_MODE0); break;
case 1: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break;
case 2: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break;
case 3: settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); break;
case 4: settings = SPISettings(500000, MSBFIRST, SPI_MODE0); break;
case 5: settings = SPISettings(250000, MSBFIRST, SPI_MODE0); break;
default: settings = SPISettings(125000, MSBFIRST, SPI_MODE0);
}
#endif // USE_SPI_LIB
return true; return true;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -561,14 +620,17 @@ uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
// send two byte per iteration // send two byte per iteration
for (uint16_t i = 0; i < 512; i += 2) { for (uint16_t i = 0; i < 512; i += 2) {
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
SPDR = src[i]; SPDR = src[i];
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
SPDR = src[i+1]; SPDR = src[i+1];
} }
// wait for last data byte // wait for last data byte
while (!(SPSR & (1 << SPIF))); while (!(SPSR & (1 << SPIF)))
;
#else // OPTIMIZE_HARDWARE_SPI #else // OPTIMIZE_HARDWARE_SPI
spiSend(token); spiSend(token);

View File

@ -31,6 +31,11 @@ uint8_t const SPI_FULL_SPEED = 0;
uint8_t const SPI_HALF_SPEED = 1; uint8_t const SPI_HALF_SPEED = 1;
/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */ /** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
uint8_t const SPI_QUARTER_SPEED = 2; uint8_t const SPI_QUARTER_SPEED = 2;
/**
* USE_SPI_LIB: if set, use the SPI library bundled with Arduino IDE, otherwise
* run with a standalone driver for AVR.
*/
#define USE_SPI_LIB
/** /**
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos. * Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13. * Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
@ -66,7 +71,9 @@ uint8_t const SPI_MISO_PIN = MISO_PIN;
/** SPI Clock pin */ /** SPI Clock pin */
uint8_t const SPI_SCK_PIN = SCK_PIN; uint8_t const SPI_SCK_PIN = SCK_PIN;
/** optimize loops for hardware SPI */ /** optimize loops for hardware SPI */
#ifndef USE_SPI_LIB
#define OPTIMIZE_HARDWARE_SPI #define OPTIMIZE_HARDWARE_SPI
#endif
#else // SOFTWARE_SPI #else // SOFTWARE_SPI
// define software SPI pins so Mega can use unmodified GPS Shield // define software SPI pins so Mega can use unmodified GPS Shield

View File

@ -17,6 +17,22 @@
* along with the Arduino SdFat Library. If not, see * along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>. * <http://www.gnu.org/licenses/>.
*/ */
#if defined(__arm__) // Arduino Due Board follows
#ifndef Sd2PinMap_h
#define Sd2PinMap_h
#include <Arduino.h>
uint8_t const SS_PIN = SS;
uint8_t const MOSI_PIN = MOSI;
uint8_t const MISO_PIN = MISO;
uint8_t const SCK_PIN = SCK;
#endif // Sd2PinMap_h
#elif defined(__AVR__) // Other AVR based Boards follows
// Warning this file was generated by a program. // Warning this file was generated by a program.
#ifndef Sd2PinMap_h #ifndef Sd2PinMap_h
#define Sd2PinMap_h #define Sd2PinMap_h
@ -350,3 +366,7 @@ static inline __attribute__((always_inline))
} }
} }
#endif // Sd2PinMap_h #endif // Sd2PinMap_h
#else
#error Architecture or board not supported.
#endif

View File

@ -23,7 +23,9 @@
* \file * \file
* SdFile and SdVolume classes * SdFile and SdVolume classes
*/ */
#ifdef __AVR__
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#endif
#include "Sd2Card.h" #include "Sd2Card.h"
#include "FatStructs.h" #include "FatStructs.h"
#include "Print.h" #include "Print.h"
@ -286,8 +288,10 @@ class SdFile : public Print {
size_t write(uint8_t b); size_t write(uint8_t b);
size_t write(const void* buf, uint16_t nbyte); size_t write(const void* buf, uint16_t nbyte);
size_t write(const char* str); size_t write(const char* str);
#ifdef __AVR__
void write_P(PGM_P str); void write_P(PGM_P str);
void writeln_P(PGM_P str); void writeln_P(PGM_P str);
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if ALLOW_DEPRECATED_FUNCTIONS #if ALLOW_DEPRECATED_FUNCTIONS
// Deprecated functions - suppress cpplint warnings with NOLINT comment // Deprecated functions - suppress cpplint warnings with NOLINT comment

View File

@ -24,12 +24,14 @@
* Useful utility functions. * Useful utility functions.
*/ */
#include <Arduino.h> #include <Arduino.h>
#ifdef __AVR__
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
/** Store and print a string in flash memory.*/ /** Store and print a string in flash memory.*/
#define PgmPrint(x) SerialPrint_P(PSTR(x)) #define PgmPrint(x) SerialPrint_P(PSTR(x))
/** Store and print a string in flash memory followed by a CR/LF.*/ /** Store and print a string in flash memory followed by a CR/LF.*/
#define PgmPrintln(x) SerialPrintln_P(PSTR(x)) #define PgmPrintln(x) SerialPrintln_P(PSTR(x))
/** Defined so doxygen works for function definitions. */ /** Defined so doxygen works for function definitions. */
#endif
#define NOINLINE __attribute__((noinline,unused)) #define NOINLINE __attribute__((noinline,unused))
#define UNUSEDOK __attribute__((unused)) #define UNUSEDOK __attribute__((unused))
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -49,6 +51,7 @@ static UNUSEDOK int FreeRam(void) {
} }
return free_memory; return free_memory;
} }
#ifdef __AVR__
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* %Print a string in flash memory to the serial port. * %Print a string in flash memory to the serial port.
@ -68,4 +71,5 @@ static NOINLINE void SerialPrintln_P(PGM_P str) {
SerialPrint_P(str); SerialPrint_P(str);
Serial.println(); Serial.println();
} }
#endif // __AVR__
#endif // #define SdFatUtil_h #endif // #define SdFatUtil_h

View File

@ -17,8 +17,10 @@
* along with the Arduino SdFat Library. If not, see * along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>. * <http://www.gnu.org/licenses/>.
*/ */
#include <SdFat.h> #include "SdFat.h"
#ifdef __AVR__
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#endif
#include <Arduino.h> #include <Arduino.h>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// callback function for date/time // callback function for date/time
@ -256,9 +258,15 @@ uint8_t SdFile::make83Name(const char* str, uint8_t* name) {
i = 8; // place for extension i = 8; // place for extension
} else { } else {
// illegal FAT characters // illegal FAT characters
PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
uint8_t b; uint8_t b;
#if defined(__AVR__)
PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
while ((b = pgm_read_byte(p++))) if (b == c) return false; while ((b = pgm_read_byte(p++))) if (b == c) return false;
#elif defined(__arm__)
const uint8_t valid[] = "|<>^+=?/[];,*\"\\";
const uint8_t *p = valid;
while ((b = *p++)) if (b == c) return false;
#endif
// check size and only allow ASCII printable characters // check size and only allow ASCII printable characters
if (i > n || c < 0X21 || c > 0X7E)return false; if (i > n || c < 0X21 || c > 0X7E)return false;
// only upper case allowed in 8.3 names - convert lower to upper // only upper case allowed in 8.3 names - convert lower to upper
@ -1232,6 +1240,7 @@ size_t SdFile::write(uint8_t b) {
size_t SdFile::write(const char* str) { size_t SdFile::write(const char* str) {
return write(str, strlen(str)); return write(str, strlen(str));
} }
#ifdef __AVR__
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Write a PROGMEM string to a file. * Write a PROGMEM string to a file.
@ -1251,3 +1260,4 @@ void SdFile::writeln_P(PGM_P str) {
write_P(str); write_P(str);
println(); println();
} }
#endif

View File

@ -17,7 +17,7 @@
* along with the Arduino SdFat Library. If not, see * along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>. * <http://www.gnu.org/licenses/>.
*/ */
#include <SdFat.h> #include "SdFat.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// raw block cache // raw block cache
// init cacheBlockNumber_to invalid SD block number // init cacheBlockNumber_to invalid SD block number

View File

@ -1,5 +1,8 @@
/* /*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
* SPI Master library for arduino. * SPI Master library for arduino.
* *
* This file is free software; you can redistribute it and/or modify * This file is free software; you can redistribute it and/or modify
@ -8,13 +11,23 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include "pins_arduino.h"
#include "SPI.h" #include "SPI.h"
SPIClass SPI; SPIClass SPI;
void SPIClass::begin() { uint8_t SPIClass::initialized = 0;
uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
uint8_t SPIClass::interruptSave = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
uint8_t SPIClass::inTransactionFlag = 0;
#endif
void SPIClass::begin()
{
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
if (!initialized) {
// Set SS to high so a connected chip will be "deselected" by default // Set SS to high so a connected chip will be "deselected" by default
digitalWrite(SS, HIGH); digitalWrite(SS, HIGH);
@ -37,30 +50,144 @@ void SPIClass::begin() {
// http://code.google.com/p/arduino/issues/detail?id=888 // http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT); pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT); pinMode(MOSI, OUTPUT);
}
initialized++; // reference count
SREG = sreg;
} }
void SPIClass::end() { void SPIClass::end() {
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
// Decrease the reference counter
if (initialized)
initialized--;
// If there are no more references disable SPI
if (!initialized) {
SPCR &= ~_BV(SPE); SPCR &= ~_BV(SPE);
} interruptMode = 0;
#ifdef SPI_TRANSACTION_MISMATCH_LED
void SPIClass::setBitOrder(uint8_t bitOrder) inTransactionFlag = 0;
{ #endif
if(bitOrder == LSBFIRST) {
SPCR |= _BV(DORD);
} else {
SPCR &= ~(_BV(DORD));
} }
SREG = sreg;
} }
void SPIClass::setDataMode(uint8_t mode) // mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT6)
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT4)
#define SPI_INT5_MASK (1<<INT5)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
#define SPI_INT0_MASK (1<<INT4)
#define SPI_INT1_MASK (1<<INT5)
#define SPI_INT2_MASK (1<<INT0)
#define SPI_INT3_MASK (1<<INT1)
#define SPI_INT4_MASK (1<<INT2)
#define SPI_INT5_MASK (1<<INT3)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#else
#ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#endif
#ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#endif
#ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#endif
#endif
void SPIClass::usingInterrupt(uint8_t interruptNumber)
{ {
SPCR = (SPCR & ~SPI_MODE_MASK) | mode; uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
interruptMode = 2;
break;
}
interruptMask |= mask;
if (!interruptMode)
interruptMode = 1;
SREG = sreg;
} }
void SPIClass::setClockDivider(uint8_t rate) void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
{ {
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); // Once in mode 2 we can't go back to 0 without a proper reference count
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); if (interruptMode == 2)
return;
uint8_t mask = 0;
uint8_t sreg = SREG;
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
switch (interruptNumber) {
#ifdef SPI_INT0_MASK
case 0: mask = SPI_INT0_MASK; break;
#endif
#ifdef SPI_INT1_MASK
case 1: mask = SPI_INT1_MASK; break;
#endif
#ifdef SPI_INT2_MASK
case 2: mask = SPI_INT2_MASK; break;
#endif
#ifdef SPI_INT3_MASK
case 3: mask = SPI_INT3_MASK; break;
#endif
#ifdef SPI_INT4_MASK
case 4: mask = SPI_INT4_MASK; break;
#endif
#ifdef SPI_INT5_MASK
case 5: mask = SPI_INT5_MASK; break;
#endif
#ifdef SPI_INT6_MASK
case 6: mask = SPI_INT6_MASK; break;
#endif
#ifdef SPI_INT7_MASK
case 7: mask = SPI_INT7_MASK; break;
#endif
default:
break;
// this case can't be reached
}
interruptMask &= ~mask;
if (!interruptMask)
interruptMode = 0;
SREG = sreg;
} }

View File

@ -1,5 +1,8 @@
/* /*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
* SPI Master library for arduino. * SPI Master library for arduino.
* *
* This file is free software; you can redistribute it and/or modify * This file is free software; you can redistribute it and/or modify
@ -11,9 +14,34 @@
#ifndef _SPI_H_INCLUDED #ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED #define _SPI_H_INCLUDED
#include <stdio.h>
#include <Arduino.h> #include <Arduino.h>
#include <avr/pgmspace.h>
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1
// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
#define SPI_HAS_NOTUSINGINTERRUPT 1
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
// This way when there is a bug fix you can check this define to alert users
// of your code if it uses better version of this library.
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
// available too.
#define SPI_ATOMIC_VERSION 1
// Uncomment this line to add detection of mismatched begin/end transactions.
// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
// on if any mismatch is ever detected.
//#define SPI_TRANSACTION_MISMATCH_LED 5
#ifndef LSBFIRST
#define LSBFIRST 0
#endif
#ifndef MSBFIRST
#define MSBFIRST 1
#endif
#define SPI_CLOCK_DIV4 0x00 #define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01 #define SPI_CLOCK_DIV16 0x01
@ -22,7 +50,6 @@
#define SPI_CLOCK_DIV2 0x04 #define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05 #define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06 #define SPI_CLOCK_DIV32 0x06
//#define SPI_CLOCK_DIV64 0x07
#define SPI_MODE0 0x00 #define SPI_MODE0 0x00
#define SPI_MODE1 0x04 #define SPI_MODE1 0x04
@ -33,38 +60,265 @@
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
#if defined(EIMSK)
#define SPI_AVR_EIMSK EIMSK
#elif defined(GICR)
#define SPI_AVR_EIMSK GICR
#elif defined(GIMSK)
#define SPI_AVR_EIMSK GIMSK
#endif
class SPISettings {
public:
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
if (__builtin_constant_p(clock)) {
init_AlwaysInline(clock, bitOrder, dataMode);
} else {
init_MightInline(clock, bitOrder, dataMode);
}
}
SPISettings() {
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
}
private:
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
init_AlwaysInline(clock, bitOrder, dataMode);
}
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
__attribute__((__always_inline__)) {
// Clock settings are defined as follows. Note that this shows SPI2X
// inverted, so the bits form increasing numbers. Also note that
// fosc/64 appears twice
// SPR1 SPR0 ~SPI2X Freq
// 0 0 0 fosc/2
// 0 0 1 fosc/4
// 0 1 0 fosc/8
// 0 1 1 fosc/16
// 1 0 0 fosc/32
// 1 0 1 fosc/64
// 1 1 0 fosc/64
// 1 1 1 fosc/128
// We find the fastest clock that is less than or equal to the
// given clock rate. The clock divider that results in clock_setting
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
// slowest (128 == 2 ^^ 7, so clock_div = 6).
uint8_t clockDiv;
// When the clock is known at compiletime, use this if-then-else
// cascade, which the compiler knows how to completely optimize
// away. When clock is not known, use a loop instead, which generates
// shorter code.
if (__builtin_constant_p(clock)) {
if (clock >= F_CPU / 2) {
clockDiv = 0;
} else if (clock >= F_CPU / 4) {
clockDiv = 1;
} else if (clock >= F_CPU / 8) {
clockDiv = 2;
} else if (clock >= F_CPU / 16) {
clockDiv = 3;
} else if (clock >= F_CPU / 32) {
clockDiv = 4;
} else if (clock >= F_CPU / 64) {
clockDiv = 5;
} else {
clockDiv = 6;
}
} else {
uint32_t clockSetting = F_CPU / 2;
clockDiv = 0;
while (clockDiv < 6 && clock < clockSetting) {
clockSetting /= 2;
clockDiv++;
}
}
// Compensate for the duplicate fosc/64
if (clockDiv == 6)
clockDiv = 7;
// Invert the SPI2X bit
clockDiv ^= 0x1;
// Pack into the SPISettings class
spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
(dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
spsr = clockDiv & SPI_2XCLOCK_MASK;
}
uint8_t spcr;
uint8_t spsr;
friend class SPIClass;
};
class SPIClass { class SPIClass {
public: public:
inline static byte transfer(byte _data); // Initialize the SPI library
static void begin();
// SPI Configuration methods // If SPI is used from within an interrupt, this function registers
// that interrupt with the SPI library, so beginTransaction() can
// prevent conflicts. The input interruptNumber is the number used
// with attachInterrupt. If SPI is used from a different interrupt
// (eg, a timer), interruptNumber should be 255.
static void usingInterrupt(uint8_t interruptNumber);
// And this does the opposite.
static void notUsingInterrupt(uint8_t interruptNumber);
// Note: the usingInterrupt and notUsingInterrupt functions should
// not to be called from ISR context or inside a transaction.
// For details see:
// https://github.com/arduino/Arduino/pull/2381
// https://github.com/arduino/Arduino/pull/2449
inline static void attachInterrupt(); // Before using SPI.transfer() or asserting chip select pins,
inline static void detachInterrupt(); // Default // this function is used to gain exclusive access to the SPI bus
// and configure the correct settings.
inline static void beginTransaction(SPISettings settings) {
if (interruptMode > 0) {
uint8_t sreg = SREG;
noInterrupts();
static void begin(); // Default #ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
interruptSave = SPI_AVR_EIMSK;
SPI_AVR_EIMSK &= ~interruptMask;
SREG = sreg;
} else
#endif
{
interruptSave = sreg;
}
}
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 1;
#endif
SPCR = settings.spcr;
SPSR = settings.spsr;
}
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
inline static uint8_t transfer(uint8_t data) {
SPDR = data;
/*
* The following NOP introduces a small delay that can prevent the wait
* loop form iterating when running at the maximum speed. This gives
* about 10% more speed, even if it seems counter-intuitive. At lower
* speeds it is unnoticed.
*/
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ; // wait
return SPDR;
}
inline static uint16_t transfer16(uint16_t data) {
union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
in.val = data;
if (!(SPCR & _BV(DORD))) {
SPDR = in.msb;
asm volatile("nop"); // See transfer(uint8_t) function
while (!(SPSR & _BV(SPIF))) ;
out.msb = SPDR;
SPDR = in.lsb;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ;
out.lsb = SPDR;
} else {
SPDR = in.lsb;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ;
out.lsb = SPDR;
SPDR = in.msb;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ;
out.msb = SPDR;
}
return out.val;
}
inline static void transfer(void *buf, size_t count) {
if (count == 0) return;
uint8_t *p = (uint8_t *)buf;
SPDR = *p;
while (--count > 0) {
uint8_t out = *(p + 1);
while (!(SPSR & _BV(SPIF))) ;
uint8_t in = SPDR;
SPDR = out;
*p++ = in;
}
while (!(SPSR & _BV(SPIF))) ;
*p = SPDR;
}
// After performing a group of transfers and releasing the chip select
// signal, this function allows others to access the SPI bus
inline static void endTransaction(void) {
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (!inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 0;
#endif
if (interruptMode > 0) {
#ifdef SPI_AVR_EIMSK
uint8_t sreg = SREG;
#endif
noInterrupts();
#ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
SPI_AVR_EIMSK = interruptSave;
SREG = sreg;
} else
#endif
{
SREG = interruptSave;
}
}
}
// Disable the SPI bus
static void end(); static void end();
static void setBitOrder(uint8_t); // This function is deprecated. New applications should use
static void setDataMode(uint8_t); // beginTransaction() to configure SPI settings.
static void setClockDivider(uint8_t); inline static void setBitOrder(uint8_t bitOrder) {
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
else SPCR &= ~(_BV(DORD));
}
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setDataMode(uint8_t dataMode) {
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
}
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setClockDivider(uint8_t clockDiv) {
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
}
// These undocumented functions should not be used. SPI.transfer()
// polls the hardware flag which is automatically cleared as the
// AVR responds to SPI's interrupt
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
private:
static uint8_t initialized;
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
static uint8_t interruptMask; // which interrupts to mask
static uint8_t interruptSave; // temp storage, to restore state
#ifdef SPI_TRANSACTION_MISMATCH_LED
static uint8_t inTransactionFlag;
#endif
}; };
extern SPIClass SPI; extern SPIClass SPI;
byte SPIClass::transfer(byte _data) {
SPDR = _data;
while (!(SPSR & _BV(SPIF)))
;
return SPDR;
}
void SPIClass::attachInterrupt() {
SPCR |= _BV(SPIE);
}
void SPIClass::detachInterrupt() {
SPCR &= ~_BV(SPIE);
}
#endif #endif

View File

@ -77,7 +77,7 @@ void loop() {
//Read the pressure data lower 16 bits: //Read the pressure data lower 16 bits:
unsigned int pressure_data_low = readRegister(0x20, 2); unsigned int pressure_data_low = readRegister(0x20, 2);
//combine the two parts into one 19-bit number: //combine the two parts into one 19-bit number:
long pressure = ((pressure_data_high << 16) | pressure_data_low)/4; long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4;
// display the temperature: // display the temperature:
Serial.println("\tPressure [Pa]=" + String(pressure)); Serial.println("\tPressure [Pa]=" + String(pressure));

View File

@ -62,10 +62,10 @@ void loop() {
void digitalPotWrite(int address, int value) { void digitalPotWrite(int address, int value) {
// take the SS pin low to select the chip: // take the SS pin low to select the chip:
digitalWrite(slaveSelectPin,LOW); digitalWrite(slaveSelectPin, LOW);
// send in the address and value via SPI: // send in the address and value via SPI:
SPI.transfer(address); SPI.transfer(address);
SPI.transfer(value); SPI.transfer(value);
// take the SS pin high to de-select the chip: // take the SS pin high to de-select the chip:
digitalWrite(slaveSelectPin,HIGH); digitalWrite(slaveSelectPin, HIGH);
} }