Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added spi_get_baudrate() + some consistency changes #395

Merged
merged 9 commits into from
Jun 1, 2021
Merged
56 changes: 37 additions & 19 deletions src/rp2_common/hardware_spi/include/hardware/spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,23 @@ void spi_deinit(spi_inst_t *spi);
*/
uint spi_set_baudrate(spi_inst_t *spi, uint baudrate);

/*! \brief Get SPI baudrate
* \ingroup hardware_spi
*
* Get SPI baudrate which was set by \see spi_set_baudrate
*
* \param spi SPI instance specifier, either \ref spi0 or \ref spi1
* \return The actual baudrate set
*/
uint spi_get_baudrate(const spi_inst_t *spi);

/*! \brief Convert SPI instance to hardware instance number
* \ingroup hardware_spi
*
* \param spi SPI instance
* \return Number of SPI, 0 or 1.
*/
static inline uint spi_get_index(spi_inst_t *spi) {
static inline uint spi_get_index(const spi_inst_t *spi) {
invalid_params_if(SPI, spi != spi0 && spi != spi1);
return spi == spi1 ? 1 : 0;
}
Expand All @@ -148,6 +158,11 @@ static inline spi_hw_t *spi_get_hw(spi_inst_t *spi) {
return (spi_hw_t *)spi;
}

static inline const spi_hw_t *spi_get_const_hw(const spi_inst_t *spi) {
spi_get_index(spi); // check it is a hw spi
return (spi_hw_t *)spi;
}

/*! \brief Configure SPI
* \ingroup hardware_spi
*
Expand Down Expand Up @@ -197,27 +212,30 @@ static inline void spi_set_slave(spi_inst_t *spi, bool slave) {
* \ingroup hardware_spi
*
* \param spi SPI instance specifier, either \ref spi0 or \ref spi1
* \return 0 if no space is available to write. Non-zero if a write is possible
*
* \note Although the controllers each have a 8 deep TX FIFO, the current HW implementation can only return 0 or 1
* rather than the space available.
* \return false if no space is available to write. True if a write is possible
*/
static inline size_t spi_is_writable(spi_inst_t *spi) {
// PL022 doesn't expose levels directly, so return values are only 0 or 1
return (spi_get_hw(spi)->sr & SPI_SSPSR_TNF_BITS) >> SPI_SSPSR_TNF_LSB;
static inline bool spi_is_writable(const spi_inst_t *spi) {
kilograham marked this conversation as resolved.
Show resolved Hide resolved
return (spi_get_const_hw(spi)->sr & SPI_SSPSR_TNF_BITS);
}
Reneg973 marked this conversation as resolved.
Show resolved Hide resolved

/*! \brief Check whether a read can be done on SPI device
* \ingroup hardware_spi
*
* \param spi SPI instance specifier, either \ref spi0 or \ref spi1
* \return Non-zero if a read is possible i.e. data is present
* \return true if a read is possible i.e. data is present
*/
static inline bool spi_is_readable(const spi_inst_t *spi) {
return (spi_get_const_hw(spi)->sr & SPI_SSPSR_RNE_BITS);
}

/*! \brief Check whether SPI is busy
* \ingroup hardware_spi
*
* \note Although the controllers each have a 8 deep RX FIFO, the current HW implementation can only return 0 or 1
* rather than the data available.
* \param spi SPI instance specifier, either \ref spi0 or \ref spi1
* \return true if SPI is busy
*/
static inline size_t spi_is_readable(spi_inst_t *spi) {
return (spi_get_hw(spi)->sr & SPI_SSPSR_RNE_BITS) >> SPI_SSPSR_RNE_LSB;
static inline bool spi_is_busy(const spi_inst_t *spi) {
return (spi_get_const_hw(spi)->sr & SPI_SSPSR_BSY_BITS);
}

/*! \brief Write/Read to/from an SPI device
Expand All @@ -232,7 +250,7 @@ static inline size_t spi_is_readable(spi_inst_t *spi) {
* \param len Length of BOTH buffers
* \return Number of bytes written/read
*/
int spi_write_read_blocking(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len);
size_t spi_write_read_blocking(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len);

/*! \brief Write to an SPI device, blocking
* \ingroup hardware_spi
Expand All @@ -245,7 +263,7 @@ int spi_write_read_blocking(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, s
* \param len Length of \p src
* \return Number of bytes written/read
*/
int spi_write_blocking(spi_inst_t *spi, const uint8_t *src, size_t len);
size_t spi_write_blocking(spi_inst_t *spi, const uint8_t *src, size_t len);

/*! \brief Read from an SPI device
* \ingroup hardware_spi
Expand All @@ -262,7 +280,7 @@ int spi_write_blocking(spi_inst_t *spi, const uint8_t *src, size_t len);
* \param len Length of buffer \p dst
* \return Number of bytes written/read
*/
int spi_read_blocking(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len);
size_t spi_read_blocking(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len);

// ----------------------------------------------------------------------------
// SPI-specific operations and aliases
Expand All @@ -283,7 +301,7 @@ int spi_read_blocking(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, s
* \param len Length of BOTH buffers in halfwords
* \return Number of halfwords written/read
*/
int spi_write16_read16_blocking(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len);
size_t spi_write16_read16_blocking(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len);

/*! \brief Write to an SPI device
* \ingroup hardware_spi
Expand All @@ -298,7 +316,7 @@ int spi_write16_read16_blocking(spi_inst_t *spi, const uint16_t *src, uint16_t *
* \param len Length of buffers
* \return Number of halfwords written/read
*/
int spi_write16_blocking(spi_inst_t *spi, const uint16_t *src, size_t len);
size_t spi_write16_blocking(spi_inst_t *spi, const uint16_t *src, size_t len);

/*! \brief Read from an SPI device
* \ingroup hardware_spi
Expand All @@ -317,7 +335,7 @@ int spi_write16_blocking(spi_inst_t *spi, const uint16_t *src, size_t len);
* \param len Length of buffer \p dst in halfwords
* \return Number of halfwords written/read
*/
int spi_read16_blocking(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len);
size_t spi_read16_blocking(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len);

#ifdef __cplusplus
}
Expand Down
31 changes: 18 additions & 13 deletions src/rp2_common/hardware_spi/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ uint spi_init(spi_inst_t *spi, uint baudrate) {
spi_set_format(spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
// Always enable DREQ signals -- harmless if DMA is not listening
hw_set_bits(&spi_get_hw(spi)->dmacr, SPI_SSPDMACR_TXDMAE_BITS | SPI_SSPDMACR_RXDMAE_BITS);
spi_set_format(spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
kilograham marked this conversation as resolved.
Show resolved Hide resolved

// Finally enable the SPI
hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
Expand Down Expand Up @@ -66,9 +65,15 @@ uint spi_set_baudrate(spi_inst_t *spi, uint baudrate) {
return freq_in / (prescale * postdiv);
}

uint spi_get_baudrate(const spi_inst_t *spi) {
uint prescale = spi_get_hw(spi)->cpsr;
uint postdiv = ((spi_get_hw(spi)->cr0 & SPI_SSPCR0_SCR_BITS) >> SPI_SSPCR0_SCR_LSB) + 1;
return clock_get_hz(clk_peri) / (prescale * postdiv);
}

// Write len bytes from src to SPI. Simultaneously read len bytes from SPI to dst.
// Note this function is guaranteed to exit in a known amount of time (bits sent * time per bit)
int __not_in_flash_func(spi_write_read_blocking)(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len) {
size_t __not_in_flash_func(spi_write_read_blocking)(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len) {
invalid_params_if(SPI, 0 > (int)len);

// Never have more transfers in flight than will fit into the RX FIFO,
Expand All @@ -87,11 +92,11 @@ int __not_in_flash_func(spi_write_read_blocking)(spi_inst_t *spi, const uint8_t
}
}

return (int)len;
return len;
}

// Write len bytes directly from src to the SPI, and discard any data received back
int __not_in_flash_func(spi_write_blocking)(spi_inst_t *spi, const uint8_t *src, size_t len) {
size_t __not_in_flash_func(spi_write_blocking)(spi_inst_t *spi, const uint8_t *src, size_t len) {
invalid_params_if(SPI, 0 > (int)len);
// Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
// is full, PL022 inhibits RX pushes, and sets a sticky flag on
Expand All @@ -113,14 +118,14 @@ int __not_in_flash_func(spi_write_blocking)(spi_inst_t *spi, const uint8_t *src,
// Don't leave overrun flag set
spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;

return (int)len;
return len;
}

// Read len bytes directly from the SPI to dst.
// repeated_tx_data is output repeatedly on SO as data is read in from SI.
// Generally this can be 0, but some devices require a specific value here,
// e.g. SD cards expect 0xff
int __not_in_flash_func(spi_read_blocking)(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len) {
size_t __not_in_flash_func(spi_read_blocking)(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len) {
invalid_params_if(SPI, 0 > (int)len);
const size_t fifo_depth = 8;
size_t rx_remaining = len, tx_remaining = len;
Expand All @@ -136,11 +141,11 @@ int __not_in_flash_func(spi_read_blocking)(spi_inst_t *spi, uint8_t repeated_tx_
}
}

return (int)len;
return len;
}

// Write len halfwords from src to SPI. Simultaneously read len halfwords from SPI to dst.
int __not_in_flash_func(spi_write16_read16_blocking)(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len) {
size_t __not_in_flash_func(spi_write16_read16_blocking)(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len) {
invalid_params_if(SPI, 0 > (int)len);
// Never have more transfers in flight than will fit into the RX FIFO,
// else FIFO will overflow if this code is heavily interrupted.
Expand All @@ -158,11 +163,11 @@ int __not_in_flash_func(spi_write16_read16_blocking)(spi_inst_t *spi, const uint
}
}

return (int)len;
return len;
}

// Write len bytes directly from src to the SPI, and discard any data received back
int __not_in_flash_func(spi_write16_blocking)(spi_inst_t *spi, const uint16_t *src, size_t len) {
size_t __not_in_flash_func(spi_write16_blocking)(spi_inst_t *spi, const uint16_t *src, size_t len) {
invalid_params_if(SPI, 0 > (int)len);
// Deliberately overflow FIFO, then clean up afterward, to minimise amount
// of APB polling required per halfword
Expand All @@ -182,12 +187,12 @@ int __not_in_flash_func(spi_write16_blocking)(spi_inst_t *spi, const uint16_t *s
// Don't leave overrun flag set
spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;

return (int)len;
return len;
}

// Read len halfwords directly from the SPI to dst.
// repeated_tx_data is output repeatedly on SO as data is read in from SI.
int __not_in_flash_func(spi_read16_blocking)(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len) {
size_t __not_in_flash_func(spi_read16_blocking)(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len) {
invalid_params_if(SPI, 0 > (int)len);
const size_t fifo_depth = 8;
size_t rx_remaining = len, tx_remaining = len;
Expand All @@ -203,5 +208,5 @@ int __not_in_flash_func(spi_read16_blocking)(spi_inst_t *spi, uint16_t repeated_
}
}

return (int)len;
return len;
}