/** * Copyright (c) 2011-2022 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef SdSpiBareUnoDriver_h #define SdSpiBareUnoDriver_h /** * \file * \brief Driver to test with no Arduino includes. */ #include #include "../common/SysCall.h" #define nop asm volatile("nop\n\t") #ifndef HIGH #define HIGH 1 #endif // HIGH #ifndef LOW #define LOW 0 #endif // LOW #ifndef INPUT #define INPUT 0 #endif // INPUT #ifndef OUTPUT #define OUTPUT 1 #endif // OUTPUT inline uint8_t unoBit(uint8_t pin) { return 1 << (pin < 8 ? pin : pin < 14 ? pin - 8 : pin - 14); } inline uint8_t unoDigitalRead(uint8_t pin) { volatile uint8_t* reg = pin < 8 ? &PIND : pin < 14 ? &PINB : &PINC; return *reg & unoBit(pin); } inline void unoDigitalWrite(uint8_t pin, uint8_t value) { volatile uint8_t* port = pin < 8 ? &PORTD : pin < 14 ? &PORTB : &PORTC; uint8_t bit = unoBit(pin); cli(); if (value) { *port |= bit; } else { *port &= ~bit; } sei(); } inline void unoPinMode(uint8_t pin, uint8_t mode) { uint8_t bit = unoBit(pin); volatile uint8_t* reg = pin < 8 ? &DDRD : pin < 14 ? &DDRB : &DDRC; cli(); if (mode == OUTPUT) { *reg |= bit; } else { *reg &= ~bit; // handle INPUT pull-up unoDigitalWrite(pin, mode != INPUT); } sei(); } #define UNO_SS 10 #define UNO_MOSI 11 #define UNO_MISO 12 #define UNO_SCK 13 //------------------------------------------------------------------------------ /** * \class SdSpiDriverBareUno * \brief Optimized SPI class for access to SD and SDHC flash memory cards. */ class SdSpiDriverBareUno { public: /** Activate SPI hardware. */ void activate() {} /** Initialize the SPI bus. * * \param[in] spiConfig SD card configuration. */ void begin(SdSpiConfig spiConfig) { m_csPin = spiConfig.csPin; unoPinMode(m_csPin, OUTPUT); unoDigitalWrite(m_csPin, HIGH); unoDigitalWrite(UNO_SS, HIGH); unoPinMode(UNO_SS, OUTPUT); SPCR |= _BV(MSTR); SPCR |= _BV(SPE); SPSR = 0; unoPinMode(UNO_SCK, OUTPUT); unoPinMode(UNO_MOSI, OUTPUT); } /** Deactivate SPI hardware. */ void deactivate() {} /** deactivate SPI driver. */ void end() {} /** Receive a byte. * * \return The byte. */ uint8_t receive() { return transfer(0XFF); } /** Receive multiple bytes. * * \param[out] buf Buffer to receive the data. * \param[in] count Number of bytes to receive. * * \return Zero for no error or nonzero error code. */ uint8_t receive(uint8_t* buf, size_t count) { if (count == 0) { return 0; } uint8_t* pr = buf; SPDR = 0XFF; while (--count > 0) { while (!(SPSR & _BV(SPIF))) { } uint8_t in = SPDR; SPDR = 0XFF; *pr++ = in; // nops to optimize loop for 16MHz CPU 8 MHz SPI nop; nop; } while (!(SPSR & _BV(SPIF))) { } *pr = SPDR; return 0; } /** Send a byte. * * \param[in] data Byte to send */ void send(uint8_t data) { transfer(data); } /** Send multiple bytes. * * \param[in] buf Buffer for data to be sent. * \param[in] count Number of bytes to send. */ void send(const uint8_t* buf, size_t count) { if (count == 0) { return; } SPDR = *buf++; while (--count > 0) { uint8_t b = *buf++; while (!(SPSR & (1 << SPIF))) { } SPDR = b; // nops to optimize loop for 16MHz CPU 8 MHz SPI nop; nop; } while (!(SPSR & (1 << SPIF))) { } } /** Set CS low. */ void select() { unoDigitalWrite(m_csPin, LOW); } /** Save high speed SPISettings after SD initialization. * * \param[in] spiConfig SPI options. */ void setSckSpeed(uint32_t maxSck) { (void)maxSck; SPSR |= 1 << SPI2X; } static uint8_t transfer(uint8_t data) { SPDR = data; while (!(SPSR & _BV(SPIF))) { } // wait return SPDR; } /** Set CS high. */ void unselect() { unoDigitalWrite(m_csPin, HIGH); } private: SdCsPin_t m_csPin; }; #endif // SdSpiBareUnoDriver_h