/* * Display_SPI.c * * Created: Sun Mar 21 2021 11:51:35 * Author Chris */ #include "Display_SPI.h" #include "Display_Config.h" #include "pico/stdlib.h" #include "hardware/spi.h" #include "hardware/dma.h" #include "hardware/irq.h" #include "pico/binary_info.h" #include "hardware/structs/spi.h" // ============================================================================================ // Defines // ============================================================================================ // Variables static uint _Baudrate; static bool _SPI_Received_Initialized; volatile bool _DMA_Transfer_Complete; static uint _DMA_Transmit_Claim; static dma_channel_config _DMA_Transmit_Channel; // ============================================================================================ // Function Declarations static inline void Display_SPI_CS_Select(); static inline void Display_SPI_CS_Deselect(); /******************************************************************* Interrupt Service Routines *******************************************************************/ void ISR_SPI_DMA_Transmit_Complete() { dma_hw->ints0 = (1u << _DMA_Transmit_Claim); Display_SPI_CS_Deselect(); _DMA_Transfer_Complete = true; } /******************************************************************* Functions *******************************************************************/ void Display_SPI_Init(bool init_spi_receive) { _SPI_Received_Initialized = init_spi_receive; _Baudrate = spi_init(DISPLAY_SPI_PORT, DISPLAY_SPI_BAUDRATE); // Initialize SPI Pinss defined in Config-Struct gpio_set_slew_rate (DISPLAY_SPI_PIN_SCK, GPIO_SLEW_RATE_FAST); gpio_set_slew_rate (DISPLAY_SPI_PIN_MOSI, GPIO_SLEW_RATE_FAST); gpio_set_function (DISPLAY_SPI_PIN_SCK, GPIO_FUNC_SPI); gpio_set_function (DISPLAY_SPI_PIN_MOSI, GPIO_FUNC_SPI); if(_SPI_Received_Initialized == true) { gpio_set_function(DISPLAY_SPI_PIN_MISO, GPIO_FUNC_SPI); } // Initialize CS-Pin as regular GPIO gpio_init (DISPLAY_SPI_PIN_CS); gpio_set_dir (DISPLAY_SPI_PIN_CS, GPIO_OUT); gpio_set_slew_rate (DISPLAY_SPI_PIN_CS, GPIO_SLEW_RATE_FAST); Display_SPI_CS_Deselect(); // Configura DMA Channel for SPI Transmit function _DMA_Transmit_Claim = dma_claim_unused_channel(true); _DMA_Transmit_Channel = dma_channel_get_default_config(_DMA_Transmit_Claim); channel_config_set_transfer_data_size(&_DMA_Transmit_Channel, DMA_SIZE_8); channel_config_set_dreq(&_DMA_Transmit_Channel, spi_get_index(DISPLAY_SPI_PORT) ? DREQ_SPI1_TX : DREQ_SPI0_TX); dma_channel_configure( _DMA_Transmit_Claim, &_DMA_Transmit_Channel, &spi_get_hw(DISPLAY_SPI_PORT)->dr, // Write Address NULL, // Read Address 0, // Element Count (Each element is of size transfer_data_size) false); // DO NOT start directly dma_channel_set_irq0_enabled(_DMA_Transmit_Claim, true); // Configure the processor to run the ISR when DMA IRQ 0 is asserted irq_set_exclusive_handler(DMA_IRQ_0, ISR_SPI_DMA_Transmit_Complete); irq_set_enabled(DMA_IRQ_0, true); _DMA_Transfer_Complete = true; } void Display_SPI_Start_Command(uint8_t command) { DISPLAY_MODE_SET_CMD(); Display_SPI_CS_Select(); spi_write_blocking(DISPLAY_SPI_PORT, &command, 1); DISPLAY_MODE_SET_DATA(); } void Display_SPI_Start_Parameter(uint8_t parameter) { spi_write_blocking(DISPLAY_SPI_PORT, ¶meter, 1); } void Display_SPI_Start_Parameter_Array(uint8_t* parameter_array, uint length) { spi_write_blocking(DISPLAY_SPI_PORT, parameter_array, length); } void Display_SPI_Finish_Command(void) { Display_SPI_CS_Deselect(); } void Display_SPI_Send_Data(uint8_t* data, uint length, bool use_dma) { Display_SPI_CS_Select(); if(use_dma) { if(dma_channel_is_busy(_DMA_Transmit_Claim)) { return; } dma_channel_set_read_addr (_DMA_Transmit_Claim, data , false); dma_channel_set_trans_count (_DMA_Transmit_Claim, length, true); } else { spi_write_blocking(DISPLAY_SPI_PORT, data, length); Display_SPI_CS_Deselect(); } } void Display_SPI_Set_Baudrate(uint baudrate) { _Baudrate = spi_init(DISPLAY_SPI_PORT, baudrate); // This works when changing the Baudrate during runtime // Using the function 'spi_set_baudrate' bring some problems // _Baudrate = spi_set_baudrate(DISPLAY_SPI_PORT, baudrate); } uint Display_SPI_Get_Baudrate(void) { return _Baudrate; } bool Display_SPI_DMA_Transfer_Ongoing(void) { return dma_channel_is_busy(_DMA_Transmit_Claim); } bool Display_SPI_DMA_Transfer_Completed(void) { bool Return_Value = _DMA_Transfer_Complete; _DMA_Transfer_Complete = false; return Return_Value; } bool Display_SPI_Read_Write(const uint8_t* write_data, uint8_t* read_data, uint length_both_buffers) { if(_SPI_Received_Initialized == false) { return false; } int Bytes_Read_Write; Bytes_Read_Write = spi_write_read_blocking(DISPLAY_SPI_PORT, write_data, read_data, length_both_buffers); return (Bytes_Read_Write == length_both_buffers); } /******************************************************************* Internal Functions *******************************************************************/ static inline void Display_SPI_CS_Select() { asm volatile("nop \n nop \n nop"); gpio_put(DISPLAY_SPI_PIN_CS, 0); // Active low asm volatile("nop \n nop \n nop"); } static inline void Display_SPI_CS_Deselect() { asm volatile("nop \n nop \n nop"); gpio_put(DISPLAY_SPI_PIN_CS, 1); asm volatile("nop \n nop \n nop"); }