circuitpython/atmel-samd/common-hal/nativeio/SPI.c

144 lines
4.9 KiB
C
Raw Normal View History

/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Scott Shawcroft
*
* 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.
*/
// This file contains all of the port specific HAL functions for the machine
// module.
#include "shared-bindings/nativeio/SPI.h"
#include "py/nlr.h"
// We use ENABLE registers below we don't want to treat as a macro.
#undef ENABLE
// Number of times to try to send packet if failed.
#define TIMEOUT 1
void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
const mcu_pin_obj_t * miso, uint32_t baudrate) {
struct spi_config config_spi_master;
spi_get_config_defaults(&config_spi_master);
Sercom* sercom = NULL;
uint32_t clock_pinmux = 0;
uint32_t mosi_pinmux = 0;
uint32_t miso_pinmux = 0;
uint8_t clock_pad = 0;
uint8_t mosi_pad = 0;
uint8_t miso_pad = 0;
for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) {
Sercom* potential_sercom = clock->sercom[i].sercom;
if (potential_sercom == NULL ||
potential_sercom->SPI.CTRLA.bit.ENABLE != 0) {
continue;
}
clock_pinmux = clock->sercom[i].pinmux;
clock_pad = clock->sercom[i].pad;
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
mosi_pinmux = mosi->sercom[j].pinmux;
mosi_pad = mosi->sercom[j].pad;
for (int k = 0; k < NUM_SERCOMS_PER_PIN; k++) {
if (potential_sercom == miso->sercom[k].sercom) {
miso_pinmux = miso->sercom[k].pinmux;
miso_pad = miso->sercom[k].pad;
sercom = potential_sercom;
break;
}
}
if (sercom != NULL) {
break;
}
}
if (sercom != NULL) {
break;
}
}
if (sercom == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
"No hardware support available with those pins."));
}
// Depends on where MOSI and CLK are.
uint8_t dopo = 8;
if (clock_pad == 1) {
if (mosi_pad == 0) {
dopo = 0;
} else if (mosi_pad == 3) {
dopo = 2;
}
} else if (clock_pad == 3) {
if (mosi_pad == 0) {
dopo = 3;
} else if (mosi_pad == 2) {
dopo = 1;
}
}
if (dopo == 8) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI MOSI and clock pins incompatible."));
}
config_spi_master.mux_setting = (dopo << SERCOM_SPI_CTRLA_DOPO_Pos) |
(miso_pad << SERCOM_SPI_CTRLA_DIPO_Pos);
// Map pad to pinmux through a short array.
uint32_t *pinmuxes[4] = {&config_spi_master.pinmux_pad0,
&config_spi_master.pinmux_pad1,
&config_spi_master.pinmux_pad2,
&config_spi_master.pinmux_pad3};
*pinmuxes[clock_pad] = clock_pinmux;
*pinmuxes[mosi_pad] = mosi_pinmux;
*pinmuxes[miso_pad] = miso_pinmux;
config_spi_master.mode_specific.master.baudrate = baudrate;
spi_init(&self->spi_master_instance, sercom, &config_spi_master);
spi_enable(&self->spi_master_instance);
}
void common_hal_nativeio_spi_deinit(nativeio_spi_obj_t *self) {
spi_disable(&self->spi_master_instance);
}
bool common_hal_nativeio_spi_write(nativeio_spi_obj_t *self,
const uint8_t *data, size_t len) {
enum status_code status = spi_write_buffer_wait(
&self->spi_master_instance,
data,
len);
return status == STATUS_OK;
}
bool common_hal_nativeio_spi_read(nativeio_spi_obj_t *self,
uint8_t *data, size_t len) {
enum status_code status = spi_read_buffer_wait(
&self->spi_master_instance,
data,
len,
0);
return status == STATUS_OK;
}