Skip to content
Snippets Groups Projects
Select Git revision
  • 8b0146c142cab3028fe2a2ebbc87196c4d2e087f
  • master default protected
  • develop
  • lurch-patch-2
  • int_frac
  • lurch-patch-1
  • more_board_header_checks
  • best_effort_wfe
  • bi-pins-order-assert
  • 1274-blocking-uart-transmission-appears-to-exit-early
  • iar/develop
  • use_nvic
  • new_pico_rand_api
  • tinyusb-1.5.0
  • lwip_deps
  • tusb_bump2
  • pico_rand
  • misc_headers_issues
  • tusb_bump
  • remove_memset_of_stuct
  • recursive_mutex_cxx
  • 2.0.0
  • 1.5.1
  • 1.5.0
  • 1.4.0
  • 1.3.1
  • 1.3.0
  • 1.2.0
  • 1.1.2
  • 1.1.1
  • 1.1.0
  • 1.0.1
  • 1.0.0
33 results

spi.c

Blame
  • spi.c 8.05 KiB
    /*
     * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
     *
     * SPDX-License-Identifier: BSD-3-Clause
     */
    
    #include "hardware/resets.h"
    #include "hardware/clocks.h"
    #include "hardware/spi.h"
    
    static inline void spi_reset(spi_inst_t *spi) {
        invalid_params_if(SPI, spi != spi0 && spi != spi1);
        reset_block(spi == spi0 ? RESETS_RESET_SPI0_BITS : RESETS_RESET_SPI1_BITS);
    }
    
    static inline void spi_unreset(spi_inst_t *spi) {
        invalid_params_if(SPI, spi != spi0 && spi != spi1);
        unreset_block_wait(spi == spi0 ? RESETS_RESET_SPI0_BITS : RESETS_RESET_SPI1_BITS);
    }
    
    uint spi_init(spi_inst_t *spi, uint baudrate) {
        spi_reset(spi);
        spi_unreset(spi);
    
        uint baud = spi_set_baudrate(spi, 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);
    
        // Finally enable the SPI
        hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
    
        return baud;
    }
    
    void spi_deinit(spi_inst_t *spi) {
        hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
        hw_clear_bits(&spi_get_hw(spi)->dmacr, SPI_SSPDMACR_TXDMAE_BITS | SPI_SSPDMACR_RXDMAE_BITS);
        spi_reset(spi);
    }
    
    uint spi_set_baudrate(spi_inst_t *spi, uint baudrate) {
        uint freq_in = clock_get_hz(clk_peri);
        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) {
            if (freq_in < prescale * 256 * (uint64_t) baudrate)
                break;
        }
        invalid_params_if(SPI, prescale > 254); // Frequency too low
    
        // Find largest post-divide which makes output <= baudrate. Post-divide is
        // an integer in the range 1 to 256 inclusive.
        for (postdiv = 256; postdiv > 1; --postdiv) {
            if (freq_in / (prescale * (postdiv - 1)) > baudrate)
                break;
        }
    
        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);