Below is an interim implementation for SPI.h, showing where I'm heading to with the interface. The lower-level C-language interface is mostly written already, but not tested. --Pekka /* * Copyright (c) 2014 ELL-i co-operative * * This file is part of ELL-i software. * * ELL-i software is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ELL-i software 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ELL-i software. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Pekka Nikander <pekka.nikander@xxxxxxxxx> 2014 * * @brief The Arduino library SPI class */ #ifndef _SPI_CLASS_H_ #define _SPI_CLASS_H_ #include <stm32f0xx.h> #include <ellduino_gpio.h> // XXX To be placed into the variant.h! #include <ellduino_spi.h> // XXX To be placed into the variant.h! #include <arduelli_thread.h> // XXX TBD -- is this the right file name? enum SPITransferMode { SPI_CONTINUE, SPI_LAST }; enum SPIBitOrder { MSBFIRST = !SPI_CR1_LSBFIRST, LSBFIRST = SPI_CR1_LSBFIRST, }; enum SPIClockDivider { SPI_CLOCK_DIV2 = !SPI_CR1_BR_2 | !SPI_CR1_BR_1 | !SPI_CR1_BR_0, SPI_CLOCK_DIV4 = !SPI_CR1_BR_2 | !SPI_CR1_BR_1 | SPI_CR1_BR_0, SPI_CLOCK_DIV8 = !SPI_CR1_BR_2 | SPI_CR1_BR_1 | !SPI_CR1_BR_0, SPI_CLOCK_DIV16 = !SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0, SPI_CLOCK_DIV32 = SPI_CR1_BR_2 | !SPI_CR1_BR_1 | !SPI_CR1_BR_0, SPI_CLOCK_DIV64 = SPI_CR1_BR_2 | !SPI_CR1_BR_1 | SPI_CR1_BR_0, SPI_CLOCK_DIV128 = SPI_CR1_BR_2 | SPI_CR1_BR_1 | !SPI_CR1_BR_0, SPI_CLOCK_DIV256 = SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0, }; enum SPIDataMode { SPI_MODE0 = !SPI_CR1_CPHA | !SPI_CR1_CPOL, SPI_MODE1 = SPI_CR1_CPHA | !SPI_CR1_CPOL, SPI_MODE2 = !SPI_CR1_CPHA | SPI_CR1_CPOL, SPI_MODE3 = SPI_CR1_CPHA | SPI_CR1_CPOL, }; XXX TODO: Figure out the data structure to store per-SS-pin data XXX TODO: Figure out a nice implementation for setClock class SPIClass { public: const SPI spi_; constexpr SPIClass(const SPI &); void begin(const uint8_t ss_pin = BOARD_DEFAULT_SS) const { digitalWrite(ss_pin, 1); /* Avoid glitch */ pinMode(ss_pin, OUTPUT); spi_master_begin(&spi_); spi_activate(); }; void end(const uint8_t ss_pin) const { spi_master_end(&spi_); pinMode(ss_pin, INPUT /* XXX DEFAULT */); }; void end(void) const { /* XXX Semantic inconsistency with begin(void) */ spi_deactivate(); } void setBitOrder(const SPIBitOrder bitOrder) const { setBitOrder(BOARD_SPI_DEFAULT_SS, bitOrder); } void setBitOrder(const uint8_t ss_pin, const SPIBitOrder bitOrder) const { XXX[ss_pin] &= ~SP1_CR1_LSBFIRST; XXX[ss_pin] |= bitOrder; } uint32_t setClockDivider(const SPIClockDivider clockDivider) const { return setClockDivider(BOARD_SPI_DEFAULT_SS, clockDivider); } uint32_t setClockDivider(const unit8_t ss_pin, const SPIClockDivider clockDivider) const { uint32_t oldValue = XXX[ss_pin] & SPI_CR1_BR; XXX[ss_pin] &= ~SPI_CR1_BR; XXX[ss_pin] |= clockDivider; return oldValue; } uint32_t setClock(const uint32_t hertz) const { return setClock(BOARD_SPI_DEFAULT_SS, hertz); } uint32_t setClock(const uint8_t ss_pin, const uint32_t hertz) const { extern "C" { extern volatile uint32_t SystemCoreClock; } const uint32_t wantedDivider = SystemCoreClock / hertz; XXX; setClockDivider(ss_pin, XXX); } void setDataMode(SPIDataMode dataMode) const { setDataMode(BOARD_SPI_DEFAULT_SS, dataMode); } void setDataMode(uint8_t ss_pin, SPIDataMode dataMode) const { XXX[ss_pin] &= ~(SPI_CR1_CPHA | SPI_CR1_CPOL); XXX[ss_pin] |= dataMode; } uint8_t transfer(uint8_t data, SPITransferMode mode = SPI_LAST) const { return transfer(BOARD_SPI_DEFAULT_SS, data, mode); } uint8_t transfer(uint8_t ss_pin, uint8_t data, SPITransferMode mode = SPI_LAST) const { return transfer(ss_pin, &data, 1, mode); } uint8_t transfer(uint8_t ss_pin, uint8_t data[], uint8_t len, SPITransferMode mode = SPI_LAST) const { activate_ss(ss_pin); const uint32_t cr1 = XXX[ss_pin]; len = spi_transfer(&spi_, cr1, data, len); if (mode == SPI_LAST) deactivate_ss(ss_pin); return len; }; private: static inline void activate_ss(uint8_t ss_pin) { XXX }; static inline void deactive_ss(uint8_t ss_pin) { XXX }; }; #define DEFINE_SPI(spi_number, ss_port, ss_pin, ss_af, miso_port, miso_pin, miso_af, mosi_port, mosi_pin, mosi_af, clk_port, clk_pin, clk_af) \ ({ DEFINE_SPI_STRUCT(spi_number, \ ss_port, ss_pin, ss_af, \ miso_port, miso_pin, miso_af, \ mosi_port, mosi_pin, mosi_af, \ clk_port, clk_pin, clk_af) }) constexpr SPIClass::SPIClass(const SPI &spi) : spi_(spi) {} #endif//_SPI_CLASS_H_