579 lines
20 KiB
C
579 lines
20 KiB
C
/*
|
|
ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @file hal_spi_lld.c
|
|
* @brief MSP430X SPI subsystem low level driver source.
|
|
*
|
|
* @addtogroup SPI
|
|
* @{
|
|
*/
|
|
|
|
#include "hal.h"
|
|
|
|
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local definitions. */
|
|
/*===========================================================================*/
|
|
|
|
/*===========================================================================*/
|
|
/* Driver exported variables. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief SPIA0 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIA0 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDA0;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIA1 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIA1 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDA1;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIA2 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIA2 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDA2;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIA3 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIA3 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDA3;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIB0 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIB0 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDB0;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIB1 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIB1 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDB1;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIB2 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIB2 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDB2;
|
|
#endif
|
|
|
|
/**
|
|
* @brief SPIB3 driver identifier.
|
|
*/
|
|
#if (MSP430X_SPI_USE_SPIB3 == TRUE) || defined(__DOXYGEN__)
|
|
SPIDriver SPIDB3;
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local variables and types. */
|
|
/*===========================================================================*/
|
|
|
|
static const uint16_t dummytx = 0xFFFFU;
|
|
static uint16_t dummyrx;
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local functions. */
|
|
/*===========================================================================*/
|
|
|
|
static void init_transfer(SPIDriver * spip) {
|
|
|
|
#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE || defined(__DOXYGEN__)
|
|
if (spip->config->dmarx_index > MSP430X_DMA_CHANNELS) {
|
|
dmaRequest(&(spip->rx_req), TIME_INFINITE);
|
|
}
|
|
else {
|
|
dmaTransfer(&(spip->dmarx), &(spip->rx_req));
|
|
}
|
|
if (spip->config->dmatx_index > MSP430X_DMA_CHANNELS) {
|
|
dmaRequest(&(spip->tx_req), TIME_INFINITE);
|
|
}
|
|
else {
|
|
dmaTransfer(&(spip->dmatx), &(spip->tx_req));
|
|
}
|
|
#else
|
|
dmaRequest(&(spip->rx_req), TIME_INFINITE);
|
|
dmaRequest(&(spip->tx_req), TIME_INFINITE);
|
|
#endif
|
|
|
|
*(spip->ifg) |= UCTXIFG;
|
|
}
|
|
|
|
/**
|
|
* @brief Shared end-of-transfer callback.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
* @note This function is called in ISR context by the DMA code.
|
|
*/
|
|
static void spi_lld_end_of_transfer(void * spip) {
|
|
|
|
/* So that future transfers will actually work */
|
|
*(((SPIDriver *)spip)->ifg) &= ~(UCTXIFG);
|
|
/* NOTE to future me - this macro sets the driver state and calls the
|
|
* configured callback end_cb, if applicable. That callback doesn't seem to
|
|
* be modifiable without reconfiguring the whole driver. */
|
|
_spi_isr_code((SPIDriver *)spip);
|
|
}
|
|
/*===========================================================================*/
|
|
/* Driver interrupt handlers. */
|
|
/*===========================================================================*/
|
|
|
|
/*===========================================================================*/
|
|
/* Driver exported functions. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief Low level SPI driver initialization.
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_init(void) {
|
|
|
|
#if MSP430X_SPI_USE_SPIA0 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDA0);
|
|
SPIDA0.regs = (msp430x_spi_reg_t *)(&UCA0CTLW0);
|
|
SPIDA0.ifg = (volatile uint16_t *)&UCA0IFG;
|
|
SPIDA0.tx_req.trigger = DMA_TRIGGER_MNEM(UCA0TXIFG);
|
|
SPIDA0.rx_req.trigger = DMA_TRIGGER_MNEM(UCA0RXIFG);
|
|
SPIDA0.tx_req.dest_addr = &(SPIDA0.regs->txbuf);
|
|
SPIDA0.rx_req.source_addr = &(SPIDA0.regs->rxbuf);
|
|
SPIDA0.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA0.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA0.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA0.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA0.tx_req.callback.callback = NULL;
|
|
SPIDA0.tx_req.callback.args = NULL;
|
|
SPIDA0.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDA0.rx_req.callback.args = &SPIDA0;
|
|
/* NOTE to my future self - this must be SINGLE because BLOCK and BURST
|
|
* don't wait for triggers and would overflow both buffers. Don't worry, it
|
|
* still works - the transfer isn't complete until SZ bytes are transferred */
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIA1 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDA1);
|
|
SPIDA1.regs = (msp430x_spi_reg_t *)(&UCA1CTLW0);
|
|
SPIDA1.ifg = (volatile uint16_t *)&UCA1IFG;
|
|
SPIDA1.tx_req.trigger = DMA_TRIGGER_MNEM(UCA1TXIFG);
|
|
SPIDA1.rx_req.trigger = DMA_TRIGGER_MNEM(UCA1RXIFG);
|
|
SPIDA1.tx_req.dest_addr = &(SPIDA1.regs->txbuf);
|
|
SPIDA1.rx_req.source_addr = &(SPIDA1.regs->rxbuf);
|
|
SPIDA1.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA1.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA1.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA1.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA1.tx_req.callback.callback = NULL;
|
|
SPIDA1.tx_req.callback.args = NULL;
|
|
SPIDA1.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDA1.rx_req.callback.args = &SPIDA1;
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIA2 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDA2);
|
|
SPIDA2.regs = (msp430x_spi_reg_t *)(&UCA2CTLW0);
|
|
SPIDA2.ifg = (volatile uint16_t *)&UCA2IFG;
|
|
SPIDA2.tx_req.trigger = DMA_TRIGGER_MNEM(UCA2TXIFG);
|
|
SPIDA2.rx_req.trigger = DMA_TRIGGER_MNEM(UCA2RXIFG);
|
|
SPIDA2.tx_req.dest_addr = &(SPIDA2.regs->txbuf);
|
|
SPIDA2.rx_req.source_addr = &(SPIDA2.regs->rxbuf);
|
|
SPIDA2.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA2.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA2.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA2.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA2.tx_req.callback.callback = NULL;
|
|
SPIDA2.tx_req.callback.args = NULL;
|
|
SPIDA2.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDA2.rx_req.callback.args = &SPIDA2;
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIA3 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDA3);
|
|
SPIDA3.regs = (msp430x_spi_reg_t *)(&UCA3CTLW0);
|
|
SPIDA3.ifg = (volatile uint16_t *)&UCA3IFG;
|
|
SPIDA3.tx_req.trigger = DMA_TRIGGER_MNEM(UCA3TXIFG);
|
|
SPIDA3.rx_req.trigger = DMA_TRIGGER_MNEM(UCA3RXIFG);
|
|
SPIDA3.tx_req.dest_addr = &(SPIDA3.regs->txbuf);
|
|
SPIDA3.rx_req.source_addr = &(SPIDA3.regs->rxbuf);
|
|
SPIDA3.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA3.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDA3.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA3.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDA3.tx_req.callback.callback = NULL;
|
|
SPIDA3.tx_req.callback.args = NULL;
|
|
SPIDA3.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDA3.rx_req.callback.args = &SPIDA3;
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIB0 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDB0);
|
|
SPIDB0.regs = (msp430x_spi_reg_t *)(&UCB0CTLW0);
|
|
SPIDB0.ifg = (volatile uint16_t *)&UCB0IFG;
|
|
SPIDB0.tx_req.trigger = DMA_TRIGGER_MNEM(UCB0TXIFG0);
|
|
SPIDB0.rx_req.trigger = DMA_TRIGGER_MNEM(UCB0RXIFG0);
|
|
SPIDB0.tx_req.dest_addr = &(SPIDB0.regs->txbuf);
|
|
SPIDB0.rx_req.source_addr = &(SPIDB0.regs->rxbuf);
|
|
SPIDB0.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB0.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB0.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB0.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB0.tx_req.callback.callback = NULL;
|
|
SPIDB0.tx_req.callback.args = NULL;
|
|
SPIDB0.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDB0.rx_req.callback.args = &SPIDB0;
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIB1 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDB1);
|
|
SPIDB1.regs = (msp430x_spi_reg_t *)(&UCB1CTLW0);
|
|
SPIDB1.ifg = (volatile uint16_t *)&UCB1IFG;
|
|
SPIDB1.tx_req.trigger = DMA_TRIGGER_MNEM(UCB1TXIFG0);
|
|
SPIDB1.rx_req.trigger = DMA_TRIGGER_MNEM(UCB1RXIFG0);
|
|
SPIDB1.tx_req.dest_addr = &(SPIDB1.regs->txbuf);
|
|
SPIDB1.rx_req.source_addr = &(SPIDB1.regs->rxbuf);
|
|
SPIDB1.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB1.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB1.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB1.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB1.tx_req.callback.callback = NULL;
|
|
SPIDB1.tx_req.callback.args = NULL;
|
|
SPIDB1.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDB1.rx_req.callback.args = &SPIDB1;
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIB2 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDB2);
|
|
SPIDB2.regs = (msp430x_spi_reg_t *)(&UCB2CTLW0);
|
|
SPIDB2.ifg = (volatile uint16_t *)&UCB2IFG;
|
|
SPIDB2.tx_req.trigger = DMA_TRIGGER_MNEM(UCB2TXIFG0);
|
|
SPIDB2.rx_req.trigger = DMA_TRIGGER_MNEM(UCB2RXIFG0);
|
|
SPIDB2.tx_req.dest_addr = &(SPIDB2.regs->txbuf);
|
|
SPIDB2.rx_req.source_addr = &(SPIDB2.regs->rxbuf);
|
|
SPIDB2.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB2.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB2.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB2.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB2.tx_req.callback.callback = NULL;
|
|
SPIDB2.tx_req.callback.args = NULL;
|
|
SPIDB2.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDB2.rx_req.callback.args = &SPIDB2;
|
|
#endif
|
|
|
|
#if MSP430X_SPI_USE_SPIB3 == TRUE
|
|
/* Driver initialization.*/
|
|
spiObjectInit(&SPIDB3);
|
|
SPIDB3.regs = (msp430x_spi_reg_t *)(&UCB3CTLW0);
|
|
SPIDB3.ifg = (volatile uint16_t *)&UCB3IFG;
|
|
SPIDB3.tx_req.trigger = DMA_TRIGGER_MNEM(UCB3TXIFG0);
|
|
SPIDB3.rx_req.trigger = DMA_TRIGGER_MNEM(UCB3RXIFG0);
|
|
SPIDB3.tx_req.dest_addr = &(SPIDB3.regs->txbuf);
|
|
SPIDB3.rx_req.source_addr = &(SPIDB3.regs->rxbuf);
|
|
SPIDB3.tx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB3.rx_req.data_mode = MSP430X_DMA_SRCBYTE | MSP430X_DMA_DSTBYTE;
|
|
SPIDB3.tx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB3.rx_req.transfer_mode = MSP430X_DMA_SINGLE;
|
|
SPIDB3.tx_req.callback.callback = NULL;
|
|
SPIDB3.tx_req.callback.args = NULL;
|
|
SPIDB3.rx_req.callback.callback = spi_lld_end_of_transfer;
|
|
SPIDB3.rx_req.callback.args = &SPIDB3;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Configures and activates the SPI peripheral.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_start(SPIDriver * spip) {
|
|
|
|
if (spip->state == SPI_STOP) {
|
|
/* Enables the peripheral.*/
|
|
#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE
|
|
/* Claim DMA streams here */
|
|
bool b;
|
|
if (spip->config->dmatx_index < MSP430X_DMA_CHANNELS) {
|
|
b = dmaAcquire(&(spip->dmatx), spip->config->dmatx_index);
|
|
osalDbgAssert(!b, "stream already allocated");
|
|
}
|
|
if (spip->config->dmarx_index < MSP430X_DMA_CHANNELS) {
|
|
b = dmaAcquire(&(spip->dmarx), spip->config->dmarx_index);
|
|
osalDbgAssert(!b, "stream already allocated");
|
|
}
|
|
#endif /* MSP430X_SPI_EXCLUSIVE_DMA */
|
|
}
|
|
uint16_t brw = 0;
|
|
uint8_t ssel = 0;
|
|
#if MSP430X_SPI_USE_SPIA0
|
|
if (spip == &SPIDA0) {
|
|
brw = MSP430X_SPIA0_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIA0_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIA1
|
|
if (spip == &SPIDA1) {
|
|
brw = MSP430X_SPIA1_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIA1_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIA2
|
|
if (spip == &SPIDA2) {
|
|
brw = MSP430X_SPIA2_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIA2_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIA3
|
|
if (spip == &SPIDA3) {
|
|
brw = MSP430X_SPIA3_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIA3_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIB0
|
|
if (spip == &SPIDB0) {
|
|
brw = MSP430X_SPIB0_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIB0_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIB1
|
|
if (spip == &SPIDB1) {
|
|
brw = MSP430X_SPIB1_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIB1_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIB2
|
|
if (spip == &SPIDB2) {
|
|
brw = MSP430X_SPIB2_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIB2_UCSSEL;
|
|
}
|
|
#endif
|
|
#if MSP430X_SPI_USE_SPIB3
|
|
if (spip == &SPIDB3) {
|
|
brw = MSP430X_SPIB3_CLK_FREQ / spip->config->bit_rate;
|
|
ssel = MSP430X_SPIB3_UCSSEL;
|
|
}
|
|
#endif
|
|
/* Configures the peripheral.*/
|
|
spip->regs->ctlw0 = UCSWRST;
|
|
spip->regs->brw = brw;
|
|
spip->regs->ctlw0 =
|
|
(spip->config->spi_mode << 14) | (spip->config->bit_order << 13) |
|
|
(spip->config->data_size << 12) | (UCMST) |
|
|
((spip->config->ss_line ? 0 : 2) << 9) | (UCSYNC) | (ssel) | (UCSTEM);
|
|
*(spip->ifg) = 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Deactivates the SPI peripheral.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_stop(SPIDriver * spip) {
|
|
|
|
if (spip->state == SPI_READY) {
|
|
/* Disables the peripheral.*/
|
|
#if MSP430X_SPI_EXCLUSIVE_DMA == TRUE
|
|
dmaRelease(&(spip->dmatx));
|
|
dmaRelease(&(spip->dmarx));
|
|
#endif
|
|
spip->regs->ctlw0 = UCSWRST;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Asserts the slave select signal and prepares for transfers.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_select(SPIDriver * spip) {
|
|
|
|
if (spip->config->ss_line) {
|
|
palClearLine(spip->config->ss_line);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Deasserts the slave select signal.
|
|
* @details The previously selected peripheral is unselected.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_unselect(SPIDriver * spip) {
|
|
|
|
if (spip->config->ss_line) {
|
|
palSetLine(spip->config->ss_line);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Ignores data on the SPI bus.
|
|
* @details This asynchronous function starts the transmission of a series of
|
|
* idle bytes on the SPI bus and ignores the received data.
|
|
* @post At the end of the operation the configured callback is invoked.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
* @param[in] n number of bytes to be ignored
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_ignore(SPIDriver * spip, size_t n) {
|
|
|
|
spip->tx_req.source_addr = &dummytx;
|
|
spip->tx_req.size = n;
|
|
spip->tx_req.addr_mode = 0;
|
|
|
|
spip->rx_req.dest_addr = &dummyrx;
|
|
spip->rx_req.size = n;
|
|
spip->rx_req.addr_mode = 0;
|
|
|
|
init_transfer(spip);
|
|
}
|
|
|
|
/**
|
|
* @brief Exchanges data on the SPI bus.
|
|
* @details This asynchronous function starts a simultaneous transmit/receive
|
|
* operation.
|
|
* @post At the end of the operation the configured callback is invoked.
|
|
* @note The buffers are organized as uint8_t arrays for data sizes below or
|
|
* equal to 8 bits else it is organized as uint16_t arrays.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
* @param[in] n number of words to be exchanged
|
|
* @param[in] txbuf the pointer to the transmit buffer
|
|
* @param[out] rxbuf the pointer to the receive buffer
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_exchange(SPIDriver * spip,
|
|
size_t n,
|
|
const void * txbuf,
|
|
void * rxbuf) {
|
|
|
|
spip->tx_req.source_addr = txbuf;
|
|
spip->tx_req.size = n;
|
|
spip->tx_req.addr_mode = MSP430X_DMA_SRCINCR;
|
|
|
|
spip->rx_req.dest_addr = rxbuf;
|
|
spip->rx_req.size = n;
|
|
spip->rx_req.addr_mode = MSP430X_DMA_DSTINCR;
|
|
|
|
init_transfer(spip);
|
|
}
|
|
|
|
/**
|
|
* @brief Sends data over the SPI bus.
|
|
* @details This asynchronous function starts a transmit operation.
|
|
* @post At the end of the operation the configured callback is invoked.
|
|
* @note The buffers are organized as uint8_t arrays for data sizes below or
|
|
* equal to 8 bits else it is organized as uint16_t arrays.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
* @param[in] n number of words to send
|
|
* @param[in] txbuf the pointer to the transmit buffer
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_send(SPIDriver * spip, size_t n, const void * txbuf) {
|
|
|
|
spip->tx_req.source_addr = txbuf;
|
|
spip->tx_req.size = n;
|
|
spip->tx_req.addr_mode = MSP430X_DMA_SRCINCR;
|
|
|
|
spip->rx_req.dest_addr = &dummyrx;
|
|
spip->rx_req.size = n;
|
|
spip->rx_req.addr_mode = 0;
|
|
|
|
init_transfer(spip);
|
|
}
|
|
|
|
/**
|
|
* @brief Receives data from the SPI bus.
|
|
* @details This asynchronous function starts a receive operation.
|
|
* @post At the end of the operation the configured callback is invoked.
|
|
* @note The buffers are organized as uint8_t arrays for data sizes below or
|
|
* equal to 8 bits else it is organized as uint16_t arrays.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
* @param[in] n number of words to receive
|
|
* @param[out] rxbuf the pointer to the receive buffer
|
|
*
|
|
* @notapi
|
|
*/
|
|
void spi_lld_receive(SPIDriver * spip, size_t n, void * rxbuf) {
|
|
|
|
spip->tx_req.source_addr = &dummytx;
|
|
spip->tx_req.size = n;
|
|
spip->tx_req.addr_mode = 0;
|
|
|
|
spip->rx_req.dest_addr = rxbuf;
|
|
spip->rx_req.size = n;
|
|
spip->rx_req.addr_mode = MSP430X_DMA_DSTINCR;
|
|
|
|
init_transfer(spip);
|
|
}
|
|
|
|
/**
|
|
* @brief Exchanges one frame using a polled wait.
|
|
* @details This synchronous function exchanges one frame using a polled
|
|
* synchronization method. This function is useful when exchanging
|
|
* small amount of data on high speed channels, usually in this
|
|
* situation is much more efficient just wait for completion using
|
|
* polling than suspending the thread waiting for an interrupt.
|
|
*
|
|
* @param[in] spip pointer to the @p SPIDriver object
|
|
* @param[in] frame the data frame to send over the SPI bus
|
|
* @return The received data frame from the SPI bus.
|
|
*/
|
|
uint16_t spi_lld_polled_exchange(SPIDriver * spip, uint16_t frame) {
|
|
|
|
osalDbgAssert(!(frame & 0xFF00U), "16-bit transfers not supported");
|
|
|
|
while (!(*(spip->ifg) & UCTXIFG))
|
|
;
|
|
spip->regs->txbuf = frame;
|
|
while (!(*(spip->ifg) & UCRXIFG))
|
|
;
|
|
return spip->regs->rxbuf;
|
|
}
|
|
|
|
#endif /* HAL_USE_SPI == TRUE */
|
|
|
|
/** @} */
|