From 0121007c853a36cebcf78e591437d6c79c964d4b Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Fri, 10 Feb 2023 19:02:46 -0600 Subject: [PATCH] Improve SPI set-up: Don't change the config whilst it is enabled (#1227) Co-authored-by: David Thacher --- .../hardware_spi/include/hardware/spi.h | 15 +++++++++++++++ src/rp2_common/hardware_spi/spi.c | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/src/rp2_common/hardware_spi/include/hardware/spi.h b/src/rp2_common/hardware_spi/include/hardware/spi.h index 699eaa37..41a70e4c 100644 --- a/src/rp2_common/hardware_spi/include/hardware/spi.h +++ b/src/rp2_common/hardware_spi/include/hardware/spi.h @@ -180,6 +180,11 @@ static inline void spi_set_format(spi_inst_t *spi, uint data_bits, spi_cpol_t cp invalid_params_if(SPI, order != SPI_MSB_FIRST); invalid_params_if(SPI, cpol != SPI_CPOL_0 && cpol != SPI_CPOL_1); invalid_params_if(SPI, cpha != SPI_CPHA_0 && cpha != SPI_CPHA_1); + + // Disable the SPI + uint32_t enable_mask = spi_get_hw(spi)->cr1 & SPI_SSPCR1_SSE_BITS; + hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS); + hw_write_masked(&spi_get_hw(spi)->cr0, ((uint)(data_bits - 1)) << SPI_SSPCR0_DSS_LSB | ((uint)cpol) << SPI_SSPCR0_SPO_LSB | @@ -187,6 +192,9 @@ static inline void spi_set_format(spi_inst_t *spi, uint data_bits, spi_cpol_t cp SPI_SSPCR0_DSS_BITS | SPI_SSPCR0_SPO_BITS | SPI_SSPCR0_SPH_BITS); + + // Re-enable the SPI + hw_set_bits(&spi_get_hw(spi)->cr1, enable_mask); } /*! \brief Set SPI master/slave @@ -199,10 +207,17 @@ static inline void spi_set_format(spi_inst_t *spi, uint data_bits, spi_cpol_t cp * \param slave true to set SPI device as a slave device, false for master. */ static inline void spi_set_slave(spi_inst_t *spi, bool slave) { + // Disable the SPI + uint32_t enable_mask = spi_get_hw(spi)->cr1 & SPI_SSPCR1_SSE_BITS; + hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS); + if (slave) hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_MS_BITS); else hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_MS_BITS); + + // Re-enable the SPI + hw_set_bits(&spi_get_hw(spi)->cr1, enable_mask); } // ---------------------------------------------------------------------------- diff --git a/src/rp2_common/hardware_spi/spi.c b/src/rp2_common/hardware_spi/spi.c index 880b5343..035a710e 100644 --- a/src/rp2_common/hardware_spi/spi.c +++ b/src/rp2_common/hardware_spi/spi.c @@ -29,6 +29,7 @@ uint spi_init(spi_inst_t *spi, uint baudrate) { // Finally enable the SPI hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS); + return baud; } @@ -43,6 +44,10 @@ uint spi_set_baudrate(spi_inst_t *spi, uint baudrate) { uint prescale, postdiv; invalid_params_if(SPI, baudrate > freq_in); + // Disable the SPI + uint32_t enable_mask = spi_get_hw(spi)->cr1 & SPI_SSPCR1_SSE_BITS; + hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS); + // Find smallest prescale value which puts output frequency in range of // post-divide. Prescale is an even number from 2 to 254 inclusive. for (prescale = 2; prescale <= 254; prescale += 2) { @@ -61,6 +66,9 @@ uint spi_set_baudrate(spi_inst_t *spi, uint baudrate) { spi_get_hw(spi)->cpsr = prescale; hw_write_masked(&spi_get_hw(spi)->cr0, (postdiv - 1) << SPI_SSPCR0_SCR_LSB, SPI_SSPCR0_SCR_BITS); + // Re-enable the SPI + hw_set_bits(&spi_get_hw(spi)->cr1, enable_mask); + // Return the frequency we were able to achieve return freq_in / (prescale * postdiv); }