Fix AVR SPI bugs

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10002 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
Fabio Utzig 2016-12-31 21:46:34 +00:00
parent 91aed554b8
commit 97d615ea05
2 changed files with 66 additions and 111 deletions

View File

@ -30,6 +30,8 @@
/* Driver local definitions. */
/*===========================================================================*/
#define DUMMY_SPI_SEND_VALUE 0xFF
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@ -64,31 +66,19 @@ OSAL_IRQ_HANDLER(SPI_STC_vect) {
SPIDriver *spip = &SPID1;
/* spi_lld_exchange or spi_lld_receive */
if (spip->rxbuf && spip->rxidx < spip->rxbytes) {
spip->rxbuf[spip->rxidx++] = SPDR; // receive
}
/* a new value has arrived, store it if we are interested in it */
if (spip->rxbuf) spip->rxbuf[spip->exidx] = SPDR;
/* rx done and tx done */
if (spip->rxidx >= spip->rxbytes && spip->txidx >= spip->txbytes) {
/* check if we are done */
if (++(spip->exidx) >= spip->exbytes) {
_spi_isr_code(spip);
}
else {
/* spi_lld_exchange, spi_lld_send or spi_lld_ignore */
if (spip->txidx < spip->txbytes) {
if (spip->txbuf) {
SPDR = spip->txbuf[spip->txidx++]; // send
} else {
SPDR = 0; spip->txidx++; // dummy send
}
}
/* spi_lld_receive */
else if (spip->rxidx < spip->rxbytes) { /* rx not done */
SPDR = 0; // dummy send to keep the clock going
} else { /* if not done send the next byte */
if (spip->txbuf) { /* if there is a buffer with values to be send then use it*/
SPDR = spip->txbuf[spip->exidx];
} else { /* if there isn't a buffer with values to be send then send a the dummy value*/
SPDR = DUMMY_SPI_SEND_VALUE;
}
}
OSAL_IRQ_EPILOGUE();
}
#endif /* AVR_SPI_USE_SPI1 */
@ -265,25 +255,6 @@ void spi_lld_unselect(SPIDriver *spip) {
}
/**
* @brief Ignores data on the SPI bus.
* @details This asynchronous function starts the transmission of a series of
* idle words 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 words to be ignored
*
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
spip->rxbuf = spip->txbuf = NULL;
spip->txbytes = n;
spip->txidx = 0;
SPDR = 0;
}
/**
* @brief Exchanges data on the SPI bus.
@ -300,64 +271,16 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
*
* @notapi
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
void spi_lld_exchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf) {
spip->rxbuf = rxbuf;
spip->txbuf = txbuf;
spip->txbytes = spip->rxbytes = n;
spip->txidx = spip->rxidx = 0;
SPDR = spip->txbuf[spip->txidx++];
}
/**
* @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->rxbuf = NULL;
spip->txbuf = txbuf;
spip->txbytes = n;
spip->txidx = 0;
SPDR = spip->txbuf[spip->txidx++];
}
/**
* @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->txbuf = NULL;
spip->rxbuf = rxbuf;
spip->rxbytes = n;
spip->rxidx = 0;
/* Write dummy byte to start communication */
SPDR = 0;
spip->exidx = 0;
spip->exbytes = n;
SPDR = (spip->txbuf ? spip->txbuf[0] : DUMMY_SPI_SEND_VALUE);
}
/**
* @brief Exchanges one frame using a polled wait.
* @details This synchronous function exchanges one frame using a polled

View File

@ -139,7 +139,7 @@ struct SPIDriver {
/**
* @brief Current configuration data.
*/
SPIConfig *config;
const SPIConfig *config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
@ -159,33 +159,68 @@ struct SPIDriver {
/**
* @brief Pointer to the buffer with data to send.
*/
uint8_t *txbuf;
const uint8_t *txbuf;
/**
* @brief Number of bytes of data to send.
*/
size_t txbytes;
/**
* @brief Current index in buffer when sending data.
*/
size_t txidx;
/**
* @brief Pointer to the buffer to put received data.
* @brief Pointer to the buffer to store received data.
*/
uint8_t *rxbuf;
/**
* @brief Number of bytes of data to receive.
* @brief Number of bytes of data to exchange.
*/
size_t rxbytes;
size_t exbytes;
/**
* @brief Current index in buffer when receiving data.
* @brief Current index in buffer when exchanging data.
*/
size_t rxidx;
size_t exidx;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Ignores data on the SPI bus.
* @details This asynchronous function starts the transmission of a series of
* idle words 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 words to be ignored
*
* @notapi
*/
#define spi_lld_ignore(spip, n) spi_lld_exchange(spip, n, NULL, NULL)
/**
* @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
*/
#define spi_lld_send(spip, n, txbuf) spi_lld_exchange(spip, n, txbuf, NULL)
/**
* @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
*/
#define spi_lld_receive(spip, n, rxbuf) spi_lld_exchange(spip, n, NULL, rxbuf)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@ -202,11 +237,8 @@ extern "C" {
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_ignore(SPIDriver *spip, size_t n);
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
#if AVR_SPI_USE_16BIT_POLLED_EXCHANGE
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);