diff options
Diffstat (limited to 'core/comm/HardwareSPI.cpp')
-rw-r--r-- | core/comm/HardwareSPI.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/core/comm/HardwareSPI.cpp b/core/comm/HardwareSPI.cpp new file mode 100644 index 0000000..51093cb --- /dev/null +++ b/core/comm/HardwareSPI.cpp @@ -0,0 +1,138 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + * ****************************************************************************/ + +/** + * @brief HardwareSPI "wiring-like" api for SPI + */ + +/* NOTES: + * + * Speeds: + * ----------------------------------- + * Interface num: SPI1 SPI2 + * Bus APB2 APB1 + * ----------------------------------- + * Prescaler Frequencies + * ----------------------------------- + * 2: N/A 18 000 000 + * 4: 18 000 000 9 000 000 + * 8: 9 000 000 4 500 000 + * 16: 4 500 000 2 250 000 + * 32: 2 250 000 1 125 000 + * 64: 1 125 000 562 500 + * 128: 562 500 281 250 + * 256: 281 250 140 625 + * + * TODO: Do the complementary PWM outputs mess up SPI2? + * */ + +#include "wiring.h" +#include "spi.h" +#include "HardwareSPI.h" + +static const uint32 prescaleFactors[MAX_SPI_FREQS] = { + SPI_PRESCALE_2, // SPI_18MHZ + SPI_PRESCALE_4, // SPI_9MHZ + SPI_PRESCALE_8, // SPI_4_5MHZ + SPI_PRESCALE_16, // SPI_2_25MHZ + SPI_PRESCALE_32, // SPI_1_125MHZ + SPI_PRESCALE_64, // SPI_562_500KHZ + SPI_PRESCALE_128, // SPI_281_250KHZ + SPI_PRESCALE_256, // SPI_140_625KHZ +}; + +/** + * @brief Initialize a SPI peripheral + * @param freq frequency to run at, must one of the following values: + * - SPI_18MHZ + * - SPI_9MHZ + * - SPI_4_5MHZ + * - SPI_2_25MHZ + * - SPI_1_125MHZ + * - SPI_562_500KHZ + * - SPI_281_250KHZ + * - SPI_140_625KHZ + * @param endianness endianness of the data frame, must be either LSBFIRST + * or MSBFIRST + * @param mode SPI standard CPOL and CPHA levels + */ +void HardwareSPI::begin(SPIFrequency freq, uint32 endianness, uint32 mode) { + uint32 spi_num = this->spi_num; + uint32 high_speed = 0; + uint32 index; + uint32 prescale; + + if ((freq >= MAX_SPI_FREQS) || + !((endianness == LSBFIRST) || + (endianness == MSBFIRST)) || + (mode >= 4)) { + return; + } + + if (spi_num == 1) { + /* SPI1 is too fast for 140625 */ + if (freq == SPI_140_625KHZ) { + return; + } + + /* Turn off PWM on shared pins */ + timers_disable_channel(3, 2); + timers_disable_channel(3, 1); + } + + endianness = (endianness == LSBFIRST) ? SPI_LSBFIRST : SPI_MSBFIRST; + prescale = (spi_num == 1) ? prescaleFactors[freq + 1] : prescaleFactors[freq]; + + spi_init(spi_num, prescale, endianness, 0); +} + +/** + * @brief Initialize a SPI peripheral with a default speed of 1.125 MHZ, MSBFIRST, + * mode 0 + * @param mode SPI standard CPOL and CPHA levels + */ +void HardwareSPI::begin(void) { + begin(SPI_1_125MHZ, MSBFIRST, 0); +} + +/** + * @brief send a byte out the spi peripheral + * @param data byte to send + */ +void HardwareSPI::send(uint8 data) { + spi_tx(this->spi_num, data); +} + + +/** + * @brief read a byte from the spi peripheral + * @return byte in the buffer + */ +uint8 HardwareSPI::recv(void) { + return spi_rx(this->spi_num); +} + +HardwareSPI::HardwareSPI(uint32 spi_num) { + this->spi_num = spi_num; +} |