diff --git a/meson.build b/meson.build index 16ff81fe..0d849d15 100644 --- a/meson.build +++ b/meson.build @@ -250,6 +250,7 @@ mk22fn512_src = ['platform/mcu/MK22FN512xxx12/boot/startup.cpp', 'platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.c', 'platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.c', 'platform/mcu/MK22FN512xxx12/drivers/usb_vcom.c', + 'platform/drivers/SPI/spi_mk22.c', 'platform/mcu/CMSIS/Device/NXP/MK22FN512xxx12/Source/system_MK22F51212.c'] mk22fn512_inc = ['platform/mcu/CMSIS/Include', diff --git a/platform/drivers/SPI/spi_mk22.c b/platform/drivers/SPI/spi_mk22.c new file mode 100644 index 00000000..a7059219 --- /dev/null +++ b/platform/drivers/SPI/spi_mk22.c @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (C) 2021 - 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program 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. * + * * + * This program 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 this program; if not, see * + ***************************************************************************/ + +#include +#include +#include "spi_mk22.h" + + +static inline uint8_t spi_sendRecv(SPI_Type *spi, const uint8_t val) +{ + spi->MCR &= ~SPI_MCR_HALT_MASK; // Start transfer + + spi->MCR |= SPI_MCR_CLR_TXF_MASK | SPI_MCR_CLR_RXF_MASK; + + while((spi->SR & SPI_SR_TFFF_MASK) == 0) ; + + spi->PUSHR = SPI_PUSHR_EOQ_MASK | val; + + spi->SR |= SPI_SR_TFFF_MASK; + + while((spi->SR & SPI_SR_RFDF_MASK) == 0) ; + spi->SR |= SPI_SR_RFDF_MASK; + + spi->MCR |= SPI_MCR_HALT_MASK; // Start transfer + + return spi->POPR; +} + +int spiMk22_init(const struct spiDevice *dev, const uint8_t pbr, const uint8_t br, + const uint8_t flags) +{ + SPI_Type *spi = (SPI_Type *) dev->priv; + switch((uint32_t) spi) + { + case SPI0_BASE: + SIM->SCGC6 |= SIM_SCGC6_SPI0_MASK; + __DSB(); + break; + + case SPI1_BASE: + SIM->SCGC6 |= SIM_SCGC6_SPI1_MASK; + __DSB(); + break; + + default: + return -ENODEV; + break; + } + + spi->MCR &= ~SPI_MCR_MDIS_MASK; // Enable the SPI module + spi->MCR |= SPI_MCR_MSTR_MASK // Master mode + | SPI_MCR_PCSIS_MASK // CS high when inactive + | SPI_MCR_DIS_RXF_MASK // Disable RX FIFO + | SPI_MCR_DIS_TXF_MASK // Disable TX FIFO + | SPI_MCR_HALT_MASK; // Stop transfers + + spi->CTAR[0] = SPI_CTAR_FMSZ(7) // 8bit frame size + | SPI_CTAR_PBR(pbr) // CLK prescaler divide by 5 + | SPI_CTAR_BR(br) // CLK scaler divide by 8 + | SPI_CTAR_PCSSCK(1) + | SPI_CTAR_PASC(1) + | SPI_CTAR_CSSCK(4) + | SPI_CTAR_ASC(4); + + if((flags & SPI_FLAG_CPOL) != 0) + spi->CTAR[0] |= SPI_CTAR_CPOL_MASK; + + if((flags & SPI_FLAG_CPHA) != 0) + spi->CTAR[0] |= SPI_CTAR_CPHA_MASK; + + if((flags & SPI_LSB_FIRST) != 0) + spi->CTAR[0] |= SPI_CTAR_LSBFE_MASK; + + if(dev->mutex != NULL) + pthread_mutex_init((pthread_mutex_t *) dev->mutex, NULL); + + return 0; +} + +void spiMk22_terminate(const struct spiDevice *dev) +{ + SPI_Type *spi = (SPI_Type *) dev->priv; + switch((uint32_t) spi) + { + case SPI0_BASE: + SIM->SCGC6 &= ~SIM_SCGC6_SPI0_MASK; + __DSB(); + break; + + case SPI1_BASE: + SIM->SCGC6 &= ~SIM_SCGC6_SPI1_MASK; + __DSB(); + break; + + default: + break; + } + + if(dev->mutex != NULL) + pthread_mutex_destroy((pthread_mutex_t *) dev->mutex); +} + +int spiMk22_transfer(const struct spiDevice *dev, const void *txBuf, + void *rxBuf, const size_t size) +{ + SPI_Type *spi = (SPI_Type *) dev->priv; + uint8_t *rxData = (uint8_t *) rxBuf; + const uint8_t *txData = (const uint8_t *) txBuf; + + // Send only + if(rxBuf == NULL) + { + for(size_t i = 0; i < size; i++) + spi_sendRecv(spi, txData[i]); + + return 0; + } + + // Receive only + if(txBuf == NULL) + { + for(size_t i = 0; i < size; i++) + rxData[i] = spi_sendRecv(spi, 0x00); + + return 0; + } + + // Transmit and receive + for(size_t i = 0; i < size; i++) + rxData[i] = spi_sendRecv(spi, txData[i]); + + return 0; +} + diff --git a/platform/drivers/SPI/spi_mk22.h b/platform/drivers/SPI/spi_mk22.h new file mode 100644 index 00000000..71a92e7e --- /dev/null +++ b/platform/drivers/SPI/spi_mk22.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2021 - 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program 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. * + * * + * This program 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 this program; if not, see * + ***************************************************************************/ + +#ifndef SPI_MK22_H +#define SPI_MK22_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Instantiate an MK22 SPI master device. + * + * @param name: device name. + * @param peripheral: underlying MCU peripheral. + * @param mutx: pointer to mutex, or NULL. + */ +#define SPI_MK22_DEVICE_DEFINE(name, peripheral, mutx) \ +extern int spiMk22_transfer(const struct spiDevice *dev, const void *txBuf, \ + void *rxBuf, const size_t size); \ +const struct spiDevice name = \ +{ \ + .transfer = &spiMk22_transfer, \ + .priv = peripheral, \ + .mutex = mutx \ +}; + +/** + * Initialise an SPI peripheral and driver. + * Is left to application code to change the operating mode and alternate function + * mapping of the corresponding gpio lines. + * + * @param dev: SPI device descriptor. + * @param pbr: value for the baud rate prescaler (see reference manual). + * @param br: value for the baud rate scaler (see reference manual). + * @param flags: SPI configuration flags. + * @return zero on success, a negative error code otherwise. + */ +int spiMk22_init(const struct spiDevice *dev, const uint8_t pbr, const uint8_t br, + const uint8_t flags); + +/** + * Shut down an SPI peripheral and driver. + * + * @param dev: SPI device descriptor. + */ +void spiMk22_terminate(const struct spiDevice *dev); + + +#ifdef __cplusplus +} +#endif + +#endif /* SPI_MK22_H */