/* * SPI Master library for nRF5x. * Copyright (c) 2015 Arduino LLC * Copyright (c) 2016 Sandeep Mistry All right reserved. * Copyright (c) 2017 hathach * * 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 */ #include "shared-bindings/busio/SPI.h" #include "py/mperrno.h" #include "py/runtime.h" #include "nrf.h" #include "pins.h" // Convert frequency to clock-speed-dependent value. Return 0 if out of range. static uint32_t baudrate_to_reg(const uint32_t baudrate) { uint32_t value; if (baudrate <= 125000) { value = SPI_FREQUENCY_FREQUENCY_K125; } else if (baudrate <= 250000) { value = SPI_FREQUENCY_FREQUENCY_K250; } else if (baudrate <= 500000) { value = SPI_FREQUENCY_FREQUENCY_K500; } else if (baudrate <= 1000000) { value = SPI_FREQUENCY_FREQUENCY_M1; } else if (baudrate <= 2000000) { value = SPI_FREQUENCY_FREQUENCY_M2; } else if (baudrate <= 4000000) { value = SPI_FREQUENCY_FREQUENCY_M4; } else { value = SPI_FREQUENCY_FREQUENCY_M8; } return value; } void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, const mcu_pin_obj_t * miso) { // 1 for I2C, 0 for SPI self->spi = NRF_SPI0; self->spi->PSELSCK = clock->pin; self->spi->PSELMOSI = mosi->pin; self->spi->PSELMISO = miso->pin; } bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->spi == NULL; } void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } self->spi->PSELSCK = SPI_PSEL_SCK_PSELSCK_Disconnected; self->spi->PSELMOSI = SPI_PSEL_MOSI_PSELMOSI_Disconnected; self->spi->PSELMISO = SPI_PSEL_MISO_PSELMISO_Disconnected; // reset_pin(self->clock_pin); // reset_pin(self->MOSI_pin); // reset_pin(self->MISO_pin); self->spi = NULL; } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { // nrf52 does not support 16 bit if ( bits != 8 ) return false; self->spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); uint32_t config = (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos); config |= ((polarity ? SPI_CONFIG_CPOL_ActiveLow : SPI_CONFIG_CPOL_ActiveHigh) << SPI_CONFIG_CPOL_Pos); config |= ((phase ? SPI_CONFIG_CPHA_Trailing : SPI_CONFIG_CPHA_Leading ) << SPI_CONFIG_CPHA_Pos); self->spi->CONFIG = config; self->spi->FREQUENCY = baudrate_to_reg(baudrate); self->spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); return true; } bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { bool grabbed_lock = false; // CRITICAL_SECTION_ENTER() // if (!self->has_lock) { grabbed_lock = true; self->has_lock = true; // } // CRITICAL_SECTION_LEAVE(); return grabbed_lock; } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { return self->has_lock; } void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { self->has_lock = false; } bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { if (len == 0) { return true; } while (len) { self->spi->TXD = *data; while(!self->spi->EVENTS_READY); (void) self->spi->RXD; data++; len--; self->spi->EVENTS_READY = 0x0UL; } return true; } bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { if (len == 0) { return true; } while (len) { self->spi->TXD = write_value; while(!self->spi->EVENTS_READY); *data = self->spi->RXD; data++; len--; self->spi->EVENTS_READY = 0x0UL; } return true; }