From 44f4c7226c0832631eb5f0b75451e4a3aee0e9cd Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 26 Mar 2013 10:05:44 +0100 Subject: [PATCH] Make SPI access atomic in Ethernet library When using the Ethernet library combined with another library that does SPI access inside an interrupt handler, the Arduino could crash if that interrupted occured while the Ethernet library was doing an SPI transfer. This commit makes all Ethernet SPI transfers happen atomically (i.e., with the global interrupt flag cleared), preventing such conflicts by delaying all interrupts until after the SPI transfer. Closes: #384 --- libraries/Ethernet/utility/w5100.cpp | 63 ++++++++++++++++------------ 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/libraries/Ethernet/utility/w5100.cpp b/libraries/Ethernet/utility/w5100.cpp index 9c748fd201d..b7076ffe018 100644 --- a/libraries/Ethernet/utility/w5100.cpp +++ b/libraries/Ethernet/utility/w5100.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "w5100.h" @@ -129,12 +130,15 @@ void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *ds uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) { - setSS(); - SPI.transfer(0xF0); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - SPI.transfer(_data); - resetSS(); + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + setSS(); + SPI.transfer(0xF0); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + SPI.transfer(_data); + resetSS(); + } return 1; } @@ -142,25 +146,30 @@ uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) { for (uint16_t i=0; i<_len; i++) { - setSS(); - SPI.transfer(0xF0); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - _addr++; - SPI.transfer(_buf[i]); - resetSS(); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + setSS(); + SPI.transfer(0xF0); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _addr++; + SPI.transfer(_buf[i]); + resetSS(); + } } return _len; } uint8_t W5100Class::read(uint16_t _addr) { - setSS(); - SPI.transfer(0x0F); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - uint8_t _data = SPI.transfer(0); - resetSS(); + uint8_t _data; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + setSS(); + SPI.transfer(0x0F); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _data = SPI.transfer(0); + resetSS(); + } return _data; } @@ -168,13 +177,15 @@ uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) { for (uint16_t i=0; i<_len; i++) { - setSS(); - SPI.transfer(0x0F); - SPI.transfer(_addr >> 8); - SPI.transfer(_addr & 0xFF); - _addr++; - _buf[i] = SPI.transfer(0); - resetSS(); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + setSS(); + SPI.transfer(0x0F); + SPI.transfer(_addr >> 8); + SPI.transfer(_addr & 0xFF); + _addr++; + _buf[i] = SPI.transfer(0); + resetSS(); + } } return _len; }